Compare commits

...

110 Commits

Author SHA1 Message Date
Andreas Hocevar
7527eddbaf Merge pull request #3308 from ahocevar/release-v3.3.0
Release v3.3.0
2015-03-03 22:28:30 +01:00
Andreas Hocevar
6854833fbd Update package version to 3.3.0 2015-03-03 22:27:25 +01:00
Andreas Hocevar
c8b90adfef Changelog for v3.3.0 2015-03-03 22:27:15 +01:00
Andreas Hocevar
d33a45dfa2 Merge pull request #3263 from cwgrant/master
Support ArcGIS Rest Services
2015-03-03 21:40:33 +01:00
Andreas Hocevar
1cec149681 Merge pull request #3295 from sarametz/wmts-getcap
Add RESTful to WMTS GetCapabilities optionsFromCapabilities
2015-03-03 21:13:00 +01:00
Frédéric Junod
a629be0e2e Merge pull request #3304 from fredj/scaleline-padding
Remove scale line inner padding
2015-03-03 17:46:29 +01:00
Frederic Junod
6c32b280f5 Remove scale line inner padding
Fixes #3291
2015-03-03 17:06:41 +01:00
Éric Lemoine
787ab91eef Merge pull request #3296 from elemoine/changes
Add upgrade-notes.md file
2015-03-03 14:28:30 +01:00
Andreas Hocevar
5b539a75bb Merge pull request #3303 from ahocevar/us-ft
Add constant for us-ft units
2015-03-03 14:01:02 +01:00
Andreas Hocevar
a6f80ef4b8 Add constant for us-ft units 2015-03-03 13:51:23 +01:00
Andreas Hocevar
de42334b19 Merge pull request #3018 from bjornharrtell/selectevent
Add SelectEvent to interaction
2015-03-03 12:56:42 +01:00
Björn Harrtell
e4b1d6e1de Add SelectEvent to Select interaction
Fixes
2015-03-03 12:22:01 +01:00
Sara Metz
cadc346de2 Added RESTful to valid requestEncoding values 2015-03-03 12:45:24 +13:00
Andreas Hocevar
927a0a4627 Merge pull request #3301 from bjornharrtell/select-tests
Select interaction unit tests
2015-03-02 21:12:15 +01:00
Björn Harrtell
d9cf8df052 Select interaction unit tests 2015-03-02 19:52:48 +01:00
Bart van den Eijnden
2ff3682eff Update README.MD with stackoverflow 2015-03-02 15:27:03 +01:00
Frédéric Junod
8836dd6e70 Merge pull request #3298 from fredj/source-object
Make ol.source.Source inherit from ol.Object
2015-03-02 15:07:33 +01:00
Frederic Junod
6ab0ed2df7 Make ol.source.Source inherit from ol.Object 2015-03-02 14:48:17 +01:00
Frédéric Junod
8dd3e7ebff Merge pull request #3297 from fredj/wmts-getter
Add getters to ol.source.WMTS
2015-03-02 11:11:12 +01:00
Éric Lemoine
7f71876dad Add upgrade-notes.md file
This file includes upgrade notes for changes to the library that require changes to application code. This file is used by the release manager to fill the "Upgrade notes" section in the v3.x.y.md changelog file.
2015-03-02 10:37:42 +01:00
Frederic Junod
54bea174ff Add new ol.source.WMTS#getMatrixSet api function 2015-03-02 09:51:11 +01:00
Frederic Junod
9d37090e6b Add new ol.source.WMTS#getFormat api function 2015-03-02 09:40:08 +01:00
Frederic Junod
b42a214252 Add new ol.source.WMTS#getVersion api function 2015-03-02 09:40:08 +01:00
Frederic Junod
61d2506970 Add new ol.source.WMTS#getStyle api function 2015-03-02 09:40:08 +01:00
Frederic Junod
3bfbd47fdb Add new ol.source.WMTS#getLayer api function 2015-03-02 09:40:08 +01:00
Éric Lemoine
4f5cc22ba0 Merge pull request #3281 from adube/fix-ie-mousemove-condition
Fix mouseMove event type comparison for IE10-11, pointermove
2015-03-02 09:15:15 +01:00
Andreas Hocevar
a7205d8aec Merge pull request #3293 from ahocevar/icon-opacity
Add missing opacity option for ol.style.IconOptions
2015-03-01 17:11:02 +01:00
Andreas Hocevar
6d0fb4d74e Add missing opacity option for ol.style.IconOptions 2015-03-01 12:07:19 +01:00
Alexandre Dubé
d1185da6b1 Replace mouseMove event condition by pointerMove
The original browser event was used to catch the mousemove event,
but in IE the 'pointermove' event is returned instead. So, instead
of using the original event, we use the map browser event, which
is always 'pointermove'.
2015-02-27 12:14:13 -05:00
Frédéric Junod
6c4b30fa02 Merge pull request #3284 from fredj/jsdoc
Fix jsdoc type for arrays of listening keys
2015-02-26 12:26:17 +01:00
Frederic Junod
e2f8c01c42 Fix jsdoc type for arrays of listening keys 2015-02-26 11:45:15 +01:00
Éric Lemoine
ad7616abb2 Merge pull request #3278 from elemoine/draweventtype
Add goog.provide for ol.DrawEventType
2015-02-26 10:46:12 +01:00
Éric Lemoine
56b08adef7 Add goog.provide for ol.DrawEventType 2015-02-25 21:59:57 +01:00
Éric Lemoine
70162d7889 Merge pull request #3272 from acanimal/3267
Added getter function to return the wrapped source within the cluster
2015-02-25 21:55:04 +01:00
Frédéric Junod
4c1be5967d Merge pull request #3275 from fredj/heatmap-properties
Add ol.layer.Heatmap#blur getter and setter
2015-02-25 17:29:48 +01:00
Frederic Junod
d12cdc336c Create the circle only when the blur and radius are set 2015-02-25 09:16:42 +01:00
Frederic Junod
232f4975c4 Add ol.layer.Heatmap#blur getter and setter 2015-02-25 08:57:04 +01:00
Éric Lemoine
45547eefbe Merge pull request #3142 from sarametz/wmts-getcap
WMTS Get Cap document with updated WMTS.optionsFromCapabilities function
2015-02-25 08:29:40 +01:00
acanimal
086202cfdd Added short description on getSource() method 2015-02-25 07:54:14 +01:00
Frédéric Junod
3079924a3d Merge pull request #3271 from fredj/jsdoc-fixes
[wip] Fix misplaced comment blocks
2015-02-25 07:13:19 +01:00
Tim Schaub
7e812959e7 Merge pull request #3273 from tschaub/unused-function
Remove unused createGetTileIfLoadedFunction function.
2015-02-24 15:35:38 -08:00
Tim Schaub
22aeb3612e Remove unused createGetTileIfLoadedFunction function 2015-02-24 15:06:10 -08:00
Sara Metz
6894bc8444 Add ability to get wmts source from capabilities
Added functionality to create a wmts tilegrid and wmts source from the
capabilities object created from ol.format.WMTSCapabilities.read().
Added tests for these functions and an example.

Also altered the REST url template replacement to be case insensitive
and added tests for this. This is because the spec uses both style
and Style and both of these are used by existing WMTS services.
2015-02-25 09:21:45 +13:00
Frederic Junod
1620a11181 Fix misplaced comment blocks
Found while testing the new google-closure release (v20150126)

The code still compiles with the older (default) version.
2015-02-24 17:13:35 +01:00
Éric Lemoine
18ec8a487f Merge pull request #3270 from elemoine/dragpan-false
Make ol.Overlay autoPan default to false
2015-02-24 15:42:57 +01:00
Éric Lemoine
329edc4ec6 Make ol.Overlay autoPan default to false 2015-02-24 15:14:10 +01:00
Tobias Sauerwein
7a5ad336c6 Merge pull request #3268 from tsauerwein/fix-example-autoPan
Fix autoPan in examples with ol.Overlay on hover
2015-02-24 09:48:22 +01:00
tsauerwein
054dc81485 Disable autoPan in examples
To avoid that the map is panned when showing
overlays on hover.
2015-02-24 09:33:40 +01:00
cwgrant
f63a856741 Add support for ArcGIS Rest Services
Adding a data source to support ArcGIS Map Server and Image Server.
Functionality is similar to the ArcGIS93Rest Layer in OpenLayers 2.
2015-02-23 22:49:29 -05:00
acanimal
eb8a1845a5 Added getter function to return the wrapped source withint the cluster 2015-02-23 22:07:35 +01:00
Tobias Sauerwein
5897cf55aa Merge pull request #3256 from tsauerwein/overlay-panIntoView
Add autoPan option to ol.Overlay
2015-02-23 17:23:00 +01:00
tsauerwein
e46e0f85fb Add autoPan option to ol.Overlay 2015-02-23 17:01:52 +01:00
Tobias Sauerwein
3fbc6fa361 Merge pull request #3261 from adube/fix-extent-foreachcorner
Fix forEachCorner extent, add TopLeft
2015-02-20 16:01:37 +01:00
Alexandre Dubé
e1336e1891 Fix forEachCorner extent, add TopLeft 2015-02-20 08:30:39 -05:00
Frédéric Junod
c30373963e Merge pull request #3260 from fredj/unused-require
Remove unused goog.require
2015-02-20 07:39:56 +01:00
Frederic Junod
96cb3d314f Remove unused goog.require 2015-02-20 07:32:55 +01:00
Tim Schaub
733167c612 Merge pull request #3246 from tschaub/tile-cache
Avoid creating unnecessary images in tile layers.
2015-02-19 10:33:31 -07:00
Frédéric Junod
84cc48a7bf Merge pull request #3254 from fredj/regular-stroke
Use lineCap, lineJoin and miterLimit stroke properties in RegularShape
2015-02-19 13:26:52 +01:00
Frederic Junod
c3d9946924 Use lineCap, lineJoin and miterLimit stroke properties 2015-02-19 12:33:16 +01:00
Frederic Junod
5e712ac88c Use correct renderOptions type 2015-02-19 12:12:00 +01:00
Tim Schaub
9e94308cdc Merge pull request #3252 from tschaub/global-spy
Avoid leaking global listenerSpy.
2015-02-19 00:09:59 -07:00
Tim Schaub
b8e3deb756 Merge pull request #3248 from tschaub/tile-events
Add tile loading events to image tile sources.
2015-02-18 16:16:24 -07:00
Tim Schaub
3e3104bbb1 Avoid leaking global listenerSpy 2015-02-18 16:05:33 -07:00
Tim Schaub
56c5cef3f8 Example style 2015-02-18 15:45:20 -07:00
Tim Schaub
199fcb05e3 Unregister image listeners when disposing of a tile 2015-02-18 15:45:14 -07:00
Tim Schaub
c42af7919e Example docs 2015-02-17 11:22:44 -07:00
Tim Schaub
77d8d48b57 Progress bar for tile loading 2015-02-17 11:22:39 -07:00
Tim Schaub
5cbae8c8f5 Add tile loading events to image tile sources 2015-02-17 11:09:30 -07:00
Tim Schaub
bf35b40b11 Fire change event every time state changes 2015-02-17 11:09:16 -07:00
Tim Schaub
e5432f7cb5 Avoid creating unnecessary images during rendering 2015-02-16 15:11:16 -07:00
Tim Schaub
2cf1fe5552 Create tile cache for all tile sources 2015-02-16 12:22:15 -07:00
Tim Schaub
eb1a46cf7d Merge pull request #3240 from openlayers/v3.2.x
Changes from the v3.2.x branch.
2015-02-14 09:22:47 -07:00
Tim Schaub
d5f18dc120 Merge pull request #3239 from openlayers/release-v3.2.1
Release v3.2.1.
2015-02-13 11:12:45 -07:00
Tim Schaub
0ddae22661 Update package version to 3.2.1 2015-02-13 10:52:02 -07:00
Tim Schaub
fb2506672c Changelog for v3.2.1 2015-02-13 10:51:31 -07:00
Tim Schaub
391ff4eeab Merge pull request #3236 from tschaub/select-fix
Select the uppermost feature.
2015-02-13 09:29:20 -07:00
Frederic Junod
4686dfc0bb Select the uppermost feature 2015-02-13 09:12:26 -07:00
Tim Schaub
a924cc4d11 Merge pull request #3233 from stweil/master
Four small fixes.
2015-02-12 12:39:23 -07:00
Stefan Weil
5c99b6349c Add missing var declaration for local variable flippedFlatPoints
Signed-off-by: Stefan Weil <sw@weilnetz.de>
2015-02-12 17:53:53 +01:00
Stefan Weil
829569c6b5 Fix typo in documentation of function getInfo
Signed-off-by: Stefan Weil <sw@weilnetz.de>
2015-02-12 17:53:53 +01:00
Stefan Weil
e6d342dc96 Replace wrong comma in JavaScript code by semicolon
Signed-off-by: Stefan Weil <sw@weilnetz.de>
2015-02-12 17:53:53 +01:00
Stefan Weil
8bfa1c45e7 examples: Remove wrong semicolon in css code
Signed-off-by: Stefan Weil <sw@weilnetz.de>
2015-02-12 17:53:53 +01:00
Tim Schaub
bfcceac68f Merge pull request #3232 from stweil/master
Fix typos found by codespell.
2015-02-12 09:02:03 -07:00
Stefan Weil
e812f2435e Fix typos found by codespell
Most of them are in comments, some in strings.

Signed-off-by: Stefan Weil <sw@weilnetz.de>
2015-02-12 16:39:55 +01:00
Frédéric Junod
c4ddc62ab4 Merge pull request #3231 from fredj/heatmap-radius
Make ol.layer.Heatmap#radius configurable
2015-02-12 16:36:56 +01:00
Frederic Junod
f117550694 Add a radius input to the heatmap-earthquakes example 2015-02-12 14:41:22 +01:00
Frederic Junod
dfda3e37a4 Add ol.layer.Heatmap#radius getter and setter 2015-02-12 14:16:48 +01:00
Frederic Junod
b5206cb354 Make ol.layer.Heatmap.createCircle_ an instance function 2015-02-12 13:45:44 +01:00
Tim Schaub
90ba1140ac Merge pull request #3225 from tschaub/attributions
Respect attributions passed to TileJSON source.
2015-02-11 10:36:27 -07:00
Tim Schaub
9cea85be80 Merge pull request #3223 from tschaub/tilesize-change
Resize the canvas when the tile size changes.
2015-02-11 10:18:27 -07:00
Tim Schaub
e79211e0c1 Respect attributions passed to TileJSON source 2015-02-11 10:15:29 -07:00
Bart van den Eijnden
ad23a9c9cd Merge pull request #3224 from bartvde/mapquest-getname
Provide the ability to get the layer name from a MapQuest source
2015-02-11 15:56:50 +01:00
Bart van den Eijnden
eafa5419c3 Provide the ability to get the layer name from a MapQuest source 2015-02-11 15:46:02 +01:00
Bart van den Eijnden
b529f0f0a0 Merge pull request #3222 from bartvde/geodesic-measure
Add geodesic option for measure
2015-02-11 13:34:32 +01:00
Bart van den Eijnden
c5c24f209a Add geodesic option for measure 2015-02-11 13:24:23 +01:00
bill-chadwick
0381689fb6 Resize the canvas when the tile size changes 2015-02-10 14:00:23 -07:00
Frédéric Junod
89954ca5fc Merge pull request #3221 from fredj/hectic-select
Select the uppermost feature
2015-02-10 14:03:18 +01:00
Frederic Junod
13f265b4e1 Select the uppermost feature 2015-02-10 09:59:09 +01:00
Tim Schaub
776ffa925f Merge pull request #3211 from photostu/master
Bing https logo fix.
2015-02-08 20:18:19 -07:00
Tim Schaub
ada6b5640a Merge pull request #3215 from tschaub/rendering
Allow reuse of layer rendering code without creating a map.
2015-02-08 17:24:16 -07:00
Tim Schaub
33c197cf16 Layer renderers should not require a map renderer 2015-02-08 07:25:10 -07:00
Tim Schaub
e0f250483d Layer renderers don't need access to the map 2015-02-07 16:56:10 -07:00
Tim Schaub
c4ee8518e1 Use frame state for size 2015-02-07 16:52:48 -07:00
Tim Schaub
d4b7bb7c57 Use frame state for pixel to coord conversion 2015-02-07 16:52:34 -07:00
Tim Schaub
a460cb3983 Fire change instead of calling render on map 2015-02-07 16:46:30 -07:00
Tim Schaub
7f18033171 Make layer renderers observable and re-render on change 2015-02-07 16:42:36 -07:00
Tim Schaub
693ec7706e createLayerRenderer must be implemented by subclass 2015-02-07 16:30:28 -07:00
Tim Schaub
9081682286 Use provided frame state instead of map for pixel to coord conversion 2015-02-07 16:12:39 -07:00
photostu
9247dc9f41 bing logo https
fix syntax to please Travis
2015-02-05 11:21:13 -05:00
photostu
4080e729df bing https logo fix
If https is missing from bing logo uri, replace
2015-02-05 10:34:33 -05:00
93 changed files with 2996 additions and 2816 deletions

View File

@@ -4,8 +4,11 @@
Welcome to [OpenLayers 3](http://openlayers.org/)!
## Examples
Check out the [hosted examples](http://openlayers.org/en/master/examples/), the [workshop](http://openlayers.org/ol3-workshop/) or poke around the evolving [API docs](http://openlayers.org/en/master/apidoc/).
Please don't ask questions in the github issue tracker but use [the mailing list](https://groups.google.com/forum/#!forum/ol3-dev) instead.
## Questions
Please don't ask questions in the github issue tracker but use [stackoverflow with tag openlayers](http://stackoverflow.com/questions/tagged/openlayers) or [the mailing list](https://groups.google.com/forum/#!forum/ol3-dev) instead.
## Contributing
Please see our guide on [contributing](CONTRIBUTING.md) if you're interested in getting involved.

View File

@@ -1095,7 +1095,7 @@ class BeautifulStoneSoup(Tag, SGMLParser):
p = self.tagStack[i]
if (not p or p.name == name) and not isNestable:
#Non-nestable tags get popped to the top or to their
#last occurance.
#last occurrence.
popTo = name
break
if (nestingResetTriggers != None
@@ -1242,14 +1242,14 @@ class BeautifulSoup(BeautifulStoneSoup):
* Tag nesting rules:
Most tags can't be nested at all. For instance, the occurance of
Most tags can't be nested at all. For instance, the occurrence of
a <p> tag should implicitly close the previous <p> tag.
<p>Para1<p>Para2
should be transformed into:
<p>Para1</p><p>Para2
Some tags can be nested arbitrarily. For instance, the occurance
Some tags can be nested arbitrarily. For instance, the occurrence
of a <blockquote> tag should _not_ implicitly close the previous
<blockquote> tag.

View File

@@ -140,7 +140,7 @@
console.log('Capturing ' + lenHtmlFiles + ' example screenshots.');
// The main interval function that is executed regularily and renders a
// The main interval function that is executed regularly and renders a
// page to a file
var interval = setInterval(function() {
if (!loadInProgress && pageindex < lenHtmlFiles) {

View File

@@ -804,7 +804,7 @@ Other less frequently used targets are:
If no target is given, the build-target will be executed.
The above list is not complete, please see the source code for not-mentioned
and only seldomly called targets.
and only seldom called targets.
'''
if __name__ == '__main__':

View File

@@ -0,0 +1,12 @@
## Upgrade notes
### v3.3.0
* The `ol.events.condition.mouseMove` function was replaced by `ol.events.condition.pointerMove` (see [#3281](https://github.com/openlayers/ol3/pull/3281)). For example, if you use `ol.events.condition.mouseMove` as the condition in a `Select` interaction then you now need to use `ol.events.condition.pointerMove`:
```js
var selectInteraction = new ol.interaction.Select({
condition: ol.events.condition.pointerMove
// …
});
```

9
changelog/v3.2.1.md Normal file
View File

@@ -0,0 +1,9 @@
# 3.2.1
## Summary
This is a patch release that fixes a regression with the select interaction in the [3.2.0 release](https://github.com/openlayers/ol3/releases/tag/v3.2.0).
## Changes
* [#3236](https://github.com/openlayers/ol3/pull/3236) - Select the uppermost feature. ([@tschaub](https://github.com/tschaub))

51
changelog/v3.3.0.md Normal file
View File

@@ -0,0 +1,51 @@
## Upgrade notes
* The `ol.events.condition.mouseMove` function was replaced by `ol.events.condition.pointerMove` (see [#3281](https://github.com/openlayers/ol3/pull/3281)). For example, if you use `ol.events.condition.mouseMove` as the condition in a `Select` interaction then you now need to use `ol.events.condition.pointerMove`:
```js
var selectInteraction = new ol.interaction.Select({
condition: ol.events.condition.pointerMove
// …
});
```
## Overview of all changes
* [#3263](https://github.com/openlayers/ol3/pull/3263) - Support ArcGIS Rest Services ([@cwgrant](https://github.com/cwgrant))
* [#3295](https://github.com/openlayers/ol3/pull/3295) - Add RESTful to WMTS GetCapabilities optionsFromCapabilities ([@sarametz](https://github.com/sarametz))
* [#3304](https://github.com/openlayers/ol3/pull/3304) - Remove scale line inner padding ([@fredj](https://github.com/fredj))
* [#3296](https://github.com/openlayers/ol3/pull/3296) - Add upgrade-notes.md file ([@elemoine](https://github.com/elemoine))
* [#3303](https://github.com/openlayers/ol3/pull/3303) - Add constant for us-ft units ([@ahocevar](https://github.com/ahocevar))
* [#3018](https://github.com/openlayers/ol3/pull/3018) - Add SelectEvent to interaction ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3301](https://github.com/openlayers/ol3/pull/3301) - Select interaction unit tests ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3298](https://github.com/openlayers/ol3/pull/3298) - Make ol.source.Source inherit from ol.Object ([@fredj](https://github.com/fredj))
* [#3297](https://github.com/openlayers/ol3/pull/3297) - Add getters to ol.source.WMTS ([@fredj](https://github.com/fredj))
* [#3281](https://github.com/openlayers/ol3/pull/3281) - Fix mouseMove event type comparison for IE10-11, pointermove ([@adube](https://github.com/adube))
* [#3293](https://github.com/openlayers/ol3/pull/3293) - Add missing opacity option for ol.style.IconOptions ([@ahocevar](https://github.com/ahocevar))
* [#3284](https://github.com/openlayers/ol3/pull/3284) - Fix jsdoc type for arrays of listening keys ([@fredj](https://github.com/fredj))
* [#3278](https://github.com/openlayers/ol3/pull/3278) - Add goog.provide for ol.DrawEventType ([@elemoine](https://github.com/elemoine))
* [#3272](https://github.com/openlayers/ol3/pull/3272) - Added getter function to return the wrapped source within the cluster ([@acanimal](https://github.com/acanimal))
* [#3275](https://github.com/openlayers/ol3/pull/3275) - Add ol.layer.Heatmap#blur getter and setter ([@fredj](https://github.com/fredj))
* [#3142](https://github.com/openlayers/ol3/pull/3142) - WMTS Get Cap document with updated WMTS.optionsFromCapabilities function ([@sarametz](https://github.com/sarametz))
* [#3271](https://github.com/openlayers/ol3/pull/3271) - [wip] Fix misplaced comment blocks ([@fredj](https://github.com/fredj))
* [#3273](https://github.com/openlayers/ol3/pull/3273) - Remove unused createGetTileIfLoadedFunction function. ([@tschaub](https://github.com/tschaub))
* [#3270](https://github.com/openlayers/ol3/pull/3270) - Make ol.Overlay autoPan default to false ([@elemoine](https://github.com/elemoine))
* [#3268](https://github.com/openlayers/ol3/pull/3268) - Fix autoPan in examples with ol.Overlay on hover ([@tsauerwein](https://github.com/tsauerwein))
* [#3256](https://github.com/openlayers/ol3/pull/3256) - Add autoPan option to ol.Overlay ([@tsauerwein](https://github.com/tsauerwein))
* [#3261](https://github.com/openlayers/ol3/pull/3261) - Fix forEachCorner extent, add TopLeft ([@adube](https://github.com/adube))
* [#3260](https://github.com/openlayers/ol3/pull/3260) - Remove unused goog.require ([@fredj](https://github.com/fredj))
* [#3246](https://github.com/openlayers/ol3/pull/3246) - Avoid creating unnecessary images in tile layers. ([@tschaub](https://github.com/tschaub))
* [#3254](https://github.com/openlayers/ol3/pull/3254) - Use lineCap, lineJoin and miterLimit stroke properties in RegularShape ([@fredj](https://github.com/fredj))
* [#3252](https://github.com/openlayers/ol3/pull/3252) - Avoid leaking global listenerSpy. ([@tschaub](https://github.com/tschaub))
* [#3248](https://github.com/openlayers/ol3/pull/3248) - Add tile loading events to image tile sources. ([@tschaub](https://github.com/tschaub))
* [#3240](https://github.com/openlayers/ol3/pull/3240) - Changes from the v3.2.x branch. ([@openlayers](https://github.com/openlayers))
* [#3233](https://github.com/openlayers/ol3/pull/3233) - Four small fixes. ([@stweil](https://github.com/stweil))
* [#3232](https://github.com/openlayers/ol3/pull/3232) - Fix typos found by codespell. ([@stweil](https://github.com/stweil))
* [#3231](https://github.com/openlayers/ol3/pull/3231) - Make ol.layer.Heatmap#radius configurable ([@fredj](https://github.com/fredj))
* [#3225](https://github.com/openlayers/ol3/pull/3225) - Respect attributions passed to TileJSON source. ([@tschaub](https://github.com/tschaub))
* [#3223](https://github.com/openlayers/ol3/pull/3223) - Resize the canvas when the tile size changes. ([@tschaub](https://github.com/tschaub))
* [#3224](https://github.com/openlayers/ol3/pull/3224) - Provide the ability to get the layer name from a MapQuest source ([@bartvde](https://github.com/bartvde))
* [#3222](https://github.com/openlayers/ol3/pull/3222) - Add geodesic option for measure ([@bartvde](https://github.com/bartvde))
* [#3221](https://github.com/openlayers/ol3/pull/3221) - Select the uppermost feature ([@fredj](https://github.com/fredj))
* [#3211](https://github.com/openlayers/ol3/pull/3211) - Bing https logo fix. ([@photostu](https://github.com/photostu))
* [#3215](https://github.com/openlayers/ol3/pull/3215) - Allow reuse of layer rendering code without creating a map. ([@tschaub](https://github.com/tschaub))

View File

@@ -21,7 +21,6 @@
font-size: 10px;
text-align: center;
margin: 1px;
padding: 0px 2px;
}
.ol-unsupported {
display: none;

View File

@@ -0,0 +1,51 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
<title>Tiled ArcGIS MapServer example</title>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="./"><img src="../resources/logo.png"> OpenLayers 3 Examples</a>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div id="map" class="map"></div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<h4 id="title">Tiled ArcGIS MapServer example</h4>
<p id="shortdesc">Example of a tiled ArcGIS layer.</p>
<div id="docs">
<p>See the <a href="arcgis-tiled.js" target="_blank">arcgis-tiled.js source</a> to see how this is done.</p>
</div>
<div id="tags">arcgis, tile, tilelayer</div>
</div>
</div>
</div>
<script src="../resources/jquery.min.js" type="text/javascript"></script>
<script src="../resources/example-behaviour.js" type="text/javascript"></script>
<script src="loader.js?id=arcgis-tiled" type="text/javascript"></script>
</body>
</html>

28
examples/arcgis-tiled.js Normal file
View File

@@ -0,0 +1,28 @@
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Tile');
goog.require('ol.source.MapQuest');
goog.require('ol.source.TileArcGISRest');
var url = 'http://sampleserver1.arcgisonline.com/ArcGIS/rest/services/' +
'Specialty/ESRI_StateCityHighway_USA/MapServer';
var layers = [
new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
}),
new ol.layer.Tile({
extent: [-13884991, 2870341, -7455066, 6338219],
source: new ol.source.TileArcGISRest({
url: url
})
})
];
var map = new ol.Map({
layers: layers,
target: 'map',
view: new ol.View({
center: [-10997148, 4569099],
zoom: 4
})
});

File diff suppressed because it is too large Load Diff

View File

@@ -29,7 +29,7 @@
<div class="row-fluid">
<div class="span12">
<div class="span8">
<h4 id="title">Earthquakes heatmap</h4>
<p id="shortdesc">Demonstrates the use of a heatmap layer.</p>
<div id="docs">
@@ -40,8 +40,17 @@
</div>
<div id="tags">heatmap, kml, vector, style</div>
</div>
</div>
<div class="span4">
<form>
<label>radius size</label>
<input id="radius" type="range" min="1" max="50" step="1" value="5"/>
<label>blur size</label>
<input id="blur" type="range" min="1" max="50" step="1" value="15"/>
</form>
</div>
</div>
</div>
<script src="../resources/jquery.min.js" type="text/javascript"></script>

View File

@@ -5,6 +5,8 @@ goog.require('ol.layer.Tile');
goog.require('ol.source.KML');
goog.require('ol.source.Stamen');
var blur = $('#blur');
var radius = $('#radius');
var vector = new ol.layer.Heatmap({
source: new ol.source.KML({
@@ -12,7 +14,8 @@ var vector = new ol.layer.Heatmap({
projection: 'EPSG:3857',
url: 'data/kml/2012_Earthquakes_Mag5.kml'
}),
radius: 5
blur: parseInt(blur.val(), 10),
radius: parseInt(radius.val(), 10)
});
vector.getSource().on('addfeature', function(event) {
@@ -38,3 +41,12 @@ var map = new ol.Map({
zoom: 2
})
});
blur.on('input', function() {
vector.setBlur(parseInt(blur.val(), 10));
});
radius.on('input', function() {
vector.setRadius(parseInt(radius.val(), 10));
});

View File

@@ -75,10 +75,11 @@
<option value="length">Length</option>
<option value="area">Area</option>
</select>
<label class="checkbox"><input type="checkbox" id="geodesic"/>use geodesic measures</label>
</form>
<div id="docs">
<p><i>NOTE: Measure is done in simple way on projected plane. Earth
<p><i>NOTE: If use geodesic measures is not checked, measure is done in simple way on projected plane. Earth
curvature is not taken into account</i></p>
<p>See the <a href="measure.js" target="_blank">measure.js source</a> to see how this is done.</p>
</div>

View File

@@ -1,5 +1,6 @@
goog.require('ol.Map');
goog.require('ol.Overlay');
goog.require('ol.Sphere');
goog.require('ol.View');
goog.require('ol.geom.LineString');
goog.require('ol.geom.Polygon');
@@ -7,6 +8,7 @@ goog.require('ol.interaction');
goog.require('ol.interaction.Draw');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
goog.require('ol.proj');
goog.require('ol.source.MapQuest');
goog.require('ol.source.Vector');
goog.require('ol.style.Circle');
@@ -14,6 +16,9 @@ goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
var wgs84Sphere = new ol.Sphere(6378137);
var raster = new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'})
});
@@ -135,6 +140,7 @@ var map = new ol.Map({
map.on('pointermove', pointerMoveHandler);
var typeSelect = document.getElementById('type');
var geodesicCheckbox = document.getElementById('geodesic');
var draw; // global so we can remove it later
function addInteraction() {
@@ -238,7 +244,19 @@ typeSelect.onchange = function(e) {
* @return {string}
*/
var formatLength = function(line) {
var length = Math.round(line.getLength() * 100) / 100;
var length;
if (geodesicCheckbox.checked) {
var coordinates = line.getCoordinates();
length = 0;
var sourceProj = map.getView().getProjection();
for (var i = 0, ii = coordinates.length - 1; i < ii; ++i) {
var c1 = ol.proj.transform(coordinates[i], sourceProj, 'EPSG:4326');
var c2 = ol.proj.transform(coordinates[i + 1], sourceProj, 'EPSG:4326');
length += wgs84Sphere.haversineDistance(c1, c2);
}
} else {
length = Math.round(line.getLength() * 100) / 100;
}
var output;
if (length > 100) {
output = (Math.round(length / 1000 * 100) / 100) +
@@ -257,7 +275,16 @@ var formatLength = function(line) {
* @return {string}
*/
var formatArea = function(polygon) {
var area = polygon.getArea();
var area;
if (geodesicCheckbox.checked) {
var sourceProj = map.getView().getProjection();
var geom = /** @type {ol.geom.Polygon} */(polygon.clone().transform(
sourceProj, 'EPSG:4326'));
var coordinates = geom.getLinearRing(0).getCoordinates();
area = Math.abs(wgs84Sphere.geodesicArea(coordinates));
} else {
area = polygon.getArea();
}
var output;
if (area > 10000) {
output = (Math.round(area / 1000000 * 100) / 100) +

View File

@@ -29,9 +29,13 @@ closer.onclick = function() {
/**
* Create an overlay to anchor the popup to the map.
*/
var overlay = new ol.Overlay({
element: container
});
var overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
element: container,
autoPan: true,
autoPanAnimation: {
duration: 250
}
}));
/**
@@ -60,7 +64,7 @@ var map = new ol.Map({
/**
* Add a click handler to the map to render the popup.
*/
map.on('click', function(evt) {
map.on('singleclick', function(evt) {
var coordinate = evt.coordinate;
var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
coordinate, 'EPSG:3857', 'EPSG:4326'));

View File

@@ -35,14 +35,16 @@
<h4 id="title">Select features example</h4>
<p id="shortdesc">Example of using the Select interaction. Choose between <code>Single-click</code>, <code>Click</code> and <code>Hover</code> as the event type for selection in the combobox below. When using <code>Single-click</code> or <code>Click</code> you can hold do <code>Shift</code> key to toggle the feature in the selection.</p>
<p>Note: when <code>Single-click</code> is used double-clicks won't select features. This in contrast to <code>Click</code>, where a double-click will both select the feature and zoom the map (because of the <code>DoubleClickZoom</code> interaction). Note that <code>Single-click</code> is less responsive than <code>Click</code> because of the delay it uses to detect double-clicks.</p>
<p>In this example, a listener is registered for the Select interaction's <code>select</code> event in order to update the selection status below.
<form class="form-inline">
<label>Action type &nbsp;</label>
<select id="type">
<option value="none" selected>None</option>
<option value="singleclick">Single-click</option>
<option value="click">Click</option>
<option value="mousemove">Hover</option>
<option value="pointermove">Hover</option>
</select>
<span id="status">&nbsp;0 selected features</span>
</form>
<div id="docs">
<p>See the <a href="select-features.js" target="_blank">select-features.js source</a> to see how this is done.</p>

View File

@@ -38,9 +38,9 @@ var selectClick = new ol.interaction.Select({
condition: ol.events.condition.click
});
// select interaction working on "mousemove"
var selectMouseMove = new ol.interaction.Select({
condition: ol.events.condition.mouseMove
// select interaction working on "pointermove"
var selectPointerMove = new ol.interaction.Select({
condition: ol.events.condition.pointerMove
});
var selectElement = document.getElementById('type');
@@ -54,13 +54,18 @@ var changeInteraction = function() {
select = selectSingleClick;
} else if (value == 'click') {
select = selectClick;
} else if (value == 'mousemove') {
select = selectMouseMove;
} else if (value == 'pointermove') {
select = selectPointerMove;
} else {
select = null;
}
if (select !== null) {
map.addInteraction(select);
select.on('select', function(e) {
$('#status').html('&nbsp;' + e.target.getFeatures().getLength() +
' selected features (last operation selected ' + e.selected.length +
' and deselected ' + e.deselected.length + ' features)');
});
}
};

View File

@@ -0,0 +1,79 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
<title>Tile load events example</title>
<style>
.map {
background: #E0ECED;
}
.wrapper {
position: relative;
}
#progress {
position: absolute;
bottom: 0;
left: 0;
height: 2px;
background: rgba(0, 60, 136, 0.4);
width: 0;
transition: width 250ms;
}
</style>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="./"><img src="../resources/logo.png"> OpenLayers 3 Examples</a>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12 wrapper">
<div id="map" class="map"></div>
<div id="progress"></div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<h4 id="title">Tile load events example</h4>
<p id="shortdesc">Example using tile load events.</p>
<div id="docs">
<p>
Image tile sources fire events related to tile loading. You can
listen for <code>tileloadstart</code>, <code>tileloadend</code>,
and <code>tileloaderror</code> type events to monitor tile loading
progress. This example registers listeners for these events and
renders a tile loading progress bar at the bottom of the map.
</p>
<p>
See the <a href="tile-load-events.js" target="_blank">tile-load-events.js source</a>
for more detail on how this is done.
</p>
</div>
<div id="tags">tile, events, loading</div>
</div>
</div>
</div>
<script src="../resources/jquery.min.js" type="text/javascript"></script>
<script src="../resources/example-behaviour.js" type="text/javascript"></script>
<script src="loader.js?id=tile-load-events" type="text/javascript"></script>
</body>
</html>

View File

@@ -0,0 +1,104 @@
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Tile');
goog.require('ol.source.TileJSON');
/**
* Renders a progress bar.
* @param {Element} el The target element.
* @constructor
*/
function Progress(el) {
this.el = el;
this.loading = 0;
this.loaded = 0;
}
/**
* Increment the count of loading tiles.
*/
Progress.prototype.addLoading = function() {
if (this.loading === 0) {
this.show();
}
++this.loading;
this.update();
};
/**
* Increment the count of loaded tiles.
*/
Progress.prototype.addLoaded = function() {
setTimeout(function() {
++this.loaded;
this.update();
}.bind(this), 100);
};
/**
* Update the progress bar.
*/
Progress.prototype.update = function() {
var width = (this.loaded / this.loading * 100).toFixed(1) + '%';
this.el.style.width = width;
if (this.loading === this.loaded) {
this.loading = 0;
this.loaded = 0;
setTimeout(this.hide.bind(this), 500);
}
};
/**
* Show the progress bar.
*/
Progress.prototype.show = function() {
this.el.style.visibility = 'visible';
};
/**
* Hide the progress bar.
*/
Progress.prototype.hide = function() {
if (this.loading === this.loaded) {
this.el.style.visibility = 'hidden';
this.el.style.width = 0;
}
};
var progress = new Progress(document.getElementById('progress'));
var source = new ol.source.TileJSON({
url: 'http://api.tiles.mapbox.com/v3/mapbox.world-bright.jsonp',
crossOrigin: 'anonymous'
});
source.on('tileloadstart', function(event) {
progress.addLoading();
});
source.on('tileloadend', function(event) {
progress.addLoaded();
});
source.on('tileloaderror', function(event) {
progress.addLoaded();
});
var map = new ol.Map({
logo: false,
layers: [
new ol.layer.Tile({source: source})
],
renderer: exampleNS.getRendererFromQueryString(),
target: 'map',
view: new ol.View({
center: [0, 0],
zoom: 2
})
});

View File

@@ -12,7 +12,7 @@
h2 {
font-size: 1.5em;
line-height: 15px;
};
}
.scale-cnt {
margin: 5px;

View File

@@ -0,0 +1,51 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="chrome=1">
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
<link rel="stylesheet" href="../css/ol.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap.min.css" type="text/css">
<link rel="stylesheet" href="../resources/layout.css" type="text/css">
<link rel="stylesheet" href="../resources/bootstrap/css/bootstrap-responsive.min.css" type="text/css">
<title>WMTS Layer example from capabilities </title>
</head>
<body>
<div class="navbar navbar-inverse navbar-fixed-top">
<div class="navbar-inner">
<div class="container">
<a class="brand" href="./"><img src="../resources/logo.png"> OpenLayers 3 Examples</a>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row-fluid">
<div class="span12">
<div id="map" class="map"></div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<h4 id="title">WMTS Capabilities example</h4>
<p id="shortdesc">Example of a WMTS source created from a WMTS capabilities document.</p>
<div id="docs">
<p>See the <a href="wmts-layer-from-capabilities.js" target="_blank">wmts-layer-from-capabilities.js source</a> to see how this is done.</p>
</div>
<div id="tags">wmts, capabilities, getcapabilities</div>
</div>
</div>
</div>
<script src="../resources/jquery.min.js" type="text/javascript"></script>
<script src="../resources/example-behaviour.js" type="text/javascript"></script>
<script src="loader.js?id=wmts-layer-from-capabilities" type="text/javascript"></script>
</body>
</html>

View File

@@ -0,0 +1,37 @@
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.format.WMTSCapabilities');
goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.OSM');
goog.require('ol.source.WMTS');
var parser = new ol.format.WMTSCapabilities();
var map;
$.ajax('data/WMTSCapabilities.xml').then(function(response) {
var result = parser.read(response);
var options = ol.source.WMTS.optionsFromCapabilities(result,
{layer: 'layer-7328', matrixSet: 'EPSG:3857'});
var projection = ol.proj.get('EPSG:3857');
var projectionExtent = projection.getExtent();
map = new ol.Map({
layers: [
new ol.layer.Tile({
source: new ol.source.OSM(),
opacity: 0.7
}),
new ol.layer.Tile({
opacity: 1,
extent: projectionExtent,
source: new ol.source.WMTS(options)
})
],
target: 'map',
view: new ol.View({
center: [19412406.33, -5050500.21],
zoom: 5
})
});
});

View File

@@ -210,6 +210,17 @@ oli.render.Event.prototype.vectorContext;
oli.source;
/**
* @interface
*/
oli.source.TileEvent = function() {};
/**
* @type {ol.Tile}
*/
oli.source.TileEvent.prototype.tile;
/**
* @interface

View File

@@ -310,7 +310,10 @@ olx.MapOptions.prototype.view;
* position: (ol.Coordinate|undefined),
* positioning: (ol.OverlayPositioning|string|undefined),
* stopEvent: (boolean|undefined),
* insertFirst: (boolean|undefined)}}
* insertFirst: (boolean|undefined),
* autoPan: (boolean|undefined),
* autoPanAnimation: (olx.animation.PanOptions|undefined),
* autoPanMargin: (number|undefined)}}
* @api stable
*/
olx.OverlayOptions;
@@ -376,6 +379,35 @@ olx.OverlayOptions.prototype.stopEvent;
olx.OverlayOptions.prototype.insertFirst;
/**
* If set to `true` the map is panned when calling `setPosition`, so that the
* overlay is entirely visible in the current viewport.
* The default is `false`.
* @type {boolean|undefined}
* @api
*/
olx.OverlayOptions.prototype.autoPan;
/**
* The options used to create a `ol.animation.pan` animation. This animation
* is only used when `autoPan` is enabled. By default the default options for
* `ol.animation.pan` are used. If set to `null` the panning is not animated.
* @type {olx.animation.PanOptions|undefined}
* @api
*/
olx.OverlayOptions.prototype.autoPanAnimation;
/**
* The margin (in pixels) between the overlay and the borders of the map when
* autopanning. The default is `20`.
* @type {number|undefined}
* @api
*/
olx.OverlayOptions.prototype.autoPanMargin;
/**
* Object literal with config options for the projection.
* @typedef {{code: string,
@@ -4978,9 +5010,97 @@ olx.source.ServerVectorOptions.prototype.logo;
*/
olx.source.ServerVectorOptions.prototype.projection;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* params: (Object.<string, *>|undefined),
* logo: (string|olx.LogoOptions|undefined),
* tileGrid: (ol.tilegrid.TileGrid|undefined),
* projection: ol.proj.ProjectionLike,
* tileLoadFunction: (ol.TileLoadFunctionType|undefined),
* url: (string|undefined),
* urls: (Array.<string>|undefined)}}
* @api
*/
olx.source.TileArcGISRestOptions;
/**
* @typedef {{crossOrigin: (null|string|undefined),
* Attributions.
* @type {Array.<ol.Attribution>|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.attributions;
/**
* ArcGIS Rest parameters. This field is optional. Service defaults will be
* used for any fields not specified. `FORMAT` is `PNG32` by default. `F` is `IMAGE` by
* default. `TRANSPARENT` is `true` by default. `BBOX, `SIZE`, `BBOXSR`,
* and `IMAGESR` will be set dynamically. Set `LAYERS` to
* override the default service layer visibility. See
* {@link http://resources.arcgis.com/en/help/arcgis-rest-api/index.html#/Export_Map/02r3000000v7000000/}
* for further reference.
* @type {Object.<string,*>|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.params;
/**
* Logo.
* @type {string|olx.LogoOptions|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.logo;
/**
* Tile grid. Base this on the resolutions, tilesize and extent supported by the
* server.
* If this is not defined, a default grid will be used: if there is a projection
* extent, the grid will be based on that; if not, a grid based on a global
* extent with origin at 0,0 will be used.
* @type {ol.tilegrid.TileGrid|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.tileGrid;
/**
* Projection.
* @type {ol.proj.ProjectionLike}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.projection;
/**
* Optional function to load a tile given a URL.
* @type {ol.TileLoadFunctionType|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.tileLoadFunction;
/**
* ArcGIS Rest service URL for a Map Service or Image Service. The
* url should include /MapServer or /ImageServer.
* @type {string|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.url;
/**
* ArcGIS Rest service urls. Use this instead of `url` when the ArcGIS Service supports multiple
* urls for export requests.
* @type {Array.<string>|undefined}
* @api
*/
olx.source.TileArcGISRestOptions.prototype.urls;
/**
* @typedef {{attributions: (Array.<ol.Attribution>|undefined),
* crossOrigin: (null|string|undefined),
* tileLoadFunction: (ol.TileLoadFunctionType|undefined),
* url: string,
* wrapX: (boolean|undefined)}}
@@ -4989,6 +5109,16 @@ olx.source.ServerVectorOptions.prototype.projection;
olx.source.TileJSONOptions;
/**
* Optional attributions for the source. If provided, these will be used
* instead of any attribution data advertised by the server. If not provided,
* any attributions advertised by the server will be used.
* @type {Array.<ol.Attribution>|undefined}
* @api stable
*/
olx.source.TileJSONOptions.prototype.attributions;
/**
* The `crossOrigin` attribute for loaded images. Note that you must provide a
* `crossOrigin` value if you are using the WebGL renderer or if you want to
@@ -5789,6 +5919,7 @@ olx.style.FillOptions.prototype.color;
* img: (Image|undefined),
* offset: (Array.<number>|undefined),
* offsetOrigin: (ol.style.IconOrigin|undefined),
* opacity: (number|undefined),
* scale: (number|undefined),
* snapToPixel: (boolean|undefined),
* rotateWithView: (boolean|undefined),
@@ -5878,6 +6009,14 @@ olx.style.IconOptions.prototype.offset;
olx.style.IconOptions.prototype.offsetOrigin;
/**
* Opacity of the icon. Default is `1`.
* @type {number|undefined}
* @api
*/
olx.style.IconOptions.prototype.opacity;
/**
* Scale.
* @type {number|undefined}

View File

@@ -1,6 +1,6 @@
{
"name": "openlayers",
"version": "3.2.0",
"version": "3.3.0",
"description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [
"map",

View File

@@ -216,7 +216,7 @@ ol.Collection.prototype.push = function(elem) {
/**
* Removes the first occurence of elem from the collection.
* Removes the first occurrence of elem from the collection.
* @param {T} elem Element.
* @return {T|undefined} The removed element or undefined if elem was not found.
* @api stable

View File

@@ -159,7 +159,7 @@ ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres) {
* 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} Formated coordinate.
* @return {string} Formatted coordinate.
* @api stable
*/
ol.coordinate.format = function(coordinate, template, opt_fractionDigits) {

View File

@@ -28,7 +28,7 @@ ol.DeviceOrientationProperty = {
*
* Many new computers, and especially mobile phones
* and tablets, provide hardware support for device orientation. Web
* developers targetting mobile devices will be especially interested in this
* developers targeting mobile devices will be especially interested in this
* class.
*
* Device orientation data are relative to a common starting point. For mobile

View File

@@ -158,7 +158,7 @@ ol.dom.setOpacity = function(element, value) {
var alpha;
if (goog.userAgent.VERSION == '8.0') {
regex = /progid:DXImageTransform\.Microsoft\.Alpha\(.*?\)/i,
regex = /progid:DXImageTransform\.Microsoft\.Alpha\(.*?\)/i;
alpha = 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' +
(value * 100) + ')';
} else {
@@ -298,3 +298,35 @@ ol.dom.transformElement2D =
// 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;
};

View File

@@ -66,16 +66,6 @@ ol.events.condition.click = function(mapBrowserEvent) {
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the browser event is a `mousemove` event.
* @api
*/
ol.events.condition.mouseMove = function(mapBrowserEvent) {
return mapBrowserEvent.originalEvent.type == 'mousemove';
};
/**
* Always false.
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
@@ -86,6 +76,16 @@ ol.events.condition.mouseMove = function(mapBrowserEvent) {
ol.events.condition.never = goog.functions.FALSE;
/**
* @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';
};
/**
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the event is a map `singleclick` event.

View File

@@ -463,7 +463,7 @@ ol.extent.forEachCorner = function(extent, callback, opt_this) {
if (val) {
return val;
}
val = callback.call(opt_this, ol.extent.getBottomRight(extent));
val = callback.call(opt_this, ol.extent.getTopLeft(extent));
if (val) {
return val;
}

View File

@@ -51,7 +51,7 @@ ol.Image = function(extent, resolution, pixelRatio, attributions, src,
/**
* @private
* @type {Array.<number>}
* @type {Array.<goog.events.Key>}
*/
this.imageListenerKeys_ = null;

View File

@@ -50,7 +50,7 @@ ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) {
/**
* @private
* @type {Array.<number>}
* @type {Array.<goog.events.Key>}
*/
this.imageListenerKeys_ = null;
@@ -64,6 +64,15 @@ ol.ImageTile = function(tileCoord, state, src, crossOrigin, tileLoadFunction) {
goog.inherits(ol.ImageTile, ol.Tile);
/**
* @inheritDoc
*/
ol.ImageTile.prototype.disposeInternal = function() {
this.unlistenImage_();
goog.base(this, 'disposeInternal');
};
/**
* @inheritDoc
* @api
@@ -136,6 +145,7 @@ ol.ImageTile.prototype.handleImageLoad_ = function() {
ol.ImageTile.prototype.load = function() {
if (this.state == ol.TileState.IDLE) {
this.state = ol.TileState.LOADING;
this.changed();
goog.asserts.assert(goog.isNull(this.imageListenerKeys_));
this.imageListenerKeys_ = [
goog.events.listenOnce(this.image_, goog.events.EventType.ERROR,

View File

@@ -1,4 +1,5 @@
goog.provide('ol.DrawEvent');
goog.provide('ol.DrawEventType');
goog.provide('ol.interaction.Draw');
goog.require('goog.asserts');

View File

@@ -3,6 +3,7 @@ goog.provide('ol.interaction.Select');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.functions');
goog.require('ol.CollectionEventType');
goog.require('ol.Feature');
@@ -13,6 +14,51 @@ goog.require('ol.interaction.Interaction');
goog.require('ol.style.Style');
/**
* @enum {string}
*/
ol.SelectEventType = {
/**
* Triggered when feature(s) has been (de)selected.
* @event ol.SelectEvent#select
* @api
*/
SELECT: 'select'
};
/**
* @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.
* @extends {goog.events.Event}
* @constructor
*/
ol.SelectEvent = function(type, selected, deselected) {
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;
};
goog.inherits(ol.SelectEvent, goog.events.Event);
/**
* @classdesc
@@ -140,6 +186,7 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
var features = this.featureOverlay_.getFeatures();
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
@@ -152,18 +199,19 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
function(feature, layer) {
selected.push(feature);
}, undefined, this.layerFilter_);
if (selected.length > 0 &&
features.getLength() == 1 &&
features.item(0) == selected[selected.length - 1]) {
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();
}
if (this.multi_) {
features.extend(selected);
} else if (selected.length > 0) {
features.push(selected[selected.length - 1]);
features.push(selected[0]);
}
}
} else {
@@ -190,8 +238,15 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
features.remove(deselected[i]);
}
features.extend(selected);
if (selected.length > 0 || deselected.length > 0) {
change = true;
}
}
return ol.events.condition.mouseMove(mapBrowserEvent);
if (change) {
this.dispatchEvent(
new ol.SelectEvent(ol.SelectEventType.SELECT, selected, deselected));
}
return ol.events.condition.pointerMove(mapBrowserEvent);
};

View File

@@ -16,7 +16,9 @@ goog.require('ol.style.Style');
* @enum {string}
*/
ol.layer.HeatmapLayerProperty = {
GRADIENT: 'gradient'
BLUR: 'blur',
GRADIENT: 'gradient',
RADIUS: 'radius'
};
@@ -52,6 +54,24 @@ ol.layer.Heatmap = function(opt_options) {
*/
this.gradient_ = null;
/**
* @private
* @type {number}
*/
this.shadow_ = goog.isDef(options.shadow) ? 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);
@@ -59,15 +79,16 @@ ol.layer.Heatmap = function(opt_options) {
this.setGradient(goog.isDef(options.gradient) ?
options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT);
var circle = ol.layer.Heatmap.createCircle_(
goog.isDef(options.radius) ? options.radius : 8,
goog.isDef(options.blur) ? options.blur : 15,
goog.isDef(options.shadow) ? options.shadow : 250);
this.setBlur(goog.isDef(options.blur) ? options.blur : 15);
/**
* @type {Array.<Array.<ol.style.Style>>}
*/
var styleCache = new Array(256);
this.setRadius(goog.isDef(options.radius) ? 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 = goog.isDef(options.weight) ? options.weight : 'weight';
var weightFunction;
@@ -80,25 +101,27 @@ ol.layer.Heatmap = function(opt_options) {
}
goog.asserts.assert(goog.isFunction(weightFunction));
this.setStyle(function(feature, resolution) {
this.setStyle(goog.bind(function(feature, resolution) {
goog.asserts.assert(!goog.isNull(this.styleCache_));
goog.asserts.assert(goog.isDef(this.circleImage_));
var weight = weightFunction(feature);
var opacity = goog.isDef(weight) ? goog.math.clamp(weight, 0, 1) : 1;
// cast to 8 bits
var index = (255 * opacity) | 0;
var style = styleCache[index];
var style = this.styleCache_[index];
if (!goog.isDef(style)) {
style = [
new ol.style.Style({
image: new ol.style.Icon({
opacity: opacity,
src: circle
src: this.circleImage_
})
})
];
styleCache[index] = style;
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.
@@ -142,27 +165,41 @@ ol.layer.Heatmap.createGradient_ = function(colors) {
/**
* @param {number} radius Radius size in pixel.
* @param {number} blur Blur size in pixel.
* @param {number} shadow Shadow offset size in pixel.
* @return {string}
* @private
*/
ol.layer.Heatmap.createCircle_ = function(radius, blur, shadow) {
ol.layer.Heatmap.prototype.createCircle_ = function() {
var radius = this.getRadius();
var blur = this.getBlur();
goog.asserts.assert(goog.isDef(radius) && goog.isDef(blur));
var halfSize = radius + blur + 1;
var size = 2 * halfSize;
var context = ol.dom.createCanvasContext2D(size, size);
context.shadowOffsetX = context.shadowOffsetY = shadow;
context.shadowOffsetX = context.shadowOffsetY = this.shadow_;
context.shadowBlur = blur;
context.shadowColor = '#000';
context.beginPath();
var center = halfSize - shadow;
var center = halfSize - this.shadow_;
context.arc(center, center, radius, 0, Math.PI * 2, true);
context.fill();
return context.canvas.toDataURL();
};
/**
* @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(
ol.layer.Heatmap.prototype,
'getBlur',
ol.layer.Heatmap.prototype.getBlur);
/**
* @return {Array.<string>} Colors.
* @api
@@ -178,6 +215,20 @@ goog.exportProperty(
ol.layer.Heatmap.prototype.getGradient);
/**
* @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(
ol.layer.Heatmap.prototype,
'getRadius',
ol.layer.Heatmap.prototype.getRadius);
/**
* @private
*/
@@ -186,12 +237,23 @@ ol.layer.Heatmap.prototype.handleGradientChanged_ = function() {
};
/**
* @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);
goog.asserts.assert(!goog.isNull(this.gradient_));
var context = event.context;
var canvas = context.canvas;
var image = context.getImageData(0, 0, canvas.width, canvas.height);
@@ -209,6 +271,20 @@ ol.layer.Heatmap.prototype.handleRender_ = function(event) {
};
/**
* @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(
ol.layer.Heatmap.prototype,
'setBlur',
ol.layer.Heatmap.prototype.setBlur);
/**
* @param {Array.<string>} colors Gradient.
* @api
@@ -221,3 +297,17 @@ goog.exportProperty(
ol.layer.Heatmap.prototype,
'setGradient',
ol.layer.Heatmap.prototype.setGradient);
/**
* @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(
ol.layer.Heatmap.prototype,
'setRadius',
ol.layer.Heatmap.prototype.setRadius);

View File

@@ -1,4 +1,4 @@
// FIXME recheck layer/map projection compatability when projection changes
// FIXME recheck layer/map projection compatibility when projection changes
// FIXME layer renderers should skip when they can't reproject
// FIXME add tilt and height?

View File

@@ -156,7 +156,7 @@ ol.MapBrowserEventHandler = function(map) {
this.dragging_ = false;
/**
* @type {Array.<number>}
* @type {Array.<goog.events.Key>}
* @private
*/
this.dragListenerKeys_ = null;

View File

@@ -11,6 +11,9 @@ 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');
/**
@@ -90,6 +93,26 @@ ol.Overlay = function(options) {
this.element_ = goog.dom.createElement(goog.dom.TagName.DIV);
this.element_.style.position = 'absolute';
/**
* @private
* @type {boolean}
*/
this.autoPan_ = goog.isDef(options.autoPan) ? options.autoPan : false;
/**
* @private
* @type {olx.animation.PanOptions}
*/
this.autoPanAnimation_ = goog.isDef(options.autoPanAnimation) ?
options.autoPanAnimation : /** @type {olx.animation.PanOptions} */ ({});
/**
* @private
* @type {number}
*/
this.autoPanMargin_ = goog.isDef(options.autoPanMargin) ?
options.autoPanMargin : 20;
/**
* @private
* @type {{bottom_: string,
@@ -291,6 +314,9 @@ ol.Overlay.prototype.handleOffsetChanged = function() {
*/
ol.Overlay.prototype.handlePositionChanged = function() {
this.updatePixelPosition_();
if (goog.isDef(this.get(ol.OverlayProperty.POSITION)) && this.autoPan_) {
this.panIntoView_();
}
};
@@ -364,6 +390,89 @@ goog.exportProperty(
ol.Overlay.prototype.setPosition);
/**
* 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_);
var map = this.getMap();
if (!goog.isDef(map) || goog.isNull(map.getTargetElement())) {
return;
}
var mapRect = this.getRect_(map.getTargetElement(), map.getSize());
var element = this.getElement();
goog.asserts.assert(!goog.isNull(element) && goog.isDef(element));
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(goog.isDef(center));
var centerPx = map.getPixelFromCoordinate(center);
var newCenterPx = [
centerPx[0] + delta[0],
centerPx[1] + delta[1]
];
if (!goog.isNull(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(!goog.isNull(element) && goog.isDef(element));
goog.asserts.assert(goog.isDef(size));
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

View File

@@ -187,7 +187,7 @@ ol.pointer.TouchSource.prototype.touchToPointer_ =
// Touch identifiers can start at 0.
// Add 2 to the touch identifier for compatibility.
e.pointerId = inTouch.identifier + 2;
// TODO: check if this is neccessary?
// TODO: check if this is necessary?
//e.target = findTarget(e);
e.bubbles = true;
e.cancelable = true;

View File

@@ -32,7 +32,8 @@ ol.proj.Units = {
DEGREES: 'degrees',
FEET: 'ft',
METERS: 'm',
PIXELS: 'pixels'
PIXELS: 'pixels',
USFEET: 'us-ft'
};
@@ -47,6 +48,7 @@ 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;

View File

@@ -9,7 +9,6 @@ goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Image');
goog.require('ol.proj');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.source.ImageVector');
goog.require('ol.vec.Mat4');
@@ -19,12 +18,11 @@ goog.require('ol.vec.Mat4');
/**
* @constructor
* @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Image} imageLayer Single image layer.
*/
ol.renderer.canvas.ImageLayer = function(mapRenderer, imageLayer) {
ol.renderer.canvas.ImageLayer = function(imageLayer) {
goog.base(this, mapRenderer, imageLayer);
goog.base(this, imageLayer);
/**
* @private
@@ -88,7 +86,9 @@ ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel =
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 = this.getMap().getCoordinateFromPixel(pixel);
var coordinate = pixel.slice();
ol.vec.Mat4.multVec2(
frameState.pixelToCoordinateMatrix, coordinate, coordinate);
var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, goog.functions.TRUE, this);

View File

@@ -17,12 +17,11 @@ goog.require('ol.vec.Mat4');
/**
* @constructor
* @extends {ol.renderer.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer.
*/
ol.renderer.canvas.Layer = function(mapRenderer, layer) {
ol.renderer.canvas.Layer = function(layer) {
goog.base(this, mapRenderer, layer);
goog.base(this, layer);
/**
* @private

View File

@@ -77,11 +77,11 @@ goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map);
*/
ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) {
if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) {
return new ol.renderer.canvas.ImageLayer(this, layer);
return new ol.renderer.canvas.ImageLayer(layer);
} else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {
return new ol.renderer.canvas.TileLayer(this, layer);
return new ol.renderer.canvas.TileLayer(layer);
} else if (ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {
return new ol.renderer.canvas.VectorLayer(this, layer);
return new ol.renderer.canvas.VectorLayer(layer);
} else {
goog.asserts.fail();
return null;

View File

@@ -13,7 +13,6 @@ goog.require('ol.TileState');
goog.require('ol.dom');
goog.require('ol.extent');
goog.require('ol.layer.Tile');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.canvas.Layer');
goog.require('ol.tilecoord');
goog.require('ol.vec.Mat4');
@@ -23,12 +22,11 @@ goog.require('ol.vec.Mat4');
/**
* @constructor
* @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Tile} tileLayer Tile layer.
*/
ol.renderer.canvas.TileLayer = function(mapRenderer, tileLayer) {
ol.renderer.canvas.TileLayer = function(tileLayer) {
goog.base(this, mapRenderer, tileLayer);
goog.base(this, tileLayer);
/**
* @private
@@ -72,6 +70,12 @@ ol.renderer.canvas.TileLayer = function(mapRenderer, tileLayer) {
*/
this.renderedCanvasZ_ = NaN;
/**
* @private
* @type {number}
*/
this.renderedTileSize_ = NaN;
/**
* @private
* @type {ol.TileRange}
@@ -230,9 +234,11 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame =
context = this.context_;
if (this.canvasSize_[0] < canvasWidth ||
this.canvasSize_[1] < canvasHeight ||
this.renderedTileSize_ !== tilePixelSize ||
(this.canvasTooBig_ && (this.canvasSize_[0] > canvasWidth ||
this.canvasSize_[1] > canvasHeight))) {
// Canvas is too small, resize it. We never shrink the canvas, unless
// 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;
@@ -259,6 +265,7 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame =
minY = tileRange.minY -
Math.floor((canvasTileRangeHeight - tileRange.getHeight()) / 2);
this.renderedCanvasZ_ = z;
this.renderedTileSize_ = tilePixelSize;
this.renderedCanvasTileRange_ = new ol.TileRange(
minX, minX + canvasTileRangeWidth - 1,
minY, minY + canvasTileRangeHeight - 1);
@@ -280,11 +287,7 @@ ol.renderer.canvas.TileLayer.prototype.prepareFrame =
/** @type {Array.<ol.Tile>} */
var tilesToClear = [];
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) {
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var findLoadedTiles = this.createLoadedTileFinder(tileSource, tilesToDrawByZ);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();

View File

@@ -17,12 +17,11 @@ goog.require('ol.renderer.vector');
/**
* @constructor
* @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} vectorLayer Vector layer.
*/
ol.renderer.canvas.VectorLayer = function(mapRenderer, vectorLayer) {
ol.renderer.canvas.VectorLayer = function(vectorLayer) {
goog.base(this, mapRenderer, vectorLayer);
goog.base(this, vectorLayer);
/**
* @private

View File

@@ -18,14 +18,13 @@ goog.require('ol.vec.Mat4');
/**
* @constructor
* @extends {ol.renderer.dom.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Image} imageLayer Image layer.
*/
ol.renderer.dom.ImageLayer = function(mapRenderer, imageLayer) {
ol.renderer.dom.ImageLayer = function(imageLayer) {
var target = goog.dom.createElement(goog.dom.TagName.DIV);
target.style.position = 'absolute';
goog.base(this, mapRenderer, imageLayer, target);
goog.base(this, imageLayer, target);
/**
* The last rendered image.

View File

@@ -8,13 +8,12 @@ goog.require('ol.renderer.Layer');
/**
* @constructor
* @extends {ol.renderer.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer.
* @param {!Element} target Target.
*/
ol.renderer.dom.Layer = function(mapRenderer, layer, target) {
ol.renderer.dom.Layer = function(layer, target) {
goog.base(this, mapRenderer, layer);
goog.base(this, layer);
/**
* @type {!Element}

View File

@@ -112,12 +112,12 @@ ol.renderer.dom.Map.prototype.disposeInternal = function() {
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(this, layer);
layerRenderer = new ol.renderer.dom.ImageLayer(layer);
} else if (ol.ENABLE_TILE && layer instanceof ol.layer.Tile) {
layerRenderer = new ol.renderer.dom.TileLayer(this, layer);
layerRenderer = new ol.renderer.dom.TileLayer(layer);
} else if (!(ol.LEGACY_IE_SUPPORT && ol.IS_LEGACY_IE) &&
ol.ENABLE_VECTOR && layer instanceof ol.layer.Vector) {
layerRenderer = new ol.renderer.dom.VectorLayer(this, layer);
layerRenderer = new ol.renderer.dom.VectorLayer(layer);
} else {
goog.asserts.fail();
return null;

View File

@@ -30,10 +30,9 @@ goog.require('ol.vec.Mat4');
/**
* @constructor
* @extends {ol.renderer.dom.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Tile} tileLayer Tile layer.
*/
ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer) {
ol.renderer.dom.TileLayer = function(tileLayer) {
var target = goog.dom.createElement(goog.dom.TagName.DIV);
target.style.position = 'absolute';
@@ -44,7 +43,7 @@ ol.renderer.dom.TileLayer = function(mapRenderer, tileLayer) {
target.style.height = '100%';
}
goog.base(this, mapRenderer, tileLayer, target);
goog.base(this, tileLayer, target);
/**
* @private
@@ -129,11 +128,7 @@ ol.renderer.dom.TileLayer.prototype.prepareFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) {
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED;
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var findLoadedTiles = this.createLoadedTileFinder(tileSource, tilesToDrawByZ);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();

View File

@@ -21,10 +21,9 @@ goog.require('ol.vec.Mat4');
/**
* @constructor
* @extends {ol.renderer.dom.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} vectorLayer Vector layer.
*/
ol.renderer.dom.VectorLayer = function(mapRenderer, vectorLayer) {
ol.renderer.dom.VectorLayer = function(vectorLayer) {
/**
* @private
@@ -39,7 +38,7 @@ ol.renderer.dom.VectorLayer = function(mapRenderer, vectorLayer) {
target.style.maxWidth = 'none';
target.style.position = 'absolute';
goog.base(this, mapRenderer, vectorLayer, target);
goog.base(this, vectorLayer, target);
/**
* @private

View File

@@ -6,6 +6,7 @@ goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('goog.functions');
goog.require('ol.ImageState');
goog.require('ol.Observable');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.layer.Layer');
@@ -13,27 +14,21 @@ 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 {goog.Disposable}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @extends {ol.Observable}
* @param {ol.layer.Layer} layer Layer.
* @suppress {checkStructDictInheritance}
* @struct
*/
ol.renderer.Layer = function(mapRenderer, layer) {
ol.renderer.Layer = function(layer) {
goog.base(this);
/**
* @private
* @type {ol.renderer.Map}
*/
this.mapRenderer_ = mapRenderer;
/**
* @private
* @type {ol.layer.Layer}
@@ -42,7 +37,7 @@ ol.renderer.Layer = function(mapRenderer, layer) {
};
goog.inherits(ol.renderer.Layer, goog.Disposable);
goog.inherits(ol.renderer.Layer, ol.Observable);
/**
@@ -67,7 +62,10 @@ ol.renderer.Layer.prototype.forEachFeatureAtCoordinate = goog.nullFunction;
*/
ol.renderer.Layer.prototype.forEachLayerAtPixel =
function(pixel, frameState, callback, thisArg) {
var coordinate = this.getMap().getCoordinateFromPixel(pixel);
var coordinate = pixel.slice();
ol.vec.Mat4.multVec2(
frameState.pixelToCoordinateMatrix, coordinate, coordinate);
var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, goog.functions.TRUE, this);
@@ -87,6 +85,34 @@ ol.renderer.Layer.prototype.forEachLayerAtPixel =
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 {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, 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(zoom, tileRange, function(tile) {
if (!tiles[zoom]) {
tiles[zoom] = {};
}
tiles[zoom][tile.tileCoord.toString()] = tile;
});
});
};
/**
* @protected
* @return {ol.layer.Layer} Layer.
@@ -96,24 +122,6 @@ ol.renderer.Layer.prototype.getLayer = function() {
};
/**
* @protected
* @return {ol.Map} Map.
*/
ol.renderer.Layer.prototype.getMap = function() {
return this.mapRenderer_.getMap();
};
/**
* @protected
* @return {ol.renderer.Map} Map renderer.
*/
ol.renderer.Layer.prototype.getMapRenderer = function() {
return this.mapRenderer_;
};
/**
* Handle changes in image state.
* @param {goog.events.Event} event Image change event.
@@ -161,7 +169,7 @@ ol.renderer.Layer.prototype.loadImage = function(image) {
ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() {
var layer = this.getLayer();
if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) {
this.getMap().render();
this.changed();
}
};
@@ -251,32 +259,6 @@ ol.renderer.Layer.prototype.updateUsedTiles =
};
/**
* @param {function(ol.Tile): boolean} isLoadedFunction Function to
* determine if the tile is loaded.
* @param {ol.source.Tile} tileSource Tile source.
* @param {number} pixelRatio Pixel ratio.
* @param {ol.proj.Projection} projection Projection.
* @protected
* @return {function(number, number, number): ol.Tile} Returns a tile if it is
* loaded.
*/
ol.renderer.Layer.prototype.createGetTileIfLoadedFunction =
function(isLoadedFunction, tileSource, pixelRatio, projection) {
return (
/**
* @param {number} z Z.
* @param {number} x X.
* @param {number} y Y.
* @return {ol.Tile} Tile.
*/
function(z, x, y) {
var tile = tileSource.getTile(z, x, y, pixelRatio, projection);
return isLoadedFunction(tile) ? tile : null;
});
};
/**
* @param {ol.Coordinate} center Center.
* @param {number} resolution Resolution.

View File

@@ -4,6 +4,8 @@ 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');
@@ -56,6 +58,12 @@ ol.renderer.Map = function(container, map) {
*/
this.layerRenderers_ = {};
/**
* @private
* @type {Object.<string, goog.events.Key>}
*/
this.layerRendererListeners_ = {};
};
goog.inherits(ol.renderer.Map, goog.Disposable);
@@ -84,9 +92,7 @@ ol.renderer.Map.prototype.calculateMatrices2D = function(frameState) {
* @protected
* @return {ol.renderer.Layer} layerRenderer Layer renderer.
*/
ol.renderer.Map.prototype.createLayerRenderer = function(layer) {
return new ol.renderer.Layer(this, layer);
};
ol.renderer.Map.prototype.createLayerRenderer = goog.abstractMethod;
/**
@@ -256,6 +262,10 @@ ol.renderer.Map.prototype.getLayerRenderer = function(layer) {
} 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;
}
};
@@ -295,6 +305,15 @@ ol.renderer.Map.prototype.getMap = function() {
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.
@@ -304,6 +323,11 @@ ol.renderer.Map.prototype.removeLayerRendererByKey_ = function(layerKey) {
goog.asserts.assert(layerKey in this.layerRenderers_);
var layerRenderer = this.layerRenderers_[layerKey];
delete this.layerRenderers_[layerKey];
goog.asserts.assert(layerKey in this.layerRendererListeners_);
goog.events.unlistenByKey(this.layerRendererListeners_[layerKey]);
delete this.layerRendererListeners_[layerKey];
return layerRenderer;
};

View File

@@ -22,7 +22,7 @@ goog.require('ol.webgl.Context');
/**
* @constructor
* @extends {ol.renderer.webgl.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
* @param {ol.layer.Image} imageLayer Tile layer.
*/
ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) {
@@ -64,7 +64,7 @@ ol.renderer.webgl.ImageLayer.prototype.createTexture_ = function(image) {
// http://learningwebgl.com/blog/?p=2101
var imageElement = image.getImage();
var gl = this.getWebGLMapRenderer().getGL();
var gl = this.mapRenderer.getGL();
return ol.webgl.Context.createTexture(
gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE);
@@ -100,7 +100,7 @@ ol.renderer.webgl.ImageLayer.prototype.forEachFeatureAtCoordinate =
ol.renderer.webgl.ImageLayer.prototype.prepareFrame =
function(frameState, layerState, context) {
var gl = this.getWebGLMapRenderer().getGL();
var gl = this.mapRenderer.getGL();
var viewState = frameState.viewState;
var viewCenter = viewState.center;
@@ -155,7 +155,7 @@ ol.renderer.webgl.ImageLayer.prototype.prepareFrame =
if (!goog.isNull(image)) {
goog.asserts.assert(!goog.isNull(texture));
var canvas = this.getWebGLMapRenderer().getContext().getCanvas();
var canvas = this.mapRenderer.getContext().getCanvas();
this.updateProjectionMatrix_(canvas.width, canvas.height,
viewCenter, viewResolution, viewRotation, image.getExtent());
@@ -235,7 +235,9 @@ ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel =
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 = this.getMap().getCoordinateFromPixel(pixel);
var coordinate = pixel.slice();
ol.vec.Mat4.multVec2(
frameState.pixelToCoordinateMatrix, coordinate, coordinate);
var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, goog.functions.TRUE, this);

View File

@@ -18,12 +18,18 @@ goog.require('ol.webgl.Context');
/**
* @constructor
* @extends {ol.renderer.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer.
*/
ol.renderer.webgl.Layer = function(mapRenderer, layer) {
goog.base(this, mapRenderer, layer);
goog.base(this, layer);
/**
* @protected
* @type {ol.renderer.webgl.Map}
*/
this.mapRenderer = mapRenderer;
/**
* @private
@@ -96,8 +102,7 @@ goog.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer);
ol.renderer.webgl.Layer.prototype.bindFramebuffer =
function(frameState, framebufferDimension) {
var mapRenderer = this.getWebGLMapRenderer();
var gl = mapRenderer.getGL();
var gl = this.mapRenderer.getGL();
if (!goog.isDef(this.framebufferDimension) ||
this.framebufferDimension != framebufferDimension) {
@@ -248,15 +253,6 @@ ol.renderer.webgl.Layer.prototype.dispatchComposeEvent_ =
};
/**
* @protected
* @return {ol.renderer.webgl.Map} MapRenderer.
*/
ol.renderer.webgl.Layer.prototype.getWebGLMapRenderer = function() {
return /** @type {ol.renderer.webgl.Map} */ (this.getMapRenderer());
};
/**
* @return {!goog.vec.Mat4.Number} Matrix.
*/

View File

@@ -25,7 +25,7 @@ goog.require('ol.webgl.Buffer');
/**
* @constructor
* @extends {ol.renderer.webgl.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
* @param {ol.layer.Tile} tileLayer Tile layer.
*/
ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {
@@ -88,13 +88,47 @@ goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer);
* @inheritDoc
*/
ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {
var mapRenderer = this.getWebGLMapRenderer();
var context = mapRenderer.getContext();
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 {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, 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(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
*/
@@ -110,7 +144,7 @@ ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() {
ol.renderer.webgl.TileLayer.prototype.prepareFrame =
function(frameState, layerState, context) {
var mapRenderer = this.getWebGLMapRenderer();
var mapRenderer = this.mapRenderer;
var gl = context.getGL();
var viewState = frameState.viewState;
@@ -191,12 +225,8 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame =
var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {};
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) {
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED &&
mapRenderer.isTileTextureLoaded(tile);
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var findLoadedTiles = this.createLoadedTileFinder(
tileSource, tilesToDrawByZ);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
var allTilesLoaded = true;
@@ -337,11 +367,10 @@ ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel =
if (goog.isNull(this.framebuffer)) {
return undefined;
}
var mapSize = this.getMap().getSize();
var pixelOnMapScaled = [
pixel[0] / mapSize[0],
(mapSize[1] - pixel[1]) / mapSize[1]];
pixel[0] / frameState.size[0],
(frameState.size[1] - pixel[1]) / frameState.size[1]];
var pixelOnFrameBufferScaled = [0, 0];
ol.vec.Mat4.multVec2(
@@ -350,7 +379,7 @@ ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel =
pixelOnFrameBufferScaled[0] * this.framebufferDimension,
pixelOnFrameBufferScaled[1] * this.framebufferDimension];
var gl = this.getWebGLMapRenderer().getContext().getGL();
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,

View File

@@ -9,13 +9,14 @@ 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.Map} mapRenderer Map renderer.
* @param {ol.renderer.webgl.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} vectorLayer Vector layer.
*/
ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) {
@@ -94,8 +95,7 @@ ol.renderer.webgl.VectorLayer.prototype.composeFrame =
ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() {
var replayGroup = this.replayGroup_;
if (!goog.isNull(replayGroup)) {
var mapRenderer = this.getWebGLMapRenderer();
var context = mapRenderer.getContext();
var context = this.mapRenderer.getContext();
replayGroup.getDeleteResourcesFunction(context)();
this.replayGroup_ = null;
}
@@ -111,8 +111,7 @@ ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate =
if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) {
return undefined;
} else {
var mapRenderer = this.getWebGLMapRenderer();
var context = mapRenderer.getContext();
var context = this.mapRenderer.getContext();
var viewState = frameState.viewState;
var layer = this.getLayer();
var layerState = this.layerState_;
@@ -147,8 +146,7 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate =
if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) {
return false;
} else {
var mapRenderer = this.getWebGLMapRenderer();
var context = mapRenderer.getContext();
var context = this.mapRenderer.getContext();
var viewState = frameState.viewState;
var layerState = this.layerState_;
return this.replayGroup_.hasFeatureAtCoordinate(coordinate,
@@ -165,7 +163,9 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate =
*/
ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel =
function(pixel, frameState, callback, thisArg) {
var coordinate = this.getMap().getCoordinateFromPixel(pixel);
var coordinate = pixel.slice();
ol.vec.Mat4.multVec2(
frameState.pixelToCoordinateMatrix, coordinate, coordinate);
var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState);
if (hasFeature) {

View File

@@ -98,6 +98,9 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse =
}
var brandLogoUri = response.brandLogoUri;
if (ol.IS_HTTPS && 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);

View File

@@ -59,6 +59,16 @@ ol.source.Cluster = function(options) {
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
*/

View File

@@ -178,6 +178,7 @@ ol.source.ImageVector.prototype.forEachFeatureAtCoordinate = function(
/**
* Get a reference to the wrapped source.
* @return {ol.source.Vector} Source.
* @api
*/

View File

@@ -24,10 +24,17 @@ ol.source.MapQuest = function(opt_options) {
var layerConfig = ol.source.MapQuestConfig[options.layer];
/**
* Layer. Possible values are `osm`, `sat`, and `hyb`.
* @type {string}
* @private
*/
this.layer_ = options.layer;
var protocol = ol.IS_HTTPS ? 'https:' : 'http:';
var url = goog.isDef(options.url) ? options.url :
protocol + '//otile{1-4}-s.mqcdn.com/tiles/1.0.0/' +
options.layer + '/{z}/{x}/{y}.jpg';
this.layer_ + '/{z}/{x}/{y}.jpg';
goog.base(this, {
attributions: layerConfig.attributions,
@@ -81,3 +88,12 @@ ol.source.MapQuestConfig = {
]
}
};
/**
* @return {string} Layer.
* @api
*/
ol.source.MapQuest.prototype.getLayer = function() {
return this.layer_;
};

View File

@@ -3,7 +3,7 @@ goog.provide('ol.source.State');
goog.require('goog.events.EventType');
goog.require('ol.Attribution');
goog.require('ol.Observable');
goog.require('ol.Object');
goog.require('ol.proj');
@@ -37,7 +37,7 @@ ol.source.SourceOptions;
* Base class for {@link ol.layer.Layer} sources.
*
* @constructor
* @extends {ol.Observable}
* @extends {ol.Object}
* @fires change Triggered when the state of the source changes.
* @param {ol.source.SourceOptions} options Source options.
* @api stable
@@ -73,7 +73,7 @@ ol.source.Source = function(options) {
options.state : ol.source.State.READY;
};
goog.inherits(ol.source.Source, ol.Observable);
goog.inherits(ol.source.Source, ol.Object);
/**

View File

@@ -0,0 +1,218 @@
goog.provide('ol.source.TileArcGISRest');
goog.require('goog.array');
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.TileUrlFunction');
goog.require('ol.extent');
goog.require('ol.proj');
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 = goog.isDef(opt_options) ? opt_options : {};
var params = goog.isDef(options.params) ? options.params : {};
goog.base(this, {
attributions: options.attributions,
logo: options.logo,
projection: options.projection,
tileGrid: options.tileGrid,
tileLoadFunction: options.tileLoadFunction,
tileUrlFunction: goog.bind(this.tileUrlFunction_, this)
});
var urls = options.urls;
if (!goog.isDef(urls) && goog.isDef(options.url)) {
urls = ol.TileUrlFunction.expandUrl(options.url);
}
/**
* @private
* @type {!Array.<string>}
*/
this.urls_ = goog.isDefAndNotNull(urls) ? urls : [];
/**
* @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 {number} 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 (goog.array.isEmpty(urls)) {
return undefined;
}
// ArcGIS Server only wants the numeric portion of the projection ID.
var srid = projection.getCode().split(':').pop();
params['SIZE'] = tileSize + ',' + tileSize;
params['BBOX'] = tileExtent.join(',');
params['BBOXSR'] = srid;
params['IMAGESR'] = srid;
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);
};
/**
* Return the URLs used for this ArcGIS source.
* @return {!Array.<string>} URLs.
* @api stable
*/
ol.source.TileArcGISRest.prototype.getUrls = function() {
return this.urls_;
};
/**
* @param {string|undefined} url URL.
* @api stable
*/
ol.source.TileArcGISRest.prototype.setUrl = function(url) {
var urls = goog.isDef(url) ? ol.TileUrlFunction.expandUrl(url) : null;
this.setUrls(urls);
};
/**
* @param {Array.<string>|undefined} urls URLs.
* @api stable
*/
ol.source.TileArcGISRest.prototype.setUrls = function(urls) {
this.urls_ = goog.isDefAndNotNull(urls) ? urls : [];
this.changed();
};
/**
* @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 (goog.isNull(tileGrid)) {
tileGrid = this.getTileGridForProjection(projection);
}
if (tileGrid.getResolutions().length <= tileCoord[0]) {
return undefined;
}
var tileExtent = tileGrid.getTileCoordExtent(
tileCoord, this.tmpExtent_);
var tileSize = tileGrid.getTileSize(tileCoord[0]);
if (pixelRatio != 1) {
tileSize = (tileSize * pixelRatio + 0.5) | 0;
}
// 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();
};

View File

@@ -1,7 +1,6 @@
goog.provide('ol.source.TileDebug');
goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileCoord');
goog.require('ol.TileState');
goog.require('ol.dom');
@@ -89,42 +88,20 @@ ol.source.TileDebug = function(options) {
tileGrid: options.tileGrid
});
/**
* @private
* @type {ol.TileCache}
*/
this.tileCache_ = new ol.TileCache();
};
goog.inherits(ol.source.TileDebug, ol.source.Tile);
/**
* @inheritDoc
*/
ol.source.TileDebug.prototype.canExpireCache = function() {
return this.tileCache_.canExpireCache();
};
/**
* @inheritDoc
*/
ol.source.TileDebug.prototype.expireCache = function(usedTiles) {
this.tileCache_.expireCache(usedTiles);
};
/**
* @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));
if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey));
} else {
var tile = new ol.DebugTile_([z, x, y], this.tileGrid);
this.tileCache_.set(tileCoordKey, tile);
this.tileCache.set(tileCoordKey, tile);
return tile;
}
};

View File

@@ -1,8 +1,9 @@
goog.provide('ol.source.TileImage');
goog.require('goog.asserts');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.ImageTile');
goog.require('ol.TileCache');
goog.require('ol.TileCoord');
goog.require('ol.TileLoadFunctionType');
goog.require('ol.TileState');
@@ -17,6 +18,7 @@ goog.require('ol.source.Tile');
* Base class for sources providing images divided into a tile grid.
*
* @constructor
* @fires ol.source.TileEvent
* @extends {ol.source.Tile}
* @param {olx.source.TileImageOptions} options Image tile options.
* @api
@@ -50,12 +52,6 @@ ol.source.TileImage = function(options) {
this.crossOrigin =
goog.isDef(options.crossOrigin) ? options.crossOrigin : null;
/**
* @protected
* @type {ol.TileCache}
*/
this.tileCache = new ol.TileCache();
/**
* @protected
* @type {ol.TileLoadFunctionType}
@@ -84,22 +80,6 @@ ol.source.TileImage.defaultTileLoadFunction = function(imageTile, src) {
};
/**
* @inheritDoc
*/
ol.source.TileImage.prototype.canExpireCache = function() {
return this.tileCache.canExpireCache();
};
/**
* @inheritDoc
*/
ol.source.TileImage.prototype.expireCache = function(usedTiles) {
this.tileCache.expireCache(usedTiles);
};
/**
* @inheritDoc
*/
@@ -118,6 +98,9 @@ ol.source.TileImage.prototype.getTile =
goog.isDef(tileUrl) ? tileUrl : '',
this.crossOrigin,
this.tileLoadFunction);
goog.events.listen(tile, goog.events.EventType.CHANGE,
this.handleTileChange_, false, this);
this.tileCache.set(tileCoordKey, tile);
return tile;
}
@@ -142,6 +125,30 @@ ol.source.TileImage.prototype.getTileUrlFunction = function() {
};
/**
* Handle tile change events.
* @param {goog.events.Event} event Event.
* @private
*/
ol.source.TileImage.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;
}
};
/**
* @param {ol.TileLoadFunctionType} tileLoadFunction Tile load function.
* @api

View File

@@ -33,6 +33,7 @@ goog.require('ol.tilegrid.XYZ');
ol.source.TileJSON = function(options) {
goog.base(this, {
attributions: options.attributions,
crossOrigin: options.crossOrigin,
projection: ol.proj.get('EPSG:3857'),
state: ol.source.State.LOADING,
@@ -87,7 +88,8 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
}),
ol.TileUrlFunction.createFromTemplates(tileJSON.tiles));
if (goog.isDef(tileJSON.attribution)) {
if (goog.isDef(tileJSON.attribution) &&
goog.isNull(this.getAttributions())) {
var attributionExtent = goog.isDef(extent) ?
extent : epsg4326Projection.getExtent();
/** @type {Object.<string, Array.<ol.TileRange>>} */

View File

@@ -1,10 +1,12 @@
goog.provide('ol.source.Tile');
goog.provide('ol.source.TileOptions');
goog.require('goog.functions');
goog.require('goog.events.Event');
goog.require('ol.Attribution');
goog.require('ol.Extent');
goog.require('ol.TileCache');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.source.Source');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid');
@@ -64,6 +66,12 @@ ol.source.Tile = function(options) {
*/
this.tileGrid = goog.isDef(options.tileGrid) ? options.tileGrid : null;
/**
* @protected
* @type {ol.TileCache}
*/
this.tileCache = new ol.TileCache();
};
goog.inherits(ol.source.Tile, ol.source.Source);
@@ -71,51 +79,47 @@ goog.inherits(ol.source.Tile, ol.source.Source);
/**
* @return {boolean} Can expire cache.
*/
ol.source.Tile.prototype.canExpireCache = goog.functions.FALSE;
ol.source.Tile.prototype.canExpireCache = function() {
return this.tileCache.canExpireCache();
};
/**
* @param {Object.<string, ol.TileRange>} usedTiles Used tiles.
*/
ol.source.Tile.prototype.expireCache = goog.abstractMethod;
ol.source.Tile.prototype.expireCache = function(usedTiles) {
this.tileCache.expireCache(usedTiles);
};
/**
* Look for loaded tiles over a given tile range and zoom level. Adds
* properties to the provided lookup representing key/tile pairs for already
* loaded tiles.
*
* @param {Object.<number, Object.<string, ol.Tile>>} loadedTilesByZ A lookup of
* loaded tiles by zoom level.
* @param {function(number, number, number): ol.Tile} getTileIfLoaded A function
* that returns the tile only if it is fully loaded.
* @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.findLoadedTiles = function(loadedTilesByZ,
getTileIfLoaded, z, tileRange) {
// FIXME this could be more efficient about filling partial holes
var fullyCovered = true;
var tile, tileCoordKey, x, y;
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
ol.source.Tile.prototype.forEachLoadedTile = function(z, tileRange, callback) {
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);
if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) {
continue;
}
tile = getTileIfLoaded(z, x, y);
if (!goog.isNull(tile)) {
if (!loadedTilesByZ[z]) {
loadedTilesByZ[z] = {};
loaded = false;
if (this.tileCache.containsKey(tileCoordKey)) {
tile = /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
loaded = tile.getState() === ol.TileState.LOADED;
if (loaded) {
loaded = (callback(tile) !== false);
}
loadedTilesByZ[z][tileCoordKey] = tile;
} else {
fullyCovered = false;
}
if (!loaded) {
covered = false;
}
}
}
return fullyCovered;
return covered;
};
@@ -206,3 +210,59 @@ ol.source.Tile.prototype.getTilePixelSize =
* @param {number} y Tile coordinate y.
*/
ol.source.Tile.prototype.useTile = goog.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
*/
TILELOADSTART: 'tileloadstart',
/**
* Triggered when a tile finishes loading.
* @event ol.source.TileEvent#tileloadend
* @api
*/
TILELOADEND: 'tileloadend',
/**
* Triggered if tile loading results in an error.
* @event ol.source.TileEvent#tileloaderror
* @api
*/
TILELOADERROR: 'tileloaderror'
};

View File

@@ -7,7 +7,6 @@ goog.require('goog.events.EventType');
goog.require('goog.net.Jsonp');
goog.require('ol.Attribution');
goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileState');
goog.require('ol.TileUrlFunction');
goog.require('ol.extent');
@@ -46,12 +45,6 @@ ol.source.TileUTFGrid = function(options) {
*/
this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction;
/**
* @private
* @type {!ol.TileCache}
*/
this.tileCache_ = new ol.TileCache();
/**
* @private
* @type {string|undefined}
@@ -64,22 +57,6 @@ ol.source.TileUTFGrid = function(options) {
goog.inherits(ol.source.TileUTFGrid, ol.source.Tile);
/**
* @inheritDoc
*/
ol.source.TileUTFGrid.prototype.canExpireCache = function() {
return this.tileCache_.canExpireCache();
};
/**
* @inheritDoc
*/
ol.source.TileUTFGrid.prototype.expireCache = function(usedTiles) {
this.tileCache_.expireCache(usedTiles);
};
/**
* @return {string|undefined} The template from TileJSON.
* @api
@@ -195,8 +172,8 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
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));
if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
} else {
goog.asserts.assert(projection);
var tileCoord = [z, x, y];
@@ -207,7 +184,7 @@ ol.source.TileUTFGrid.prototype.getTile =
goog.isDef(tileUrl) ? tileUrl : '',
this.tileGrid.getTileCoordExtent(tileCoord),
this.preemptive_);
this.tileCache_.set(tileCoordKey, tile);
this.tileCache.set(tileCoordKey, tile);
return tile;
}
};
@@ -218,8 +195,8 @@ ol.source.TileUTFGrid.prototype.getTile =
*/
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);
if (this.tileCache.containsKey(tileCoordKey)) {
this.tileCache.get(tileCoordKey);
}
};

View File

@@ -5,6 +5,7 @@ goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.uri.utils');
goog.require('ol.TileUrlFunction');
goog.require('ol.TileUrlFunctionType');
@@ -40,8 +41,17 @@ ol.source.WMTS = function(options) {
// TODO: add support for TileMatrixLimits
var version = goog.isDef(options.version) ? options.version : '1.0.0';
var format = goog.isDef(options.format) ? options.format : 'image/jpeg';
/**
* @private
* @type {string}
*/
this.version_ = goog.isDef(options.version) ? options.version : '1.0.0';
/**
* @private
* @type {string}
*/
this.format_ = goog.isDef(options.format) ? options.format : 'image/jpeg';
/**
* @private
@@ -56,6 +66,24 @@ ol.source.WMTS = function(options) {
this.coordKeyPrefix_ = '';
this.resetCoordKeyPrefix_();
/**
* @private
* @type {string}
*/
this.layer_ = options.layer;
/**
* @private
* @type {string}
*/
this.matrixSet_ = options.matrixSet;
/**
* @private
* @type {string}
*/
this.style_ = options.style;
// FIXME: should we guess this requestEncoding from options.url(s)
// structure? that would mean KVP only if a template is not provided.
var requestEncoding = goog.isDef(options.requestEncoding) ?
@@ -66,18 +94,20 @@ ol.source.WMTS = function(options) {
// 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': options.layer,
'Style': options.style,
'TileMatrixSet': options.matrixSet
'layer': this.layer_,
'style': this.style_,
'tilematrixset': this.matrixSet_
};
if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) {
goog.object.extend(context, {
'Service': 'WMTS',
'Request': 'GetTile',
'Version': version,
'Format': format
'Version': this.version_,
'Format': this.format_
});
}
@@ -96,7 +126,7 @@ ol.source.WMTS = function(options) {
template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ?
goog.uri.utils.appendParamsFromMap(template, context) :
template.replace(/\{(\w+?)\}/g, function(m, p) {
return (p in context) ? context[p] : m;
return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m;
});
return (
@@ -204,6 +234,15 @@ ol.source.WMTS.prototype.getDimensions = function() {
};
/**
* @return {string} Format.
* @api
*/
ol.source.WMTS.prototype.getFormat = function() {
return this.format_;
};
/**
* @inheritDoc
*/
@@ -212,6 +251,42 @@ ol.source.WMTS.prototype.getKeyZXY = function(z, x, y) {
};
/**
* @return {string} Layer.
* @api
*/
ol.source.WMTS.prototype.getLayer = function() {
return this.layer_;
};
/**
* @return {string} MatrixSet.
* @api
*/
ol.source.WMTS.prototype.getMatrixSet = function() {
return this.matrixSet_;
};
/**
* @return {string} Style.
* @api
*/
ol.source.WMTS.prototype.getStyle = function() {
return this.style_;
};
/**
* @return {string} Version.
* @api
*/
ol.source.WMTS.prototype.getVersion = function() {
return this.version_;
};
/**
* @private
*/
@@ -239,90 +314,149 @@ ol.source.WMTS.prototype.updateDimensions = function(dimensions) {
/**
* @param {Object} wmtsCap An object representing the capabilities document.
* @param {string} layer The layer identifier.
* @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, layer) {
ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
/* jshint -W069 */
// TODO: add support for TileMatrixLimits
goog.asserts.assert(!goog.isNull(config['layer']));
var layers = wmtsCap['contents']['layers'];
var layers = wmtsCap['Contents']['Layer'];
var l = goog.array.find(layers, function(elt, index, array) {
return elt['identifier'] == layer;
return elt['Identifier'] == config['layer'];
});
goog.asserts.assert(!goog.isNull(l));
goog.asserts.assert(l['tileMatrixSetLinks'].length > 0);
var matrixSet = /** @type {string} */
(l['tileMatrixSetLinks'][0]['tileMatrixSet']);
var format = /** @type {string} */ (l['formats'][0]);
var idx = goog.array.findIndex(l['styles'], function(elt, index, array) {
return elt['isDefault'];
goog.asserts.assert(l['TileMatrixSetLink'].length > 0);
var idx, matrixSet;
if (l['TileMatrixSetLink'].length > 1) {
idx = goog.array.findIndex(l['TileMatrixSetLink'],
function(elt, index, array) {
return elt['TileMatrixSet'] == config['matrixSet'];
});
} else if (goog.isDef(config['projection'])) {
idx = goog.array.findIndex(l['TileMatrixSetLink'],
function(elt, index, array) {
return elt['TileMatrixSet']['SupportedCRS'].replace(
/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'
) == config['projection'];
});
} else {
idx = 0;
}
if (idx < 0) {
idx = 0;
}
matrixSet = /** @type {string} */
(l['TileMatrixSetLink'][idx]['TileMatrixSet']);
goog.asserts.assert(!goog.isNull(matrixSet));
var format = /** @type {string} */ (l['Format'][0]);
if (goog.isDef(config['format'])) {
format = config['format'];
}
idx = goog.array.findIndex(l['Style'], function(elt, index, array) {
if (goog.isDef(config['style'])) {
return elt['Title'] == config['style'];
} else {
return elt['isDefault'];
}
});
if (idx < 0) {
idx = 0;
}
var style = /** @type {string} */ (l['styles'][idx]['identifier']);
var style = /** @type {string} */ (l['Style'][idx]['Identifier']);
var dimensions = {};
goog.array.forEach(l['dimensions'], function(elt, index, array) {
var key = elt['identifier'];
var value = elt['default'];
if (goog.isDef(value)) {
goog.asserts.assert(goog.array.contains(elt['values'], value));
} else {
value = elt['values'][0];
}
goog.asserts.assert(goog.isDef(value));
dimensions[key] = value;
});
if (goog.isDef(l['Dimension'])) {
goog.array.forEach(l['Dimension'], function(elt, index, array) {
var key = elt['Identifier'];
var value = elt['default'];
if (goog.isDef(value)) {
goog.asserts.assert(goog.array.contains(elt['values'], value));
} else {
value = elt['values'][0];
}
goog.asserts.assert(goog.isDef(value));
dimensions[key] = value;
});
}
var matrixSets = wmtsCap['contents']['tileMatrixSets'];
goog.asserts.assert(matrixSet in matrixSets);
var matrixSetObj = matrixSets[matrixSet];
var matrixSets = wmtsCap['Contents']['TileMatrixSet'];
var matrixSetObj = goog.array.find(matrixSets, function(elt, index, array) {
return elt['Identifier'] == matrixSet;
});
goog.asserts.assert(!goog.isNull(matrixSetObj));
var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
matrixSetObj);
var projection = ol.proj.get(matrixSetObj['supportedCRS']);
var gets = wmtsCap['operationsMetadata']['GetTile']['dcp']['http']['get'];
var encodings = goog.object.getKeys(
gets[0]['constraints']['GetEncoding']['allowedValues']);
goog.asserts.assert(encodings.length > 0);
var urls;
var requestEncoding;
switch (encodings[0]) {
case 'REST':
case 'RESTful':
// The OGC documentation is not clear if we should use REST or RESTful,
// ArcGis use RESTful, and OpenLayers use REST.
requestEncoding = ol.source.WMTSRequestEncoding.REST;
goog.asserts.assert(l['resourceUrls'].hasOwnProperty('tile'));
goog.asserts.assert(l['resourceUrls']['tile'].hasOwnProperty(format));
urls = /** @type {Array.<string>} */
(l['resourceUrls']['tile'][format]);
break;
case 'KVP':
requestEncoding = ol.source.WMTSRequestEncoding.KVP;
urls = [];
goog.array.forEach(gets, function(elt, index, array) {
if (elt['constraints']['GetEncoding']['allowedValues'].hasOwnProperty(
ol.source.WMTSRequestEncoding.KVP)) {
urls.push(/** @type {string} */ (elt['url']));
}
});
goog.asserts.assert(urls.length > 0);
break;
default:
goog.asserts.fail();
var projection;
if (goog.isDef(config['projection'])) {
projection = ol.proj.get(config['projection']);
} else {
projection = ol.proj.get(matrixSetObj['SupportedCRS'].replace(
/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'));
}
/** @type {!Array.<string>} */
var urls = [];
var requestEncoding = config['requestEncoding'];
requestEncoding = goog.isDef(requestEncoding) ? requestEncoding : '';
goog.asserts.assert(
goog.array.contains(['REST', 'RESTful', 'KVP', ''], requestEncoding));
if (!wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') ||
goog.string.startsWith(requestEncoding, 'REST')) {
// Add REST tile resource url
requestEncoding = ol.source.WMTSRequestEncoding.REST;
goog.array.forEach(l['ResourceURL'], 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'];
var constraint = goog.array.find(gets[0]['Constraint'],
function(elt, index, array) {
return elt['name'] == 'GetEncoding';
});
var encodings = constraint['AllowedValues']['Value'];
if (encodings.length > 0 && goog.array.contains(encodings, 'KVP')) {
requestEncoding = ol.source.WMTSRequestEncoding.KVP;
urls.push(/** @type {string} */ (gets[0]['href']));
}
}
goog.asserts.assert(urls.length > 0);
return {
urls: urls,
layer: layer,
layer: config['layer'],
matrixSet: matrixSet,
format: format,
projection: projection,

View File

@@ -2,7 +2,7 @@
* @license
* Latitude/longitude spherical geodesy formulae taken from
* http://www.movable-type.co.uk/scripts/latlong.html
* Licenced under CC-BY-3.0.
* Licensed under CC-BY-3.0.
*/
// FIXME add intersection of two paths given start points and bearings
@@ -57,6 +57,36 @@ ol.Sphere.prototype.cosineDistance = function(c1, c2) {
};
/**
* 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 += goog.math.toRadians(x2 - x1) *
(2 + Math.sin(goog.math.toRadians(y1)) +
Math.sin(goog.math.toRadians(y2)));
x1 = x2;
y1 = y2;
}
return area * this.radius * this.radius / 2.0;
};
/**
* Returns the distance of c3 from the great circle path defined by c1 and c2.
*
@@ -110,6 +140,7 @@ ol.Sphere.prototype.finalBearing = function(c1, c2) {
* @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 = goog.math.toRadians(c1[1]);

View File

@@ -377,7 +377,7 @@ ol.style.IconImage_ = function(image, src, crossOrigin, imageState) {
/**
* @private
* @type {Array.<number>}
* @type {Array.<goog.events.Key>}
*/
this.imageListenerKeys_ = null;

View File

@@ -278,8 +278,15 @@ ol.style.RegularShape.prototype.unlistenImageChange = goog.nullFunction;
/**
* @typedef {{strokeStyle: (string|undefined), strokeWidth: number,
* size: number, lineDash: Array.<number>}}
* @typedef {{
* strokeStyle: (string|undefined),
* strokeWidth: number,
* size: number,
* lineCap: string,
* lineDash: Array.<number>,
* lineJoin: string,
* miterLimit: number
* }}
*/
ol.style.RegularShape.RenderOptions;
@@ -290,6 +297,9 @@ ol.style.RegularShape.RenderOptions;
*/
ol.style.RegularShape.prototype.render_ = function(atlasManager) {
var imageSize;
var lineCap = '';
var lineJoin = '';
var miterLimit = 0;
var lineDash = null;
var strokeStyle;
var strokeWidth = 0;
@@ -304,6 +314,18 @@ ol.style.RegularShape.prototype.render_ = function(atlasManager) {
if (!ol.has.CANVAS_LINE_DASH) {
lineDash = null;
}
lineJoin = this.stroke_.getLineJoin();
if (!goog.isDef(lineJoin)) {
lineJoin = ol.render.canvas.defaultLineJoin;
}
lineCap = this.stroke_.getLineCap();
if (!goog.isDef(lineCap)) {
lineCap = ol.render.canvas.defaultLineCap;
}
miterLimit = this.stroke_.getMiterLimit();
if (!goog.isDef(miterLimit)) {
miterLimit = ol.render.canvas.defaultMiterLimit;
}
}
var size = 2 * (this.radius_ + strokeWidth) + 1;
@@ -313,7 +335,10 @@ ol.style.RegularShape.prototype.render_ = function(atlasManager) {
strokeStyle: strokeStyle,
strokeWidth: strokeWidth,
size: size,
lineDash: lineDash
lineCap: lineCap,
lineDash: lineDash,
lineJoin: lineJoin,
miterLimit: miterLimit
};
if (!goog.isDef(atlasManager)) {
@@ -373,7 +398,7 @@ ol.style.RegularShape.prototype.render_ = function(atlasManager) {
/**
* @private
* @param {ol.style.Circle.RenderOptions} renderOptions
* @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).
@@ -407,6 +432,9 @@ ol.style.RegularShape.prototype.draw_ = function(renderOptions, context, x, y) {
if (!goog.isNull(renderOptions.lineDash)) {
context.setLineDash(renderOptions.lineDash);
}
context.lineCap = renderOptions.lineCap;
context.lineJoin = renderOptions.lineJoin;
context.miterLimit = renderOptions.miterLimit;
context.stroke();
}
context.closePath();

View File

@@ -64,6 +64,7 @@ ol.tilegrid.WMTS.prototype.getMatrixIds = function() {
* @param {Object} matrixSet An object representing a matrixSet in the
* capabilities document.
* @return {ol.tilegrid.WMTS} WMTS tileGrid instance.
* @api
*/
ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
function(matrixSet) {
@@ -77,16 +78,20 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
/** @type {!Array.<number>} */
var tileSizes = [];
var supportedCRSPropName = 'supportedCRS';
var matrixIdsPropName = 'matrixIds';
var identifierPropName = 'identifier';
var scaleDenominatorPropName = 'scaleDenominator';
var topLeftCornerPropName = 'topLeftCorner';
var tileWidthPropName = 'tileWidth';
var tileHeightPropName = 'tileHeight';
var supportedCRSPropName = 'SupportedCRS';
var matrixIdsPropName = 'TileMatrix';
var identifierPropName = 'Identifier';
var scaleDenominatorPropName = 'ScaleDenominator';
var topLeftCornerPropName = 'TopLeftCorner';
var tileWidthPropName = 'TileWidth';
var tileHeightPropName = 'TileHeight';
var projection = ol.proj.get(matrixSet[supportedCRSPropName]);
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];
@@ -95,7 +100,12 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
goog.array.forEach(matrixSet[matrixIdsPropName],
function(elt, index, array) {
matrixIds.push(elt[identifierPropName]);
origins.push(elt[topLeftCornerPropName]);
if (switchOriginXY) {
origins.push([elt[topLeftCornerPropName][1],
elt[topLeftCornerPropName][0]]);
} else {
origins.push(elt[topLeftCornerPropName]);
}
resolutions.push(elt[scaleDenominatorPropName] * 0.28E-3 /
metersPerUnit);
var tileWidth = elt[tileWidthPropName];

View File

@@ -4,6 +4,7 @@ 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');
@@ -67,11 +68,17 @@ ol.TileQueue.prototype.getTilesLoading = function() {
/**
* @param {goog.events.Event} event Event.
* @protected
*/
ol.TileQueue.prototype.handleTileChange = function() {
--this.tilesLoading_;
this.tileChangeCallback_();
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) {
--this.tilesLoading_;
this.tileChangeCallback_();
}
};
@@ -85,7 +92,7 @@ ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {
var i, tile;
for (i = 0; i < newLoads; ++i) {
tile = /** @type {ol.Tile} */ (this.dequeue()[0]);
goog.events.listenOnce(tile, goog.events.EventType.CHANGE,
goog.events.listen(tile, goog.events.EventType.CHANGE,
this.handleTileChange, false, this);
tile.load();
}

View File

@@ -72,7 +72,7 @@ function getSymbols(patterns, callback) {
/**
* Generate a list of symbol names given a list of patterns. Patterns may
* include a * wildcard at the end of the string, in which case all symbol names
* that start with the preceeding string will be matched (e.g 'foo.Bar#*' will
* that start with the preceding string will be matched (e.g 'foo.Bar#*' will
* match all symbol names that start with 'foo.Bar#').
*
* @param {Array.<string>} patterns A list of symbol names to match. Wildcards

View File

@@ -11,7 +11,7 @@ var googRegEx = /^goog\..*$/;
/**
* Read the symbols from info file.
* @param {funciton(Error, Array.<string>, Array.<Object>)} callback Called
* @param {function(Error, Array.<string>, Array.<Object>)} callback Called
* with the patterns and symbols (or any error).
*/
function getInfo(callback) {

View File

@@ -220,7 +220,7 @@ describe('ol.format.GPX', function() {
expect(serialized).to.xmleql(ol.xml.parse(text));
});
it('can tranform, read and write a trk with a trkseg', function() {
it('can transform, read and write a trk with a trkseg', function() {
var text =
'<gpx xmlns="http://www.topografix.com/GPX/1/1">' +
' <trk>' +

View File

@@ -919,7 +919,7 @@ describe('ol.format.KML', function() {
expect(g.getGeometries()).to.be.empty();
});
it('can read heterogenous GeometryCollection geometries', function() {
it('can read heterogeneous GeometryCollection geometries', function() {
var text =
'<kml xmlns="http://earth.google.com/kml/2.2">' +
' <Placemark>' +
@@ -2407,7 +2407,7 @@ describe('ol.format.KML', function() {
expect(features).to.have.length(50);
});
it('creates features with heterogenous geometry collections', function() {
it('creates features with heterogeneous geometry collections', function() {
// FIXME decide if we should instead create features with multiple geoms
var feature = features[0];
expect(feature).to.be.an(ol.Feature);

View File

@@ -4,7 +4,7 @@ describe('ol.format.Polyline', function() {
var format;
var points;
var flatPoints, encodedFlatPoints;
var flatPoints, encodedFlatPoints, flippedFlatPoints;
var floats, smallFloats, encodedFloats;
var signedIntegers, encodedSignedIntegers;
var unsignedIntegers, encodedUnsignedIntegers;

File diff suppressed because one or more lines are too long

View File

@@ -28,12 +28,10 @@ access interface to some TileMatrixSets</ows:Abstract>
<ows:Address>
<ows:DeliveryPoint>Fac Ciencies UAB</ows:DeliveryPoint>
<ows:City>Bellaterra</ows:City>
<ows:AdministrativeArea>Barcelona
</ows:AdministrativeArea>
<ows:AdministrativeArea>Barcelona</ows:AdministrativeArea>
<ows:PostalCode>08193</ows:PostalCode>
<ows:Country>Spain</ows:Country>
<ows:ElectronicMailAddress>joan.maso@uab.cat
</ows:ElectronicMailAddress>
<ows:ElectronicMailAddress>joan.maso@uab.cat</ows:ElectronicMailAddress>
</ows:Address>
</ows:ContactInfo>
</ows:ServiceContact>
@@ -70,8 +68,7 @@ access interface to some TileMatrixSets</ows:Abstract>
<Contents>
<Layer>
<ows:Title>Blue Marble Next Generation</ows:Title>
<ows:Abstract>Blue Marble Next Generation NASA Product
</ows:Abstract>
<ows:Abstract>Blue Marble Next Generation NASA Product</ows:Abstract>
<ows:WGS84BoundingBox>
<ows:LowerCorner>-180 -90</ows:LowerCorner>
<ows:UpperCorner>180 90</ows:UpperCorner>
@@ -84,8 +81,7 @@ access interface to some TileMatrixSets</ows:Abstract>
</Style>
<Style>
<ows:Title>Thick And Red</ows:Title>
<ows:Abstract>Specify this style if you want your maps to have thick red coastlines.
</ows:Abstract>
<ows:Abstract>Specify this style if you want your maps to have thick red coastlines.</ows:Abstract>
<ows:Identifier>thickAndRed</ows:Identifier>
</Style>
<Format>image/jpeg</Format>
@@ -93,15 +89,206 @@ access interface to some TileMatrixSets</ows:Abstract>
<TileMatrixSetLink>
<TileMatrixSet>BigWorldPixel</TileMatrixSet>
</TileMatrixSetLink>
<TileMatrixSetLink>
<TileMatrixSet>google3857</TileMatrixSet>
</TileMatrixSetLink>
<ResourceURL format="image/png" resourceType="tile" template="http://www.example.com/wmts/coastlines/{TileMatrix}/{TileRow}/{TileCol}.png"/>
<ResourceURL format="application/gml+xml; version=3.1" resourceType="FeatureInfo" template="http://www.example.com/wmts/coastlines/{TileMatrixSet}/{TileMatrix}/{TileRow}/{TileCol}/{J}/{I}.xml"/>
</Layer>
<TileMatrixSet>
<!-- -180 85.05112878 -->
<ows:Identifier>google3857</ows:Identifier>
<ows:BoundingBox crs="urn:ogc:def:crs:EPSG:6.18:3:3857">
<ows:LowerCorner>1799448.394855 6124949.747770</ows:LowerCorner>
<ows:UpperCorner>1848250.442089 6162571.828177</ows:UpperCorner>
</ows:BoundingBox>
<ows:SupportedCRS>urn:ogc:def:crs:EPSG:6.18:3:3857</ows:SupportedCRS>
<WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GoogleMapsCompatible</WellKnownScaleSet>
<TileMatrix>
<ows:Identifier>0</ows:Identifier>
<ScaleDenominator>559082264.029</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>1</MatrixWidth>
<MatrixHeight>1</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>1</ows:Identifier>
<ScaleDenominator>279541132.015</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>2</MatrixWidth>
<MatrixHeight>2</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>2</ows:Identifier>
<ScaleDenominator>139770566.007</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>4</MatrixWidth>
<MatrixHeight>4</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>3</ows:Identifier>
<ScaleDenominator>69885283.0036</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>8</MatrixWidth>
<MatrixHeight>8</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>4</ows:Identifier>
<ScaleDenominator>34942641.5018</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>16</MatrixWidth>
<MatrixHeight>16</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>5</ows:Identifier>
<ScaleDenominator>17471320.7509</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>32</MatrixWidth>
<MatrixHeight>32</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>6</ows:Identifier>
<ScaleDenominator>8735660.37545</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>64</MatrixWidth>
<MatrixHeight>64</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>7</ows:Identifier>
<ScaleDenominator>4367830.18773</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>128</MatrixWidth>
<MatrixHeight>128</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>8</ows:Identifier>
<ScaleDenominator>2183915.09386</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>256</MatrixWidth>
<MatrixHeight>256</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>9</ows:Identifier>
<ScaleDenominator>1091957.54693</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>512</MatrixWidth>
<MatrixHeight>512</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>10</ows:Identifier>
<ScaleDenominator>545978.773466</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>1024</MatrixWidth>
<MatrixHeight>1024</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>11</ows:Identifier>
<ScaleDenominator>272989.386733</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>2048</MatrixWidth>
<MatrixHeight>2048</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>12</ows:Identifier>
<ScaleDenominator>136494.693366</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>4096</MatrixWidth>
<MatrixHeight>4096</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>13</ows:Identifier>
<ScaleDenominator>68247.3466832</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>8192</MatrixWidth>
<MatrixHeight>8192</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>14</ows:Identifier>
<ScaleDenominator>34123.6733416</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>16384</MatrixWidth>
<MatrixHeight>16384</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>15</ows:Identifier>
<ScaleDenominator>17061.8366708</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>32768</MatrixWidth>
<MatrixHeight>32768</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>16</ows:Identifier>
<ScaleDenominator>8530.91833540</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>65536</MatrixWidth>
<MatrixHeight>65536</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>17</ows:Identifier>
<ScaleDenominator>4265.45916770</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>131072</MatrixWidth>
<MatrixHeight>131072</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>18</ows:Identifier>
<ScaleDenominator>2132.72958385</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>262144</MatrixWidth>
<MatrixHeight>262144</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>19</ows:Identifier>
<ScaleDenominator>1066.36479193</ScaleDenominator>
<TopLeftCorner>-20037508.3428 20037508.3428</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>524288</MatrixWidth>
<MatrixHeight>524288</MatrixHeight>
</TileMatrix>
</TileMatrixSet>
<TileMatrixSet>
<ows:Identifier>BigWorldPixel</ows:Identifier>
<ows:SupportedCRS>urn:ogc:def:crs:OGC:1.3:CRS84
</ows:SupportedCRS>
<WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GlobalCRS84Pixel
</WellKnownScaleSet>
<ows:SupportedCRS>urn:ogc:def:crs:OGC:1.3:CRS84</ows:SupportedCRS>
<WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GlobalCRS84Pixel</WellKnownScaleSet>
<TileMatrix>
<ows:Identifier>10000m</ows:Identifier>
<ScaleDenominator>33130800.83133142</ScaleDenominator>
@@ -158,27 +345,27 @@ access interface to some TileMatrixSets</ows:Abstract>
</TileMatrix>
</TileMatrixSet>
<TileMatrixSet>
<ows:Identifier>BigWorld</ows:Identifier>
<ows:SupportedCRS>urn:ogc:def:crs:OGC:1.3:CRS84</ows:SupportedCRS>
<TileMatrix>
<ows:Identifier>1e6</ows:Identifier>
<ScaleDenominator>1e6</ScaleDenominator>
<TopLeftCorner>-180 84</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>60000</MatrixWidth>
<MatrixHeight>50000</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>2.5e6</ows:Identifier>
<ScaleDenominator>2.5e6</ScaleDenominator>
<TopLeftCorner>-180 84</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>9000</MatrixWidth>
<MatrixHeight>7000</MatrixHeight>
</TileMatrix>
</TileMatrixSet>
<ows:Identifier>BigWorld</ows:Identifier>
<ows:SupportedCRS>urn:ogc:def:crs:OGC:1.3:CRS84</ows:SupportedCRS>
<TileMatrix>
<ows:Identifier>1e6</ows:Identifier>
<ScaleDenominator>1e6</ScaleDenominator>
<TopLeftCorner>-180 84</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>60000</MatrixWidth>
<MatrixHeight>50000</MatrixHeight>
</TileMatrix>
<TileMatrix>
<ows:Identifier>2.5e6</ows:Identifier>
<ScaleDenominator>2.5e6</ScaleDenominator>
<TopLeftCorner>-180 84</TopLeftCorner>
<TileWidth>256</TileWidth>
<TileHeight>256</TileHeight>
<MatrixWidth>9000</MatrixWidth>
<MatrixHeight>7000</MatrixHeight>
</TileMatrix>
</TileMatrixSet>
</Contents>
<ServiceMetadataURL xlink:href="http://www.maps.bob/wmts/1.0.0/WMTSCapabilities.xml"/>
</Capabilities>

View File

@@ -44,9 +44,11 @@ describe('ol.format.WMTSCapabilities', function() {
expect(layer.Style[0].LegendURL[0].format).to.be.eql('image/png');
expect(layer.TileMatrixSetLink).to.be.an('array');
expect(layer.TileMatrixSetLink).to.have.length(1);
expect(layer.TileMatrixSetLink).to.have.length(2);
expect(layer.TileMatrixSetLink[0].TileMatrixSet).to.be
.eql('BigWorldPixel');
expect(layer.TileMatrixSetLink[1].TileMatrixSet).to.be
.eql('google3857');
var wgs84Bbox = layer.WGS84BoundingBox;
expect(wgs84Bbox).to.be.an('array');
@@ -67,7 +69,7 @@ describe('ol.format.WMTSCapabilities', function() {
it('Can read Capabilities.Content.TileMatrixSet', function() {
expect(capabilities.Contents.TileMatrixSet).to.be.ok();
var bigWorld = capabilities.Contents.TileMatrixSet[1];
var bigWorld = capabilities.Contents.TileMatrixSet[2];
expect(bigWorld).to.be.ok();
expect(bigWorld.Identifier).to.be.eql('BigWorld');
expect(bigWorld.SupportedCRS).to.be.eql('urn:ogc:def:crs:OGC:1.3:CRS84');

View File

@@ -504,7 +504,7 @@ describe('ol.interaction.Draw', function() {
expect(interaction.sketchFeature_).to.be(null);
});
it('fires change:active', function() {
listenerSpy = sinon.spy(function() {
var listenerSpy = sinon.spy(function() {
// test that the interaction's change:active listener is called first
expect(interaction.overlay_.map_).to.be(null);
});
@@ -523,7 +523,7 @@ describe('ol.interaction.Draw', function() {
expect(interaction.overlay_.map_).to.be(map);
});
it('fires change:active', function() {
listenerSpy = sinon.spy(function() {
var listenerSpy = sinon.spy(function() {
// test that the interaction's change:active listener is called first
expect(interaction.overlay_.map_).not.to.be(null);
});
@@ -592,6 +592,7 @@ goog.require('goog.dispose');
goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.style');
goog.require('ol.DrawEventType');
goog.require('ol.Map');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.View');

View File

@@ -0,0 +1,212 @@
goog.provide('ol.test.interaction.Select');
describe('ol.interaction.Select', function() {
var target, map, source;
var width = 360;
var height = 180;
beforeEach(function(done) {
target = document.createElement('div');
var style = target.style;
style.position = 'absolute';
style.left = '-1000px';
style.top = '-1000px';
style.width = width + 'px';
style.height = height + 'px';
document.body.appendChild(target);
var geometry = new ol.geom.Polygon([[[0, 0], [0, 40], [40, 40], [40, 0]]]);
var geometry2 = new ol.geom.Polygon([[[0, 0], [0, 40], [40, 40], [40, 0]]]);
var feature = new ol.Feature({
geometry: geometry
});
var feature2 = new ol.Feature({
geometry: geometry2
});
source = new ol.source.Vector({
features: [feature, feature2]
});
var layer = new ol.layer.Vector({source: source});
map = new ol.Map({
target: target,
layers: [layer],
view: new ol.View({
projection: 'EPSG:4326',
center: [0, 0],
resolution: 1
})
});
map.on('postrender', function() {
done();
});
});
afterEach(function() {
goog.dispose(map);
document.body.removeChild(target);
});
/**
* Simulates a browser event on the map viewport. The client x/y location
* will be adjusted as if the map were centered at 0,0.
* @param {string} type Event type.
* @param {number} x Horizontal offset from map center.
* @param {number} y Vertical offset from map center.
* @param {boolean=} opt_shiftKey Shift key is pressed.
*/
function simulateEvent(type, x, y, opt_shiftKey) {
var viewport = map.getViewport();
// calculated in case body has top < 0 (test runner with small window)
var position = goog.style.getClientPosition(viewport);
var shiftKey = goog.isDef(opt_shiftKey) ? opt_shiftKey : false;
var event = new ol.MapBrowserPointerEvent(type, map,
new ol.pointer.PointerEvent(type,
new goog.events.BrowserEvent({
clientX: position.x + x + width / 2,
clientY: position.y + y + height / 2,
shiftKey: shiftKey
})));
console.debug(event);
map.handleMapBrowserEvent(event);
}
describe('constructor', function() {
it('creates a new interaction', function() {
var select = new ol.interaction.Select();
expect(select).to.be.a(ol.interaction.Select);
expect(select).to.be.a(ol.interaction.Interaction);
});
});
describe('selecting a polygon', function() {
var select;
beforeEach(function() {
select = new ol.interaction.Select();
map.addInteraction(select);
});
it('select with single-click', function() {
simulateEvent(ol.MapBrowserEvent.EventType.SINGLECLICK, 10, -20);
var features = select.getFeatures();
expect(features.getLength()).to.equal(1);
});
});
describe('multiselecting polygons', function() {
var select;
beforeEach(function() {
select = new ol.interaction.Select({
multi: true
});
map.addInteraction(select);
});
it('select with single-click', function() {
simulateEvent(ol.MapBrowserEvent.EventType.SINGLECLICK, 10, -20);
var features = select.getFeatures();
expect(features.getLength()).to.equal(2);
});
});
describe('#setActive()', function() {
var interaction;
beforeEach(function() {
interaction = new ol.interaction.Select();
expect(interaction.getActive()).to.be(true);
map.addInteraction(interaction);
expect(interaction.featureOverlay_).not.to.be(null);
simulateEvent(ol.MapBrowserEvent.EventType.SINGLECLICK, 10, -20);
});
afterEach(function() {
map.removeInteraction(interaction);
});
describe('#setActive(false)', function() {
it('keeps the the selection', function() {
interaction.setActive(false);
expect(interaction.getFeatures().getLength()).to.equal(1);
});
});
describe('#setActive(true)', function() {
beforeEach(function() {
interaction.setActive(false);
});
it('sets the map into the feature overlay', function() {
interaction.setActive(true);
expect(interaction.featureOverlay_.map_).to.be(map);
});
it('fires change:active', function() {
var listenerSpy = sinon.spy(function() {
// test that the interaction's change:active listener is called first
expect(interaction.featureOverlay_.map_).not.to.be(null);
});
interaction.on('change:active', listenerSpy);
interaction.setActive(true);
expect(listenerSpy.callCount).to.be(1);
});
});
});
describe('#setMap()', function() {
var interaction;
beforeEach(function() {
interaction = new ol.interaction.Select();
expect(interaction.getActive()).to.be(true);
});
describe('#setMap(null)', function() {
beforeEach(function() {
map.addInteraction(interaction);
});
afterEach(function() {
map.removeInteraction(interaction);
});
describe('#setMap(null) when interaction is active', function() {
it('unsets the map from the feature overlay', function() {
interaction.setMap(null);
expect(interaction.featureOverlay_.map_).to.be(null);
});
});
});
describe('#setMap(map)', function() {
describe('#setMap(map) when interaction is active', function() {
it('sets the map into the feature overlay', function() {
interaction.setMap(map);
expect(interaction.featureOverlay_.map_).to.be(map);
});
});
});
});
});
goog.require('goog.dispose');
goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.style');
goog.require('ol.Feature');
goog.require('ol.Map');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.View');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Select');
goog.require('ol.interaction.Interaction');
goog.require('ol.layer.Vector');
goog.require('ol.pointer.PointerEvent');
goog.require('ol.source.Vector');

View File

@@ -366,10 +366,15 @@ describe('ol.proj', function() {
'+proj=lcc +lat_1=29.3 +lat_2=30.7 +lat_0=28.66666666666667 ' +
'+lon_0=-91.33333333333333 +x_0=609601.2192024384 +y_0=0 ' +
'+ellps=clrk66 +datum=NAD27 +to_meter=0.3048006096012192 +no_defs');
proj4.defs('EPSG:3739', '+proj=tmerc +lat_0=40.5 ' +
'+lon_0=-110.0833333333333 +k=0.9999375 +x_0=800000.0000101599 ' +
'+y_0=99999.99998983997 +ellps=GRS80 +towgs84=0,0,0,0,0,0,0 ' +
'+units=us-ft +no_defs');
});
afterEach(function() {
delete proj4.defs['EPSG:26782'];
delete proj4.defs['EPSG:3739'];
});
it('returns value in meters', function() {
@@ -382,6 +387,11 @@ describe('ol.proj', function() {
expect(epsg26782.getMetersPerUnit()).to.eql(0.3048006096012192);
});
it('works for proj4js projections with units other than m', function() {
var epsg3739 = ol.proj.get('EPSG:3739');
expect(epsg3739.getMetersPerUnit()).to.eql(1200 / 3937);
});
});
});

View File

@@ -82,7 +82,7 @@ describe('ol.render.canvas.LineStringReplay', function() {
describe('#getBufferedMaxExtent()', function() {
it('buffers the max extent to accomodate stroke width', function() {
it('buffers the max extent to accommodate stroke width', function() {
var tolerance = 1;
var extent = [-180, -90, 180, 90];
var resolution = 10;
@@ -104,7 +104,7 @@ describe('ol.render.canvas.PolygonReplay', function() {
describe('#getBufferedMaxExtent()', function() {
it('buffers the max extent to accomodate stroke width', function() {
it('buffers the max extent to accommodate stroke width', function() {
var tolerance = 1;
var extent = [-180, -90, 180, 90];
var resolution = 10;

View File

@@ -5,10 +5,8 @@ describe('ol.renderer.Layer', function() {
var eventType = goog.events.EventType.CHANGE;
beforeEach(function() {
var map = new ol.Map({});
var mapRenderer = map.getRenderer();
var layer = new ol.layer.Layer({});
renderer = new ol.renderer.Layer(mapRenderer, layer);
renderer = new ol.renderer.Layer(layer);
});
describe('#loadImage', function() {
@@ -84,6 +82,5 @@ describe('ol.renderer.Layer', function() {
goog.require('goog.events.EventType');
goog.require('ol.Image');
goog.require('ol.ImageState');
goog.require('ol.Map');
goog.require('ol.layer.Layer');
goog.require('ol.renderer.Layer');

View File

@@ -0,0 +1,242 @@
goog.provide('ol.test.source.TileArcGISRest');
describe('ol.source.TileArcGISRest', function() {
var options;
beforeEach(function() {
options = {
params: {},
url: 'http://example.com/MapServer'
};
});
describe('#getTile', function() {
it('returns a tile with the expected URL', function() {
var source = new ol.source.TileArcGISRest(options);
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:3857'));
expect(tile).to.be.an(ol.ImageTile);
var uri = new goog.Uri(tile.src_);
expect(uri.getScheme()).to.be('http');
expect(uri.getDomain()).to.be('example.com');
expect(uri.getPath()).to.be('/MapServer/export');
var queryData = uri.getQueryData();
expect(queryData.get('BBOX')).to.be(
'-10018754.171394622,-15028131.257091932,' +
'-5009377.085697311,-10018754.17139462');
expect(queryData.get('FORMAT')).to.be('PNG32');
expect(queryData.get('SIZE')).to.be('256,256');
expect(queryData.get('IMAGESR')).to.be('3857');
expect(queryData.get('BBOXSR')).to.be('3857');
expect(queryData.get('TRANSPARENT')).to.be('true');
});
it('returns a tile with the expected URL with url list', function() {
options.urls = ['http://test1.com/MapServer',
'http://test2.com/MapServer'];
var source = new ol.source.TileArcGISRest(options);
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:3857'));
expect(tile).to.be.an(ol.ImageTile);
var uri = new goog.Uri(tile.src_);
expect(uri.getScheme()).to.be('http');
expect(uri.getDomain()).to.match(/test[12]\.com/);
expect(uri.getPath()).to.be('/MapServer/export');
var queryData = uri.getQueryData();
expect(queryData.get('BBOX')).to.be(
'-10018754.171394622,-15028131.257091932,' +
'-5009377.085697311,-10018754.17139462');
expect(queryData.get('FORMAT')).to.be('PNG32');
expect(queryData.get('SIZE')).to.be('256,256');
expect(queryData.get('IMAGESR')).to.be('3857');
expect(queryData.get('BBOXSR')).to.be('3857');
expect(queryData.get('TRANSPARENT')).to.be('true');
});
it('returns a tile with the expected URL for ImageServer', function() {
options.url = 'http://example.com/ImageServer';
var source = new ol.source.TileArcGISRest(options);
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:3857'));
expect(tile).to.be.an(ol.ImageTile);
var uri = new goog.Uri(tile.src_);
expect(uri.getScheme()).to.be('http');
expect(uri.getDomain()).to.be('example.com');
expect(uri.getPath()).to.be('/ImageServer/exportImage');
var queryData = uri.getQueryData();
expect(queryData.get('BBOX')).to.be(
'-10018754.171394622,-15028131.257091932,' +
'-5009377.085697311,-10018754.17139462');
expect(queryData.get('FORMAT')).to.be('PNG32');
expect(queryData.get('SIZE')).to.be('256,256');
expect(queryData.get('IMAGESR')).to.be('3857');
expect(queryData.get('BBOXSR')).to.be('3857');
expect(queryData.get('TRANSPARENT')).to.be('true');
});
it('allows various parameters to be overridden', function() {
options.params.FORMAT = 'png';
options.params.TRANSPARENT = false;
var source = new ol.source.TileArcGISRest(options);
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:4326'));
var uri = new goog.Uri(tile.src_);
var queryData = uri.getQueryData();
expect(queryData.get('FORMAT')).to.be('png');
expect(queryData.get('TRANSPARENT')).to.be('false');
});
it('allows adding rest option', function() {
options.params.LAYERS = 'show:1,3,4';
var source = new ol.source.TileArcGISRest(options);
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:4326'));
var uri = new goog.Uri(tile.src_);
var queryData = uri.getQueryData();
expect(queryData.get('LAYERS')).to.be('show:1,3,4');
});
});
describe('#updateParams', function() {
it('add a new param', function() {
var source = new ol.source.TileArcGISRest(options);
source.updateParams({ 'TEST': 'value' });
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:3857'));
var uri = new goog.Uri(tile.src_);
var queryData = uri.getQueryData();
expect(queryData.get('TEST')).to.be('value');
});
it('updates an existing param', function() {
options.params.TEST = 'value';
var source = new ol.source.TileArcGISRest(options);
source.updateParams({ 'TEST': 'newValue' });
var tile = source.getTile(3, 2, 1, 1, ol.proj.get('EPSG:3857'));
var uri = new goog.Uri(tile.src_);
var queryData = uri.getQueryData();
expect(queryData.get('TEST')).to.be('newValue');
});
});
describe('#getParams', function() {
it('verify getting a param', function() {
options.params.TEST = 'value';
var source = new ol.source.TileArcGISRest(options);
var setParams = source.getParams();
expect(setParams).to.eql({ TEST: 'value' });
});
it('verify on adding a param', function() {
options.params.TEST = 'value';
var source = new ol.source.TileArcGISRest(options);
source.updateParams({ 'TEST2': 'newValue' });
var setParams = source.getParams();
expect(setParams).to.eql({ TEST: 'value', TEST2: 'newValue' });
});
it('verify on update a param', function() {
options.params.TEST = 'value';
var source = new ol.source.TileArcGISRest(options);
source.updateParams({ 'TEST': 'newValue' });
var setParams = source.getParams();
expect(setParams).to.eql({ TEST: 'newValue' });
});
});
describe('#getUrls', function() {
it('verify getting array of urls', function() {
options.urls = ['http://test.com/MapServer',
'http://test2.com/MapServer'];
var source = new ol.source.TileArcGISRest(options);
var urls = source.getUrls();
expect(urls).to.eql(['http://test.com/MapServer',
'http://test2.com/MapServer']);
});
});
describe('#setUrls', function() {
it('verify setting urls when not set yet', function() {
var source = new ol.source.TileArcGISRest(options);
source.setUrls(['http://test.com/MapServer',
'http://test2.com/MapServer']);
var urls = source.getUrls();
expect(urls).to.eql(['http://test.com/MapServer',
'http://test2.com/MapServer']);
});
it('verify setting urls with existing list', function() {
options.urls = ['http://test.com/MapServer',
'http://test2.com/MapServer'];
var source = new ol.source.TileArcGISRest(options);
source.setUrls(['http://test3.com/MapServer',
'http://test4.com/MapServer']);
var urls = source.getUrls();
expect(urls).to.eql(['http://test3.com/MapServer',
'http://test4.com/MapServer']);
});
});
describe('#setUrl', function() {
it('verify setting url with no urls', function() {
var source = new ol.source.TileArcGISRest(options);
source.setUrl('http://test.com/MapServer');
var urls = source.getUrls();
expect(urls).to.eql(['http://test.com/MapServer']);
});
it('verify setting url with list of urls', function() {
options.urls = ['http://test.com/MapServer',
'http://test2.com/MapServer'];
var source = new ol.source.TileArcGISRest(options);
source.setUrl('http://test3.com/MapServer');
var urls = source.getUrls();
expect(urls).to.eql(['http://test3.com/MapServer']);
});
});
});
goog.require('goog.Uri');
goog.require('ol.ImageTile');
goog.require('ol.source.TileArcGISRest');
goog.require('ol.proj');

View File

@@ -12,176 +12,105 @@ describe('ol.source.Tile', function() {
});
});
describe('#findLoadedTiles()', function() {
describe('#forEachLoadedTile()', function() {
it('adds no tiles if none are already loaded', function() {
// a source with no loaded tiles
var callback;
beforeEach(function() {
callback = sinon.spy();
});
it('does not call the callback if no tiles are loaded', function() {
var source = new ol.test.source.TileMock({});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 3);
var zoom = 3;
var range = grid.getTileRangeForExtentAndZ(extent, zoom);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
source.findLoadedTiles(loadedTilesByZ, getTileIfLoaded, 3, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).to.be(0);
source.forEachLoadedTile(zoom, range, callback);
expect(callback.callCount).to.be(0);
});
it('adds loaded tiles to the lookup (z: 0)', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'0/0/0': true,
'1/0/0': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 0);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
source.findLoadedTiles(loadedTilesByZ, getTileIfLoaded, 0, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).to.be(1);
var tile = loadedTilesByZ['0']['0/0/0'];
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.LOADED);
});
it('adds loaded tiles to the lookup (z: 1)', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'0/0/0': true,
'1/0/0': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
source.findLoadedTiles(loadedTilesByZ, getTileIfLoaded, 1, range);
var keys = goog.object.getKeys(loadedTilesByZ);
expect(keys.length).to.be(1);
var tile = loadedTilesByZ['1']['1/0/0'];
expect(tile).to.be.a(ol.Tile);
expect(tile.state).to.be(ol.TileState.LOADED);
});
it('returns true when all tiles are already loaded', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': true
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(true);
});
it('returns true when all tiles are already loaded (part 2)', function() {
// a source with no loaded tiles
it('does not call getTile() if no tiles are loaded', function() {
var source = new ol.test.source.TileMock({});
var loadedTilesByZ = {
'1': {
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': true,
'1/1/2': true
}
};
sinon.spy(source, 'getTile');
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
var zoom = 3;
var range = grid.getTileRangeForExtentAndZ(extent, zoom);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(true);
source.forEachLoadedTile(zoom, range, callback);
expect(source.getTile.callCount).to.be(0);
source.getTile.restore();
});
it('returns false when all tiles are already loaded', function() {
// a source with no loaded tiles
it('calls callback for each loaded tile', function() {
var source = new ol.test.source.TileMock({
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': false
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADING,
'1/1/1': ol.TileState.LOADED
});
var loadedTilesByZ = {};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
var zoom = 1;
var range = new ol.TileRange(0, 1, 0, 1);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(false);
source.forEachLoadedTile(zoom, range, callback);
expect(callback.callCount).to.be(3);
});
it('returns false when all tiles are already loaded (part 2)', function() {
it('returns true if range is fully loaded', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({});
var source = new ol.test.source.TileMock({
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADED,
'1/1/1': ol.TileState.LOADED
});
var loadedTilesByZ = {
'1': {
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': false
}
};
var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
var zoom = 1;
var range = new ol.TileRange(0, 1, 0, 1);
function getTileIfLoaded(z, x, y) {
var tile = source.getTile(z, x, y);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ?
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(false);
var covered = source.forEachLoadedTile(zoom, range, function() {
return true;
});
expect(covered).to.be(true);
});
it('returns false if range is not fully loaded', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADING,
'1/1/1': ol.TileState.LOADED
});
var zoom = 1;
var range = new ol.TileRange(0, 1, 0, 1);
var covered = source.forEachLoadedTile(zoom, range, function() {
return true;
});
expect(covered).to.be(false);
});
it('allows callback to override loaded check', function() {
// a source with no loaded tiles
var source = new ol.test.source.TileMock({
'1/0/0': ol.TileState.LOADED,
'1/0/1': ol.TileState.LOADED,
'1/1/0': ol.TileState.LOADED,
'1/1/1': ol.TileState.LOADED
});
var zoom = 1;
var range = new ol.TileRange(0, 1, 0, 1);
var covered = source.forEachLoadedTile(zoom, range, function() {
return false;
});
expect(covered).to.be(false);
});
});
@@ -196,9 +125,10 @@ describe('ol.source.Tile', function() {
*
* @constructor
* @extends {ol.source.Tile}
* @param {Object.<string, boolean>} loaded Lookup of already loaded tiles.
* @param {Object.<string, ol.TileState>} tileStates Lookup of tile key to
* tile state.
*/
ol.test.source.TileMock = function(loaded) {
ol.test.source.TileMock = function(tileStates) {
var tileGrid = new ol.tilegrid.TileGrid({
resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256],
origin: [-180, -180],
@@ -210,11 +140,9 @@ ol.test.source.TileMock = function(loaded) {
tileGrid: tileGrid
});
/**
* @type {Object.<string, boolean>}
* @private
*/
this.loaded_ = loaded;
for (var key in tileStates) {
this.tileCache.set(key, new ol.Tile(key.split('/'), tileStates[key]));
}
};
goog.inherits(ol.test.source.TileMock, ol.source.Tile);
@@ -224,9 +152,14 @@ goog.inherits(ol.test.source.TileMock, ol.source.Tile);
* @inheritDoc
*/
ol.test.source.TileMock.prototype.getTile = function(z, x, y) {
var key = ol.tilecoord.getKeyZXY(z, x, y);
var tileState = this.loaded_[key] ? ol.TileState.LOADED : ol.TileState.IDLE;
return new ol.Tile([z, x, y], tileState);
var key = this.getKeyZXY(z, x, y);
if (this.tileCache.containsKey(key)) {
return /** @type {!ol.Tile} */ (this.tileCache.get(key));
} else {
var tile = new ol.Tile(key, ol.TileState.IDLE);
this.tileCache.set(key, tile);
return tile;
}
};
@@ -243,8 +176,8 @@ describe('ol.test.source.TileMock', function() {
describe('#getTile()', function() {
it('returns a tile with state based on constructor arg', function() {
var source = new ol.test.source.TileMock({
'0/0/0': true,
'1/0/0': true
'0/0/0': ol.TileState.LOADED,
'1/0/0': ol.TileState.LOADED
});
var tile;
@@ -270,9 +203,9 @@ describe('ol.test.source.TileMock', function() {
goog.require('goog.object');
goog.require('ol.Tile');
goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.proj');
goog.require('ol.source.Source');
goog.require('ol.source.Tile');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid');

View File

@@ -0,0 +1,143 @@
goog.provide('ol.test.source.WMTS');
describe('ol.source.WMTS', function() {
describe('when creating options from capabilities', function() {
var parser = new ol.format.WMTSCapabilities();
var capabilities;
before(function(done) {
afterLoadText('spec/ol/format/wmts/ogcsample.xml', function(xml) {
try {
capabilities = parser.read(xml);
} catch (e) {
done(e);
}
done();
});
});
it('can create KVP options from spec/ol/format/wmts/ogcsample.xml',
function() {
var options;
options = ol.source.WMTS.optionsFromCapabilities(
capabilities,
{ layer: 'BlueMarbleNextGeneration', matrixSet: 'google3857' });
expect(options.urls).to.be.an('array');
expect(options.urls).to.have.length(1);
expect(options.urls[0]).to.be.eql(
'http://www.maps.bob/cgi-bin/MiraMon5_0.cgi?');
expect(options.layer).to.be.eql('BlueMarbleNextGeneration');
expect(options.matrixSet).to.be.eql('google3857');
expect(options.format).to.be.eql('image/jpeg');
expect(options.projection).to.be.a(ol.proj.Projection);
expect(options.projection).to.be.eql(ol.proj.get('EPSG:3857'));
expect(options.requestEncoding).to.be.eql('KVP');
expect(options.tileGrid).to.be.a(ol.tilegrid.WMTS);
expect(options.style).to.be.eql('DarkBlue');
expect(options.dimensions).to.eql({});
});
it('can create REST options from spec/ol/format/wmts/ogcsample.xml',
function() {
var options;
options = ol.source.WMTS.optionsFromCapabilities(
capabilities,
{ layer: 'BlueMarbleNextGeneration', matrixSet: 'google3857',
requestEncoding: 'REST' });
expect(options.urls).to.be.an('array');
expect(options.urls).to.have.length(1);
expect(options.urls[0]).to.be.eql(
'http://www.example.com/wmts/coastlines/{TileMatrix}/{TileRow}/{TileCol}.png');
expect(options.layer).to.be.eql('BlueMarbleNextGeneration');
expect(options.matrixSet).to.be.eql('google3857');
expect(options.format).to.be.eql('image/png');
expect(options.projection).to.be.a(ol.proj.Projection);
expect(options.projection).to.be.eql(ol.proj.get('EPSG:3857'));
expect(options.requestEncoding).to.be.eql('REST');
expect(options.tileGrid).to.be.a(ol.tilegrid.WMTS);
expect(options.style).to.be.eql('DarkBlue');
expect(options.dimensions).to.eql({});
});
});
describe('when creating tileUrlFunction', function() {
it('can replace lowercase REST parameters',
function() {
var source = new ol.source.WMTS({
layer: 'layer',
style: 'default',
urls: ['http://www.example.com/wmts/coastlines/{layer}/{style}/' +
'{tilematrixset}/{TileMatrix}/{TileCol}/{TileRow}.jpg'],
matrixSet: 'EPSG:3857',
requestEncoding: 'REST',
tileGrid: new ol.tilegrid.WMTS({
origin: [-20037508.342789244, 20037508.342789244],
resolutions: [559082264.029 * 0.28E-3,
279541132.015 * 0.28E-3,
139770566.007 * 0.28E-3],
matrixIds: [0, 1, 2]
})
});
var projection = ol.proj.get('EPSG:3857');
var url = source.tileUrlFunction.call(source,
[1, 1, -2], 1, projection);
expect(url).to.be.eql('http://www.example.com/wmts/coastlines/' +
'layer/default/EPSG:3857/1/1/1.jpg');
});
it('can replace camelcase REST parameters',
function() {
var source = new ol.source.WMTS({
layer: 'layer',
style: 'default',
urls: ['http://www.example.com/wmts/coastlines/{Layer}/{Style}/' +
'{tilematrixset}/{TileMatrix}/{TileCol}/{TileRow}.jpg'],
matrixSet: 'EPSG:3857',
requestEncoding: 'REST',
tileGrid: new ol.tilegrid.WMTS({
origin: [-20037508.342789244, 20037508.342789244],
resolutions: [559082264.029 * 0.28E-3,
279541132.015 * 0.28E-3,
139770566.007 * 0.28E-3],
matrixIds: [0, 1, 2]
})
});
var projection = ol.proj.get('EPSG:3857');
var url = source.tileUrlFunction.call(source,
[1, 1, -2], 1, projection);
expect(url).to.be.eql('http://www.example.com/wmts/coastlines/' +
'layer/default/EPSG:3857/1/1/1.jpg');
});
});
});
goog.require('ol.format.WMTSCapabilities');
goog.require('ol.proj');
goog.require('ol.proj.Projection');
goog.require('ol.tilegrid.WMTS');
goog.require('ol.source.WMTS');

View File

@@ -264,8 +264,30 @@ describe('ol.Sphere', function() {
});
describe('Vincenty area', function() {
var geometry;
before(function(done) {
afterLoadText('spec/ol/format/wkt/illinois.wkt', function(wkt) {
try {
var format = new ol.format.WKT();
geometry = format.readGeometry(wkt);
} catch (e) {
done(e);
}
done();
});
});
it('results match the expected area of Ilinois', function() {
var coords = geometry.getPolygon(0).getLinearRing(0).getCoordinates();
expect(ol.sphere.WGS84.geodesicArea(coords)).to.equal(145978332359.37125);
});
});
});
goog.require('goog.math');
goog.require('ol.Sphere');
goog.require('ol.sphere.WGS84');
goog.require('ol.format.WKT');

View File

@@ -0,0 +1,68 @@
goog.provide('ol.test.tilegrid.WMTS');
describe('ol.tilegrid.WMTS', function() {
describe('when creating tileGrid from capabilities', function() {
var parser = new ol.format.WMTSCapabilities();
var capabilities;
before(function(done) {
afterLoadText('spec/ol/format/wmts/ogcsample.xml', function(xml) {
try {
capabilities = parser.read(xml);
} catch (e) {
done(e);
}
done();
});
});
it('can create tileGrid for EPSG:3857',
function() {
var matrixSetObj = capabilities.Contents.TileMatrixSet[0];
var tileGrid;
tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
matrixSetObj);
expect(tileGrid.matrixIds_).to.be.an('array');
expect(tileGrid.matrixIds_).to.have.length(20);
expect(tileGrid.matrixIds_).to.eql(
['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11',
'12', '13', '14', '15', '16', '17', '18', '19']);
expect(tileGrid.resolutions_).to.be.an('array');
expect(tileGrid.resolutions_).to.have.length(20);
expect(tileGrid.resolutions_).to.eql(
[156543.03392811998, 78271.51696419998, 39135.758481959994,
19567.879241008, 9783.939620504, 4891.969810252, 2445.984905126,
1222.9924525644, 611.4962262807999, 305.74811314039994,
152.87405657047998, 76.43702828523999, 38.21851414248,
19.109257071295996, 9.554628535647998, 4.777314267823999,
2.3886571339119995, 1.1943285669559998, 0.5971642834779999,
0.29858214174039993]);
expect(tileGrid.origins_).to.be.an('array');
expect(tileGrid.origins_).to.have.length(20);
expect(tileGrid.origins_).to.eql(
[[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428],
[-20037508.3428, 20037508.3428], [-20037508.3428, 20037508.3428]
]);
expect(tileGrid.tileSizes_).to.be.an('array');
expect(tileGrid.tileSizes_).to.have.length(20);
expect(tileGrid.tileSizes_).to.eql(
[256, 256, 256, 256, 256, 256, 256, 256, 256, 256,
256, 256, 256, 256, 256, 256, 256, 256, 256, 256]);
});
});
});
goog.require('ol.format.WMTSCapabilities');
goog.require('ol.tilegrid.WMTS');