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/)! 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/). 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. 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] p = self.tagStack[i]
if (not p or p.name == name) and not isNestable: if (not p or p.name == name) and not isNestable:
#Non-nestable tags get popped to the top or to their #Non-nestable tags get popped to the top or to their
#last occurance. #last occurrence.
popTo = name popTo = name
break break
if (nestingResetTriggers != None if (nestingResetTriggers != None
@@ -1242,14 +1242,14 @@ class BeautifulSoup(BeautifulStoneSoup):
* Tag nesting rules: * 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. a <p> tag should implicitly close the previous <p> tag.
<p>Para1<p>Para2 <p>Para1<p>Para2
should be transformed into: should be transformed into:
<p>Para1</p><p>Para2 <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 of a <blockquote> tag should _not_ implicitly close the previous
<blockquote> tag. <blockquote> tag.

View File

@@ -140,7 +140,7 @@
console.log('Capturing ' + lenHtmlFiles + ' example screenshots.'); 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 // page to a file
var interval = setInterval(function() { var interval = setInterval(function() {
if (!loadInProgress && pageindex < lenHtmlFiles) { 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. 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 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__': 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; font-size: 10px;
text-align: center; text-align: center;
margin: 1px; margin: 1px;
padding: 0px 2px;
} }
.ol-unsupported { .ol-unsupported {
display: none; 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="row-fluid">
<div class="span12"> <div class="span8">
<h4 id="title">Earthquakes heatmap</h4> <h4 id="title">Earthquakes heatmap</h4>
<p id="shortdesc">Demonstrates the use of a heatmap layer.</p> <p id="shortdesc">Demonstrates the use of a heatmap layer.</p>
<div id="docs"> <div id="docs">
@@ -40,9 +40,18 @@
</div> </div>
<div id="tags">heatmap, kml, vector, style</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> </div>
</div>
<script src="../resources/jquery.min.js" type="text/javascript"></script> <script src="../resources/jquery.min.js" type="text/javascript"></script>
<script src="loader.js?id=heatmap-earthquakes" type="text/javascript"></script> <script src="loader.js?id=heatmap-earthquakes" type="text/javascript"></script>

View File

@@ -5,6 +5,8 @@ goog.require('ol.layer.Tile');
goog.require('ol.source.KML'); goog.require('ol.source.KML');
goog.require('ol.source.Stamen'); goog.require('ol.source.Stamen');
var blur = $('#blur');
var radius = $('#radius');
var vector = new ol.layer.Heatmap({ var vector = new ol.layer.Heatmap({
source: new ol.source.KML({ source: new ol.source.KML({
@@ -12,7 +14,8 @@ var vector = new ol.layer.Heatmap({
projection: 'EPSG:3857', projection: 'EPSG:3857',
url: 'data/kml/2012_Earthquakes_Mag5.kml' 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) { vector.getSource().on('addfeature', function(event) {
@@ -38,3 +41,12 @@ var map = new ol.Map({
zoom: 2 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="length">Length</option>
<option value="area">Area</option> <option value="area">Area</option>
</select> </select>
<label class="checkbox"><input type="checkbox" id="geodesic"/>use geodesic measures</label>
</form> </form>
<div id="docs"> <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> 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> <p>See the <a href="measure.js" target="_blank">measure.js source</a> to see how this is done.</p>
</div> </div>

View File

@@ -1,5 +1,6 @@
goog.require('ol.Map'); goog.require('ol.Map');
goog.require('ol.Overlay'); goog.require('ol.Overlay');
goog.require('ol.Sphere');
goog.require('ol.View'); goog.require('ol.View');
goog.require('ol.geom.LineString'); goog.require('ol.geom.LineString');
goog.require('ol.geom.Polygon'); goog.require('ol.geom.Polygon');
@@ -7,6 +8,7 @@ goog.require('ol.interaction');
goog.require('ol.interaction.Draw'); goog.require('ol.interaction.Draw');
goog.require('ol.layer.Tile'); goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector'); goog.require('ol.layer.Vector');
goog.require('ol.proj');
goog.require('ol.source.MapQuest'); goog.require('ol.source.MapQuest');
goog.require('ol.source.Vector'); goog.require('ol.source.Vector');
goog.require('ol.style.Circle'); goog.require('ol.style.Circle');
@@ -14,6 +16,9 @@ goog.require('ol.style.Fill');
goog.require('ol.style.Stroke'); goog.require('ol.style.Stroke');
goog.require('ol.style.Style'); goog.require('ol.style.Style');
var wgs84Sphere = new ol.Sphere(6378137);
var raster = new ol.layer.Tile({ var raster = new ol.layer.Tile({
source: new ol.source.MapQuest({layer: 'sat'}) source: new ol.source.MapQuest({layer: 'sat'})
}); });
@@ -135,6 +140,7 @@ var map = new ol.Map({
map.on('pointermove', pointerMoveHandler); map.on('pointermove', pointerMoveHandler);
var typeSelect = document.getElementById('type'); var typeSelect = document.getElementById('type');
var geodesicCheckbox = document.getElementById('geodesic');
var draw; // global so we can remove it later var draw; // global so we can remove it later
function addInteraction() { function addInteraction() {
@@ -238,7 +244,19 @@ typeSelect.onchange = function(e) {
* @return {string} * @return {string}
*/ */
var formatLength = function(line) { 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; var output;
if (length > 100) { if (length > 100) {
output = (Math.round(length / 1000 * 100) / 100) + output = (Math.round(length / 1000 * 100) / 100) +
@@ -257,7 +275,16 @@ var formatLength = function(line) {
* @return {string} * @return {string}
*/ */
var formatArea = function(polygon) { 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; var output;
if (area > 10000) { if (area > 10000) {
output = (Math.round(area / 1000000 * 100) / 100) + 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. * Create an overlay to anchor the popup to the map.
*/ */
var overlay = new ol.Overlay({ var overlay = new ol.Overlay(/** @type {olx.OverlayOptions} */ ({
element: container 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. * 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 coordinate = evt.coordinate;
var hdms = ol.coordinate.toStringHDMS(ol.proj.transform( var hdms = ol.coordinate.toStringHDMS(ol.proj.transform(
coordinate, 'EPSG:3857', 'EPSG:4326')); coordinate, 'EPSG:3857', 'EPSG:4326'));

View File

@@ -35,14 +35,16 @@
<h4 id="title">Select features example</h4> <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 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>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"> <form class="form-inline">
<label>Action type &nbsp;</label> <label>Action type &nbsp;</label>
<select id="type"> <select id="type">
<option value="none" selected>None</option> <option value="none" selected>None</option>
<option value="singleclick">Single-click</option> <option value="singleclick">Single-click</option>
<option value="click">Click</option> <option value="click">Click</option>
<option value="mousemove">Hover</option> <option value="pointermove">Hover</option>
</select> </select>
<span id="status">&nbsp;0 selected features</span>
</form> </form>
<div id="docs"> <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> <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 condition: ol.events.condition.click
}); });
// select interaction working on "mousemove" // select interaction working on "pointermove"
var selectMouseMove = new ol.interaction.Select({ var selectPointerMove = new ol.interaction.Select({
condition: ol.events.condition.mouseMove condition: ol.events.condition.pointerMove
}); });
var selectElement = document.getElementById('type'); var selectElement = document.getElementById('type');
@@ -54,13 +54,18 @@ var changeInteraction = function() {
select = selectSingleClick; select = selectSingleClick;
} else if (value == 'click') { } else if (value == 'click') {
select = selectClick; select = selectClick;
} else if (value == 'mousemove') { } else if (value == 'pointermove') {
select = selectMouseMove; select = selectPointerMove;
} else { } else {
select = null; select = null;
} }
if (select !== null) { if (select !== null) {
map.addInteraction(select); 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 { h2 {
font-size: 1.5em; font-size: 1.5em;
line-height: 15px; line-height: 15px;
}; }
.scale-cnt { .scale-cnt {
margin: 5px; 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; oli.source;
/**
* @interface
*/
oli.source.TileEvent = function() {};
/**
* @type {ol.Tile}
*/
oli.source.TileEvent.prototype.tile;
/** /**
* @interface * @interface

View File

@@ -310,7 +310,10 @@ olx.MapOptions.prototype.view;
* position: (ol.Coordinate|undefined), * position: (ol.Coordinate|undefined),
* positioning: (ol.OverlayPositioning|string|undefined), * positioning: (ol.OverlayPositioning|string|undefined),
* stopEvent: (boolean|undefined), * stopEvent: (boolean|undefined),
* insertFirst: (boolean|undefined)}} * insertFirst: (boolean|undefined),
* autoPan: (boolean|undefined),
* autoPanAnimation: (olx.animation.PanOptions|undefined),
* autoPanMargin: (number|undefined)}}
* @api stable * @api stable
*/ */
olx.OverlayOptions; olx.OverlayOptions;
@@ -376,6 +379,35 @@ olx.OverlayOptions.prototype.stopEvent;
olx.OverlayOptions.prototype.insertFirst; 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. * Object literal with config options for the projection.
* @typedef {{code: string, * @typedef {{code: string,
@@ -4978,9 +5010,97 @@ olx.source.ServerVectorOptions.prototype.logo;
*/ */
olx.source.ServerVectorOptions.prototype.projection; 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), * tileLoadFunction: (ol.TileLoadFunctionType|undefined),
* url: string, * url: string,
* wrapX: (boolean|undefined)}} * wrapX: (boolean|undefined)}}
@@ -4989,6 +5109,16 @@ olx.source.ServerVectorOptions.prototype.projection;
olx.source.TileJSONOptions; 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 * 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 * `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), * img: (Image|undefined),
* offset: (Array.<number>|undefined), * offset: (Array.<number>|undefined),
* offsetOrigin: (ol.style.IconOrigin|undefined), * offsetOrigin: (ol.style.IconOrigin|undefined),
* opacity: (number|undefined),
* scale: (number|undefined), * scale: (number|undefined),
* snapToPixel: (boolean|undefined), * snapToPixel: (boolean|undefined),
* rotateWithView: (boolean|undefined), * rotateWithView: (boolean|undefined),
@@ -5878,6 +6009,14 @@ olx.style.IconOptions.prototype.offset;
olx.style.IconOptions.prototype.offsetOrigin; olx.style.IconOptions.prototype.offsetOrigin;
/**
* Opacity of the icon. Default is `1`.
* @type {number|undefined}
* @api
*/
olx.style.IconOptions.prototype.opacity;
/** /**
* Scale. * Scale.
* @type {number|undefined} * @type {number|undefined}

View File

@@ -1,6 +1,6 @@
{ {
"name": "openlayers", "name": "openlayers",
"version": "3.2.0", "version": "3.3.0",
"description": "Build tools and sources for developing OpenLayers based mapping applications", "description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [ "keywords": [
"map", "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. * @param {T} elem Element.
* @return {T|undefined} The removed element or undefined if elem was not found. * @return {T|undefined} The removed element or undefined if elem was not found.
* @api stable * @api stable

View File

@@ -159,7 +159,7 @@ ol.coordinate.degreesToStringHDMS_ = function(degrees, hemispheres) {
* that will be replaced by first and second coordinate values. * that will be replaced by first and second coordinate values.
* @param {number=} opt_fractionDigits The number of digits to include * @param {number=} opt_fractionDigits The number of digits to include
* after the decimal point. Default is `0`. * after the decimal point. Default is `0`.
* @return {string} Formated coordinate. * @return {string} Formatted coordinate.
* @api stable * @api stable
*/ */
ol.coordinate.format = function(coordinate, template, opt_fractionDigits) { ol.coordinate.format = function(coordinate, template, opt_fractionDigits) {

View File

@@ -28,7 +28,7 @@ ol.DeviceOrientationProperty = {
* *
* Many new computers, and especially mobile phones * Many new computers, and especially mobile phones
* and tablets, provide hardware support for device orientation. Web * 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. * class.
* *
* Device orientation data are relative to a common starting point. For mobile * 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; var alpha;
if (goog.userAgent.VERSION == '8.0') { if (goog.userAgent.VERSION == '8.0') {
regex = /progid:DXImageTransform\.Microsoft\.Alpha\(.*?\)/i, regex = /progid:DXImageTransform\.Microsoft\.Alpha\(.*?\)/i;
alpha = 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' + alpha = 'progid:DXImageTransform.Microsoft.Alpha(Opacity=' +
(value * 100) + ')'; (value * 100) + ')';
} else { } else {
@@ -298,3 +298,35 @@ ol.dom.transformElement2D =
// content size. // 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. * Always false.
* @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event. * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
@@ -86,6 +76,16 @@ ol.events.condition.mouseMove = function(mapBrowserEvent) {
ol.events.condition.never = goog.functions.FALSE; 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. * @param {ol.MapBrowserEvent} mapBrowserEvent Map browser event.
* @return {boolean} True if the event is a map `singleclick` 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) { if (val) {
return val; return val;
} }
val = callback.call(opt_this, ol.extent.getBottomRight(extent)); val = callback.call(opt_this, ol.extent.getTopLeft(extent));
if (val) { if (val) {
return val; return val;
} }

View File

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

View File

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

View File

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

View File

@@ -3,6 +3,7 @@ goog.provide('ol.interaction.Select');
goog.require('goog.array'); goog.require('goog.array');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.Event');
goog.require('goog.functions'); goog.require('goog.functions');
goog.require('ol.CollectionEventType'); goog.require('ol.CollectionEventType');
goog.require('ol.Feature'); goog.require('ol.Feature');
@@ -13,6 +14,51 @@ goog.require('ol.interaction.Interaction');
goog.require('ol.style.Style'); 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 * @classdesc
@@ -140,6 +186,7 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
var features = this.featureOverlay_.getFeatures(); var features = this.featureOverlay_.getFeatures();
var /** @type {Array.<ol.Feature>} */ deselected = []; var /** @type {Array.<ol.Feature>} */ deselected = [];
var /** @type {Array.<ol.Feature>} */ selected = []; var /** @type {Array.<ol.Feature>} */ selected = [];
var change = false;
if (set) { if (set) {
// Replace the currently selected feature(s) with the feature(s) at the // 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 // 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) { function(feature, layer) {
selected.push(feature); selected.push(feature);
}, undefined, this.layerFilter_); }, undefined, this.layerFilter_);
if (selected.length > 0 && if (selected.length > 0 && features.getLength() == 1 &&
features.getLength() == 1 && features.item(0) == selected[0]) {
features.item(0) == selected[selected.length - 1]) {
// No change // No change
} else { } else {
change = true;
if (features.getLength() !== 0) { if (features.getLength() !== 0) {
deselected = Array.prototype.concat(features.getArray());
features.clear(); features.clear();
} }
if (this.multi_) { if (this.multi_) {
features.extend(selected); features.extend(selected);
} else if (selected.length > 0) { } else if (selected.length > 0) {
features.push(selected[selected.length - 1]); features.push(selected[0]);
} }
} }
} else { } else {
@@ -190,8 +238,15 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
features.remove(deselected[i]); features.remove(deselected[i]);
} }
features.extend(selected); 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} * @enum {string}
*/ */
ol.layer.HeatmapLayerProperty = { ol.layer.HeatmapLayerProperty = {
GRADIENT: 'gradient' BLUR: 'blur',
GRADIENT: 'gradient',
RADIUS: 'radius'
}; };
@@ -52,6 +54,24 @@ ol.layer.Heatmap = function(opt_options) {
*/ */
this.gradient_ = null; 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, goog.events.listen(this,
ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT), ol.Object.getChangeEventType(ol.layer.HeatmapLayerProperty.GRADIENT),
this.handleGradientChanged_, false, this); this.handleGradientChanged_, false, this);
@@ -59,15 +79,16 @@ ol.layer.Heatmap = function(opt_options) {
this.setGradient(goog.isDef(options.gradient) ? this.setGradient(goog.isDef(options.gradient) ?
options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT); options.gradient : ol.layer.Heatmap.DEFAULT_GRADIENT);
var circle = ol.layer.Heatmap.createCircle_( this.setBlur(goog.isDef(options.blur) ? options.blur : 15);
goog.isDef(options.radius) ? options.radius : 8,
goog.isDef(options.blur) ? options.blur : 15,
goog.isDef(options.shadow) ? options.shadow : 250);
/** this.setRadius(goog.isDef(options.radius) ? options.radius : 8);
* @type {Array.<Array.<ol.style.Style>>}
*/ goog.events.listen(this, [
var styleCache = new Array(256); 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 weight = goog.isDef(options.weight) ? options.weight : 'weight';
var weightFunction; var weightFunction;
@@ -80,25 +101,27 @@ ol.layer.Heatmap = function(opt_options) {
} }
goog.asserts.assert(goog.isFunction(weightFunction)); 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 weight = weightFunction(feature);
var opacity = goog.isDef(weight) ? goog.math.clamp(weight, 0, 1) : 1; var opacity = goog.isDef(weight) ? goog.math.clamp(weight, 0, 1) : 1;
// cast to 8 bits // cast to 8 bits
var index = (255 * opacity) | 0; var index = (255 * opacity) | 0;
var style = styleCache[index]; var style = this.styleCache_[index];
if (!goog.isDef(style)) { if (!goog.isDef(style)) {
style = [ style = [
new ol.style.Style({ new ol.style.Style({
image: new ol.style.Icon({ image: new ol.style.Icon({
opacity: opacity, opacity: opacity,
src: circle src: this.circleImage_
}) })
}) })
]; ];
styleCache[index] = style; this.styleCache_[index] = style;
} }
return style; return style;
}); }, this));
// For performance reasons, don't sort the features before rendering. // For performance reasons, don't sort the features before rendering.
// The render order is not relevant for a heatmap representation. // 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} * @return {string}
* @private * @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 halfSize = radius + blur + 1;
var size = 2 * halfSize; var size = 2 * halfSize;
var context = ol.dom.createCanvasContext2D(size, size); var context = ol.dom.createCanvasContext2D(size, size);
context.shadowOffsetX = context.shadowOffsetY = shadow; context.shadowOffsetX = context.shadowOffsetY = this.shadow_;
context.shadowBlur = blur; context.shadowBlur = blur;
context.shadowColor = '#000'; context.shadowColor = '#000';
context.beginPath(); context.beginPath();
var center = halfSize - shadow; var center = halfSize - this.shadow_;
context.arc(center, center, radius, 0, Math.PI * 2, true); context.arc(center, center, radius, 0, Math.PI * 2, true);
context.fill(); context.fill();
return context.canvas.toDataURL(); 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. * @return {Array.<string>} Colors.
* @api * @api
@@ -178,6 +215,20 @@ goog.exportProperty(
ol.layer.Heatmap.prototype.getGradient); 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 * @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 * @param {ol.render.Event} event Post compose event
* @private * @private
*/ */
ol.layer.Heatmap.prototype.handleRender_ = function(event) { ol.layer.Heatmap.prototype.handleRender_ = function(event) {
goog.asserts.assert(event.type == ol.render.EventType.RENDER); goog.asserts.assert(event.type == ol.render.EventType.RENDER);
goog.asserts.assert(!goog.isNull(this.gradient_));
var context = event.context; var context = event.context;
var canvas = context.canvas; var canvas = context.canvas;
var image = context.getImageData(0, 0, canvas.width, canvas.height); 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. * @param {Array.<string>} colors Gradient.
* @api * @api
@@ -221,3 +297,17 @@ goog.exportProperty(
ol.layer.Heatmap.prototype, ol.layer.Heatmap.prototype,
'setGradient', 'setGradient',
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 layer renderers should skip when they can't reproject
// FIXME add tilt and height? // FIXME add tilt and height?

View File

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

View File

@@ -11,6 +11,9 @@ goog.require('ol.Coordinate');
goog.require('ol.Map'); goog.require('ol.Map');
goog.require('ol.MapEventType'); goog.require('ol.MapEventType');
goog.require('ol.Object'); 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_ = goog.dom.createElement(goog.dom.TagName.DIV);
this.element_.style.position = 'absolute'; 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 * @private
* @type {{bottom_: string, * @type {{bottom_: string,
@@ -291,6 +314,9 @@ ol.Overlay.prototype.handleOffsetChanged = function() {
*/ */
ol.Overlay.prototype.handlePositionChanged = function() { ol.Overlay.prototype.handlePositionChanged = function() {
this.updatePixelPosition_(); this.updatePixelPosition_();
if (goog.isDef(this.get(ol.OverlayProperty.POSITION)) && this.autoPan_) {
this.panIntoView_();
}
}; };
@@ -364,6 +390,89 @@ goog.exportProperty(
ol.Overlay.prototype.setPosition); 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. * Set the positioning for this overlay.
* @param {ol.OverlayPositioning} positioning how the overlay is * @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. // Touch identifiers can start at 0.
// Add 2 to the touch identifier for compatibility. // Add 2 to the touch identifier for compatibility.
e.pointerId = inTouch.identifier + 2; e.pointerId = inTouch.identifier + 2;
// TODO: check if this is neccessary? // TODO: check if this is necessary?
//e.target = findTarget(e); //e.target = findTarget(e);
e.bubbles = true; e.bubbles = true;
e.cancelable = true; e.cancelable = true;

View File

@@ -32,7 +32,8 @@ ol.proj.Units = {
DEGREES: 'degrees', DEGREES: 'degrees',
FEET: 'ft', FEET: 'ft',
METERS: 'm', 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; 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.FEET] = 0.3048;
ol.proj.METERS_PER_UNIT[ol.proj.Units.METERS] = 1; 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.extent');
goog.require('ol.layer.Image'); goog.require('ol.layer.Image');
goog.require('ol.proj'); goog.require('ol.proj');
goog.require('ol.renderer.Map');
goog.require('ol.renderer.canvas.Layer'); goog.require('ol.renderer.canvas.Layer');
goog.require('ol.source.ImageVector'); goog.require('ol.source.ImageVector');
goog.require('ol.vec.Mat4'); goog.require('ol.vec.Mat4');
@@ -19,12 +18,11 @@ goog.require('ol.vec.Mat4');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.canvas.Layer} * @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Image} imageLayer Single image layer. * @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 * @private
@@ -88,7 +86,9 @@ ol.renderer.canvas.ImageLayer.prototype.forEachLayerAtPixel =
if (this.getLayer().getSource() instanceof ol.source.ImageVector) { if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
// for ImageVector sources use the original hit-detection logic, // for ImageVector sources use the original hit-detection logic,
// so that for example also transparent polygons are detected // 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( var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, goog.functions.TRUE, this); coordinate, frameState, goog.functions.TRUE, this);

View File

@@ -17,12 +17,11 @@ goog.require('ol.vec.Mat4');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.Layer} * @extends {ol.renderer.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer. * @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 * @private

View File

@@ -77,11 +77,11 @@ goog.inherits(ol.renderer.canvas.Map, ol.renderer.Map);
*/ */
ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) { ol.renderer.canvas.Map.prototype.createLayerRenderer = function(layer) {
if (ol.ENABLE_IMAGE && layer instanceof ol.layer.Image) { 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) { } 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) { } 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 { } else {
goog.asserts.fail(); goog.asserts.fail();
return null; return null;

View File

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

View File

@@ -17,12 +17,11 @@ goog.require('ol.renderer.vector');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.canvas.Layer} * @extends {ol.renderer.canvas.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Vector} vectorLayer Vector layer. * @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 * @private

View File

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

View File

@@ -8,13 +8,12 @@ goog.require('ol.renderer.Layer');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.Layer} * @extends {ol.renderer.Layer}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer. * @param {ol.layer.Layer} layer Layer.
* @param {!Element} target Target. * @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} * @type {!Element}

View File

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

View File

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

View File

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

View File

@@ -6,6 +6,7 @@ goog.require('goog.events');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('goog.functions'); goog.require('goog.functions');
goog.require('ol.ImageState'); goog.require('ol.ImageState');
goog.require('ol.Observable');
goog.require('ol.TileRange'); goog.require('ol.TileRange');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.layer.Layer'); goog.require('ol.layer.Layer');
@@ -13,27 +14,21 @@ goog.require('ol.source.Source');
goog.require('ol.source.State'); goog.require('ol.source.State');
goog.require('ol.source.Tile'); goog.require('ol.source.Tile');
goog.require('ol.tilecoord'); goog.require('ol.tilecoord');
goog.require('ol.vec.Mat4');
/** /**
* @constructor * @constructor
* @extends {goog.Disposable} * @extends {ol.Observable}
* @param {ol.renderer.Map} mapRenderer Map renderer.
* @param {ol.layer.Layer} layer Layer. * @param {ol.layer.Layer} layer Layer.
* @suppress {checkStructDictInheritance} * @suppress {checkStructDictInheritance}
* @struct * @struct
*/ */
ol.renderer.Layer = function(mapRenderer, layer) { ol.renderer.Layer = function(layer) {
goog.base(this); goog.base(this);
/**
* @private
* @type {ol.renderer.Map}
*/
this.mapRenderer_ = mapRenderer;
/** /**
* @private * @private
* @type {ol.layer.Layer} * @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 = ol.renderer.Layer.prototype.forEachLayerAtPixel =
function(pixel, frameState, callback, thisArg) { 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( var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, goog.functions.TRUE, this); coordinate, frameState, goog.functions.TRUE, this);
@@ -87,6 +85,34 @@ ol.renderer.Layer.prototype.forEachLayerAtPixel =
ol.renderer.Layer.prototype.hasFeatureAtCoordinate = goog.functions.FALSE; 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 * @protected
* @return {ol.layer.Layer} Layer. * @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. * Handle changes in image state.
* @param {goog.events.Event} event Image change event. * @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() { ol.renderer.Layer.prototype.renderIfReadyAndVisible = function() {
var layer = this.getLayer(); var layer = this.getLayer();
if (layer.getVisible() && layer.getSourceState() == ol.source.State.READY) { 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 {ol.Coordinate} center Center.
* @param {number} resolution Resolution. * @param {number} resolution Resolution.

View File

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

View File

@@ -22,7 +22,7 @@ goog.require('ol.webgl.Context');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.webgl.Layer} * @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. * @param {ol.layer.Image} imageLayer Tile layer.
*/ */
ol.renderer.webgl.ImageLayer = function(mapRenderer, imageLayer) { 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 // http://learningwebgl.com/blog/?p=2101
var imageElement = image.getImage(); var imageElement = image.getImage();
var gl = this.getWebGLMapRenderer().getGL(); var gl = this.mapRenderer.getGL();
return ol.webgl.Context.createTexture( return ol.webgl.Context.createTexture(
gl, imageElement, goog.webgl.CLAMP_TO_EDGE, goog.webgl.CLAMP_TO_EDGE); 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 = ol.renderer.webgl.ImageLayer.prototype.prepareFrame =
function(frameState, layerState, context) { function(frameState, layerState, context) {
var gl = this.getWebGLMapRenderer().getGL(); var gl = this.mapRenderer.getGL();
var viewState = frameState.viewState; var viewState = frameState.viewState;
var viewCenter = viewState.center; var viewCenter = viewState.center;
@@ -155,7 +155,7 @@ ol.renderer.webgl.ImageLayer.prototype.prepareFrame =
if (!goog.isNull(image)) { if (!goog.isNull(image)) {
goog.asserts.assert(!goog.isNull(texture)); goog.asserts.assert(!goog.isNull(texture));
var canvas = this.getWebGLMapRenderer().getContext().getCanvas(); var canvas = this.mapRenderer.getContext().getCanvas();
this.updateProjectionMatrix_(canvas.width, canvas.height, this.updateProjectionMatrix_(canvas.width, canvas.height,
viewCenter, viewResolution, viewRotation, image.getExtent()); viewCenter, viewResolution, viewRotation, image.getExtent());
@@ -235,7 +235,9 @@ ol.renderer.webgl.ImageLayer.prototype.forEachLayerAtPixel =
if (this.getLayer().getSource() instanceof ol.source.ImageVector) { if (this.getLayer().getSource() instanceof ol.source.ImageVector) {
// for ImageVector sources use the original hit-detection logic, // for ImageVector sources use the original hit-detection logic,
// so that for example also transparent polygons are detected // 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( var hasFeature = this.forEachFeatureAtCoordinate(
coordinate, frameState, goog.functions.TRUE, this); coordinate, frameState, goog.functions.TRUE, this);

View File

@@ -18,12 +18,18 @@ goog.require('ol.webgl.Context');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.Layer} * @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. * @param {ol.layer.Layer} layer Layer.
*/ */
ol.renderer.webgl.Layer = function(mapRenderer, 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 * @private
@@ -96,8 +102,7 @@ goog.inherits(ol.renderer.webgl.Layer, ol.renderer.Layer);
ol.renderer.webgl.Layer.prototype.bindFramebuffer = ol.renderer.webgl.Layer.prototype.bindFramebuffer =
function(frameState, framebufferDimension) { function(frameState, framebufferDimension) {
var mapRenderer = this.getWebGLMapRenderer(); var gl = this.mapRenderer.getGL();
var gl = mapRenderer.getGL();
if (!goog.isDef(this.framebufferDimension) || if (!goog.isDef(this.framebufferDimension) ||
this.framebufferDimension != 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. * @return {!goog.vec.Mat4.Number} Matrix.
*/ */

View File

@@ -25,7 +25,7 @@ goog.require('ol.webgl.Buffer');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.webgl.Layer} * @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. * @param {ol.layer.Tile} tileLayer Tile layer.
*/ */
ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) { ol.renderer.webgl.TileLayer = function(mapRenderer, tileLayer) {
@@ -88,13 +88,47 @@ goog.inherits(ol.renderer.webgl.TileLayer, ol.renderer.webgl.Layer);
* @inheritDoc * @inheritDoc
*/ */
ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() { ol.renderer.webgl.TileLayer.prototype.disposeInternal = function() {
var mapRenderer = this.getWebGLMapRenderer(); var context = this.mapRenderer.getContext();
var context = mapRenderer.getContext();
context.deleteBuffer(this.renderArrayBuffer_); context.deleteBuffer(this.renderArrayBuffer_);
goog.base(this, 'disposeInternal'); 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 * @inheritDoc
*/ */
@@ -110,7 +144,7 @@ ol.renderer.webgl.TileLayer.prototype.handleWebGLContextLost = function() {
ol.renderer.webgl.TileLayer.prototype.prepareFrame = ol.renderer.webgl.TileLayer.prototype.prepareFrame =
function(frameState, layerState, context) { function(frameState, layerState, context) {
var mapRenderer = this.getWebGLMapRenderer(); var mapRenderer = this.mapRenderer;
var gl = context.getGL(); var gl = context.getGL();
var viewState = frameState.viewState; var viewState = frameState.viewState;
@@ -191,12 +225,8 @@ ol.renderer.webgl.TileLayer.prototype.prepareFrame =
var tilesToDrawByZ = {}; var tilesToDrawByZ = {};
tilesToDrawByZ[z] = {}; tilesToDrawByZ[z] = {};
var getTileIfLoaded = this.createGetTileIfLoadedFunction(function(tile) { var findLoadedTiles = this.createLoadedTileFinder(
return !goog.isNull(tile) && tile.getState() == ol.TileState.LOADED && tileSource, tilesToDrawByZ);
mapRenderer.isTileTextureLoaded(tile);
}, tileSource, pixelRatio, projection);
var findLoadedTiles = goog.bind(tileSource.findLoadedTiles, tileSource,
tilesToDrawByZ, getTileIfLoaded);
var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError(); var useInterimTilesOnError = tileLayer.getUseInterimTilesOnError();
var allTilesLoaded = true; var allTilesLoaded = true;
@@ -337,11 +367,10 @@ ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel =
if (goog.isNull(this.framebuffer)) { if (goog.isNull(this.framebuffer)) {
return undefined; return undefined;
} }
var mapSize = this.getMap().getSize();
var pixelOnMapScaled = [ var pixelOnMapScaled = [
pixel[0] / mapSize[0], pixel[0] / frameState.size[0],
(mapSize[1] - pixel[1]) / mapSize[1]]; (frameState.size[1] - pixel[1]) / frameState.size[1]];
var pixelOnFrameBufferScaled = [0, 0]; var pixelOnFrameBufferScaled = [0, 0];
ol.vec.Mat4.multVec2( ol.vec.Mat4.multVec2(
@@ -350,7 +379,7 @@ ol.renderer.webgl.TileLayer.prototype.forEachLayerAtPixel =
pixelOnFrameBufferScaled[0] * this.framebufferDimension, pixelOnFrameBufferScaled[0] * this.framebufferDimension,
pixelOnFrameBufferScaled[1] * this.framebufferDimension]; pixelOnFrameBufferScaled[1] * this.framebufferDimension];
var gl = this.getWebGLMapRenderer().getContext().getGL(); var gl = this.mapRenderer.getContext().getGL();
gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer); gl.bindFramebuffer(gl.FRAMEBUFFER, this.framebuffer);
var imageData = new Uint8Array(4); var imageData = new Uint8Array(4);
gl.readPixels(pixelOnFrameBuffer[0], pixelOnFrameBuffer[1], 1, 1, 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.render.webgl.ReplayGroup');
goog.require('ol.renderer.vector'); goog.require('ol.renderer.vector');
goog.require('ol.renderer.webgl.Layer'); goog.require('ol.renderer.webgl.Layer');
goog.require('ol.vec.Mat4');
/** /**
* @constructor * @constructor
* @extends {ol.renderer.webgl.Layer} * @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. * @param {ol.layer.Vector} vectorLayer Vector layer.
*/ */
ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) { ol.renderer.webgl.VectorLayer = function(mapRenderer, vectorLayer) {
@@ -94,8 +95,7 @@ ol.renderer.webgl.VectorLayer.prototype.composeFrame =
ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() { ol.renderer.webgl.VectorLayer.prototype.disposeInternal = function() {
var replayGroup = this.replayGroup_; var replayGroup = this.replayGroup_;
if (!goog.isNull(replayGroup)) { if (!goog.isNull(replayGroup)) {
var mapRenderer = this.getWebGLMapRenderer(); var context = this.mapRenderer.getContext();
var context = mapRenderer.getContext();
replayGroup.getDeleteResourcesFunction(context)(); replayGroup.getDeleteResourcesFunction(context)();
this.replayGroup_ = null; this.replayGroup_ = null;
} }
@@ -111,8 +111,7 @@ ol.renderer.webgl.VectorLayer.prototype.forEachFeatureAtCoordinate =
if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) { if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) {
return undefined; return undefined;
} else { } else {
var mapRenderer = this.getWebGLMapRenderer(); var context = this.mapRenderer.getContext();
var context = mapRenderer.getContext();
var viewState = frameState.viewState; var viewState = frameState.viewState;
var layer = this.getLayer(); var layer = this.getLayer();
var layerState = this.layerState_; var layerState = this.layerState_;
@@ -147,8 +146,7 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate =
if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) { if (goog.isNull(this.replayGroup_) || goog.isNull(this.layerState_)) {
return false; return false;
} else { } else {
var mapRenderer = this.getWebGLMapRenderer(); var context = this.mapRenderer.getContext();
var context = mapRenderer.getContext();
var viewState = frameState.viewState; var viewState = frameState.viewState;
var layerState = this.layerState_; var layerState = this.layerState_;
return this.replayGroup_.hasFeatureAtCoordinate(coordinate, return this.replayGroup_.hasFeatureAtCoordinate(coordinate,
@@ -165,7 +163,9 @@ ol.renderer.webgl.VectorLayer.prototype.hasFeatureAtCoordinate =
*/ */
ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel = ol.renderer.webgl.VectorLayer.prototype.forEachLayerAtPixel =
function(pixel, frameState, callback, thisArg) { 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); var hasFeature = this.hasFeatureAtCoordinate(coordinate, frameState);
if (hasFeature) { if (hasFeature) {

View File

@@ -98,6 +98,9 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse =
} }
var brandLogoUri = response.brandLogoUri; 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 copyright = response.copyright; // FIXME do we need to display this?
var resource = response.resourceSets[0].resources[0]; var resource = response.resourceSets[0].resources[0];
goog.asserts.assert(resource.imageWidth == resource.imageHeight); 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); 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 * @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. * @return {ol.source.Vector} Source.
* @api * @api
*/ */

View File

@@ -24,10 +24,17 @@ ol.source.MapQuest = function(opt_options) {
var layerConfig = ol.source.MapQuestConfig[options.layer]; 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 protocol = ol.IS_HTTPS ? 'https:' : 'http:';
var url = goog.isDef(options.url) ? options.url : var url = goog.isDef(options.url) ? options.url :
protocol + '//otile{1-4}-s.mqcdn.com/tiles/1.0.0/' + 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, { goog.base(this, {
attributions: layerConfig.attributions, 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('goog.events.EventType');
goog.require('ol.Attribution'); goog.require('ol.Attribution');
goog.require('ol.Observable'); goog.require('ol.Object');
goog.require('ol.proj'); goog.require('ol.proj');
@@ -37,7 +37,7 @@ ol.source.SourceOptions;
* Base class for {@link ol.layer.Layer} sources. * Base class for {@link ol.layer.Layer} sources.
* *
* @constructor * @constructor
* @extends {ol.Observable} * @extends {ol.Object}
* @fires change Triggered when the state of the source changes. * @fires change Triggered when the state of the source changes.
* @param {ol.source.SourceOptions} options Source options. * @param {ol.source.SourceOptions} options Source options.
* @api stable * @api stable
@@ -73,7 +73,7 @@ ol.source.Source = function(options) {
options.state : ol.source.State.READY; 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.provide('ol.source.TileDebug');
goog.require('ol.Tile'); goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileCoord'); goog.require('ol.TileCoord');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.dom'); goog.require('ol.dom');
@@ -89,42 +88,20 @@ ol.source.TileDebug = function(options) {
tileGrid: options.tileGrid tileGrid: options.tileGrid
}); });
/**
* @private
* @type {ol.TileCache}
*/
this.tileCache_ = new ol.TileCache();
}; };
goog.inherits(ol.source.TileDebug, ol.source.Tile); 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 * @inheritDoc
*/ */
ol.source.TileDebug.prototype.getTile = function(z, x, y) { ol.source.TileDebug.prototype.getTile = function(z, x, y) {
var tileCoordKey = this.getKeyZXY(z, x, y); var tileCoordKey = this.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) { if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.DebugTile_} */ (this.tileCache_.get(tileCoordKey)); return /** @type {!ol.DebugTile_} */ (this.tileCache.get(tileCoordKey));
} else { } else {
var tile = new ol.DebugTile_([z, x, y], this.tileGrid); var tile = new ol.DebugTile_([z, x, y], this.tileGrid);
this.tileCache_.set(tileCoordKey, tile); this.tileCache.set(tileCoordKey, tile);
return tile; return tile;
} }
}; };

View File

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

View File

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

View File

@@ -1,10 +1,12 @@
goog.provide('ol.source.Tile'); goog.provide('ol.source.Tile');
goog.provide('ol.source.TileOptions'); goog.provide('ol.source.TileOptions');
goog.require('goog.functions'); goog.require('goog.events.Event');
goog.require('ol.Attribution'); goog.require('ol.Attribution');
goog.require('ol.Extent'); goog.require('ol.Extent');
goog.require('ol.TileCache');
goog.require('ol.TileRange'); goog.require('ol.TileRange');
goog.require('ol.TileState');
goog.require('ol.source.Source'); goog.require('ol.source.Source');
goog.require('ol.tilecoord'); goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid'); goog.require('ol.tilegrid.TileGrid');
@@ -64,6 +66,12 @@ ol.source.Tile = function(options) {
*/ */
this.tileGrid = goog.isDef(options.tileGrid) ? options.tileGrid : null; 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); 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. * @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. * @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 {number} z Zoom level.
* @param {ol.TileRange} tileRange Tile range. * @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. * @return {boolean} The tile range is fully covered with loaded tiles.
*/ */
ol.source.Tile.prototype.findLoadedTiles = function(loadedTilesByZ, ol.source.Tile.prototype.forEachLoadedTile = function(z, tileRange, callback) {
getTileIfLoaded, z, tileRange) { var covered = true;
// FIXME this could be more efficient about filling partial holes var tile, tileCoordKey, loaded;
var fullyCovered = true; for (var x = tileRange.minX; x <= tileRange.maxX; ++x) {
var tile, tileCoordKey, x, y; for (var y = tileRange.minY; y <= tileRange.maxY; ++y) {
for (x = tileRange.minX; x <= tileRange.maxX; ++x) {
for (y = tileRange.minY; y <= tileRange.maxY; ++y) {
tileCoordKey = this.getKeyZXY(z, x, y); tileCoordKey = this.getKeyZXY(z, x, y);
if (loadedTilesByZ[z] && loadedTilesByZ[z][tileCoordKey]) { loaded = false;
continue; 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);
} }
tile = getTileIfLoaded(z, x, y);
if (!goog.isNull(tile)) {
if (!loadedTilesByZ[z]) {
loadedTilesByZ[z] = {};
} }
loadedTilesByZ[z][tileCoordKey] = tile; if (!loaded) {
} else { covered = false;
fullyCovered = false;
} }
} }
} }
return fullyCovered; return covered;
}; };
@@ -206,3 +210,59 @@ ol.source.Tile.prototype.getTilePixelSize =
* @param {number} y Tile coordinate y. * @param {number} y Tile coordinate y.
*/ */
ol.source.Tile.prototype.useTile = goog.nullFunction; 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('goog.net.Jsonp');
goog.require('ol.Attribution'); goog.require('ol.Attribution');
goog.require('ol.Tile'); goog.require('ol.Tile');
goog.require('ol.TileCache');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.TileUrlFunction'); goog.require('ol.TileUrlFunction');
goog.require('ol.extent'); goog.require('ol.extent');
@@ -46,12 +45,6 @@ ol.source.TileUTFGrid = function(options) {
*/ */
this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction; this.tileUrlFunction_ = ol.TileUrlFunction.nullTileUrlFunction;
/**
* @private
* @type {!ol.TileCache}
*/
this.tileCache_ = new ol.TileCache();
/** /**
* @private * @private
* @type {string|undefined} * @type {string|undefined}
@@ -64,22 +57,6 @@ ol.source.TileUTFGrid = function(options) {
goog.inherits(ol.source.TileUTFGrid, ol.source.Tile); 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. * @return {string|undefined} The template from TileJSON.
* @api * @api
@@ -195,8 +172,8 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
ol.source.TileUTFGrid.prototype.getTile = ol.source.TileUTFGrid.prototype.getTile =
function(z, x, y, pixelRatio, projection) { function(z, x, y, pixelRatio, projection) {
var tileCoordKey = this.getKeyZXY(z, x, y); var tileCoordKey = this.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) { if (this.tileCache.containsKey(tileCoordKey)) {
return /** @type {!ol.Tile} */ (this.tileCache_.get(tileCoordKey)); return /** @type {!ol.Tile} */ (this.tileCache.get(tileCoordKey));
} else { } else {
goog.asserts.assert(projection); goog.asserts.assert(projection);
var tileCoord = [z, x, y]; var tileCoord = [z, x, y];
@@ -207,7 +184,7 @@ ol.source.TileUTFGrid.prototype.getTile =
goog.isDef(tileUrl) ? tileUrl : '', goog.isDef(tileUrl) ? tileUrl : '',
this.tileGrid.getTileCoordExtent(tileCoord), this.tileGrid.getTileCoordExtent(tileCoord),
this.preemptive_); this.preemptive_);
this.tileCache_.set(tileCoordKey, tile); this.tileCache.set(tileCoordKey, tile);
return tile; return tile;
} }
}; };
@@ -218,8 +195,8 @@ ol.source.TileUTFGrid.prototype.getTile =
*/ */
ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) { ol.source.TileUTFGrid.prototype.useTile = function(z, x, y) {
var tileCoordKey = this.getKeyZXY(z, x, y); var tileCoordKey = this.getKeyZXY(z, x, y);
if (this.tileCache_.containsKey(tileCoordKey)) { if (this.tileCache.containsKey(tileCoordKey)) {
this.tileCache_.get(tileCoordKey); this.tileCache.get(tileCoordKey);
} }
}; };

View File

@@ -5,6 +5,7 @@ goog.require('goog.array');
goog.require('goog.asserts'); goog.require('goog.asserts');
goog.require('goog.math'); goog.require('goog.math');
goog.require('goog.object'); goog.require('goog.object');
goog.require('goog.string');
goog.require('goog.uri.utils'); goog.require('goog.uri.utils');
goog.require('ol.TileUrlFunction'); goog.require('ol.TileUrlFunction');
goog.require('ol.TileUrlFunctionType'); goog.require('ol.TileUrlFunctionType');
@@ -40,8 +41,17 @@ ol.source.WMTS = function(options) {
// TODO: add support for TileMatrixLimits // 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 * @private
@@ -56,6 +66,24 @@ ol.source.WMTS = function(options) {
this.coordKeyPrefix_ = ''; this.coordKeyPrefix_ = '';
this.resetCoordKeyPrefix_(); 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) // FIXME: should we guess this requestEncoding from options.url(s)
// structure? that would mean KVP only if a template is not provided. // structure? that would mean KVP only if a template is not provided.
var requestEncoding = goog.isDef(options.requestEncoding) ? 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 // we could issue a getCapabilities xhr to retrieve missing configuration
var tileGrid = options.tileGrid; 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 = { var context = {
'Layer': options.layer, 'layer': this.layer_,
'Style': options.style, 'style': this.style_,
'TileMatrixSet': options.matrixSet 'tilematrixset': this.matrixSet_
}; };
if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) { if (requestEncoding == ol.source.WMTSRequestEncoding.KVP) {
goog.object.extend(context, { goog.object.extend(context, {
'Service': 'WMTS', 'Service': 'WMTS',
'Request': 'GetTile', 'Request': 'GetTile',
'Version': version, 'Version': this.version_,
'Format': format 'Format': this.format_
}); });
} }
@@ -96,7 +126,7 @@ ol.source.WMTS = function(options) {
template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ? template = (requestEncoding == ol.source.WMTSRequestEncoding.KVP) ?
goog.uri.utils.appendParamsFromMap(template, context) : goog.uri.utils.appendParamsFromMap(template, context) :
template.replace(/\{(\w+?)\}/g, function(m, p) { template.replace(/\{(\w+?)\}/g, function(m, p) {
return (p in context) ? context[p] : m; return (p.toLowerCase() in context) ? context[p.toLowerCase()] : m;
}); });
return ( 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 * @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 * @private
*/ */
@@ -239,35 +314,84 @@ ol.source.WMTS.prototype.updateDimensions = function(dimensions) {
/** /**
* @param {Object} wmtsCap An object representing the capabilities document. * @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. * @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 */ /* jshint -W069 */
// TODO: add support for TileMatrixLimits // 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) { 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(!goog.isNull(l));
goog.asserts.assert(l['tileMatrixSetLinks'].length > 0);
var matrixSet = /** @type {string} */ goog.asserts.assert(l['TileMatrixSetLink'].length > 0);
(l['tileMatrixSetLinks'][0]['tileMatrixSet']); var idx, matrixSet;
var format = /** @type {string} */ (l['formats'][0]); if (l['TileMatrixSetLink'].length > 1) {
var idx = goog.array.findIndex(l['styles'], function(elt, index, array) { 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']; return elt['isDefault'];
}
}); });
if (idx < 0) { if (idx < 0) {
idx = 0; idx = 0;
} }
var style = /** @type {string} */ (l['styles'][idx]['identifier']); var style = /** @type {string} */ (l['Style'][idx]['Identifier']);
var dimensions = {}; var dimensions = {};
goog.array.forEach(l['dimensions'], function(elt, index, array) { if (goog.isDef(l['Dimension'])) {
var key = elt['identifier']; goog.array.forEach(l['Dimension'], function(elt, index, array) {
var key = elt['Identifier'];
var value = elt['default']; var value = elt['default'];
if (goog.isDef(value)) { if (goog.isDef(value)) {
goog.asserts.assert(goog.array.contains(elt['values'], value)); goog.asserts.assert(goog.array.contains(elt['values'], value));
@@ -277,52 +401,62 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, layer) {
goog.asserts.assert(goog.isDef(value)); goog.asserts.assert(goog.isDef(value));
dimensions[key] = value; dimensions[key] = value;
}); });
}
var matrixSets = wmtsCap['contents']['tileMatrixSets']; var matrixSets = wmtsCap['Contents']['TileMatrixSet'];
goog.asserts.assert(matrixSet in matrixSets); var matrixSetObj = goog.array.find(matrixSets, function(elt, index, array) {
var matrixSetObj = matrixSets[matrixSet]; return elt['Identifier'] == matrixSet;
});
goog.asserts.assert(!goog.isNull(matrixSetObj));
var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet( var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
matrixSetObj); matrixSetObj);
var projection = ol.proj.get(matrixSetObj['supportedCRS']); 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'));
}
var gets = wmtsCap['operationsMetadata']['GetTile']['dcp']['http']['get']; /** @type {!Array.<string>} */
var encodings = goog.object.getKeys( var urls = [];
gets[0]['constraints']['GetEncoding']['allowedValues']); var requestEncoding = config['requestEncoding'];
goog.asserts.assert(encodings.length > 0); requestEncoding = goog.isDef(requestEncoding) ? requestEncoding : '';
var urls; goog.asserts.assert(
var requestEncoding; goog.array.contains(['REST', 'RESTful', 'KVP', ''], requestEncoding));
switch (encodings[0]) {
case 'REST': if (!wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') ||
case 'RESTful': goog.string.startsWith(requestEncoding, 'REST')) {
// The OGC documentation is not clear if we should use REST or RESTful, // Add REST tile resource url
// ArcGis use RESTful, and OpenLayers use REST.
requestEncoding = ol.source.WMTSRequestEncoding.REST; requestEncoding = ol.source.WMTSRequestEncoding.REST;
goog.asserts.assert(l['resourceUrls'].hasOwnProperty('tile')); goog.array.forEach(l['ResourceURL'], function(elt, index, array) {
goog.asserts.assert(l['resourceUrls']['tile'].hasOwnProperty(format)); if (elt['resourceType'] == 'tile') {
urls = /** @type {Array.<string>} */ format = elt['format'];
(l['resourceUrls']['tile'][format]); urls.push(/** @type {string} */ (elt['template']));
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); } else {
break; var gets = wmtsCap['OperationsMetadata']['GetTile']['DCP']['HTTP']['Get'];
default:
goog.asserts.fail(); 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 { return {
urls: urls, urls: urls,
layer: layer, layer: config['layer'],
matrixSet: matrixSet, matrixSet: matrixSet,
format: format, format: format,
projection: projection, projection: projection,

View File

@@ -2,7 +2,7 @@
* @license * @license
* Latitude/longitude spherical geodesy formulae taken from * Latitude/longitude spherical geodesy formulae taken from
* http://www.movable-type.co.uk/scripts/latlong.html * 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 // 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. * 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} c1 Coordinate 1.
* @param {ol.Coordinate} c2 Coordinate 2. * @param {ol.Coordinate} c2 Coordinate 2.
* @return {number} Haversine distance. * @return {number} Haversine distance.
* @api
*/ */
ol.Sphere.prototype.haversineDistance = function(c1, c2) { ol.Sphere.prototype.haversineDistance = function(c1, c2) {
var lat1 = goog.math.toRadians(c1[1]); var lat1 = goog.math.toRadians(c1[1]);

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,7 @@ goog.provide('ol.TileQueue');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('ol.Coordinate'); goog.require('ol.Coordinate');
goog.require('ol.TileState');
goog.require('ol.structs.PriorityQueue'); goog.require('ol.structs.PriorityQueue');
@@ -67,11 +68,17 @@ ol.TileQueue.prototype.getTilesLoading = function() {
/** /**
* @param {goog.events.Event} event Event.
* @protected * @protected
*/ */
ol.TileQueue.prototype.handleTileChange = function() { 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.tilesLoading_;
this.tileChangeCallback_(); this.tileChangeCallback_();
}
}; };
@@ -85,7 +92,7 @@ ol.TileQueue.prototype.loadMoreTiles = function(maxTotalLoading, maxNewLoads) {
var i, tile; var i, tile;
for (i = 0; i < newLoads; ++i) { for (i = 0; i < newLoads; ++i) {
tile = /** @type {ol.Tile} */ (this.dequeue()[0]); 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); this.handleTileChange, false, this);
tile.load(); 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 * 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 * 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#'). * match all symbol names that start with 'foo.Bar#').
* *
* @param {Array.<string>} patterns A list of symbol names to match. Wildcards * @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. * 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). * with the patterns and symbols (or any error).
*/ */
function getInfo(callback) { function getInfo(callback) {

View File

@@ -220,7 +220,7 @@ describe('ol.format.GPX', function() {
expect(serialized).to.xmleql(ol.xml.parse(text)); 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 = var text =
'<gpx xmlns="http://www.topografix.com/GPX/1/1">' + '<gpx xmlns="http://www.topografix.com/GPX/1/1">' +
' <trk>' + ' <trk>' +

View File

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

View File

@@ -4,7 +4,7 @@ describe('ol.format.Polyline', function() {
var format; var format;
var points; var points;
var flatPoints, encodedFlatPoints; var flatPoints, encodedFlatPoints, flippedFlatPoints;
var floats, smallFloats, encodedFloats; var floats, smallFloats, encodedFloats;
var signedIntegers, encodedSignedIntegers; var signedIntegers, encodedSignedIntegers;
var unsignedIntegers, encodedUnsignedIntegers; 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:Address>
<ows:DeliveryPoint>Fac Ciencies UAB</ows:DeliveryPoint> <ows:DeliveryPoint>Fac Ciencies UAB</ows:DeliveryPoint>
<ows:City>Bellaterra</ows:City> <ows:City>Bellaterra</ows:City>
<ows:AdministrativeArea>Barcelona <ows:AdministrativeArea>Barcelona</ows:AdministrativeArea>
</ows:AdministrativeArea>
<ows:PostalCode>08193</ows:PostalCode> <ows:PostalCode>08193</ows:PostalCode>
<ows:Country>Spain</ows:Country> <ows:Country>Spain</ows:Country>
<ows:ElectronicMailAddress>joan.maso@uab.cat <ows:ElectronicMailAddress>joan.maso@uab.cat</ows:ElectronicMailAddress>
</ows:ElectronicMailAddress>
</ows:Address> </ows:Address>
</ows:ContactInfo> </ows:ContactInfo>
</ows:ServiceContact> </ows:ServiceContact>
@@ -70,8 +68,7 @@ access interface to some TileMatrixSets</ows:Abstract>
<Contents> <Contents>
<Layer> <Layer>
<ows:Title>Blue Marble Next Generation</ows:Title> <ows:Title>Blue Marble Next Generation</ows:Title>
<ows:Abstract>Blue Marble Next Generation NASA Product <ows:Abstract>Blue Marble Next Generation NASA Product</ows:Abstract>
</ows:Abstract>
<ows:WGS84BoundingBox> <ows:WGS84BoundingBox>
<ows:LowerCorner>-180 -90</ows:LowerCorner> <ows:LowerCorner>-180 -90</ows:LowerCorner>
<ows:UpperCorner>180 90</ows:UpperCorner> <ows:UpperCorner>180 90</ows:UpperCorner>
@@ -84,8 +81,7 @@ access interface to some TileMatrixSets</ows:Abstract>
</Style> </Style>
<Style> <Style>
<ows:Title>Thick And Red</ows:Title> <ows:Title>Thick And Red</ows:Title>
<ows:Abstract>Specify this style if you want your maps to have thick red coastlines. <ows:Abstract>Specify this style if you want your maps to have thick red coastlines.</ows:Abstract>
</ows:Abstract>
<ows:Identifier>thickAndRed</ows:Identifier> <ows:Identifier>thickAndRed</ows:Identifier>
</Style> </Style>
<Format>image/jpeg</Format> <Format>image/jpeg</Format>
@@ -93,15 +89,206 @@ access interface to some TileMatrixSets</ows:Abstract>
<TileMatrixSetLink> <TileMatrixSetLink>
<TileMatrixSet>BigWorldPixel</TileMatrixSet> <TileMatrixSet>BigWorldPixel</TileMatrixSet>
</TileMatrixSetLink> </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="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"/> <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> </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> <TileMatrixSet>
<ows:Identifier>BigWorldPixel</ows:Identifier> <ows:Identifier>BigWorldPixel</ows:Identifier>
<ows:SupportedCRS>urn:ogc:def:crs:OGC:1.3:CRS84 <ows:SupportedCRS>urn:ogc:def:crs:OGC:1.3:CRS84</ows:SupportedCRS>
</ows:SupportedCRS> <WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GlobalCRS84Pixel</WellKnownScaleSet>
<WellKnownScaleSet>urn:ogc:def:wkss:OGC:1.0:GlobalCRS84Pixel
</WellKnownScaleSet>
<TileMatrix> <TileMatrix>
<ows:Identifier>10000m</ows:Identifier> <ows:Identifier>10000m</ows:Identifier>
<ScaleDenominator>33130800.83133142</ScaleDenominator> <ScaleDenominator>33130800.83133142</ScaleDenominator>

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.Style[0].LegendURL[0].format).to.be.eql('image/png');
expect(layer.TileMatrixSetLink).to.be.an('array'); 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 expect(layer.TileMatrixSetLink[0].TileMatrixSet).to.be
.eql('BigWorldPixel'); .eql('BigWorldPixel');
expect(layer.TileMatrixSetLink[1].TileMatrixSet).to.be
.eql('google3857');
var wgs84Bbox = layer.WGS84BoundingBox; var wgs84Bbox = layer.WGS84BoundingBox;
expect(wgs84Bbox).to.be.an('array'); expect(wgs84Bbox).to.be.an('array');
@@ -67,7 +69,7 @@ describe('ol.format.WMTSCapabilities', function() {
it('Can read Capabilities.Content.TileMatrixSet', function() { it('Can read Capabilities.Content.TileMatrixSet', function() {
expect(capabilities.Contents.TileMatrixSet).to.be.ok(); 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).to.be.ok();
expect(bigWorld.Identifier).to.be.eql('BigWorld'); expect(bigWorld.Identifier).to.be.eql('BigWorld');
expect(bigWorld.SupportedCRS).to.be.eql('urn:ogc:def:crs:OGC:1.3:CRS84'); 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); expect(interaction.sketchFeature_).to.be(null);
}); });
it('fires change:active', function() { 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 // test that the interaction's change:active listener is called first
expect(interaction.overlay_.map_).to.be(null); expect(interaction.overlay_.map_).to.be(null);
}); });
@@ -523,7 +523,7 @@ describe('ol.interaction.Draw', function() {
expect(interaction.overlay_.map_).to.be(map); expect(interaction.overlay_.map_).to.be(map);
}); });
it('fires change:active', function() { 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 // test that the interaction's change:active listener is called first
expect(interaction.overlay_.map_).not.to.be(null); expect(interaction.overlay_.map_).not.to.be(null);
}); });
@@ -592,6 +592,7 @@ goog.require('goog.dispose');
goog.require('goog.events'); goog.require('goog.events');
goog.require('goog.events.BrowserEvent'); goog.require('goog.events.BrowserEvent');
goog.require('goog.style'); goog.require('goog.style');
goog.require('ol.DrawEventType');
goog.require('ol.Map'); goog.require('ol.Map');
goog.require('ol.MapBrowserPointerEvent'); goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.View'); 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 ' + '+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 ' + '+lon_0=-91.33333333333333 +x_0=609601.2192024384 +y_0=0 ' +
'+ellps=clrk66 +datum=NAD27 +to_meter=0.3048006096012192 +no_defs'); '+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() { afterEach(function() {
delete proj4.defs['EPSG:26782']; delete proj4.defs['EPSG:26782'];
delete proj4.defs['EPSG:3739'];
}); });
it('returns value in meters', function() { it('returns value in meters', function() {
@@ -382,6 +387,11 @@ describe('ol.proj', function() {
expect(epsg26782.getMetersPerUnit()).to.eql(0.3048006096012192); 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() { 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 tolerance = 1;
var extent = [-180, -90, 180, 90]; var extent = [-180, -90, 180, 90];
var resolution = 10; var resolution = 10;
@@ -104,7 +104,7 @@ describe('ol.render.canvas.PolygonReplay', function() {
describe('#getBufferedMaxExtent()', 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 tolerance = 1;
var extent = [-180, -90, 180, 90]; var extent = [-180, -90, 180, 90];
var resolution = 10; var resolution = 10;

View File

@@ -5,10 +5,8 @@ describe('ol.renderer.Layer', function() {
var eventType = goog.events.EventType.CHANGE; var eventType = goog.events.EventType.CHANGE;
beforeEach(function() { beforeEach(function() {
var map = new ol.Map({});
var mapRenderer = map.getRenderer();
var layer = new ol.layer.Layer({}); var layer = new ol.layer.Layer({});
renderer = new ol.renderer.Layer(mapRenderer, layer); renderer = new ol.renderer.Layer(layer);
}); });
describe('#loadImage', function() { describe('#loadImage', function() {
@@ -84,6 +82,5 @@ describe('ol.renderer.Layer', function() {
goog.require('goog.events.EventType'); goog.require('goog.events.EventType');
goog.require('ol.Image'); goog.require('ol.Image');
goog.require('ol.ImageState'); goog.require('ol.ImageState');
goog.require('ol.Map');
goog.require('ol.layer.Layer'); goog.require('ol.layer.Layer');
goog.require('ol.renderer.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() { var callback;
// a source with no loaded tiles 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 source = new ol.test.source.TileMock({});
var loadedTilesByZ = {};
var grid = source.getTileGrid(); var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180]; 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) { source.forEachLoadedTile(zoom, range, callback);
var tile = source.getTile(z, x, y); expect(callback.callCount).to.be(0);
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);
}); });
it('adds loaded tiles to the lookup (z: 0)', function() { it('does not call getTile() if no tiles are loaded', 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
var source = new ol.test.source.TileMock({}); var source = new ol.test.source.TileMock({});
sinon.spy(source, 'getTile');
var loadedTilesByZ = {
'1': {
'1/0/0': true,
'1/0/1': true,
'1/1/0': true,
'1/1/1': true,
'1/1/2': true
}
};
var grid = source.getTileGrid(); var grid = source.getTileGrid();
var extent = [-180, -180, 180, 180]; 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) { source.forEachLoadedTile(zoom, range, callback);
var tile = source.getTile(z, x, y); expect(source.getTile.callCount).to.be(0);
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ? source.getTile.restore();
tile : null;
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(true);
}); });
it('returns false when all tiles are already loaded', function() {
it('calls callback for each loaded tile', function() {
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);
source.forEachLoadedTile(zoom, range, callback);
expect(callback.callCount).to.be(3);
});
it('returns true if range is fully loaded', function() {
// a source with no loaded tiles // a source with no loaded tiles
var source = new ol.test.source.TileMock({ var source = new ol.test.source.TileMock({
'1/0/0': true, '1/0/0': ol.TileState.LOADED,
'1/0/1': true, '1/0/1': ol.TileState.LOADED,
'1/1/0': true, '1/1/0': ol.TileState.LOADED,
'1/1/1': false '1/1/1': ol.TileState.LOADED
}); });
var loadedTilesByZ = {}; var zoom = 1;
var grid = source.getTileGrid(); var range = new ol.TileRange(0, 1, 0, 1);
var extent = [-180, -180, 180, 180];
var range = grid.getTileRangeForExtentAndZ(extent, 1);
function getTileIfLoaded(z, x, y) { var covered = source.forEachLoadedTile(zoom, range, function() {
var tile = source.getTile(z, x, y); return true;
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ? });
tile : null; expect(covered).to.be(true);
}
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range);
expect(loaded).to.be(false);
}); });
it('returns false when all tiles are already loaded (part 2)', function() { it('returns false if range is not fully loaded', function() {
// a source with no loaded tiles // 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.LOADING,
'1/1/1': ol.TileState.LOADED
});
var loadedTilesByZ = { var zoom = 1;
'1': { var range = new ol.TileRange(0, 1, 0, 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);
function getTileIfLoaded(z, x, y) { var covered = source.forEachLoadedTile(zoom, range, function() {
var tile = source.getTile(z, x, y); return true;
return (!goog.isNull(tile) && tile.getState() === ol.TileState.LOADED) ? });
tile : null; expect(covered).to.be(false);
} });
var loaded = source.findLoadedTiles(
loadedTilesByZ, getTileIfLoaded, 1, range); it('allows callback to override loaded check', function() {
expect(loaded).to.be(false); // 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 * @constructor
* @extends {ol.source.Tile} * @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({ var tileGrid = new ol.tilegrid.TileGrid({
resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256], resolutions: [360 / 256, 180 / 256, 90 / 256, 45 / 256],
origin: [-180, -180], origin: [-180, -180],
@@ -210,11 +140,9 @@ ol.test.source.TileMock = function(loaded) {
tileGrid: tileGrid tileGrid: tileGrid
}); });
/** for (var key in tileStates) {
* @type {Object.<string, boolean>} this.tileCache.set(key, new ol.Tile(key.split('/'), tileStates[key]));
* @private }
*/
this.loaded_ = loaded;
}; };
goog.inherits(ol.test.source.TileMock, ol.source.Tile); goog.inherits(ol.test.source.TileMock, ol.source.Tile);
@@ -224,9 +152,14 @@ goog.inherits(ol.test.source.TileMock, ol.source.Tile);
* @inheritDoc * @inheritDoc
*/ */
ol.test.source.TileMock.prototype.getTile = function(z, x, y) { ol.test.source.TileMock.prototype.getTile = function(z, x, y) {
var key = ol.tilecoord.getKeyZXY(z, x, y); var key = this.getKeyZXY(z, x, y);
var tileState = this.loaded_[key] ? ol.TileState.LOADED : ol.TileState.IDLE; if (this.tileCache.containsKey(key)) {
return new ol.Tile([z, x, y], tileState); 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() { describe('#getTile()', function() {
it('returns a tile with state based on constructor arg', function() { it('returns a tile with state based on constructor arg', function() {
var source = new ol.test.source.TileMock({ var source = new ol.test.source.TileMock({
'0/0/0': true, '0/0/0': ol.TileState.LOADED,
'1/0/0': true '1/0/0': ol.TileState.LOADED
}); });
var tile; var tile;
@@ -270,9 +203,9 @@ describe('ol.test.source.TileMock', function() {
goog.require('goog.object'); goog.require('goog.object');
goog.require('ol.Tile'); goog.require('ol.Tile');
goog.require('ol.TileRange');
goog.require('ol.TileState'); goog.require('ol.TileState');
goog.require('ol.proj'); goog.require('ol.proj');
goog.require('ol.source.Source'); goog.require('ol.source.Source');
goog.require('ol.source.Tile'); goog.require('ol.source.Tile');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid'); 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('goog.math');
goog.require('ol.Sphere'); 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');