Compare commits

...

100 Commits

Author SHA1 Message Date
Andreas Hocevar
2e406c9633 Merge pull request #3767 from openlayers/release-v3.6.0
Release v3.6.0
2015-06-07 14:18:09 +02:00
Andreas Hocevar
9f4112a8f9 Update package version to 3.6.0 2015-06-07 14:16:34 +02:00
Andreas Hocevar
30ddbad4fe Changelog for v3.6.0 2015-06-07 14:14:49 +02:00
Marc Jansen
efd1caf00f Merge pull request #3764 from alvinlindstam/intersectsExtent
Add tests and implementation for intersectsExtent (ol.geom.Geometry)
2015-06-05 14:52:50 +02:00
Marc Jansen
488a55c83c Add more tests for intersectsExtent 2015-06-05 14:20:06 +02:00
Alvin Lindstam
1dc6c99328 Make ol.geom.Circle support #intersectsExtent, with tests 2015-06-05 14:19:46 +02:00
Alvin Lindstam
405d5666e2 Add tests for intersectsExtent/getExtent
This commit adds tests for `intersectsExtent` of Point, LineString, Polygon,
MultiPoint, MultiLineString, MultiPolygon and GeometryCollection.

It also adds a basic test for `getExtent` of MultiPolygon
2015-06-05 14:19:46 +02:00
Andreas Hocevar
bad5a97d20 Merge pull request #3757 from bjornharrtell/selectevent-browser
Add mapBrowserEvent as a member of ol.SelectEvent
2015-06-04 18:56:55 +02:00
Björn Harrtell
9a9b838235 Add mapBrowserEvent as a member of ol.SelectEvent 2015-06-04 16:53:53 +02:00
Marc Jansen
5bdfc35d35 Merge pull request #3759 from gberaudo/api_tilegrid_createTileCoordTransform
Mark tilegrid.createTileCoordTransform() @api
2015-06-04 10:19:34 +02:00
Guillaume Beraudo
361d83dc73 Mark tilegrid.createTileCoordTransform() @api
Necessary since the removal of tilegridXYZ type.
2015-06-04 09:24:35 +02:00
Andreas Hocevar
8f2cfe9420 Merge pull request #3747 from ahocevar/tilecoordtransform
Make tileCoordTransform a member again
2015-06-03 14:11:00 +02:00
Andreas Hocevar
5d9708be11 Add tests 2015-06-03 12:41:35 +02:00
Andreas Hocevar
ea7879f616 Merge pull request #3751 from ahocevar/tilejson-test
Do not rely on remote services for tests
2015-06-01 11:23:52 +02:00
Andreas Hocevar
682c816b9b Do not rely on remote services for tests 2015-06-01 10:09:38 +02:00
Marc Jansen
b1289dbae7 Merge pull request #3749 from marcjansen/typo
Fix typo in API docs
2015-06-01 08:51:56 +02:00
Marc Jansen
cf99bcbba1 Fix typo in API docs 2015-06-01 07:56:58 +02:00
Andreas Hocevar
5ae2521724 Make tileCoordTransform configurable
Instead of using the static createOriginTopLeftTileCoordTransform
function, the correct transform is now a non-API config option of the tile
grid.
2015-05-31 22:22:41 +02:00
Marc Jansen
81b13f295b Merge pull request #3739 from marcjansen/simpler-scientific-wkt
Simplify detection of scientific notation in WKT format
2015-05-31 15:50:50 +02:00
Marc Jansen
e43573bcf2 Merge pull request #3741 from marcjansen/callback-docs
Enhance docs of arguments and return values of callbacks / filters
2015-05-29 13:52:27 +02:00
Marc Jansen
894be51b36 Merge pull request #3740 from probins/fireselect
Add @fires to select interaction
2015-05-29 13:30:05 +02:00
Marc Jansen
b06f3457da Enhance docs of arguments of callbacks/filters 2015-05-29 13:20:58 +02:00
Peter Robins
7f1053d2cd Add @fires to select interaction 2015-05-29 10:59:07 +00:00
Marc Jansen
96741e1f0b Simplify detection of scientific notation
This change allows us to remove some avoidable function calls (specifically
to goog.isDef(c) and  c.toLowerCase()). Additionally, the new check is simpler
to read.
2015-05-29 09:33:29 +02:00
Andreas Hocevar
f5cd9a3eba Merge pull request #3738 from ahocevar/tileurlfunction-docs
Improve doucmentation for ol.TileUrlFunctionType
2015-05-28 22:48:19 +02:00
Andreas Hocevar
4196e34c73 Improve doucmentation for ol.TileUrlFunctionType 2015-05-28 18:52:35 +02:00
Frédéric Junod
22bed40f5c Merge pull request #3736 from fredj/examples_html_markup
Fix invalid example HTML markup
2015-05-28 10:44:51 +02:00
Frédéric Junod
a33008be9e Merge pull request #3735 from probins/snap
Snap example: remove featureoverlay from tags
2015-05-28 10:26:52 +02:00
Frederic Junod
746116d266 Fix invalid example HTML markup 2015-05-28 10:23:14 +02:00
Peter Robins
1f6d2eff96 Snap example: remove featureoverlay from tags 2015-05-28 07:57:17 +00:00
Marc Jansen
764f821a70 Merge pull request #3732 from marcjansen/control-blur-binding
Add a method to bind button bluring on mouseout/focusout
2015-05-27 09:22:15 +02:00
Marc Jansen
41596d808b Add method to bind bluring on mouseout/focusout 2015-05-26 22:32:09 +02:00
Frédéric Junod
ec208916d2 Merge pull request #3659 from fredj/undo_forEachFeatureAtCoordinate
Revert "Implement ol.renderer.Layer#forEachFeatureAtCoordinate"
2015-05-26 09:34:06 +02:00
Bart van den Eijnden
78dcbe6b8e Merge pull request #3683 from probins/group
Improve Map docs for layers and layergroups
2015-05-23 17:25:25 +02:00
Peter Robins
074941bf1f Improve Map docs for layers and layergroups 2015-05-23 11:53:37 +00:00
Éric Lemoine
824a77e41b Merge pull request #3720 from elemoine/missingprovides
Add missing goog.provides in drawinteraction.js
2015-05-22 12:15:56 +02:00
Éric Lemoine
e766d00e7b Add upgrade note of ol.DrawEvent and ol.DrawEventType 2015-05-22 11:58:48 +02:00
Frédéric Junod
2e2d08f552 Merge pull request #3725 from fredj/doc
Document default value for olx.interaction.ModifyOptions#pixelTolerance
2015-05-22 11:43:38 +02:00
Frederic Junod
9870fe58e0 Document default value for olx.interaction.ModifyOptions#pixelTolerance 2015-05-22 11:26:58 +02:00
Andreas Hocevar
80efbb60d0 Merge pull request #3722 from ahocevar/tilejson-tilegrid
Use the correct TileCoord transform function
2015-05-22 11:08:07 +02:00
Andreas Hocevar
111e6db8c8 Add tests 2015-05-22 10:55:18 +02:00
Andreas Hocevar
f40aa54c18 Use the correct TileCoord transform function 2015-05-22 09:19:59 +02:00
Éric Lemoine
531b35d7c2 Be consistent with the way we name types 2015-05-21 17:32:32 +02:00
Éric Lemoine
879307da1b Add missing goog.provides in drawinteraction.js 2015-05-21 15:41:51 +02:00
Éric Lemoine
acb0a8da53 Merge pull request #3692 from bill-chadwick/windows
Updates for building on Windows using Cygwin.
2015-05-21 12:57:34 +02:00
Tobias Sauerwein
e87b616de8 Merge pull request #3718 from tsauerwein/renderOrder-assertion
Add a assertion for renderOrder
2015-05-21 11:20:27 +02:00
tsauerwein
a3f9b3ba43 Add assertion for renderOrder 2015-05-21 09:26:47 +02:00
Bart van den Eijnden
680f140858 Merge pull request #3711 from marcjansen/color
Fix and test ol.color.blend
2015-05-20 15:25:54 +02:00
Marc Jansen
b6a4188ce4 Fix and test ol.color.blend 2015-05-20 12:50:52 +02:00
Andreas Hocevar
4be106d014 Merge pull request #3673 from ahocevar/draw-regular-polygon
More control over ol.interaction.Draw, to allow e.g. square drawing
2015-05-20 12:08:15 +02:00
Andreas Hocevar
100020fd59 Refactoring for more consistency
* Min and max number of points configurable for lines and polygons
* Polygons from custom geometryFunction now have a sketch line
* The example shows how to use a custom geometryFunction
2015-05-20 10:28:16 +02:00
Marc Jansen
3580cdc823 Merge pull request #3710 from marcjansen/extent-tests
Add more tests for ol.extent
2015-05-20 06:26:49 +02:00
Marc Jansen
f0720b2f97 Add more tests for ol.extent 2015-05-19 22:25:55 +02:00
Bart van den Eijnden
e578f98c73 Merge pull request #3709 from bartvde/issue-3709
vector-wfs example does not work in JSFiddle
2015-05-19 21:58:50 +02:00
Bart van den Eijnden
1dbf8cd4d6 Make sure vector-wfs example works in JSFiddle 2015-05-19 21:08:30 +02:00
Marc Jansen
0f36d1a7c2 Merge pull request #3699 from marcjansen/scientific-wkt
Add support for scientific notation to WKT format
2015-05-18 12:00:56 +02:00
Marc Jansen
2b76bc05a5 Add support for scientific notation to WKT format 2015-05-18 11:27:39 +02:00
Marc Jansen
1ac41c7403 Merge pull request #3696 from marcjansen/will-it-blend
Add an example for various blend modes
2015-05-15 17:09:33 +02:00
Marc Jansen
96550c8fcf Merge pull request #3697 from marcjansen/npm-license-warning
Use a valid SPDX license expression
2015-05-15 16:58:50 +02:00
Marc Jansen
26f1062dbf Use a valid SPDX license expression 2015-05-15 13:55:22 +02:00
Marc Jansen
26ad3fe6b1 Add an example for various blend modes 2015-05-15 13:33:31 +02:00
Éric Lemoine
34986b0870 Merge pull request #3694 from probins/patch-2
Correct typo in upgrade-notes
2015-05-15 10:26:06 +02:00
Andreas Hocevar
19c91235ce Add convenience function to create a regular polygon geometryFunction 2015-05-14 23:24:29 +02:00
Andreas Hocevar
901a0f6d8e Add functions to create regular polygons 2015-05-14 23:24:29 +02:00
Andreas Hocevar
250221cded Add new geometryFunction option
This allows applications to control the geometry that is created from the
drawing sketch. Will e.g. be useful to create a regular polygon instead of
a circle when in Circle mode.
2015-05-14 23:24:29 +02:00
Andreas Hocevar
4e94908440 Define getCoordinates and setCoordinates in the base class
Since these methods are implemented by all subclasses, it makes sense to
define them in the base class as abstract method.
2015-05-14 23:24:29 +02:00
Peter Robins
23b207dae4 Correct typo in upgrade-notes 2015-05-14 16:08:16 +01:00
Éric Lemoine
16c4082898 Merge pull request #3693 from tremby/contains-extent-doc
Fix ol.extent.containsExtent documentation
2015-05-14 09:10:45 +02:00
bill-chadwick
51c8bcae57 Updates for building on Windows using Cygwin.
Tested on Windows 7.
2015-05-14 07:08:16 +01:00
Bart Nagel
b606f4996b Fix ol.extent.containsExtent documentation
The `ol.extent.containsExtent` documentation had its arguments backwards
(or the implementation did).

The documentation said "the first extent is contained by or on the edge
of the second", but the function checked the opposite.

The wording was also a little strange, since from the name of the
function alone `containsExtent` I'd guess that the first argument would
be the (potential) container, and the second would be the (potentially)
contained. But the documentation has the wording "check if one extent is
*contained by* or on the edge of another", suggesting the first argument
is the contained and the second the container.

This patch keeps the current functionality but clarifies the
documentation.
2015-05-13 12:10:06 -07:00
Éric Lemoine
7dc2a2b97e Merge pull request #3689 from probins/wmts
Fix WMTS.optionsFromCapabilities if no OperationsMetadata section
2015-05-13 15:22:34 +02:00
Peter Robins
a243149d02 Fix WMTS.optionsFromCapabilities if no OperationsMetadata section 2015-05-13 12:43:12 +00:00
Frédéric Junod
a314813511 Merge pull request #3688 from fredj/failIfMajorPerformanceCaveat_externs
Add two missing properties to extern of WebGLContextAttributes
2015-05-12 15:14:05 +02:00
Frederic Junod
fe79389fd3 Add two missing properties to extern of WebGLContextAttributes
To be removed when the closure-compiler is updated
2015-05-12 13:55:13 +02:00
Bart van den Eijnden
d5c69b2e5e Merge pull request #3682 from bartvde/api-addlayer
Add a note about using the collection in addLayer
2015-05-10 17:32:19 +02:00
Bart van den Eijnden
2724292de1 Add a note about using the collection in addLayer 2015-05-10 12:20:02 +02:00
Éric Lemoine
829337c219 Merge pull request #3649 from elemoine/servejs
More specific regex in serve.js
2015-05-09 16:34:43 +02:00
Tim Schaub
549d0a7601 Merge pull request #3677 from tschaub/example-metadata
Add metadata to examples,
2015-05-09 08:34:04 -06:00
Tim Schaub
b602285992 Add metadata to the mobile full-screen example 2015-05-08 06:39:06 -06:00
Tim Schaub
82b1355591 Add metadata to the geolocation orientation example 2015-05-08 06:31:34 -06:00
Marc Jansen
249f432b2e Merge pull request #3672 from marcjansen/link-faq
Add link to FAQ-document and fix internal links
2015-05-08 12:27:17 +02:00
Marc Jansen
45a5b1d24e Add link to FAQ-document and fix internal links 2015-05-08 11:02:39 +02:00
Marc Jansen
c5b788f370 Merge pull request #3665 from marcjansen/missing-resources
Add proj4js and projection definition files to example resources
2015-05-06 15:26:22 +02:00
Marc Jansen
ebded733f7 Add proj4js/projection definition files to example 2015-05-06 13:27:27 +02:00
Tobias Sauerwein
e4e91b82d6 Merge pull request #3662 from tsauerwein/renderbuffer-docs
Clarify docs for renderBuffer option
2015-05-06 09:09:12 +02:00
Tim Schaub
8f9cde0595 Merge pull request #3664 from tschaub/download-page
Link to download page.
2015-05-05 15:27:23 -06:00
Tim Schaub
f47d873ae5 Link to download page 2015-05-05 14:11:11 -06:00
Andreas Hocevar
492a3c8f7a Merge pull request #3639 from ahocevar/tilegrid-extent
Add extent support to ol.tilegrid.TileGrid
2015-05-05 19:22:10 +02:00
Tim Schaub
0bf70489b6 Merge pull request #3663 from tschaub/fewer-version-numbers
Readme should not include the version number.
2015-05-05 11:21:42 -06:00
Andreas Hocevar
32efd99397 Do not require projection extent for WMTS bbox validity check 2015-05-05 18:52:33 +02:00
Andreas Hocevar
0650a97371 Explain tilegrid and xyz source changes 2015-05-05 18:52:33 +02:00
Andreas Hocevar
b05193fa45 Replace ol.tilegrid.XYZ with an ol.tilegrid.createXYZ function 2015-05-05 18:52:33 +02:00
Andreas Hocevar
a116878a57 Allow extents to restrict tile ranges requested from the server
The addition of full extent tile ranges also allows us to simplify wrapX
handling for tile layers. By limiting wrapX to true and false as possible
values, we can remove a lot of guessing logic.
2015-05-05 18:52:33 +02:00
Andreas Hocevar
700903ca5c Add tests for ol.tilegrid.TileGrid
These tests are taken from ol.tilegrid.XYZ, to make sure that
ol.tilegrid.TileGrid works the same way. The additional tests show that the
#getTileCoordForXYAndResolution_() method do not handle coordinates at
tile boundaries properly, so this is fixed.
2015-05-05 18:52:32 +02:00
Tim Schaub
4192092dcf Readme should not include the version number
We should not repeat the version number throughout the source.  Eventually, the download page will be http://openlayers.org/download/.
2015-05-05 10:28:03 -06:00
tsauerwein
c0d9a822f8 Clarify docs for renderBuffer 2015-05-05 17:22:33 +02:00
Frederic Junod
bb6192bc10 Revert "Implement ol.renderer.Layer#forEachFeatureAtCoordinate"
This reverts commit dd07fd7977.
2015-05-05 09:38:50 +02:00
Frédéric Junod
56e8575e41 Merge pull request #3637 from fredj/forEachFeatureAtCoordinate
Implement ol.renderer.Layer#forEachFeatureAtCoordinate
2015-05-05 07:48:54 +02:00
Éric Lemoine
762bb0f055 More specific regex in serve.js
This is to be able to use the dev server (`npm start`) to serve the hosted examples (located in the `build/hosted/<branch>` dir after `make host-examples`).
2015-04-30 09:14:40 +02:00
Frederic Junod
dd07fd7977 Implement ol.renderer.Layer#forEachFeatureAtCoordinate
And remove identical implementation in children classes.
2015-04-28 14:08:45 +02:00
86 changed files with 2733 additions and 860 deletions

View File

@@ -329,3 +329,33 @@ Occasionally other changes to `master` might mean that your pull request cannot
be merged automatically. In this case you may need to rebase your branch on a
more recent `master`, resolve any conflicts, and `git push --force` to update
your branch so that it can be merged automatically.
## Building on Windows
Most developers build on Linux. Building on Windows is possible under Cygwin.
When installing Cygwin from https://www.cygwin.com/, include the developer
tools to get GNU make.
First (before npm install), to avoid file permission problems between Windows
and Cygwin, edit Cygwin's /etc/fstab file to disable ACLs like this
`none /cygdrive cygdrive binary,noacl,posix=0,user 0 0`
Python is normally installed with Cygwin so need not be installed separately.
By default Cygwin will use its own version of Python rather than Window's,
so the Python modules should be installed for Cygwin's Python.
The build targets `check-deps`, `serve`, `lint`, `build`, `test`, `check` and
`host-examples` described above should all work. `host-examples` takes quite a
while to run. If a target does not run properly first time, try it again.
Currently, Firefox fails to run http://localhost:3000/build/examples
from make serve, but Chrome and Internet Explorer will.
Microsoft Visual Studio's javascript debugger may be used to debug the
build/hosted/your-branch/examples. It will be convenient to set
build/hosted/your-branch/examples/index.html as the startup page.
Your ol3 source tree need not be under the Cygwin root.
if you checkout to c:/ol3 then you can build under Cygwin at /cygdrive/c/ol3 .
However, keep the path to the ol3 files short otherwise you may see
`ENAMETOOLONG` errors.

View File

@@ -23,7 +23,11 @@ CHECK_EXAMPLE_TIMESTAMPS = $(patsubst examples/%.html,build/timestamps/check-%-t
TASKS_JS := $(shell find tasks -name '*.js')
CLOSURE_LIB = $(shell node -e 'process.stdout.write(require("closure-util").getLibraryPath())')
ifeq (CYGWIN,$(findstring CYGWIN,$(OS)))
CLOSURE_LIB = $(shell cygpath -u $(shell node -e 'process.stdout.write(require("closure-util").getLibraryPath())'))
else
CLOSURE_LIB = $(shell node -e 'process.stdout.write(require("closure-util").getLibraryPath())')
endif
ifeq ($(OS),Darwin)
STAT_COMPRESSED = stat -f ' compressed: %z bytes'

View File

@@ -7,7 +7,7 @@
## Getting Started
- Download the [latest release](https://github.com/openlayers/ol3/releases/tag/v3.4.0)
- Download the [latest release](http://openlayers.org/download/)
- Install with npm: `npm install openlayers`
- Clone the repo: `git clone git@github.com:openlayers/ol3.git`

View File

@@ -1,5 +1,20 @@
## Upgrade notes
### v3.6.0
#### `ol.interaction.Draw` changes
* The `minPointsPerRing` config option has been renamed to `minPoints`. It is now also available for linestring drawing, not only for polygons.
* The `ol.DrawEvent` and `ol.DrawEventType` types were renamed to `ol.interaction.DrawEvent` and `ol.interaction.DrawEventType`. This has an impact on your code only if your code is compiled together with ol3.
#### `ol.tilegrid` changes
* The `ol.tilegrid.XYZ` constructor has been replaced by a static `ol.tilegrid.createXYZ()` function. The `ol.tilegrid.createXYZ()` function takes the same arguments as the previous `ol.tilegrid.XYZ` constructor, but returns an `ol.tilegrid.TileGrid` instance.
* The internal tile coordinate scheme for XYZ sources has been changed. Previously, the `y` of tile coordinates was transformed to the coordinates used by sources by calculating `-y-1`. Now, it is transformed by calculating `height-y-1`, where height is the number of rows of the tile grid at the zoom level of the tile coordinate.
* The `widths` constructor option of `ol.tilegrid.TileGrid` and subclasses is no longer available, and it is no longer necessary to get proper wrapping at the 180° meridian. However, for `ol.tilegrid.WMTS`, there is a new option `sizes`, where each entry is an `ol.Size` with the `width` ('TileMatrixWidth' in WMTS capabilities) as first and the `height` ('TileMatrixHeight') as second entry of the array. For other tile grids, users can
now specify an `extent` instead of `widths`. These settings are used to restrict the range of tiles that sources will request.
* For `ol.source.TileWMS`, the default value of `warpX` used to be `undefined`, meaning that WMS requests with out-of-extent tile BBOXes would be sent. Now `wrapX` can only be `true` or `false`, and the new default is `true`. No application code changes should be required, but the resulting WMS requests for out-of-extent tiles will no longer use out-of-extent BBOXes, but ones that are shifted to real-world coordinates.
### v3.5.0
#### `ol.Object` and `bindTo`

64
changelog/v3.6.0.md Normal file
View File

@@ -0,0 +1,64 @@
# v3.6.0
## Summary
The v3.6.0 release includes features and fixes from 40 pull requests since v3.5.0. To simplify the code base, there were some changes to "experimental" features. Please follow the upgrade notes to make your applications work with the latest release.
## Upgrade notes
### `ol.interaction.Draw` changes
* The `minPointsPerRing` config option has been renamed to `minPoints`. It is now also available for linestring drawing, not only for polygons.
* The `ol.DrawEvent` and `ol.DrawEventType` types were renamed to `ol.interaction.DrawEvent` and `ol.interaction.DrawEventType`. This has an impact on your code only if your code is compiled together with ol3.
### `ol.tilegrid` changes
* The `ol.tilegrid.XYZ` constructor has been replaced by a static `ol.tilegrid.createXYZ()` function. The `ol.tilegrid.createXYZ()` function takes the same arguments as the previous `ol.tilegrid.XYZ` constructor, but returns an `ol.tilegrid.TileGrid` instance.
* The internal tile coordinate scheme for XYZ sources has been changed. Previously, the `y` of tile coordinates was transformed to the coordinates used by sources by calculating `-y-1`. Now, it is transformed by calculating `height-y-1`, where height is the number of rows of the tile grid at the zoom level of the tile coordinate.
* The `widths` constructor option of `ol.tilegrid.TileGrid` and subclasses is no longer available, and it is no longer necessary to get proper wrapping at the 180° meridian. However, for `ol.tilegrid.WMTS`, there is a new option `sizes`, where each entry is an `ol.Size` with the `width` ('TileMatrixWidth' in WMTS capabilities) as first and the `height` ('TileMatrixHeight') as second entry of the array. For other tile grids, users can
now specify an `extent` instead of `widths`. These settings are used to restrict the range of tiles that sources will request.
* For `ol.source.TileWMS`, the default value of `warpX` used to be `undefined`, meaning that WMS requests with out-of-extent tile BBOXes would be sent. Now `wrapX` can only be `true` or `false`, and the new default is `true`. No application code changes should be required, but the resulting WMS requests for out-of-extent tiles will no longer use out-of-extent BBOXes, but ones that are shifted to real-world coordinates.
## New features and fixes
* [#3764](https://github.com/openlayers/ol3/pull/3764) - Add tests and implementation for intersectsExtent (ol.geom.Geometry) ([@alvinlindstam](https://github.com/alvinlindstam))
* [#3757](https://github.com/openlayers/ol3/pull/3757) - Add mapBrowserEvent as a member of ol.SelectEvent ([@bjornharrtell](https://github.com/bjornharrtell))
* [#3759](https://github.com/openlayers/ol3/pull/3759) - Mark tilegrid.createTileCoordTransform() @api ([@gberaudo](https://github.com/gberaudo))
* [#3747](https://github.com/openlayers/ol3/pull/3747) - Make tileCoordTransform a member again ([@ahocevar](https://github.com/ahocevar))
* [#3751](https://github.com/openlayers/ol3/pull/3751) - Do not rely on remote services for tests ([@ahocevar](https://github.com/ahocevar))
* [#3749](https://github.com/openlayers/ol3/pull/3749) - Fix typo in API docs ([@marcjansen](https://github.com/marcjansen))
* [#3739](https://github.com/openlayers/ol3/pull/3739) - Simplify detection of scientific notation in WKT format ([@marcjansen](https://github.com/marcjansen))
* [#3741](https://github.com/openlayers/ol3/pull/3741) - Enhance docs of arguments and return values of callbacks / filters ([@marcjansen](https://github.com/marcjansen))
* [#3740](https://github.com/openlayers/ol3/pull/3740) - Add @fires to select interaction ([@probins](https://github.com/probins))
* [#3738](https://github.com/openlayers/ol3/pull/3738) - Improve doucmentation for ol.TileUrlFunctionType ([@ahocevar](https://github.com/ahocevar))
* [#3736](https://github.com/openlayers/ol3/pull/3736) - Fix invalid example HTML markup ([@fredj](https://github.com/fredj))
* [#3735](https://github.com/openlayers/ol3/pull/3735) - Snap example: remove featureoverlay from tags ([@probins](https://github.com/probins))
* [#3732](https://github.com/openlayers/ol3/pull/3732) - Add a method to bind button bluring on mouseout/focusout ([@marcjansen](https://github.com/marcjansen))
* [#3659](https://github.com/openlayers/ol3/pull/3659) - Revert "Implement ol.renderer.Layer#forEachFeatureAtCoordinate" ([@fredj](https://github.com/fredj))
* [#3683](https://github.com/openlayers/ol3/pull/3683) - Improve Map docs for layers and layergroups ([@probins](https://github.com/probins))
* [#3720](https://github.com/openlayers/ol3/pull/3720) - Add missing goog.provides in drawinteraction.js ([@elemoine](https://github.com/elemoine))
* [#3725](https://github.com/openlayers/ol3/pull/3725) - Document default value for olx.interaction.ModifyOptions#pixelTolerance ([@fredj](https://github.com/fredj))
* [#3722](https://github.com/openlayers/ol3/pull/3722) - Use the correct TileCoord transform function ([@ahocevar](https://github.com/ahocevar))
* [#3692](https://github.com/openlayers/ol3/pull/3692) - Updates for building on Windows using Cygwin. ([@bill-chadwick](https://github.com/bill-chadwick))
* [#3718](https://github.com/openlayers/ol3/pull/3718) - Add a assertion for renderOrder ([@tsauerwein](https://github.com/tsauerwein))
* [#3711](https://github.com/openlayers/ol3/pull/3711) - Fix and test ol.color.blend ([@marcjansen](https://github.com/marcjansen))
* [#3673](https://github.com/openlayers/ol3/pull/3673) - More control over ol.interaction.Draw, to allow e.g. square drawing ([@ahocevar](https://github.com/ahocevar))
* [#3710](https://github.com/openlayers/ol3/pull/3710) - Add more tests for ol.extent ([@marcjansen](https://github.com/marcjansen))
* [#3709](https://github.com/openlayers/ol3/pull/3709) - vector-wfs example does not work in JSFiddle ([@bartvde](https://github.com/bartvde))
* [#3699](https://github.com/openlayers/ol3/pull/3699) - Add support for scientific notation to WKT format ([@marcjansen](https://github.com/marcjansen))
* [#3696](https://github.com/openlayers/ol3/pull/3696) - Add an example for various blend modes ([@marcjansen](https://github.com/marcjansen))
* [#3697](https://github.com/openlayers/ol3/pull/3697) - Use a valid SPDX license expression ([@marcjansen](https://github.com/marcjansen))
* [#3694](https://github.com/openlayers/ol3/pull/3694) - Correct typo in upgrade-notes ([@probins](https://github.com/probins))
* [#3693](https://github.com/openlayers/ol3/pull/3693) - Fix ol.extent.containsExtent documentation ([@tremby](https://github.com/tremby))
* [#3689](https://github.com/openlayers/ol3/pull/3689) - Fix WMTS.optionsFromCapabilities if no OperationsMetadata section ([@probins](https://github.com/probins))
* [#3688](https://github.com/openlayers/ol3/pull/3688) - Add two missing properties to extern of WebGLContextAttributes ([@fredj](https://github.com/fredj))
* [#3682](https://github.com/openlayers/ol3/pull/3682) - Add a note about using the collection in addLayer ([@bartvde](https://github.com/bartvde))
* [#3649](https://github.com/openlayers/ol3/pull/3649) - More specific regex in serve.js ([@elemoine](https://github.com/elemoine))
* [#3677](https://github.com/openlayers/ol3/pull/3677) - Add metadata to examples, ([@tschaub](https://github.com/tschaub))
* [#3672](https://github.com/openlayers/ol3/pull/3672) - Add link to FAQ-document and fix internal links ([@marcjansen](https://github.com/marcjansen))
* [#3665](https://github.com/openlayers/ol3/pull/3665) - Add proj4js and projection definition files to example resources ([@marcjansen](https://github.com/marcjansen))
* [#3662](https://github.com/openlayers/ol3/pull/3662) - Clarify docs for renderBuffer option ([@tsauerwein](https://github.com/tsauerwein))
* [#3664](https://github.com/openlayers/ol3/pull/3664) - Link to download page. ([@tschaub](https://github.com/tschaub))
* [#3639](https://github.com/openlayers/ol3/pull/3639) - Add extent support to ol.tilegrid.TileGrid ([@ahocevar](https://github.com/ahocevar))
* [#3663](https://github.com/openlayers/ol3/pull/3663) - Readme should not include the version number. ([@tschaub](https://github.com/tschaub))
* [#3637](https://github.com/openlayers/ol3/pull/3637) - Implement ol.renderer.Layer#forEachFeatureAtCoordinate ([@fredj](https://github.com/fredj))

View File

@@ -73,7 +73,7 @@
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre>
</div>
</form>
</div>
</div>

View File

@@ -14,15 +14,16 @@ free to ping us or to send a pull request enhancing this document.
Table of contents:
* [What projection is OpenLayers using?](#what-projection-is-openlayers-using)
* [How do I change the projection of my map?](#how-do-i-change-the-projection-of-my-map)
* [Why is my map centered on the gulf of guinea (or africa, the ocean, null-island)?](#why-is-my-map-centered-on-the-gulf-of-guinea-or-africa-the-ocean-null-island)
* [Why is the order of a coordinate [lon,lat], and not [lat,lon]?](#why-is-the-order-of-a-coordinate-lonlat-and-not-latlon)
* [Why aren't there any features in my source?](#why-arent-there-any-features-in-my-source)
* [How do I force a re-render of the map?](#how-do-i-force-a-re-render-of-the-map)
* [How do I create a custom build of OpenLayers?](#how-do-i-create-a-custom-build-of-openlayers)
* [Do I need to write my own code using Closure library?](#do-i-need-to-write-my-own-code-using-closure-library)
* [Do I need to compress my code with Closure compiler?](#do-i-need-to-compress-my-code-with-closure-compiler)
* [What projection is OpenLayers using?](#what-projection-is-openlayers-using-)
* [How do I change the projection of my map?](#how-do-i-change-the-projection-of-my-map-)
* [Why is my map centered on the gulf of guinea (or africa, the ocean, null-island)?](#why-is-my-map-centered-on-the-gulf-of-guinea-or-africa-the-ocean-null-island-)
* [Why is the order of a coordinate [lon,lat], and not [lat,lon]?](#why-is-the-order-of-a-coordinate-lon-lat-and-not-lat-lon-)
* [Why aren't there any features in my source?](#why-aren-t-there-any-features-in-my-source-)
* [How do I force a re-render of the map?](#how-do-i-force-a-re-render-of-the-map-)
* [How do I create a custom build of OpenLayers?](#how-do-i-create-a-custom-build-of-openlayers-)
* [Do I need to write my own code using Closure library?](#do-i-need-to-write-my-own-code-using-closure-library-)
* [Do I need to compress my code with Closure compiler?](#do-i-need-to-compress-my-code-with-closure-compiler-)
## What projection is OpenLayers using?
@@ -302,7 +303,7 @@ map.renderSync();
## How do I create a custom build of OpenLayers?
Please refer to [this blog post](http://boundlessgeo.com/2014/10/openlayers-custom-builds-revisited/)
Please refer to the [official create custom builds tutorial](tutorials/custom-builds.html)
which explains how to create a custom build of OpenLayers with just those parts
included that you want.
@@ -326,7 +327,8 @@ compiler](https://developers.google.com/closure/compiler/).
It may be a good choice though, because when your application code and the
OpenLayers source code is compiled together using closure compiler, the
resulting build will most probably be the smallest in terms of byte-size. For
more details refer to [this tutorial](compile-application.md).
more details refer to the
[compile application and OpenLayers together tutorial](tutorials/closure.html).
If you don't want to use the closure compiler, or you can't, you are not at all
forced to use it.

View File

@@ -13,6 +13,10 @@ Make sure to also check out the [OpenLayers 3 workshop](../../../ol3-workshop/).
Find additional reference material in the [API docs](../apidoc).
# Questions
# Frequently Asked Questions (FAQ)
If you cannot find an answer in the documentation, you can ask your question on [stackoverflow using the tag 'openlayers-3'](http://stackoverflow.com/questions/tagged/openlayers-3).
We have put together a document that lists [Frequently Asked Questions (FAQ)](faq.html) and our answers. Common problems that may arise when using OpenLayers 3 are explained there, and chances are you'll find an appropriate solution in this document.
# More questions?
If you cannot find an answer in the documentation or the FAQ, you can ask your question on [stackoverflow using the tag 'openlayers-3'](http://stackoverflow.com/questions/tagged/openlayers-3).

4
examples/blend-modes.css Normal file
View File

@@ -0,0 +1,4 @@
.map{
background-repeat: repeat;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAN1wAADdcBQiibeAAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAAAApSURBVBiVY7x///5/BjSgqKjIiC7GhC6ACwygQgxHMzAwMGDz4FDwDAD5/wevjSk4mwAAAABJRU5ErkJggg==);
}

76
examples/blend-modes.html Normal file
View File

@@ -0,0 +1,76 @@
---
template: example.html
title: Blend modes example
shortdesc: Shows how to change the canvas compositing / blending mode in post- and precompose eventhandlers.
docs: >
<p>This example shows how to change the canvas compositing / blending mode in
post- and precompose event handlers. The Canvas 2D API provides the property
<code>globalCompositeOperation</code> with which one can influence which
composition operation will be used when drawing on the canvas. The various
options are well described on the <a href="https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/globalCompositeOperation">MDN
documentation page</a>.</p>
<p>In this example three circles on the corners of an equilateral triangle are
drawn with red, green or blue styles respectively. By setting the
<code>globalCompositeOperation</code> you can change how these colors turn out
when they are combined on the map.</p>
<p>You can select an operation in the select-field and you can also control
which layers will be affected by the chosen operation through the layer
checkboxes.</p>
tags: "blendmode, blend-mode, blend mode, blendingmode, blending-mode, blending mode, composition, compositing, canvas, vector"
---
<div class="row-fluid">
<div class="span12">
<div id="map" class="map"></div>
</div>
</div>
<div class="row-fluid">
<div class="span12">
<form class="form-horizontal">
<label>
<select id="blend-mode" class="form-control">
<option value="source-over">source-over (default)</option>
<option>source-in</option>
<option>source-out</option>
<option>source-atop</option>
<option>destination-over</option>
<option>destination-in</option>
<option>destination-out</option>
<option>destination-atop</option>
<option>lighter</option>
<option>copy</option>
<option>xor</option>
<option>multiply</option>
<option>screen</option>
<option>overlay</option>
<option>darken</option>
<option>lighten</option>
<option>color-dodge</option>
<option>color-burn</option>
<option>hard-light</option>
<option>soft-light</option>
<option selected>difference</option>
<option>exclusion</option>
<option>hue</option>
<option>saturation</option>
<option>color</option>
<option>luminosity</option>
</select>
Canvas compositing / blending mode
</label>
<label>
<input type="checkbox" id="affect-red" checked>
Red circle affected
</label>
<label>
<input type="checkbox" id="affect-green" checked>
Green circle affected
</label>
<label>
<input type="checkbox" id="affect-blue" checked>
Blue circle affected
</label>
</form>
</div>
</div>

177
examples/blend-modes.js Normal file
View File

@@ -0,0 +1,177 @@
goog.require('ol.Feature');
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.geom.Point');
goog.require('ol.layer.Vector');
goog.require('ol.source.Vector');
goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
// Create separate layers for red, green an blue circles.
//
// Every layer has one feature that is styled with a circle, together the
// features form the corners of an equilateral triangle and their styles overlap
var redLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature(new ol.geom.Point([0, 0]))]
}),
style: new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: 'rgba(255,0,0,0.8)'
}),
stroke: new ol.style.Stroke({
color: 'rgb(255,0,0)',
width: 15
}),
radius: 120
})
})
});
var greenLayer = new ol.layer.Vector({
source: new ol.source.Vector({
// 433.013 is roughly 250 * Math.sqrt(3)
features: [new ol.Feature(new ol.geom.Point([250, 433.013]))]
}),
style: new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: 'rgba(0,255,0,0.8)'
}),
stroke: new ol.style.Stroke({
color: 'rgb(0,255,0)',
width: 15
}),
radius: 120
})
})
});
var blueLayer = new ol.layer.Vector({
source: new ol.source.Vector({
features: [new ol.Feature(new ol.geom.Point([500, 0]))]
}),
style: new ol.style.Style({
image: new ol.style.Circle({
fill: new ol.style.Fill({
color: 'rgba(0,0,255,0.8)'
}),
stroke: new ol.style.Stroke({
color: 'rgb(0,0,255)',
width: 15
}),
radius: 120
})
})
});
// Create the map, the view is centered on the triangle. Zooming and panning is
// restricted to a sane area
var map = new ol.Map({
layers: [
redLayer,
greenLayer,
blueLayer
],
target: 'map',
view: new ol.View({
center: [250, 220],
extent: [0, 0, 500, 500],
resolution: 4,
minResolution: 2,
maxResolution: 32
})
});
// Various helper methods and event handlers
/**
* This method sets the globalCompositeOperation to the value of the select
* field and it is bound to the precompose event of the layers.
*
* @param {ol.render.Event} evt The render event.
*/
var setBlendModeFromSelect = function(evt) {
evt.context.globalCompositeOperation = select.value;
};
/**
* This method resets the globalCompositeOperation to the default value of
* 'source-over' and it is bound to the postcompose event of the layers.
*
* @param {ol.render.Event} evt The render event.
*/
var resetBlendModeFromSelect = function(evt) {
evt.context.globalCompositeOperation = 'source-over';
};
/**
* Bind the pre- and postcompose handlers to the passed layer.
*
* @param {ol.layer.Vector} layer The layer to bind the handlers to.
*/
var bindLayerListeners = function(layer) {
layer.on('precompose', setBlendModeFromSelect);
layer.on('postcompose', resetBlendModeFromSelect);
};
/**
* Unind the pre- and postcompose handlers to the passed layers.
*
* @param {ol.layer.Vector} layer The layer to unbind the handlers from.
*/
var unbindLayerListeners = function(layer) {
layer.un('precompose', setBlendModeFromSelect);
layer.un('postcompose', resetBlendModeFromSelect);
};
/**
* Handler for the click event of the 'affect-XXX' checkboxes.
*
* @this {HTMLInputElement}
*/
var affectLayerClicked = function() {
var layer;
if (this.id == 'affect-red') {
layer = redLayer;
} else if (this.id == 'affect-green') {
layer = greenLayer;
} else {
layer = blueLayer;
}
if (this.checked) {
bindLayerListeners(layer);
} else {
unbindLayerListeners(layer);
}
map.render();
};
// Get the form elements and bind the listeners
var select = document.getElementById('blend-mode');
var affectRed = document.getElementById('affect-red');
var affectGreen = document.getElementById('affect-green');
var affectBlue = document.getElementById('affect-blue');
// Rerender map when blend mode changes
select.addEventListener('change', function() {
map.render();
});
// Unbind / bind listeners depending on the checked state when the checkboxes
// are clicked
affectRed.addEventListener('click', affectLayerClicked);
affectGreen.addEventListener('click', affectLayerClicked);
affectBlue.addEventListener('click', affectLayerClicked);
// Initially bind listeners
bindLayerListeners(redLayer);
bindLayerListeners(greenLayer);
bindLayerListeners(blueLayer);

View File

@@ -5,7 +5,6 @@ goog.require('ol.layer.Tile');
goog.require('ol.proj');
goog.require('ol.source.OSM');
goog.require('ol.source.TileDebug');
goog.require('ol.tilegrid.XYZ');
var map = new ol.Map({
@@ -16,9 +15,7 @@ var map = new ol.Map({
new ol.layer.Tile({
source: new ol.source.TileDebug({
projection: 'EPSG:3857',
tileGrid: new ol.tilegrid.XYZ({
maxZoom: 22
})
tileGrid: ol.tilegrid.createXYZ({maxZoom: 22})
})
})
],

View File

@@ -6,7 +6,10 @@ docs: >
Example of using the Draw interaction. Select a geometry type from the
dropdown above to start drawing. To finish drawing, click the last
point. To activate freehand drawing for lines and polygons, hold the `Shift`
key.
key. Square drawing is achieved by using Circle mode with a `geometryFunction`
that creates a 4-sided regular polygon instead of a circle. Box drawing uses a
custom `geometryFunction` that takes start and end point of a line with 2
points and creates a rectangular box.
tags: "draw, edit, freehand, vector"
---
<div class="row-fluid">
@@ -20,6 +23,8 @@ tags: "draw, edit, freehand, vector"
<option value="LineString">LineString</option>
<option value="Polygon">Polygon</option>
<option value="Circle">Circle</option>
<option value="Square">Square</option>
<option value="Box">Box</option>
</select>
</form>
</div>

View File

@@ -1,5 +1,6 @@
goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Draw');
goog.require('ol.layer.Tile');
goog.require('ol.layer.Vector');
@@ -51,9 +52,30 @@ var draw; // global so we can remove it later
function addInteraction() {
var value = typeSelect.value;
if (value !== 'None') {
var geometryFunction, maxPoints;
if (value === 'Square') {
value = 'Circle';
geometryFunction = ol.interaction.Draw.createRegularPolygon(4);
} else if (value === 'Box') {
value = 'LineString';
maxPoints = 2;
geometryFunction = function(coordinates, geometry) {
if (!geometry) {
geometry = new ol.geom.Polygon(null);
}
var start = coordinates[0];
var end = coordinates[1];
geometry.setCoordinates([
[start, [start[0], end[1]], end, [end[0], start[1]], start]
]);
return geometry;
};
}
draw = new ol.interaction.Draw({
source: source,
type: /** @type {ol.geom.GeometryType} */ (value)
type: /** @type {ol.geom.GeometryType} */ (value),
geometryFunction: geometryFunction,
maxPoints: maxPoints
});
map.addInteraction(draw);
}

View File

@@ -1,5 +1,8 @@
---
template: "example-verbatim.html"
template: example-verbatim.html
title: Geolocation Tracking with Orientation
shortdesc: Example of a geolocated and oriented map.
tags: "fullscreen, geolocation, orientation, mobile"
---
<!doctype html>
<html lang="en">
@@ -41,15 +44,8 @@ template: "example-verbatim.html"
<button id="geolocate">Geolocate Me!</button>
<button id="simulate">Simulate</button>
</div>
<script src="http://code.jquery.com/jquery-1.9.1.min.js" type="text/javascript"></script>
<script src="./resources/common.js" type="text/javascript"></script>
<script src="loader.js?id=geolocation-orientation" type="text/javascript"></script>
<div style="display: none;">
<div id="title">Geolocation tracking with orientation example</div>
<div id="shortdesc">Example of a geolocated and oriented map.</div>
<div id="tags">fullscreen, geolocation, orientation, mobile</div>
</div>
</body>
</html>

View File

@@ -1,5 +1,8 @@
---
template: "example-verbatim.html"
template: example-verbatim.html
title: Full-Screen Mobile
shortdesc: Example of a full screen map.
tags: "fullscreen, geolocation, mobile"
---
<!doctype html>
<html lang="en">
@@ -23,11 +26,5 @@ template: "example-verbatim.html"
<script src="./resources/common.js" type="text/javascript"></script>
<script src="http://cdnjs.cloudflare.com/ajax/libs/fastclick/1.0.6/fastclick.min.js" type="text/javascript"></script>
<script src="loader.js?id=mobile-full-screen" type="text/javascript"></script>
<div style="display: none;">
<div id="title">Mobile full screen example</div>
<div id="shortdesc">Example of a full screen map.</div>
<div id="tags">fullscreen, bing, geolocation, mobile</div>
</div>
</body>
</html>

View File

@@ -29,7 +29,7 @@ docs: >
</select>
</div>
</form>
tags: "draw, edit, modify, vector, featureoverlay, snap"
tags: "draw, edit, modify, vector, snap"
---
<div class="row-fluid">
<div class="span12">

View File

@@ -7,13 +7,12 @@ goog.require('ol.source.TileVector');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.tilegrid.XYZ');
var waterLayer = new ol.layer.Vector({
source: new ol.source.TileVector({
format: new ol.format.TopoJSON(),
projection: 'EPSG:3857',
tileGrid: new ol.tilegrid.XYZ({
tileGrid: ol.tilegrid.createXYZ({
maxZoom: 19
}),
url: 'http://{a-c}.tile.openstreetmap.us/' +
@@ -31,7 +30,7 @@ var roadLayer = new ol.layer.Vector({
source: new ol.source.TileVector({
format: new ol.format.TopoJSON(),
projection: 'EPSG:3857',
tileGrid: new ol.tilegrid.XYZ({
tileGrid: ol.tilegrid.createXYZ({
maxZoom: 19
}),
url: 'http://{a-c}.tile.openstreetmap.us/' +
@@ -87,7 +86,7 @@ var buildingLayer = new ol.layer.Vector({
defaultProjection: 'EPSG:4326'
}),
projection: 'EPSG:3857',
tileGrid: new ol.tilegrid.XYZ({
tileGrid: ol.tilegrid.createXYZ({
maxZoom: 19
}),
url: 'http://{a-c}.tile.openstreetmap.us/' +
@@ -106,7 +105,7 @@ var landuseLayer = new ol.layer.Vector({
defaultProjection: 'EPSG:4326'
}),
projection: 'EPSG:3857',
tileGrid: new ol.tilegrid.XYZ({
tileGrid: ol.tilegrid.createXYZ({
maxZoom: 19
}),
url: 'http://{a-c}.tile.openstreetmap.us/' +

View File

@@ -12,7 +12,6 @@ goog.require('ol.loadingstrategy');
goog.require('ol.proj');
goog.require('ol.source.Vector');
goog.require('ol.source.XYZ');
goog.require('ol.tilegrid.XYZ');
var serviceUrl = 'http://services.arcgis.com/rOo16HdIMeOBI4Mb/arcgis/rest/' +
@@ -45,7 +44,7 @@ var vectorSource = new ol.source.Vector({
}
}});
},
strategy: ol.loadingstrategy.tile(new ol.tilegrid.XYZ({
strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
tileSize: 512
}))
});

View File

@@ -11,7 +11,6 @@ goog.require('ol.source.XYZ');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.tilegrid.XYZ');
var serviceUrl = 'http://sampleserver3.arcgisonline.com/ArcGIS/rest/services/' +
@@ -91,7 +90,7 @@ var vectorSource = new ol.source.Vector({
}
}});
},
strategy: ol.loadingstrategy.tile(new ol.tilegrid.XYZ({
strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
tileSize: 512
}))
});

View File

@@ -12,7 +12,6 @@ goog.require('ol.style.Circle');
goog.require('ol.style.Fill');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.tilegrid.XYZ');
var styles = {
'amenity': {
@@ -102,7 +101,7 @@ var vectorSource = new ol.source.Vector({
vectorSource.addFeatures(features);
});
},
strategy: ol.loadingstrategy.tile(new ol.tilegrid.XYZ({
strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
maxZoom: 19
}))
});

View File

@@ -8,7 +8,6 @@ goog.require('ol.source.BingMaps');
goog.require('ol.source.Vector');
goog.require('ol.style.Stroke');
goog.require('ol.style.Style');
goog.require('ol.tilegrid.XYZ');
// format used to parse WFS GetFeature responses
@@ -24,14 +23,17 @@ var vectorSource = new ol.source.Vector({
// parameter to the URL
$.ajax({url: url, dataType: 'jsonp', jsonp: false});
},
strategy: ol.loadingstrategy.tile(new ol.tilegrid.XYZ({
strategy: ol.loadingstrategy.tile(ol.tilegrid.createXYZ({
maxZoom: 19
}))
});
// the global function whose name is specified in the URL of JSONP WFS
// GetFeature requests
var loadFeatures = function(response) {
/**
* JSONP WFS callback function.
* @param {Object} response The response object.
*/
window.loadFeatures = function(response) {
vectorSource.addFeatures(geojsonFormat.readFeatures(response));
};

View File

@@ -15,7 +15,7 @@ for (var i = 0, ii = resolutions.length; i < ii; ++i) {
resolutions[i] = startResolution / Math.pow(2, i);
}
var tileGrid = new ol.tilegrid.TileGrid({
origin: ol.extent.getBottomLeft(projExtent),
extent: [-13884991, 2870341, -7455066, 6338219],
resolutions: resolutions,
tileSize: [512, 256]
});
@@ -25,7 +25,6 @@ var layers = [
source: new ol.source.MapQuest({layer: 'sat'})
}),
new ol.layer.Tile({
extent: [-13884991, 2870341, -7455066, 6338219],
source: new ol.source.TileWMS({
url: 'http://demo.boundlessgeo.com/geoserver/wms',
params: {'LAYERS': 'topp:states', 'TILED': true},

View File

@@ -5,6 +5,9 @@ shortdesc: Example of integrating Proj4js for coordinate transforms.
docs: >
With transparent [Proj4js](http://proj4js.org/) integration, OpenLayers can transform coordinates between arbitrary projections.
tags: "wms, single image, proj4js, projection"
resources:
- http://cdnjs.cloudflare.com/ajax/libs/proj4js/2.3.6/proj4.js
- http://epsg.io/21781-1753.js
---
<div class="row-fluid">
<div class="span12">

View File

@@ -13,8 +13,7 @@ var layers = [
source: new ol.source.TileWMS({
url: 'http://demo.boundlessgeo.com/geoserver/ne/wms',
params: {'LAYERS': 'ne:ne_10m_admin_0_countries', 'TILED': true},
serverType: 'geoserver',
wrapX: true
serverType: 'geoserver'
})
})
];

View File

@@ -35,7 +35,7 @@ var map = new ol.Map({
target: 'map',
layers: [
new ol.layer.Tile({
/* ol.source.XYZ and ol.tilegrid.XYZ have no resolutions config */
/* ol.source.XYZ and ol.tilegrid.TileGrid have no resolutions config */
source: new ol.source.TileImage({
attributions: [attribution],
tileUrlFunction: function(tileCoord, pixelRatio, projection) {

View File

@@ -30,3 +30,15 @@ Touch.prototype.webkitRadiusX;
/** @type {number} */
Touch.prototype.webkitRadiusY;
/**
* @type {boolean}
*/
WebGLContextAttributes.prototype.preferLowPowerToHighPerformance;
/**
* @type {boolean}
*/
WebGLContextAttributes.prototype.failIfMajorPerformanceCaveat;

View File

@@ -120,21 +120,27 @@ oli.MapEvent.prototype.frameState;
/**
* @interface
*/
oli.SelectEvent = function() {};
oli.SelectEvent = function() {};
/**
* @type {Array.<ol.Feature>}
*/
/**
* @type {Array.<ol.Feature>}
*/
oli.SelectEvent.prototype.deselected;
/**
* @type {Array.<ol.Feature>}
*/
/**
* @type {Array.<ol.Feature>}
*/
oli.SelectEvent.prototype.selected;
/**
* @type {ol.MapBrowserEvent}
*/
oli.SelectEvent.prototype.mapBrowserEvent;
/**
* @type {Object}

View File

@@ -226,7 +226,10 @@ olx.MapOptions.prototype.keyboardEventTarget;
/**
* Layers. If this is not defined, a map with no layers will be rendered.
* Layers. If this is not defined, a map with no layers will be rendered. Note
* that layers are rendered in the order supplied, so if you want, for example,
* a vector layer to appear on top of a tile layer, it must come after the tile
* layer.
* @type {Array.<ol.layer.Base>|ol.Collection.<ol.layer.Base>|undefined}
* @api stable
*/
@@ -2357,8 +2360,10 @@ olx.interaction.DragZoomOptions.prototype.style;
* source: (ol.source.Vector|undefined),
* snapTolerance: (number|undefined),
* type: ol.geom.GeometryType,
* minPointsPerRing: (number|undefined),
* maxPoints: (number|undefined),
* minPoints: (number|undefined),
* style: (ol.style.Style|Array.<ol.style.Style>|ol.style.StyleFunction|undefined),
* geometryFunction: (ol.interaction.DrawGeometryFunctionType|undefined),
* geometryName: (string|undefined),
* condition: (ol.events.ConditionType|undefined),
* freehandCondition: (ol.events.ConditionType|undefined)}}
@@ -2393,7 +2398,7 @@ olx.interaction.DrawOptions.prototype.snapTolerance;
/**
* Drawing type ('Point', 'LineString', 'Polygon', 'MultiPoint',
* 'MultiLineString', or 'MultiPolygon').
* 'MultiLineString', 'MultiPolygon' or 'Circle').
* @type {ol.geom.GeometryType}
* @api
*/
@@ -2401,12 +2406,21 @@ olx.interaction.DrawOptions.prototype.type;
/**
* The number of points that must be drawn before a polygon ring can be finished.
* Default is `3`.
* The number of points that can be drawn before a polygon ring or line string
* is finished. The default is no restriction.
* @type {number|undefined}
* @api
*/
olx.interaction.DrawOptions.prototype.minPointsPerRing;
olx.interaction.DrawOptions.prototype.maxPoints;
/**
* The number of points that must be drawn before a polygon ring or line string
* can be finished. Default is `3` for polygon rings and `2` for line strings.
* @type {number|undefined}
* @api
*/
olx.interaction.DrawOptions.prototype.minPoints;
/**
@@ -2417,6 +2431,14 @@ olx.interaction.DrawOptions.prototype.minPointsPerRing;
olx.interaction.DrawOptions.prototype.style;
/**
* Function that is called when a geometry's coordinates are updated.
* @type {ol.interaction.DrawGeometryFunctionType|undefined}
* @api
*/
olx.interaction.DrawOptions.prototype.geometryFunction;
/**
* Geometry name to use for features created by the draw interaction.
* @type {string|undefined}
@@ -2542,7 +2564,7 @@ olx.interaction.ModifyOptions.prototype.deleteCondition;
/**
* Pixel tolerance for considering the pointer close enough to a segment or
* vertex for editing.
* vertex for editing. Default is `10`.
* @type {number|undefined}
* @api
*/
@@ -3556,8 +3578,9 @@ olx.layer.VectorOptions.prototype.opacity;
/**
* The buffer around the viewport extent used by the renderer when getting
* features from the vector source. Recommended value: the size of the
* largest symbol or line width. Default is 100 pixels.
* features from the vector source for the rendering or hit-detection.
* Recommended value: the size of the largest symbol, line width or label.
* Default is 100 pixels.
* @type {number|undefined}
* @api
*/
@@ -4942,11 +4965,10 @@ olx.source.TileWMSOptions.prototype.urls;
/**
* Whether to wrap the world horizontally. The default, `undefined`, is to
* request out-of-bounds tiles from the server. This works well in e.g.
* GeoServer. When set to `false`, only one world will be rendered. When set to
* `true`, tiles will be requested for one world only, but they will be wrapped
* horizontally to render multiple worlds.
* Whether to wrap the world horizontally. When set to `false`, only one world
* will be rendered. When `true`, tiles will be requested for one world only,
* but they will be wrapped horizontally to render multiple worlds. The default
* is `true`.
* @type {boolean|undefined}
* @api
*/
@@ -6014,18 +6036,31 @@ olx.tilegrid;
/**
* @typedef {{minZoom: (number|undefined),
* @typedef {{createTileCoordTransform: (undefined|function({extent: (ol.Extent|undefined)}):function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):ol.TileCoord),
* extent: (ol.Extent|undefined),
* minZoom: (number|undefined),
* origin: (ol.Coordinate|undefined),
* origins: (Array.<ol.Coordinate>|undefined),
* resolutions: !Array.<number>,
* sizes: (Array.<ol.Size>|undefined),
* tileSize: (number|ol.Size|undefined),
* tileSizes: (Array.<number|ol.Size>|undefined),
* widths: (Array.<number>|undefined)}}
* tileSizes: (Array.<number|ol.Size>|undefined)}}
* @api
*/
olx.tilegrid.TileGridOptions;
/**
* Extent for the tile grid. No tiles outside this extent will be requested by
* {@link ol.source.Tile} sources. When no `origin` or `origins` are
* configured, the `origin` will be set to the bottom-left corner of the extent.
* When no `sizes` are configured, they will be calculated from the extent.
* @type {ol.Extent|undefined}
* @api
*/
olx.tilegrid.TileGridOptions.prototype.extent;
/**
* Minimum zoom. Default is 0.
* @type {number|undefined}
@@ -6035,7 +6070,7 @@ olx.tilegrid.TileGridOptions.prototype.minZoom;
/**
* Origin. Default is null.
* Origin, i.e. the bottom-left corner of the grid. Default is null.
* @type {ol.Coordinate|undefined}
* @api stable
*/
@@ -6043,8 +6078,9 @@ olx.tilegrid.TileGridOptions.prototype.origin;
/**
* Origins. If given, the array length should match the length of the
* `resolutions` array, i.e. each resolution can have a different origin.
* Origins, i.e. the bottom-left corners of the grid for each zoom level. If
* given, the array length should match the length of the `resolutions` array,
* i.e. each resolution can have a different origin.
* @type {Array.<ol.Coordinate>|undefined}
* @api stable
*/
@@ -6061,6 +6097,17 @@ olx.tilegrid.TileGridOptions.prototype.origins;
olx.tilegrid.TileGridOptions.prototype.resolutions;
/**
* Number of tile rows and columns of the grid for each zoom level. This setting
* is only needed for tile coordinate transforms that need to work with origins
* other than the bottom-left corner of the grid. No tiles outside this range
* will be requested by sources. If an `extent` is also configured, it takes
* precedence.
* @type {Array.<ol.Size>|undefined}
*/
olx.tilegrid.TileGridOptions.prototype.sizes;
/**
* Tile size. Default is `[256, 256]`.
* @type {number|ol.Size|undefined}
@@ -6079,32 +6126,32 @@ olx.tilegrid.TileGridOptions.prototype.tileSizes;
/**
* Number of tile columns that cover the grid's extent for each zoom level. Only
* required when used with a source that has `wrapX` set to `true`, and only
* when the grid's origin differs from the one of the projection's extent. The
* array length has to match the length of the `resolutions` array, i.e. each
* resolution will have a matching entry here.
* @type {Array.<number>|undefined}
* @api
*/
olx.tilegrid.TileGridOptions.prototype.widths;
/**
* @typedef {{origin: (ol.Coordinate|undefined),
* @typedef {{extent: (ol.Extent|undefined),
* origin: (ol.Coordinate|undefined),
* origins: (Array.<ol.Coordinate>|undefined),
* resolutions: !Array.<number>,
* matrixIds: !Array.<string>,
* sizes: (Array.<ol.Size>|undefined),
* tileSize: (number|ol.Size|undefined),
* tileSizes: (Array.<number|ol.Size>|undefined),
* widths: (Array.<number>|undefined)}}
* tileSizes: (Array.<number|ol.Size>|undefined)}}
* @api
*/
olx.tilegrid.WMTSOptions;
/**
* Origin.
* Extent for the tile grid. No tiles outside this extent will be requested by
* {@link ol.source.WMTS} sources. When no `origin` or `origins` are
* configured, the `origin` will be calculated from the extent.
* When no `sizes` are configured, they will be calculated from the extent.
* @type {ol.Extent|undefined}
* @api
*/
olx.tilegrid.WMTSOptions.prototype.extent;
/**
* Origin, i.e. the top-left corner of the grid.
* @type {ol.Coordinate|undefined}
* @api
*/
@@ -6112,7 +6159,8 @@ olx.tilegrid.WMTSOptions.prototype.origin;
/**
* Origins. The length of this array needs to match the length of the
* Origins, i.e. the top-left corners of the grid for each zoom level. The
* length of this array needs to match the length of the
* `resolutions` array.
* @type {Array.<ol.Coordinate>|undefined}
* @api
@@ -6139,6 +6187,18 @@ olx.tilegrid.WMTSOptions.prototype.resolutions;
olx.tilegrid.WMTSOptions.prototype.matrixIds;
/**
* Number of tile rows and columns of the grid for each zoom level. The values
* here are the `TileMatrixWidth` and `TileMatrixHeight` advertised in the
* GetCapabilities response of the WMTS, and define the grid's extent together
* with the `origin`. An `extent` can be configured in addition, and will
* further limit the extent for which tile requests are made by sources.
* @type {Array.<ol.Size>|undefined}
* @api
*/
olx.tilegrid.WMTSOptions.prototype.sizes;
/**
* Tile size.
* @type {number|ol.Size|undefined}

View File

@@ -1,6 +1,6 @@
{
"name": "openlayers",
"version": "3.5.0",
"version": "3.6.0",
"description": "Build tools and sources for developing OpenLayers based mapping applications",
"keywords": [
"map",
@@ -19,7 +19,7 @@
"type": "git",
"url": "git://github.com/openlayers/ol3.git"
},
"license": "BSD",
"license": "BSD-2-Clause",
"bugs": {
"url": "https://github.com/openlayers/ol3/issues"
},

View File

@@ -78,8 +78,8 @@ ol.Attribution.prototype.intersectsAnyTileRange =
if (testTileRange.intersects(tileRange)) {
return true;
}
var extentTileRange = tileGrid.getTileRange(
parseInt(zKey, 10), projection);
var extentTileRange = tileGrid.getTileRangeForExtentAndZ(
projection.getExtent(), parseInt(zKey, 10));
var width = extentTileRange.getWidth();
if (tileRange.minX < extentTileRange.minX ||
tileRange.maxX > extentTileRange.maxX) {

View File

@@ -64,12 +64,12 @@ ol.color.blend = function(dst, src, opt_color) {
// FIXME do we need to scale by 255?
var out = goog.isDef(opt_color) ? opt_color : [];
var dstA = dst[3];
var srcA = dst[3];
var srcA = src[3];
if (dstA == 1) {
out[0] = (src[0] * srcA + dst[0] * (1 - srcA) + 0.5) | 0;
out[1] = (src[1] * srcA + dst[1] * (1 - srcA) + 0.5) | 0;
out[2] = (src[2] * srcA + dst[2] * (1 - srcA) + 0.5) | 0;
out[4] = 1;
out[3] = 1;
} else if (srcA === 0) {
out[0] = dst[0];
out[1] = dst[1];

View File

@@ -3,6 +3,7 @@ goog.provide('ol.control.Control');
goog.require('goog.array');
goog.require('goog.dom');
goog.require('goog.events');
goog.require('goog.events.EventType');
goog.require('ol.MapEventType');
goog.require('ol.Object');
@@ -78,6 +79,24 @@ ol.control.Control = function(options) {
goog.inherits(ol.control.Control, ol.Object);
/**
* Bind a listener that blurs the passed element on any mouseout- or
* focusout-event.
*
* @param {!Element} button The button which shall blur on mouseout- or
* focusout-event.
* @protected
*/
ol.control.Control.bindMouseOutFocusOutBlur = function(button) {
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], /** @this {Element} */ function() {
this.blur();
}, false);
};
/**
* @inheritDoc
*/

View File

@@ -67,12 +67,7 @@ ol.control.FullScreen = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
ol.control.Control.bindMouseOutFocusOutBlur(button);
goog.events.listen(goog.global.document,
goog.dom.fullscreen.EventType.CHANGE,

View File

@@ -90,12 +90,7 @@ ol.control.OverviewMap = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
ol.control.Control.bindMouseOutFocusOutBlur(button);
var ovmapDiv = goog.dom.createDom(goog.dom.TagName.DIV, 'ol-overviewmap-map');

View File

@@ -60,12 +60,7 @@ ol.control.Rotate = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
ol.control.Rotate.prototype.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
ol.control.Control.bindMouseOutFocusOutBlur(button);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;

View File

@@ -50,12 +50,7 @@ ol.control.Zoom = function(opt_options) {
goog.events.EventType.CLICK, goog.partial(
ol.control.Zoom.prototype.handleClick_, delta), false, this);
goog.events.listen(inElement, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
ol.control.Control.bindMouseOutFocusOutBlur(inElement);
var outElement = goog.dom.createDom(goog.dom.TagName.BUTTON, {
'class': className + '-out',

View File

@@ -43,12 +43,7 @@ ol.control.ZoomToExtent = function(opt_options) {
goog.events.listen(button, goog.events.EventType.CLICK,
this.handleClick_, false, this);
goog.events.listen(button, [
goog.events.EventType.MOUSEOUT,
goog.events.EventType.FOCUSOUT
], function() {
this.blur();
}, false);
ol.control.Control.bindMouseOutFocusOutBlur(button);
var cssClasses = className + ' ' + ol.css.CLASS_UNSELECTABLE + ' ' +
ol.css.CLASS_CONTROL;

View File

@@ -164,12 +164,15 @@ ol.extent.containsCoordinate = function(extent, coordinate) {
/**
* Check if one extent is contained by or on the edge of another.
* Check if one extent contains another.
*
* An extent is deemed contained if it lies completely within the other extent,
* including if they share one or more edges.
*
* @param {ol.Extent} extent1 Extent 1.
* @param {ol.Extent} extent2 Extent 2.
* @return {boolean} The first extent is contained by or on the edge of the
* second.
* @return {boolean} The second extent is contained by or on the edge of the
* first.
* @api stable
*/
ol.extent.containsExtent = function(extent1, extent2) {

View File

@@ -491,12 +491,23 @@ ol.format.WKT.Lexer.prototype.nextToken = function() {
ol.format.WKT.Lexer.prototype.readNumber_ = function() {
var c, index = this.index_;
var decimal = false;
var scientificNotation = false;
do {
if (c == '.') {
decimal = true;
} else if (c == 'e' || c == 'E') {
scientificNotation = true;
}
c = this.nextChar_();
} while (this.isNumeric_(c, decimal));
} while (
this.isNumeric_(c, decimal) ||
// if we haven't detected a scientific number before, 'e' or 'E'
// hint that we should continue to read
!scientificNotation && (c == 'e' || c == 'E') ||
// once we know that we have a scientific number, both '-' and '+'
// are allowed
scientificNotation && (c == '-' || c == '+')
);
return parseFloat(this.wkt.substring(index, this.index_--));
};

View File

@@ -137,6 +137,29 @@ ol.geom.Circle.prototype.getType = function() {
};
/**
* @inheritDoc
* @api stable
*/
ol.geom.Circle.prototype.intersectsExtent = function(extent) {
var circleExtent = this.getExtent();
if (ol.extent.intersects(extent, circleExtent)) {
var center = this.getCenter();
if (extent[0] <= center[0] && extent[2] >= center[0]) {
return true;
}
if (extent[1] <= center[1] && extent[3] >= center[1]) {
return true;
}
return ol.extent.forEachCorner(extent, this.containsCoordinate, this);
}
return false;
};
/**
* Set the center of the circle as {@link ol.Coordinate coordinate}.
* @param {ol.Coordinate} center Center.

View File

@@ -2,6 +2,7 @@ goog.provide('ol.geom.Polygon');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('ol.extent');
goog.require('ol.geom.GeometryLayout');
goog.require('ol.geom.GeometryType');
@@ -422,3 +423,53 @@ ol.geom.Polygon.fromExtent = function(extent) {
ol.geom.GeometryLayout.XY, flatCoordinates, [flatCoordinates.length]);
return polygon;
};
/**
* Create a regular polygon from a circle.
* @param {ol.geom.Circle} circle Circle geometry.
* @param {number=} opt_sides Number of sides of the polygon. Default is 32.
* @param {number=} opt_angle Start angle for the first vertex of the polygon in
* radians. Default is 0.
* @return {ol.geom.Polygon} Polygon geometry.
* @api
*/
ol.geom.Polygon.fromCircle = function(circle, opt_sides, opt_angle) {
var sides = goog.isDef(opt_sides) ? opt_sides : 32;
var stride = circle.getStride();
var layout = circle.getLayout();
var polygon = new ol.geom.Polygon(null, layout);
var flatCoordinates = goog.array.repeat(0, stride * (sides + 1));
var ends = [flatCoordinates.length];
polygon.setFlatCoordinates(layout, flatCoordinates, ends);
ol.geom.Polygon.makeRegular(
polygon, circle.getCenter(), circle.getRadius(), opt_angle);
return polygon;
};
/**
* Modify the coordinates of a polygon to make it a regular polygon.
* @param {ol.geom.Polygon} polygon Polygon geometry.
* @param {ol.Coordinate} center Center of the regular polygon.
* @param {number} radius Radius of the regular polygon.
* @param {number=} opt_angle Start angle for the first vertex of the polygon in
* radians. Default is 0.
*/
ol.geom.Polygon.makeRegular = function(polygon, center, radius, opt_angle) {
var flatCoordinates = polygon.getFlatCoordinates();
var layout = polygon.getLayout();
var stride = polygon.getStride();
var ends = polygon.getEnds();
goog.asserts.assert(ends.length === 1, 'only 1 ring is supported');
var sides = flatCoordinates.length / stride - 1;
var startAngle = goog.isDef(opt_angle) ? opt_angle : 0;
var angle, coord, offset;
for (var i = 0; i <= sides; ++i) {
offset = i * stride;
angle = startAngle + (goog.math.modulo(i, sides) * 2 * Math.PI / sides);
flatCoordinates[offset] = center[0] + (radius * Math.cos(angle));
flatCoordinates[offset + 1] = center[1] + (radius * Math.sin(angle));
}
polygon.setFlatCoordinates(layout, flatCoordinates, ends);
};

View File

@@ -98,6 +98,12 @@ ol.geom.SimpleGeometry.prototype.computeExtent = function(extent) {
};
/**
* @return {Array} Coordinates.
*/
ol.geom.SimpleGeometry.prototype.getCoordinates = goog.abstractMethod;
/**
* Return the first coordinate of the geometry.
* @return {ol.Coordinate} First coordinate.
@@ -209,6 +215,13 @@ ol.geom.SimpleGeometry.prototype.setFlatCoordinatesInternal =
};
/**
* @param {Array} coordinates Coordinates.
* @param {ol.geom.GeometryLayout=} opt_layout Layout.
*/
ol.geom.SimpleGeometry.prototype.setCoordinates = goog.abstractMethod;
/**
* @param {ol.geom.GeometryLayout|undefined} layout Layout.
* @param {Array} coordinates Coordinates.

View File

@@ -1,6 +1,8 @@
goog.provide('ol.DrawEvent');
goog.provide('ol.DrawEventType');
goog.provide('ol.interaction.Draw');
goog.provide('ol.interaction.DrawEvent');
goog.provide('ol.interaction.DrawEventType');
goog.provide('ol.interaction.DrawGeometryFunctionType');
goog.provide('ol.interaction.DrawMode');
goog.require('goog.asserts');
goog.require('goog.events');
@@ -12,6 +14,7 @@ goog.require('ol.FeatureOverlay');
goog.require('ol.MapBrowserEvent');
goog.require('ol.MapBrowserEvent.EventType');
goog.require('ol.Object');
goog.require('ol.coordinate');
goog.require('ol.events.condition');
goog.require('ol.geom.Circle');
goog.require('ol.geom.GeometryType');
@@ -21,6 +24,7 @@ goog.require('ol.geom.MultiPoint');
goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.geom.SimpleGeometry');
goog.require('ol.interaction.InteractionProperty');
goog.require('ol.interaction.Pointer');
goog.require('ol.source.Vector');
@@ -30,16 +34,16 @@ goog.require('ol.style.Style');
/**
* @enum {string}
*/
ol.DrawEventType = {
ol.interaction.DrawEventType = {
/**
* Triggered upon feature draw start
* @event ol.DrawEvent#drawstart
* @event ol.interaction.DrawEvent#drawstart
* @api stable
*/
DRAWSTART: 'drawstart',
/**
* Triggered upon feature draw end
* @event ol.DrawEvent#drawend
* @event ol.interaction.DrawEvent#drawend
* @api stable
*/
DRAWEND: 'drawend'
@@ -55,10 +59,10 @@ ol.DrawEventType = {
* @constructor
* @extends {goog.events.Event}
* @implements {oli.DrawEvent}
* @param {ol.DrawEventType} type Type.
* @param {ol.interaction.DrawEventType} type Type.
* @param {ol.Feature} feature The feature drawn.
*/
ol.DrawEvent = function(type, feature) {
ol.interaction.DrawEvent = function(type, feature) {
goog.base(this, type);
@@ -70,7 +74,7 @@ ol.DrawEvent = function(type, feature) {
this.feature = feature;
};
goog.inherits(ol.DrawEvent, goog.events.Event);
goog.inherits(ol.interaction.DrawEvent, goog.events.Event);
@@ -80,7 +84,7 @@ goog.inherits(ol.DrawEvent, goog.events.Event);
*
* @constructor
* @extends {ol.interaction.Pointer}
* @fires ol.DrawEvent
* @fires ol.interaction.DrawEvent
* @param {olx.interaction.DrawOptions} options Options.
* @api stable
*/
@@ -126,15 +130,6 @@ ol.interaction.Draw = function(options) {
this.snapTolerance_ = goog.isDef(options.snapTolerance) ?
options.snapTolerance : 12;
/**
* The number of points that must be drawn before a polygon ring can be
* finished. The default is 3.
* @type {number}
* @private
*/
this.minPointsPerRing_ = goog.isDef(options.minPointsPerRing) ?
options.minPointsPerRing : 3;
/**
* Geometry type.
* @type {ol.geom.GeometryType}
@@ -149,6 +144,77 @@ ol.interaction.Draw = function(options) {
*/
this.mode_ = ol.interaction.Draw.getMode_(this.type_);
/**
* The number of points that must be drawn before a polygon ring or line
* string can be finished. The default is 3 for polygon rings and 2 for
* line strings.
* @type {number}
* @private
*/
this.minPoints_ = goog.isDef(options.minPoints) ?
options.minPoints :
(this.mode_ === ol.interaction.DrawMode.POLYGON ? 3 : 2);
/**
* The number of points that can be drawn before a polygon ring or line string
* is finished. The default is no restriction.
* @type {number}
* @private
*/
this.maxPoints_ = goog.isDef(options.maxPoints) ?
options.maxPoints : Infinity;
var geometryFunction = options.geometryFunction;
if (!goog.isDef(geometryFunction)) {
if (this.type_ === ol.geom.GeometryType.CIRCLE) {
/**
* @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
* @param {ol.geom.SimpleGeometry=} opt_geometry
* @return {ol.geom.SimpleGeometry}
*/
geometryFunction = function(coordinates, opt_geometry) {
var circle = goog.isDef(opt_geometry) ? opt_geometry :
new ol.geom.Circle([NaN, NaN]);
goog.asserts.assertInstanceof(circle, ol.geom.Circle,
'geometry must be an ol.geom.Circle');
var squaredLength = ol.coordinate.squaredDistance(
coordinates[0], coordinates[1]);
circle.setCenterAndRadius(coordinates[0], Math.sqrt(squaredLength));
return circle;
};
} else {
var Constructor;
var mode = this.mode_;
if (mode === ol.interaction.DrawMode.POINT) {
Constructor = ol.geom.Point;
} else if (mode === ol.interaction.DrawMode.LINE_STRING) {
Constructor = ol.geom.LineString;
} else if (mode === ol.interaction.DrawMode.POLYGON) {
Constructor = ol.geom.Polygon;
}
/**
* @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
* @param {ol.geom.SimpleGeometry=} opt_geometry
* @return {ol.geom.SimpleGeometry}
*/
geometryFunction = function(coordinates, opt_geometry) {
var geometry = opt_geometry;
if (goog.isDef(geometry)) {
geometry.setCoordinates(coordinates);
} else {
geometry = new Constructor(coordinates);
}
return geometry;
};
}
}
/**
* @type {ol.interaction.DrawGeometryFunctionType}
* @private
*/
this.geometryFunction_ = geometryFunction;
/**
* Finish coordinate for the feature (first point for polygons, last point for
* linestrings).
@@ -171,6 +237,13 @@ ol.interaction.Draw = function(options) {
*/
this.sketchPoint_ = null;
/**
* Sketch coordinates. Used when drawing a line or polygon.
* @type {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>}
* @private
*/
this.sketchCoords_ = null;
/**
* Sketch line. Used when drawing polygon.
* @type {ol.Feature}
@@ -179,11 +252,11 @@ ol.interaction.Draw = function(options) {
this.sketchLine_ = null;
/**
* Sketch polygon. Used when drawing polygon.
* @type {Array.<Array.<ol.Coordinate>>}
* Sketch line coordinates. Used when drawing a polygon or circle.
* @type {Array.<ol.Coordinate>}
* @private
*/
this.sketchPolygonCoords_ = null;
this.sketchLineCoords_ = null;
/**
* Squared tolerance for handling up events. If the squared distance
@@ -362,20 +435,15 @@ ol.interaction.Draw.prototype.handlePointerMove_ = function(event) {
ol.interaction.Draw.prototype.atFinish_ = function(event) {
var at = false;
if (!goog.isNull(this.sketchFeature_)) {
var geometry = this.sketchFeature_.getGeometry();
var potentiallyDone = false;
var potentiallyFinishCoordinates = [this.finishCoordinate_];
if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
'geometry should be an ol.geom.LineString');
potentiallyDone = geometry.getCoordinates().length > 2;
potentiallyDone = this.sketchCoords_.length > this.minPoints_;
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
'geometry should be an ol.geom.Polygon');
potentiallyDone = geometry.getCoordinates()[0].length >
this.minPointsPerRing_;
potentiallyFinishCoordinates = [this.sketchPolygonCoords_[0][0],
this.sketchPolygonCoords_[0][this.sketchPolygonCoords_[0].length - 2]];
potentiallyDone = this.sketchCoords_[0].length >
this.minPoints_;
potentiallyFinishCoordinates = [this.sketchCoords_[0][0],
this.sketchCoords_[0][this.sketchCoords_[0].length - 2]];
}
if (potentiallyDone) {
var map = event.map;
@@ -425,23 +493,22 @@ ol.interaction.Draw.prototype.createOrUpdateSketchPoint_ = function(event) {
ol.interaction.Draw.prototype.startDrawing_ = function(event) {
var start = event.coordinate;
this.finishCoordinate_ = start;
var geometry;
if (this.mode_ === ol.interaction.DrawMode.POINT) {
geometry = new ol.geom.Point(start.slice());
this.sketchCoords_ = start.slice();
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
this.sketchCoords_ = [[start.slice(), start.slice()]];
this.sketchLineCoords_ = this.sketchCoords_[0];
} else {
if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
geometry = new ol.geom.LineString([start.slice(), start.slice()]);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
this.sketchLine_ = new ol.Feature(new ol.geom.LineString([start.slice(),
start.slice()]));
this.sketchPolygonCoords_ = [[start.slice(), start.slice()]];
geometry = new ol.geom.Polygon(this.sketchPolygonCoords_);
} else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
geometry = new ol.geom.Circle(start.slice(), 0);
this.sketchLine_ = new ol.Feature(new ol.geom.LineString([start.slice(),
start.slice()]));
this.sketchCoords_ = [start.slice(), start.slice()];
if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
this.sketchLineCoords_ = this.sketchCoords_;
}
}
if (!goog.isNull(this.sketchLineCoords_)) {
this.sketchLine_ = new ol.Feature(
new ol.geom.LineString(this.sketchLineCoords_));
}
var geometry = this.geometryFunction_(this.sketchCoords_);
goog.asserts.assert(goog.isDef(geometry), 'geometry should be defined');
this.sketchFeature_ = new ol.Feature();
if (goog.isDef(this.geometryName_)) {
@@ -449,8 +516,8 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) {
}
this.sketchFeature_.setGeometry(geometry);
this.updateSketchFeatures_();
this.dispatchEvent(new ol.DrawEvent(ol.DrawEventType.DRAWSTART,
this.sketchFeature_));
this.dispatchEvent(new ol.interaction.DrawEvent(
ol.interaction.DrawEventType.DRAWSTART, this.sketchFeature_));
};
@@ -462,60 +529,50 @@ ol.interaction.Draw.prototype.startDrawing_ = function(event) {
ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
var coordinate = event.coordinate;
var geometry = this.sketchFeature_.getGeometry();
var coordinates, last, sketchLineGeom;
goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
'geometry should be ol.geom.SimpleGeometry or subclass');
var coordinates, last;
if (this.mode_ === ol.interaction.DrawMode.POINT) {
goog.asserts.assertInstanceof(geometry, ol.geom.Point,
'geometry should be an ol.geom.Point');
last = geometry.getCoordinates();
last[0] = coordinate[0];
last[1] = coordinate[1];
geometry.setCoordinates(last);
} else {
if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
'geometry should be an ol.geom.LineString');
coordinates = geometry.getCoordinates();
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
'geometry should be an ol.geom.Polygon');
coordinates = this.sketchPolygonCoords_[0];
} else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
goog.asserts.assertInstanceof(geometry, ol.geom.Circle,
'geometry should be an ol.geom.Circle');
coordinates = geometry.getCenter();
}
last = this.sketchCoords_;
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
coordinates = this.sketchCoords_[0];
last = coordinates[coordinates.length - 1];
if (this.atFinish_(event)) {
// snap to finish
coordinate = this.finishCoordinate_.slice();
}
} else {
coordinates = this.sketchCoords_;
last = coordinates[coordinates.length - 1];
}
last[0] = coordinate[0];
last[1] = coordinate[1];
goog.asserts.assert(!goog.isNull(this.sketchCoords_),
'sketchCoords_ must not be null');
this.geometryFunction_(this.sketchCoords_, geometry);
if (!goog.isNull(this.sketchPoint_)) {
var sketchPointGeom = this.sketchPoint_.getGeometry();
goog.asserts.assertInstanceof(sketchPointGeom, ol.geom.Point,
'sketchPointGeom should be an ol.geom.Point');
sketchPointGeom.setCoordinates(coordinate);
last = coordinates[coordinates.length - 1];
last[0] = coordinate[0];
last[1] = coordinate[1];
if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
'geometry should be an ol.geom.LineString');
geometry.setCoordinates(coordinates);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
sketchLineGeom = this.sketchLine_.getGeometry();
goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
'sketchLineGeom should be an ol.geom.LineString');
sketchLineGeom.setCoordinates(coordinates);
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
'geometry should be an ol.geom.Polygon');
geometry.setCoordinates(this.sketchPolygonCoords_);
} else if (this.mode_ === ol.interaction.DrawMode.CIRCLE) {
goog.asserts.assertInstanceof(geometry, ol.geom.Circle,
'geometry should be an ol.geom.Circle');
sketchLineGeom = this.sketchLine_.getGeometry();
goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
'sketchLineGeom should be an ol.geom.LineString');
sketchLineGeom.setCoordinates([geometry.getCenter(), coordinate]);
geometry.setRadius(sketchLineGeom.getLength());
}
var sketchLineGeom;
if (geometry instanceof ol.geom.Polygon &&
this.mode_ !== ol.interaction.DrawMode.POLYGON) {
if (goog.isNull(this.sketchLine_)) {
this.sketchLine_ = new ol.Feature(new ol.geom.LineString(null));
}
var ring = geometry.getLinearRing(0);
sketchLineGeom = this.sketchLine_.getGeometry();
goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
'sketchLineGeom must be an ol.geom.LineString');
sketchLineGeom.setFlatCoordinates(
ring.getLayout(), ring.getFlatCoordinates());
} else if (!goog.isNull(this.sketchLineCoords_)) {
sketchLineGeom = this.sketchLine_.getGeometry();
goog.asserts.assertInstanceof(sketchLineGeom, ol.geom.LineString,
'sketchLineGeom must be an ol.geom.LineString');
sketchLineGeom.setCoordinates(this.sketchLineCoords_);
}
this.updateSketchFeatures_();
};
@@ -529,57 +586,57 @@ ol.interaction.Draw.prototype.modifyDrawing_ = function(event) {
ol.interaction.Draw.prototype.addToDrawing_ = function(event) {
var coordinate = event.coordinate;
var geometry = this.sketchFeature_.getGeometry();
goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
'geometry must be an ol.geom.SimpleGeometry');
var done;
var coordinates;
if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
this.finishCoordinate_ = coordinate.slice();
goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
'geometry should be an ol.geom.LineString');
coordinates = geometry.getCoordinates();
coordinates = this.sketchCoords_;
coordinates.push(coordinate.slice());
geometry.setCoordinates(coordinates);
done = coordinates.length > this.maxPoints_;
this.geometryFunction_(coordinates, geometry);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
this.sketchPolygonCoords_[0].push(coordinate.slice());
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
'geometry should be an ol.geom.Polygon');
geometry.setCoordinates(this.sketchPolygonCoords_);
coordinates = this.sketchCoords_[0];
coordinates.push(coordinate.slice());
done = coordinates.length > this.maxPoints_;
if (done) {
this.finishCoordinate_ = coordinates[0];
}
this.geometryFunction_(this.sketchCoords_, geometry);
}
this.updateSketchFeatures_();
if (done) {
this.finishDrawing();
}
};
/**
* Stop drawing and add the sketch feature to the target layer.
* The {@link ol.DrawEventType.DRAWEND} event is dispatched before inserting
* the feature.
* The {@link ol.interaction.DrawEventType.DRAWEND} event is dispatched before
* inserting the feature.
* @api
*/
ol.interaction.Draw.prototype.finishDrawing = function() {
var sketchFeature = this.abortDrawing_();
goog.asserts.assert(!goog.isNull(sketchFeature),
'sketchFeature should not be null');
var coordinates;
var coordinates = this.sketchCoords_;
var geometry = sketchFeature.getGeometry();
if (this.mode_ === ol.interaction.DrawMode.POINT) {
goog.asserts.assertInstanceof(geometry, ol.geom.Point,
'geometry should be an ol.geom.Point');
coordinates = geometry.getCoordinates();
} else if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
goog.asserts.assertInstanceof(geometry, ol.geom.LineString,
'geometry should be an ol.geom.LineString');
coordinates = geometry.getCoordinates();
goog.asserts.assertInstanceof(geometry, ol.geom.SimpleGeometry,
'geometry must be an ol.geom.SimpleGeometry');
if (this.mode_ === ol.interaction.DrawMode.LINE_STRING) {
// remove the redundant last point
coordinates.pop();
geometry.setCoordinates(coordinates);
this.geometryFunction_(coordinates, geometry);
} else if (this.mode_ === ol.interaction.DrawMode.POLYGON) {
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
'geometry should be an ol.geom.Polygon');
// When we finish drawing a polygon on the last point,
// the last coordinate is duplicated as for LineString
// we force the replacement by the first point
this.sketchPolygonCoords_[0].pop();
this.sketchPolygonCoords_[0].push(this.sketchPolygonCoords_[0][0]);
geometry.setCoordinates(this.sketchPolygonCoords_);
coordinates = geometry.getCoordinates();
coordinates[0].pop();
coordinates[0].push(coordinates[0][0]);
this.geometryFunction_(coordinates, geometry);
}
// cast multi-part geometries
@@ -592,7 +649,8 @@ ol.interaction.Draw.prototype.finishDrawing = function() {
}
// First dispatch event to allow full set up of feature
this.dispatchEvent(new ol.DrawEvent(ol.DrawEventType.DRAWEND, sketchFeature));
this.dispatchEvent(new ol.interaction.DrawEvent(
ol.interaction.DrawEventType.DRAWEND, sketchFeature));
// Then insert feature
if (!goog.isNull(this.features_)) {
@@ -660,6 +718,44 @@ ol.interaction.Draw.prototype.updateState_ = function() {
};
/**
* Create a `geometryFunction` for `mode: 'Circle'` that will create a regular
* polygon with a user specified number of sides and start angle instead of an
* `ol.geom.Circle` geometry.
* @param {number=} opt_sides Number of sides of the regular polygon. Default is
* 32.
* @param {number=} opt_angle Angle of the first point in radians. 0 means East.
* Default is the angle defined by the heading from the center of the
* regular polygon to the current pointer position.
* @return {ol.interaction.DrawGeometryFunctionType} Function that draws a
* polygon.
* @api
*/
ol.interaction.Draw.createRegularPolygon = function(opt_sides, opt_angle) {
return (
/**
* @param {ol.Coordinate|Array.<ol.Coordinate>|Array.<Array.<ol.Coordinate>>} coordinates
* @param {ol.geom.SimpleGeometry=} opt_geometry
* @return {ol.geom.SimpleGeometry}
*/
function(coordinates, opt_geometry) {
var center = coordinates[0];
var end = coordinates[1];
var radius = Math.sqrt(
ol.coordinate.squaredDistance(center, end));
var geometry = goog.isDef(opt_geometry) ? opt_geometry :
ol.geom.Polygon.fromCircle(new ol.geom.Circle(center), opt_sides);
goog.asserts.assertInstanceof(geometry, ol.geom.Polygon,
'geometry must be a polygon');
var angle = goog.isDef(opt_angle) ? opt_angle :
Math.atan((end[1] - center[1]) / (end[0] - center[0]));
ol.geom.Polygon.makeRegular(geometry, center, radius, angle);
return geometry;
}
);
};
/**
* Get the drawing mode. The mode for mult-part geometries is the same as for
* their single-part cousins.
@@ -686,6 +782,19 @@ ol.interaction.Draw.getMode_ = function(type) {
};
/**
* Function that takes coordinates and an optional existing geometry as
* arguments, and returns a geometry. The optional existing geometry is the
* geometry that is returned when the function is called without a second
* argument.
* @typedef {function(!(ol.Coordinate|Array.<ol.Coordinate>|
* Array.<Array.<ol.Coordinate>>), ol.geom.SimpleGeometry=):
* ol.geom.SimpleGeometry}
* @api
*/
ol.interaction.DrawGeometryFunctionType;
/**
* Draw mode. This collapses multi-part geometry types with their single-part
* cousins.

View File

@@ -46,11 +46,13 @@ ol.interaction.SelectFilterFunction;
* @param {string} type The event type.
* @param {Array.<ol.Feature>} selected Selected features.
* @param {Array.<ol.Feature>} deselected Deselected features.
* @param {ol.MapBrowserEvent} mapBrowserEvent Associated
* {@link ol.MapBrowserEvent}.
* @implements {oli.SelectEvent}
* @extends {goog.events.Event}
* @constructor
*/
ol.SelectEvent = function(type, selected, deselected) {
ol.SelectEvent = function(type, selected, deselected, mapBrowserEvent) {
goog.base(this, type);
/**
@@ -66,6 +68,13 @@ ol.SelectEvent = function(type, selected, deselected) {
* @api
*/
this.deselected = deselected;
/**
* Associated {@link ol.MapBrowserEvent}.
* @type {ol.MapBrowserEvent}
* @api
*/
this.mapBrowserEvent = mapBrowserEvent;
};
goog.inherits(ol.SelectEvent, goog.events.Event);
@@ -81,6 +90,7 @@ goog.inherits(ol.SelectEvent, goog.events.Event);
* @constructor
* @extends {ol.interaction.Interaction}
* @param {olx.interaction.SelectOptions=} opt_options Options.
* @fires ol.SelectEvent
* @api stable
*/
ol.interaction.Select = function(opt_options) {
@@ -265,7 +275,8 @@ ol.interaction.Select.handleEvent = function(mapBrowserEvent) {
}
if (change) {
this.dispatchEvent(
new ol.SelectEvent(ol.SelectEventType.SELECT, selected, deselected));
new ol.SelectEvent(ol.SelectEventType.SELECT, selected, deselected,
mapBrowserEvent));
}
return ol.events.condition.pointerMove(mapBrowserEvent);
};

View File

@@ -1,5 +1,6 @@
goog.provide('ol.layer.Vector');
goog.require('goog.asserts');
goog.require('goog.object');
goog.require('ol.layer.Layer');
goog.require('ol.style.Style');
@@ -32,6 +33,11 @@ ol.layer.Vector = function(opt_options) {
var options = goog.isDef(opt_options) ?
opt_options : /** @type {olx.layer.VectorOptions} */ ({});
goog.asserts.assert(
!goog.isDef(options.renderOrder) || goog.isNull(options.renderOrder) ||
goog.isFunction(options.renderOrder),
'renderOrder must be a comparator function');
var baseOptions = goog.object.clone(options);
delete baseOptions.style;
@@ -153,6 +159,10 @@ ol.layer.Vector.prototype.getUpdateWhileInteracting = function() {
* Render order.
*/
ol.layer.Vector.prototype.setRenderOrder = function(renderOrder) {
goog.asserts.assert(
!goog.isDef(renderOrder) || goog.isNull(renderOrder) ||
goog.isFunction(renderOrder),
'renderOrder must be a comparator function');
this.set(ol.layer.VectorProperty.RENDER_ORDER, renderOrder);
};

View File

@@ -151,6 +151,15 @@ ol.MapProperty = {
* a further element within the viewport, either DOM or Canvas, depending on the
* renderer.
*
* Layers are stored as a `ol.Collection` in layerGroups. A top-level group is
* provided by the library. This is what is accessed by `getLayerGroup` and
* `setLayerGroup`. Layers entered in the options are added to this group, and
* `addLayer` and `removeLayer` change the layer collection in the group.
* `getLayers` is a convenience function for `getLayerGroup().getLayers()`.
* Note that `ol.layer.Group` is a subclass of `ol.layer.Base`, so layers
* entered in the options or added with `addLayer` can be groups, which can
* contain further groups, and so on.
*
* @constructor
* @extends {ol.Object}
* @param {olx.MapOptions} options Map options.
@@ -503,7 +512,9 @@ ol.Map.prototype.addInteraction = function(interaction) {
/**
* Adds the given layer to the top of this map.
* Adds the given layer to the top of this map. If you want to add a layer
* elsewhere in the stack, use `getLayers()` and the methods available on
* {@link ol.Collection}.
* @param {ol.layer.Base} layer Layer.
* @api stable
*/
@@ -564,15 +575,19 @@ ol.Map.prototype.disposeInternal = function() {
* included in the detection.
* @param {ol.Pixel} pixel Pixel.
* @param {function(this: S, ol.Feature, ol.layer.Layer): T} callback Feature
* callback. If the detected feature is not on a layer, but on a
* {@link ol.FeatureOverlay}, then the 2nd argument to this function will
* be `null`. To stop detection, callback functions can return a truthy
* value.
* callback. The callback will be called with two arguments. The first
* argument is one {@link ol.Feature feature} at the pixel, the second is
* the {@link ol.layer.Layer layer} of the feature. If the detected feature
* is not on a layer, but on a {@link ol.FeatureOverlay}, then the second
* argument to this function will be `null`. To stop detection, callback
* functions can return a truthy value.
* @param {S=} opt_this Value to use as `this` when executing `callback`.
* @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
* filter function, only layers which are visible and for which this
* function returns `true` will be tested for features. By default, all
* visible layers will be tested. Feature overlays will always be tested.
* filter function. The filter function will receive one argument, the
* {@link ol.layer.Layer layer-candidate} and it should return a boolean
* value. Only layers which are visible and for which this function returns
* `true` will be tested for features. By default, all visible layers will
* be tested. Feature overlays will always be tested.
* @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
* @return {T|undefined} Callback result, i.e. the return value of last
* callback execution, or the first truthy callback return value.
@@ -602,15 +617,18 @@ ol.Map.prototype.forEachFeatureAtPixel =
* always be included in the detection.
* @param {ol.Pixel} pixel Pixel.
* @param {function(this: S, ol.layer.Layer): T} callback Layer
* callback. If the detected feature is not on a layer, but on a
* {@link ol.FeatureOverlay}, then the argument to this function will
* be `null`. To stop detection, callback functions can return a truthy
* value.
* callback. Will receive one argument, the {@link ol.layer.Layer layer}
* that contains the color pixel. If the detected color value is not from a
* layer, but from a {@link ol.FeatureOverlay}, then the argument to this
* function will be `null`. To stop detection, callback functions can return
* a truthy value.
* @param {S=} opt_this Value to use as `this` when executing `callback`.
* @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
* filter function, only layers which are visible and for which this
* function returns `true` will be tested for features. By default, all
* visible layers will be tested. Feature overlays will always be tested.
* filter function. The filter function will receive one argument, the
* {@link ol.layer.Layer layer-candidate} and it should return a boolean
* value. Only layers which are visible and for which this function returns
* `true` will be tested for features. By default, all visible layers will
* be tested. Feature overlays will always be tested.
* @param {U=} opt_this2 Value to use as `this` when executing `layerFilter`.
* @return {T|undefined} Callback result, i.e. the return value of last
* callback execution, or the first truthy callback return value.
@@ -638,9 +656,11 @@ ol.Map.prototype.forEachLayerAtPixel =
* always be included in the detection.
* @param {ol.Pixel} pixel Pixel.
* @param {(function(this: U, ol.layer.Layer): boolean)=} opt_layerFilter Layer
* filter function, only layers which are visible and for which this
* function returns `true` will be tested for features. By default, all
* visible layers will be tested. Feature overlays will always be tested.
* filter function. The filter function will receive one argument, the
* {@link ol.layer.Layer layer-candidate} and it should return a boolean
* value. Only layers which are visible and for which this function returns
* `true` will be tested for features. By default, all visible layers will
* be tested. Feature overlays will always be tested.
* @param {U=} opt_this Value to use as `this` when executing `layerFilter`.
* @return {boolean} Is there a feature at the given pixel?
* @template U

View File

@@ -12,7 +12,6 @@ goog.require('ol.proj');
goog.require('ol.source.State');
goog.require('ol.source.TileImage');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.XYZ');
@@ -103,12 +102,14 @@ ol.source.BingMaps.prototype.handleImageryMetadataResponse =
var maxZoom = this.maxZoom_ == -1 ? resource.zoomMax : this.maxZoom_;
var sourceProjection = this.getProjection();
var tileGrid = new ol.tilegrid.XYZ({
extent: ol.tilegrid.extentFromProjection(sourceProjection),
var extent = ol.tilegrid.extentFromProjection(sourceProjection);
var tileSize = resource.imageWidth == resource.imageHeight ?
resource.imageWidth : [resource.imageWidth, resource.imageHeight];
var tileGrid = ol.tilegrid.createXYZ({
extent: extent,
minZoom: resource.zoomMin,
maxZoom: maxZoom,
tileSize: resource.imageWidth == resource.imageHeight ?
resource.imageWidth : [resource.imageWidth, resource.imageHeight]
tileSize: tileSize
});
this.tileGrid = tileGrid;

View File

@@ -75,9 +75,9 @@ ol.source.Source = function(options) {
/**
* @private
* @type {boolean|undefined}
* @type {boolean}
*/
this.wrapX_ = options.wrapX;
this.wrapX_ = goog.isDef(options.wrapX) ? options.wrapX : false;
};
goog.inherits(ol.source.Source, ol.Object);

View File

@@ -93,7 +93,8 @@ ol.source.TileImage.prototype.getTile =
} else {
goog.asserts.assert(projection, 'argument projection is truthy');
var tileCoord = [z, x, y];
var urlTileCoord = this.getWrapXTileCoord(tileCoord, projection);
var urlTileCoord = this.getTileCoordForTileUrlFunction(
tileCoord, projection);
var tileUrl = goog.isNull(urlTileCoord) ? undefined :
this.tileUrlFunction(urlTileCoord, pixelRatio, projection);
var tile = new this.tileClass(

View File

@@ -17,7 +17,6 @@ goog.require('ol.extent');
goog.require('ol.proj');
goog.require('ol.source.State');
goog.require('ol.source.TileImage');
goog.require('ol.tilegrid.XYZ');
@@ -69,7 +68,7 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
}
var minZoom = tileJSON.minzoom || 0;
var maxZoom = tileJSON.maxzoom || 22;
var tileGrid = new ol.tilegrid.XYZ({
var tileGrid = ol.tilegrid.createXYZ({
extent: ol.tilegrid.extentFromProjection(sourceProjection),
maxZoom: maxZoom,
minZoom: minZoom
@@ -77,7 +76,7 @@ ol.source.TileJSON.prototype.handleTileJSONResponse = function(tileJSON) {
this.tileGrid = tileGrid;
this.tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform(
tileGrid.createTileCoordTransform({extent: extent}),
tileGrid.createTileCoordTransform(),
ol.TileUrlFunction.createFromTemplates(tileJSON.tiles));
if (goog.isDef(tileJSON.attribution) &&

View File

@@ -2,6 +2,7 @@ goog.provide('ol.source.Tile');
goog.provide('ol.source.TileEvent');
goog.provide('ol.source.TileOptions');
goog.require('goog.asserts');
goog.require('goog.events.Event');
goog.require('ol.Attribution');
goog.require('ol.Extent');
@@ -216,28 +217,23 @@ ol.source.Tile.prototype.getTilePixelSize =
/**
* Handles x-axis wrapping. When `wrapX` is `undefined` or the projection is not
* a global projection, `tileCoord` will be returned unaltered. When `wrapX` is
* `true`, the tile coordinate will be wrapped horizontally.
* When `wrapX` is `false`, `null` will be returned for tiles that are
* outside the projection extent.
* Handles x-axis wrapping and returns a tile coordinate when it is within
* the resolution and extent range.
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection=} opt_projection Projection.
* @return {ol.TileCoord} Tile coordinate.
* @return {ol.TileCoord} Tile coordinate to be passed to the tileUrlFunction or
* null if no tile URL should be created for the passed `tileCoord`.
*/
ol.source.Tile.prototype.getWrapXTileCoord =
ol.source.Tile.prototype.getTileCoordForTileUrlFunction =
function(tileCoord, opt_projection) {
var projection = goog.isDef(opt_projection) ?
opt_projection : this.getProjection();
var tileGrid = this.getTileGridForProjection(projection);
var wrapX = this.getWrapX();
if (goog.isDef(wrapX) && tileGrid.isGlobal(tileCoord[0], projection)) {
return wrapX ?
ol.tilecoord.wrapX(tileCoord, tileGrid, projection) :
ol.tilecoord.clipX(tileCoord, tileGrid, projection);
} else {
return tileCoord;
goog.asserts.assert(!goog.isNull(tileGrid), 'tile grid needed');
if (this.getWrapX()) {
tileCoord = ol.tilecoord.wrapX(tileCoord, tileGrid, projection);
}
return ol.tilecoord.restrictByExtentAndZ(tileCoord, tileGrid);
};

View File

@@ -13,7 +13,6 @@ goog.require('ol.extent');
goog.require('ol.proj');
goog.require('ol.source.State');
goog.require('ol.source.Tile');
goog.require('ol.tilegrid.XYZ');
@@ -122,7 +121,7 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
}
var minZoom = tileJSON.minzoom || 0;
var maxZoom = tileJSON.maxzoom || 22;
var tileGrid = new ol.tilegrid.XYZ({
var tileGrid = ol.tilegrid.createXYZ({
extent: ol.tilegrid.extentFromProjection(sourceProjection),
maxZoom: maxZoom,
minZoom: minZoom
@@ -138,9 +137,7 @@ ol.source.TileUTFGrid.prototype.handleTileJSONResponse = function(tileJSON) {
}
this.tileUrlFunction_ = ol.TileUrlFunction.withTileCoordTransform(
tileGrid.createTileCoordTransform({
extent: extent
}),
tileGrid.createTileCoordTransform(),
ol.TileUrlFunction.createFromTemplates(grids));
if (goog.isDef(tileJSON.attribution)) {

View File

@@ -49,7 +49,7 @@ ol.source.TileWMS = function(opt_options) {
tileGrid: options.tileGrid,
tileLoadFunction: options.tileLoadFunction,
tileUrlFunction: goog.bind(this.tileUrlFunction_, this),
wrapX: options.wrapX
wrapX: goog.isDef(options.wrapX) ? options.wrapX : true
});
var urls = options.urls;

View File

@@ -11,7 +11,6 @@ goog.require('ol.TileUrlFunctionType');
goog.require('ol.extent');
goog.require('ol.proj');
goog.require('ol.source.TileImage');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.WMTS');
@@ -181,31 +180,8 @@ ol.source.WMTS = function(options) {
goog.array.map(this.urls_, createFromWMTSTemplate)) :
ol.TileUrlFunction.nullTileUrlFunction;
var tmpExtent = ol.extent.createEmpty();
tileUrlFunction = ol.TileUrlFunction.withTileCoordTransform(
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection} projection Projection.
* @param {ol.TileCoord=} opt_tileCoord Tile coordinate.
* @return {ol.TileCoord} Tile coordinate.
*/
function(tileCoord, projection, opt_tileCoord) {
goog.asserts.assert(!goog.isNull(tileGrid),
'tileGrid must not be null');
if (tileGrid.getResolutions().length <= tileCoord[0]) {
return null;
}
var x = tileCoord[1];
var y = -tileCoord[2] - 1;
var tileExtent = tileGrid.getTileCoordExtent(tileCoord, tmpExtent);
var extent = projection.getExtent();
if (!ol.extent.intersects(tileExtent, extent) ||
ol.extent.touches(tileExtent, extent)) {
return null;
}
return ol.tilecoord.createOrUpdate(tileCoord[0], x, y, opt_tileCoord);
},
ol.tilegrid.createOriginTopLeftTileCoordTransform(tileGrid),
tileUrlFunction);
goog.base(this, {
@@ -379,7 +355,7 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
goog.asserts.assert(l['TileMatrixSetLink'].length > 0,
'layer has TileMatrixSetLink');
var idx, matrixSet, wrapX;
var idx, matrixSet;
if (l['TileMatrixSetLink'].length > 1) {
idx = goog.array.findIndex(l['TileMatrixSetLink'],
function(elt, index, array) {
@@ -404,13 +380,6 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
goog.asserts.assert(!goog.isNull(matrixSet),
'TileMatrixSet must not be null');
var wgs84BoundingBox = l['WGS84BoundingBox'];
if (goog.isDef(wgs84BoundingBox)) {
var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent();
wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] &&
wgs84BoundingBox[2] == wgs84ProjectionExtent[2]);
}
var format = /** @type {string} */ (l['Format'][0]);
if (goog.isDef(config['format'])) {
format = config['format'];
@@ -450,9 +419,6 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
goog.asserts.assert(!goog.isNull(matrixSetObj),
'found matrixSet in Contents/TileMatrixSet');
var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
matrixSetObj);
var projection;
if (goog.isDef(config['projection'])) {
projection = ol.proj.get(config['projection']);
@@ -461,6 +427,27 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
/urn:ogc:def:crs:(\w+):(.*:)?(\w+)$/, '$1:$3'));
}
var wgs84BoundingBox = l['WGS84BoundingBox'];
var extent, wrapX;
if (goog.isDef(wgs84BoundingBox)) {
var wgs84ProjectionExtent = ol.proj.get('EPSG:4326').getExtent();
wrapX = (wgs84BoundingBox[0] == wgs84ProjectionExtent[0] &&
wgs84BoundingBox[2] == wgs84ProjectionExtent[2]);
extent = ol.proj.transformExtent(
wgs84BoundingBox, 'EPSG:4326', projection);
var projectionExtent = projection.getExtent();
if (!goog.isNull(projectionExtent)) {
// If possible, do a sanity check on the extent - it should never be
// bigger than the validity extent of the projection of a matrix set.
if (!ol.extent.containsExtent(projectionExtent, extent)) {
extent = undefined;
}
}
}
var tileGrid = ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet(
matrixSetObj, extent);
/** @type {!Array.<string>} */
var urls = [];
var requestEncoding = config['requestEncoding'];
@@ -471,7 +458,8 @@ ol.source.WMTS.optionsFromCapabilities = function(wmtsCap, config) {
'requestEncoding (%s) is one of "REST", "RESTful", "KVP" or ""',
requestEncoding);
if (!wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') ||
if (!wmtsCap.hasOwnProperty('OperationsMetadata') ||
!wmtsCap['OperationsMetadata'].hasOwnProperty('GetTile') ||
goog.string.startsWith(requestEncoding, 'REST')) {
// Add REST tile resource url
requestEncoding = ol.source.WMTSRequestEncoding.REST;

View File

@@ -3,7 +3,6 @@ goog.provide('ol.source.XYZ');
goog.require('ol.Attribution');
goog.require('ol.TileUrlFunction');
goog.require('ol.source.TileImage');
goog.require('ol.tilegrid.XYZ');
@@ -20,7 +19,7 @@ ol.source.XYZ = function(options) {
var projection = goog.isDef(options.projection) ?
options.projection : 'EPSG:3857';
var tileGrid = new ol.tilegrid.XYZ({
var tileGrid = ol.tilegrid.createXYZ({
extent: ol.tilegrid.extentFromProjection(projection),
maxZoom: options.maxZoom,
tileSize: options.tileSize

View File

@@ -3,7 +3,7 @@ goog.provide('ol.tilecoord');
goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.math');
goog.require('ol.extent');
/**
@@ -149,25 +149,42 @@ ol.tilecoord.toString = function(tileCoord) {
*/
ol.tilecoord.wrapX = function(tileCoord, tileGrid, projection) {
var z = tileCoord[0];
var x = tileCoord[1];
var tileRange = tileGrid.getTileRange(z, projection);
if (x < tileRange.minX || x > tileRange.maxX) {
x = goog.math.modulo(x, tileRange.getWidth());
return [z, x, tileCoord[2]];
var center = tileGrid.getTileCoordCenter(tileCoord);
var projectionExtent = ol.tilegrid.extentFromProjection(projection);
if (!ol.extent.containsCoordinate(projectionExtent, center)) {
var worldWidth = ol.extent.getWidth(projectionExtent);
var worldsAway = Math.ceil((projectionExtent[0] - center[0]) / worldWidth);
center[0] += worldWidth * worldsAway;
return tileGrid.getTileCoordForCoordAndZ(center, z);
} else {
return tileCoord;
}
return tileCoord;
};
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
* @param {ol.proj.Projection} projection Projection.
* @param {!ol.tilegrid.TileGrid} tileGrid Tile grid.
* @return {ol.TileCoord} Tile coordinate.
*/
ol.tilecoord.clipX = function(tileCoord, tileGrid, projection) {
ol.tilecoord.restrictByExtentAndZ = function(tileCoord, tileGrid) {
var z = tileCoord[0];
var x = tileCoord[1];
var tileRange = tileGrid.getTileRange(z, projection);
return (x < tileRange.minX || x > tileRange.maxX) ? null : tileCoord;
var y = tileCoord[2];
if (tileGrid.getMinZoom() > z || z > tileGrid.getMaxZoom()) {
return null;
}
var extent = tileGrid.getExtent();
var tileRange;
if (goog.isNull(extent)) {
tileRange = tileGrid.getFullTileRange(z);
} else {
tileRange = tileGrid.getTileRangeForExtentAndZ(extent, z);
}
if (goog.isNull(tileRange)) {
return tileCoord;
} else {
return tileRange.containsXY(x, y) ? tileCoord : null;
}
};

View File

@@ -4,6 +4,7 @@ goog.require('goog.array');
goog.require('goog.asserts');
goog.require('goog.functions');
goog.require('goog.math');
goog.require('goog.object');
goog.require('ol');
goog.require('ol.Coordinate');
goog.require('ol.TileCoord');
@@ -69,6 +70,14 @@ ol.tilegrid.TileGrid = function(options) {
goog.asserts.assert(this.origins_.length == this.resolutions_.length,
'number of origins and resolutions must be equal');
}
var extent = options.extent;
if (goog.isDef(extent) &&
goog.isNull(this.origin_) && goog.isNull(this.origins_)) {
this.origin_ = ol.extent.getBottomLeft(extent);
}
goog.asserts.assert(
(goog.isNull(this.origin_) && !goog.isNull(this.origins_)) ||
(!goog.isNull(this.origin_) && goog.isNull(this.origins_)),
@@ -97,6 +106,56 @@ ol.tilegrid.TileGrid = function(options) {
(!goog.isNull(this.tileSize_) && goog.isNull(this.tileSizes_)),
'either tileSize or tileSizes must be configured, never both');
/**
* @private
* @type {ol.Extent}
*/
this.extent_ = goog.isDef(extent) ? extent : null;
/**
* Creates a TileCoord transform function for use with this tile grid.
* Transforms the internal tile coordinates with bottom-left origin to
* the tile coordinates used by the {@link ol.TileUrlFunction}.
* The returned function expects an {@link ol.TileCoord} as first and an
* {@link ol.proj.Projection} as second argument and returns a transformed
* {@link ol.TileCoord}.
* @param {{extent: (ol.Extent|undefined)}=} opt_options Options.
* @return {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):
* ol.TileCoord} Tile coordinate transform.
* @api
*/
this.createTileCoordTransform = goog.isDef(options.createTileCoordTransform) ?
options.createTileCoordTransform :
goog.functions.identity;
/**
* @private
* @type {Array.<ol.TileRange>}
*/
this.fullTileRanges_ = null;
if (goog.isDef(options.sizes)) {
goog.asserts.assert(options.sizes.length == this.resolutions_.length,
'number of sizes and resolutions must be equal');
this.fullTileRanges_ = goog.array.map(options.sizes, function(size, z) {
goog.asserts.assert(size[0] > 0, 'width must be > 0');
goog.asserts.assert(size[1] !== 0, 'height must not be 0');
var tileRange = new ol.TileRange(0, size[0] - 1, 0, size[1] - 1);
if (tileRange.maxY < tileRange.minY) {
tileRange.minY = size[1];
tileRange.maxY = -1;
}
if (this.minZoom <= z && z <= this.maxZoom && goog.isDef(extent)) {
goog.asserts.assert(tileRange.containsTileRange(
this.getTileRangeForExtentAndZ(extent, z)),
'extent tile range must not exceed tilegrid width and height');
}
return tileRange;
}, this);
} else if (goog.isDefAndNotNull(extent)) {
this.calculateTileRanges_(extent);
}
/**
* @private
@@ -104,17 +163,6 @@ ol.tilegrid.TileGrid = function(options) {
*/
this.tmpSize_ = [0, 0];
/**
* @private
* @type {Array.<number>}
*/
this.widths_ = null;
if (goog.isDef(options.widths)) {
this.widths_ = options.widths;
goog.asserts.assert(this.widths_.length == this.resolutions_.length,
'number of widths and resolutions must be equal');
}
};
@@ -125,18 +173,6 @@ ol.tilegrid.TileGrid = function(options) {
ol.tilegrid.TileGrid.tmpTileCoord_ = [0, 0, 0];
/**
* Returns the identity function. May be overridden in subclasses.
* @param {{extent: (ol.Extent|undefined)}=} opt_options Options.
* @return {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):
* ol.TileCoord} Tile coordinate transform.
*/
ol.tilegrid.TileGrid.prototype.createTileCoordTransform =
function(opt_options) {
return goog.functions.identity;
};
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {function(this: T, number, ol.TileRange): boolean} callback Callback.
@@ -161,6 +197,15 @@ ol.tilegrid.TileGrid.prototype.forEachTileCoordParentTileRange =
};
/**
* Get the extent for this tile grid, if it was configured.
* @return {ol.Extent} Extent.
*/
ol.tilegrid.TileGrid.prototype.getExtent = function() {
return this.extent_;
};
/**
* Get the maximum zoom level for the grid.
* @return {number} Max zoom.
@@ -365,8 +410,11 @@ ol.tilegrid.TileGrid.prototype.getTileCoordForXYAndResolution_ = function(
var origin = this.getOrigin(z);
var tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);
var tileCoordX = scale * (x - origin[0]) / (resolution * tileSize[0]);
var tileCoordY = scale * (y - origin[1]) / (resolution * tileSize[1]);
var adjust = reverseIntersectionPolicy ? 0.5 : 0;
var xFromOrigin = ((x - origin[0]) / resolution + adjust) | 0;
var yFromOrigin = ((y - origin[1]) / resolution + adjust) | 0;
var tileCoordX = scale * xFromOrigin / tileSize[0];
var tileCoordY = scale * yFromOrigin / tileSize[1];
if (reverseIntersectionPolicy) {
tileCoordX = Math.ceil(tileCoordX) - 1;
@@ -409,25 +457,6 @@ ol.tilegrid.TileGrid.prototype.getTileCoordResolution = function(tileCoord) {
};
/**
* @param {number} z Zoom level.
* @param {ol.proj.Projection} projection Projection.
* @param {ol.TileRange=} opt_tileRange Tile range.
* @return {ol.TileRange} Tile range.
*/
ol.tilegrid.TileGrid.prototype.getTileRange =
function(z, projection, opt_tileRange) {
var projectionExtentTileRange = this.getTileRangeForExtentAndZ(
ol.tilegrid.extentFromProjection(projection), z);
var width = this.getWidth(z);
if (!goog.isDef(width)) {
width = projectionExtentTileRange.getWidth();
}
return ol.TileRange.createOrUpdate(
0, width - 1, 0, projectionExtentTileRange.getHeight(), opt_tileRange);
};
/**
* Get the tile size for a zoom level. The type of the return value matches the
* `tileSize` or `tileSizes` that the tile grid was configured with. To always
@@ -452,15 +481,16 @@ ol.tilegrid.TileGrid.prototype.getTileSize = function(z) {
/**
* @param {number} z Zoom level.
* @return {number|undefined} Width for the specified zoom level or `undefined`
* if unknown.
* @return {ol.TileRange} Extent tile range for the specified zoom level.
*/
ol.tilegrid.TileGrid.prototype.getWidth = function(z) {
if (!goog.isNull(this.widths_)) {
ol.tilegrid.TileGrid.prototype.getFullTileRange = function(z) {
if (goog.isNull(this.fullTileRanges_)) {
return null;
} else {
goog.asserts.assert(this.minZoom <= z && z <= this.maxZoom,
'z is not in allowed range (%s <= %s <= %s',
this.minZoom, z, this.maxZoom);
return this.widths_[z];
return this.fullTileRanges_[z];
}
};
@@ -476,22 +506,21 @@ ol.tilegrid.TileGrid.prototype.getZForResolution = function(resolution) {
/**
* @param {number} z Zoom level.
* @param {ol.proj.Projection} projection Projection.
* @return {boolean} Whether the tile grid is defined for the whole globe when
* used with the provided `projection` at zoom level `z`.
* @param {!ol.Extent} extent Extent for this tile grid.
* @private
*/
ol.tilegrid.TileGrid.prototype.isGlobal = function(z, projection) {
var width = this.getWidth(z);
if (goog.isDef(width)) {
var projTileGrid = ol.tilegrid.getForProjection(projection);
var projExtent = projection.getExtent();
return ol.size.toSize(this.getTileSize(z), this.tmpSize_)[0] * width ==
projTileGrid.getTileSize(z) *
projTileGrid.getTileRangeForExtentAndZ(projExtent, z).getWidth();
} else {
return projection.isGlobal();
ol.tilegrid.TileGrid.prototype.calculateTileRanges_ = function(extent) {
var extentWidth = ol.extent.getWidth(extent);
var extentHeight = ol.extent.getHeight(extent);
var fullTileRanges = new Array(this.resolutions_.length);
var tileSize;
for (var z = 0, zz = fullTileRanges.length; z < zz; ++z) {
tileSize = ol.size.toSize(this.getTileSize(z), this.tmpSize_);
fullTileRanges[z] = new ol.TileRange(
0, Math.ceil(extentWidth / tileSize[0] / this.resolutions_[z]) - 1,
0, Math.ceil(extentHeight / tileSize[1] / this.resolutions_[z]) - 1);
}
this.fullTileRanges_ = fullTileRanges;
};
@@ -521,36 +550,59 @@ ol.tilegrid.getForProjection = function(projection) {
*/
ol.tilegrid.createForExtent =
function(extent, opt_maxZoom, opt_tileSize, opt_corner) {
var tileSize = goog.isDef(opt_tileSize) ?
ol.size.toSize(opt_tileSize) : ol.size.toSize(ol.DEFAULT_TILE_SIZE);
var corner = goog.isDef(opt_corner) ?
opt_corner : ol.extent.Corner.BOTTOM_LEFT;
var resolutions = ol.tilegrid.resolutionsFromExtent(
extent, opt_maxZoom, ol.size.toSize(tileSize));
var widths = new Array(resolutions.length);
var extentWidth = ol.extent.getWidth(extent);
for (var z = resolutions.length - 1; z >= 0; --z) {
widths[z] = extentWidth / tileSize[0] / resolutions[z];
}
extent, opt_maxZoom, opt_tileSize);
return new ol.tilegrid.TileGrid({
extent: extent,
origin: ol.extent.getCorner(extent, corner),
resolutions: resolutions,
tileSize: goog.isDef(opt_tileSize) ? opt_tileSize : ol.DEFAULT_TILE_SIZE,
widths: widths
tileSize: opt_tileSize
});
};
/**
* Creates a tile grid with a standard XYZ tiling scheme.
* @param {olx.tilegrid.XYZOptions=} opt_options Tile grid options.
* @return {ol.tilegrid.TileGrid} Tile grid instance.
* @api
*/
ol.tilegrid.createXYZ = function(opt_options) {
var options = /** @type {olx.tilegrid.TileGridOptions} */ ({});
goog.object.extend(options, goog.isDef(opt_options) ?
opt_options : /** @type {olx.tilegrid.XYZOptions} */ ({}));
if (!goog.isDef(options.extent)) {
options.extent = ol.proj.get('EPSG:3857').getExtent();
}
options.resolutions = ol.tilegrid.resolutionsFromExtent(
options.extent, options.maxZoom, options.tileSize);
delete options.maxZoom;
/**
* @param {{extent: (ol.Extent|undefined)}=} opt_options Options.
* @return {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):
* ol.TileCoord} Tile coordinate transform.
* @this {ol.tilegrid.TileGrid}
*/
options.createTileCoordTransform = function(opt_options) {
return ol.tilegrid.createOriginTopLeftTileCoordTransform(this);
};
return new ol.tilegrid.TileGrid(options);
};
/**
* Create a resolutions array from an extent. A zoom factor of 2 is assumed.
* @param {ol.Extent} extent Extent.
* @param {number=} opt_maxZoom Maximum zoom level (default is
* ol.DEFAULT_MAX_ZOOM).
* @param {ol.Size=} opt_tileSize Tile size (default uses ol.DEFAULT_TILE_SIZE).
* @param {number|ol.Size=} opt_tileSize Tile size (default uses
* ol.DEFAULT_TILE_SIZE).
* @return {!Array.<number>} Resolutions array.
*/
ol.tilegrid.resolutionsFromExtent =
@@ -561,8 +613,8 @@ ol.tilegrid.resolutionsFromExtent =
var height = ol.extent.getHeight(extent);
var width = ol.extent.getWidth(extent);
var tileSize = goog.isDef(opt_tileSize) ?
opt_tileSize : ol.size.toSize(ol.DEFAULT_TILE_SIZE);
var tileSize = ol.size.toSize(goog.isDef(opt_tileSize) ?
opt_tileSize : ol.DEFAULT_TILE_SIZE);
var maxResolution = Math.max(
width / tileSize[0], height / tileSize[1]);
@@ -608,3 +660,32 @@ ol.tilegrid.extentFromProjection = function(projection) {
}
return extent;
};
/**
* @param {ol.tilegrid.TileGrid} tileGrid Tile grid.
* @return {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):
* ol.TileCoord} Tile coordinate transform.
*/
ol.tilegrid.createOriginTopLeftTileCoordTransform = function(tileGrid) {
goog.asserts.assert(!goog.isNull(tileGrid), 'tileGrid required');
return (
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection} projection Projection.
* @param {ol.TileCoord=} opt_tileCoord Destination tile coordinate.
* @return {ol.TileCoord} Tile coordinate.
*/
function(tileCoord, projection, opt_tileCoord) {
if (goog.isNull(tileCoord)) {
return null;
}
var z = tileCoord[0];
var fullTileRange = tileGrid.getFullTileRange(z);
var height = (goog.isNull(fullTileRange) || fullTileRange.minY < 0) ?
0 : fullTileRange.getHeight();
return ol.tilecoord.createOrUpdate(
z, tileCoord[1], height - tileCoord[2] - 1, opt_tileCoord);
}
);
};

View File

@@ -32,12 +32,13 @@ ol.tilegrid.WMTS = function(options) {
// FIXME: should the matrixIds become optionnal?
goog.base(this, {
extent: options.extent,
origin: options.origin,
origins: options.origins,
resolutions: options.resolutions,
tileSize: options.tileSize,
tileSizes: options.tileSizes,
widths: options.widths
sizes: options.sizes
});
};
@@ -69,11 +70,13 @@ ol.tilegrid.WMTS.prototype.getMatrixIds = function() {
* Create a tile grid from a WMTS capabilities matrix set.
* @param {Object} matrixSet An object representing a matrixSet in the
* capabilities document.
* @param {ol.Extent=} opt_extent An optional extent to restrict the tile
* ranges the server provides.
* @return {ol.tilegrid.WMTS} WMTS tileGrid instance.
* @api
*/
ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
function(matrixSet) {
function(matrixSet, opt_extent) {
/** @type {!Array.<number>} */
var resolutions = [];
@@ -83,8 +86,8 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
var origins = [];
/** @type {!Array.<ol.Size>} */
var tileSizes = [];
/** @type {!Array.<number>} */
var widths = [];
/** @type {!Array.<ol.Size>} */
var sizes = [];
var supportedCRSPropName = 'SupportedCRS';
var matrixIdsPropName = 'TileMatrix';
@@ -108,26 +111,30 @@ ol.tilegrid.WMTS.createFromCapabilitiesMatrixSet =
goog.array.forEach(matrixSet[matrixIdsPropName],
function(elt, index, array) {
matrixIds.push(elt[identifierPropName]);
var resolution = elt[scaleDenominatorPropName] * 0.28E-3 /
metersPerUnit;
var tileWidth = elt[tileWidthPropName];
var tileHeight = elt[tileHeightPropName];
var matrixHeight = elt['MatrixHeight'];
if (switchOriginXY) {
origins.push([elt[topLeftCornerPropName][1],
elt[topLeftCornerPropName][0]]);
} else {
origins.push(elt[topLeftCornerPropName]);
}
resolutions.push(elt[scaleDenominatorPropName] * 0.28E-3 /
metersPerUnit);
var tileWidth = elt[tileWidthPropName];
var tileHeight = elt[tileHeightPropName];
resolutions.push(resolution);
tileSizes.push(tileWidth == tileHeight ?
tileWidth : [tileWidth, tileHeight]);
widths.push(elt['MatrixWidth']);
// top-left origin, so height is negative
sizes.push([elt['MatrixWidth'], -matrixHeight]);
});
return new ol.tilegrid.WMTS({
extent: opt_extent,
origins: origins,
resolutions: resolutions,
matrixIds: matrixIds,
tileSizes: tileSizes,
widths: widths
sizes: sizes
});
};

View File

@@ -1,130 +0,0 @@
goog.provide('ol.tilegrid.XYZ');
goog.require('goog.math');
goog.require('ol');
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.extent');
goog.require('ol.extent.Corner');
goog.require('ol.proj');
goog.require('ol.proj.EPSG3857');
goog.require('ol.size');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid');
/**
* @classdesc
* Set the grid pattern for sources accessing XYZ tiled-image servers.
*
* @constructor
* @extends {ol.tilegrid.TileGrid}
* @param {olx.tilegrid.XYZOptions} options XYZ options.
* @struct
* @api
*/
ol.tilegrid.XYZ = function(options) {
var extent = goog.isDef(options.extent) ?
options.extent : ol.proj.EPSG3857.EXTENT;
var tileSize;
if (goog.isDef(options.tileSize)) {
tileSize = ol.size.toSize(options.tileSize);
}
var resolutions = ol.tilegrid.resolutionsFromExtent(
extent, options.maxZoom, tileSize);
goog.base(this, {
minZoom: options.minZoom,
origin: ol.extent.getCorner(extent, ol.extent.Corner.TOP_LEFT),
resolutions: resolutions,
tileSize: options.tileSize
});
};
goog.inherits(ol.tilegrid.XYZ, ol.tilegrid.TileGrid);
/**
* @inheritDoc
*/
ol.tilegrid.XYZ.prototype.createTileCoordTransform = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var minZ = this.minZoom;
var maxZ = this.maxZoom;
/** @type {Array.<ol.TileRange>} */
var tileRangeByZ = null;
if (goog.isDef(options.extent)) {
tileRangeByZ = new Array(maxZ + 1);
var z;
for (z = 0; z <= maxZ; ++z) {
if (z < minZ) {
tileRangeByZ[z] = null;
} else {
tileRangeByZ[z] = this.getTileRangeForExtentAndZ(options.extent, z);
}
}
}
return (
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection} projection Projection.
* @param {ol.TileCoord=} opt_tileCoord Destination tile coordinate.
* @return {ol.TileCoord} Tile coordinate.
*/
function(tileCoord, projection, opt_tileCoord) {
var z = tileCoord[0];
if (z < minZ || maxZ < z) {
return null;
}
var n = Math.pow(2, z);
var x = tileCoord[1];
var y = tileCoord[2];
if (y < -n || -1 < y) {
return null;
}
if (!goog.isNull(tileRangeByZ)) {
if (!tileRangeByZ[z].containsXY(x, y)) {
return null;
}
}
return ol.tilecoord.createOrUpdate(z, x, -y - 1, opt_tileCoord);
});
};
/**
* @inheritDoc
*/
ol.tilegrid.XYZ.prototype.getTileCoordChildTileRange =
function(tileCoord, opt_tileRange) {
if (tileCoord[0] < this.maxZoom) {
var doubleX = 2 * tileCoord[1];
var doubleY = 2 * tileCoord[2];
return ol.TileRange.createOrUpdate(
doubleX, doubleX + 1,
doubleY, doubleY + 1,
opt_tileRange);
} else {
return null;
}
};
/**
* @inheritDoc
*/
ol.tilegrid.XYZ.prototype.forEachTileCoordParentTileRange =
function(tileCoord, callback, opt_this, opt_tileRange) {
var tileRange = ol.TileRange.createOrUpdate(
0, tileCoord[1], 0, tileCoord[2], opt_tileRange);
var z;
for (z = tileCoord[0] - 1; z >= this.minZoom; --z) {
tileRange.minX = tileRange.maxX >>= 1;
tileRange.minY = tileRange.maxY >>= 1;
if (callback.call(opt_this, z, tileRange)) {
return true;
}
}
return false;
};

View File

@@ -19,61 +19,65 @@ goog.require('ol.tilegrid.TileGrid');
*/
ol.tilegrid.Zoomify = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : options;
/**
* @param {{extent: (ol.Extent|undefined)}=} opt_options Options.
* @return {function(ol.TileCoord, ol.proj.Projection, ol.TileCoord=):
* ol.TileCoord} Tile coordinate transform.
* @this {ol.tilegrid.Zoomify}
*/
var createTileCoordTransform = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var minZ = this.minZoom;
var maxZ = this.maxZoom;
/** @type {Array.<ol.TileRange>} */
var tileRangeByZ = null;
if (goog.isDef(options.extent)) {
tileRangeByZ = new Array(maxZ + 1);
var z;
for (z = 0; z <= maxZ; ++z) {
if (z < minZ) {
tileRangeByZ[z] = null;
} else {
tileRangeByZ[z] = this.getTileRangeForExtentAndZ(options.extent, z);
}
}
}
return (
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection} projection Projection.
* @param {ol.TileCoord=} opt_tileCoord Destination tile coordinate.
* @return {ol.TileCoord} Tile coordinate.
*/
function(tileCoord, projection, opt_tileCoord) {
var z = tileCoord[0];
if (z < minZ || maxZ < z) {
return null;
}
var n = Math.pow(2, z);
var x = tileCoord[1];
if (x < 0 || n <= x) {
return null;
}
var y = tileCoord[2];
if (y < -n || -1 < y) {
return null;
}
if (!goog.isNull(tileRangeByZ)) {
if (!tileRangeByZ[z].containsXY(x, -y - 1)) {
return null;
}
}
return ol.tilecoord.createOrUpdate(z, x, -y - 1, opt_tileCoord);
});
};
goog.base(this, {
createTileCoordTransform: createTileCoordTransform,
origin: [0, 0],
resolutions: options.resolutions
});
};
goog.inherits(ol.tilegrid.Zoomify, ol.tilegrid.TileGrid);
/**
* @inheritDoc
*/
ol.tilegrid.Zoomify.prototype.createTileCoordTransform = function(opt_options) {
var options = goog.isDef(opt_options) ? opt_options : {};
var minZ = this.minZoom;
var maxZ = this.maxZoom;
/** @type {Array.<ol.TileRange>} */
var tileRangeByZ = null;
if (goog.isDef(options.extent)) {
tileRangeByZ = new Array(maxZ + 1);
var z;
for (z = 0; z <= maxZ; ++z) {
if (z < minZ) {
tileRangeByZ[z] = null;
} else {
tileRangeByZ[z] = this.getTileRangeForExtentAndZ(options.extent, z);
}
}
}
return (
/**
* @param {ol.TileCoord} tileCoord Tile coordinate.
* @param {ol.proj.Projection} projection Projection.
* @param {ol.TileCoord=} opt_tileCoord Destination tile coordinate.
* @return {ol.TileCoord} Tile coordinate.
*/
function(tileCoord, projection, opt_tileCoord) {
var z = tileCoord[0];
if (z < minZ || maxZ < z) {
return null;
}
var n = Math.pow(2, z);
var x = tileCoord[1];
if (x < 0 || n <= x) {
return null;
}
var y = tileCoord[2];
if (y < -n || -1 < y) {
return null;
}
if (!goog.isNull(tileRangeByZ)) {
if (!tileRangeByZ[z].containsXY(x, -y - 1)) {
return null;
}
}
return ol.tilecoord.createOrUpdate(z, x, -y - 1, opt_tileCoord);
});
};

View File

@@ -14,6 +14,28 @@ goog.require('ol.tilecoord');
* for the projection as arguments and returns a `{string}` or
* undefined representing the tile URL.
*
* The {@link ol.TileCoord}'s `x` value
* increases from left to right, `y` increases from bottom to top. At the
* bottom left corner, `x` and `y` are `0`. To convert `y` to increase from
* top to bottom, use the following code:
* ```js
* var tileGrid = new ol.tilegrid.TileGrid({
* extent: extent,
* resolutions: resolutions,
* tileSize: tileSize
* });
*
* function calculateY(tileCoord) {
* var z = tileCoord[0];
* var yFromBottom = tileCoord[2];
* var resolution = tileGrid.getResolution(z);
* var tileHeight = ol.size.toSize(tileSize)[1];
* var matrixHeight =
* Math.floor(ol.extent.getHeight(extent) / tileHeight / resolution);
* return matrixHeight - yFromBottom - 1;
* };
* ```
*
* @typedef {function(ol.TileCoord, number,
* ol.proj.Projection): (string|undefined)}
* @api

View File

@@ -5,6 +5,7 @@ var spawn = require('child_process').spawn;
var async = require('async');
var fse = require('fs-extra');
var walk = require('walk').walk;
var isWindows = process.platform.indexOf('win') === 0;
var sourceDir = path.join(__dirname, '..', 'src');
var externsDir = path.join(__dirname, '..', 'externs');
@@ -14,6 +15,12 @@ var externsPaths = [
];
var infoPath = path.join(__dirname, '..', 'build', 'info.json');
var jsdoc = path.join(__dirname, '..', 'node_modules', '.bin', 'jsdoc');
// on Windows, use jsdoc.cmd
if (isWindows) {
jsdoc += '.cmd';
}
var jsdocConfig = path.join(
__dirname, '..', 'config', 'jsdoc', 'info', 'conf.json');
@@ -92,6 +99,17 @@ function getNewer(date, newer, callback) {
callback(new Error('Trouble walking ' + sourceDir));
});
walker.on('end', function() {
/**
* Windows has restrictions on length of command line, so passing all the
* changed paths to a task will fail if this limit is exceeded.
* To get round this, if this is Windows and there are newer files, just
* pass the sourceDir to the task so it can do the walking.
*/
if (isWindows) {
paths = [sourceDir].concat(externsPaths);
}
callback(null, newer ? paths : []);
});
}

View File

@@ -44,7 +44,7 @@ var createServer = exports.createServer = function(callback) {
manager.on('ready', function() {
server = new closure.Server({
manager: manager,
loader: /^.*\/loader\.js/,
loader: /^\/(?:(?:build\/examples)|(?:test(?:_rendering)?))\/loader\.js/,
getMain: function(req) {
var main;
var query = url.parse(req.url, true).query;

View File

@@ -3,6 +3,33 @@ goog.provide('ol.test.color');
describe('ol.color', function() {
describe('ol.color.blend', function() {
it('blends red (a=1) and blue (a=1) to blue (a=1)', function() {
var red = [255, 0, 0, 1];
var blue = [0, 0, 255, 1];
var blended = ol.color.blend(red, blue);
expect(blended).to.eql([0, 0, 255, 1]);
});
it('blends red (a=1) and blue (a=0) to red (a=1)', function() {
var red = [255, 0, 0, 1];
var blue = [0, 0, 255, 0];
var blended = ol.color.blend(red, blue);
expect(blended).to.eql([255, 0, 0, 1]);
});
it('blends red (a=0.5) and blue (a=0.5) to purple (a=0.75)', function() {
var red = [255, 0, 0, 0.5];
var blue = [0, 0, 255, 0.5];
var blended = ol.color.blend(red, blue);
expect(blended).to.eql([85, 0, 170, 0.75]);
});
it('blends red (a=0.5) and blue (a=0) to red (a=0.5)', function() {
var red = [255, 0, 0, 0.5];
var blue = [0, 0, 255, 0];
var blended = ol.color.blend(red, blue);
expect(blended).to.eql([255, 0, 0, 0.5]);
});
});
describe('ol.color.fromString', function() {
before(function() {

File diff suppressed because one or more lines are too long

View File

@@ -24,6 +24,267 @@ describe('ol.extent', function() {
});
describe('closestSquaredDistanceXY', function() {
it('returns correct result when x left of extent', function() {
var extent = ol.extent.createOrUpdate(0, 0, 1, 1);
var x = -2;
var y = 0;
expect(ol.extent.closestSquaredDistanceXY(extent, x, y)).to.be(4);
});
it('returns correct result when x right of extent', function() {
var extent = ol.extent.createOrUpdate(0, 0, 1, 1);
var x = 3;
var y = 0;
expect(ol.extent.closestSquaredDistanceXY(extent, x, y)).to.be(4);
});
it('returns correct result for other x values', function() {
var extent = ol.extent.createOrUpdate(0, 0, 1, 1);
var x = 0.5;
var y = 3;
expect(ol.extent.closestSquaredDistanceXY(extent, x, y)).to.be(4);
});
it('returns correct result when y below extent', function() {
var extent = ol.extent.createOrUpdate(0, 0, 1, 1);
var x = 0;
var y = -2;
expect(ol.extent.closestSquaredDistanceXY(extent, x, y)).to.be(4);
});
it('returns correct result when y above extent', function() {
var extent = ol.extent.createOrUpdate(0, 0, 1, 1);
var x = 0;
var y = 3;
expect(ol.extent.closestSquaredDistanceXY(extent, x, y)).to.be(4);
});
it('returns correct result for other y values', function() {
var extent = ol.extent.createOrUpdate(0, 0, 1, 1);
var x = 3;
var y = 0.5;
expect(ol.extent.closestSquaredDistanceXY(extent, x, y)).to.be(4);
});
});
describe('createOrUpdateFromCoordinate', function() {
it('works when no extent passed', function() {
var coords = [0, 1];
var expected = [0, 1, 0, 1];
var got = ol.extent.createOrUpdateFromCoordinate(coords);
expect(got).to.eql(expected);
});
it('updates a passed extent', function() {
var extent = ol.extent.createOrUpdate(-4, -7, -3, -6);
var coords = [0, 1];
var expected = [0, 1, 0, 1];
ol.extent.createOrUpdateFromCoordinate(coords, extent);
expect(extent).to.eql(expected);
});
});
describe('createOrUpdateFromCoordinates', function() {
it('works when single coordinate and no extent passed', function() {
var coords = [[0, 1]];
var expected = [0, 1, 0, 1];
var got = ol.extent.createOrUpdateFromCoordinates(coords);
expect(got).to.eql(expected);
});
it('changes the passed extent when single coordinate', function() {
var extent = ol.extent.createOrUpdate(-4, -7, -3, -6);
var coords = [[0, 1]];
var expected = [0, 1, 0, 1];
ol.extent.createOrUpdateFromCoordinates(coords, extent);
expect(extent).to.eql(expected);
});
it('works when multiple coordinates and no extent passed', function() {
var coords = [[0, 1], [2, 3]];
var expected = [0, 1, 2, 3];
var got = ol.extent.createOrUpdateFromCoordinates(coords);
expect(got).to.eql(expected);
});
it('changes the passed extent when multiple coordinates given', function() {
var extent = ol.extent.createOrUpdate(-4, -7, -3, -6);
var coords = [[0, 1], [-2, -1]];
var expected = [-2, -1, 0, 1];
ol.extent.createOrUpdateFromCoordinates(coords, extent);
expect(extent).to.eql(expected);
});
});
describe('createOrUpdateFromRings', function() {
it('works when single ring and no extent passed', function() {
var ring = [[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]];
var rings = [ring];
var expected = [0, 0, 2, 2];
var got = ol.extent.createOrUpdateFromRings(rings);
expect(got).to.eql(expected);
});
it('changes the passed extent when single ring given', function() {
var ring = [[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]];
var rings = [ring];
var extent = [1, 1, 4, 7];
var expected = [0, 0, 2, 2];
ol.extent.createOrUpdateFromRings(rings, extent);
expect(extent).to.eql(expected);
});
it('works when multiple rings and no extent passed', function() {
var ring1 = [[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]];
var ring2 = [[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]];
var rings = [ring1, ring2];
var expected = [0, 0, 3, 3];
var got = ol.extent.createOrUpdateFromRings(rings);
expect(got).to.eql(expected);
});
it('changes the passed extent when multiple rings given', function() {
var ring1 = [[0, 0], [0, 2], [2, 2], [2, 0], [0, 0]];
var ring2 = [[1, 1], [1, 3], [3, 3], [3, 1], [1, 1]];
var rings = [ring1, ring2];
var extent = [1, 1, 4, 7];
var expected = [0, 0, 3, 3];
ol.extent.createOrUpdateFromRings(rings, extent);
expect(extent).to.eql(expected);
});
});
describe('empty', function() {
it('returns the empty extent', function() {
var extent = [1, 2, 3, 4];
var expected = [Infinity, Infinity, -Infinity, -Infinity];
var got = ol.extent.empty(extent);
expect(got).to.eql(expected);
});
it('empties a passed extent in place', function() {
var extent = [1, 2, 3, 4];
var expected = [Infinity, Infinity, -Infinity, -Infinity];
ol.extent.empty(extent);
expect(extent).to.eql(expected);
});
});
describe('forEachCorner', function() {
var callbackFalse;
var callbackTrue;
beforeEach(function() {
callbackFalse = sinon.spy(function() {
return false;
});
callbackTrue = sinon.spy(function() {
return true;
});
});
it('calls the passed callback for each corner', function() {
var extent = [1, 2, 3, 4];
ol.extent.forEachCorner(extent, callbackFalse);
expect(callbackFalse.callCount).to.be(4);
});
it('calls the passed callback with each corner', function() {
var extent = [1, 2, 3, 4];
ol.extent.forEachCorner(extent, callbackFalse);
var firstCallFirstArg = callbackFalse.args[0][0];
var secondCallFirstArg = callbackFalse.args[1][0];
var thirdCallFirstArg = callbackFalse.args[2][0];
var fourthCallFirstArg = callbackFalse.args[3][0];
expect(firstCallFirstArg).to.eql([1, 2]); // bl
expect(secondCallFirstArg).to.eql([3, 2]); // br
expect(thirdCallFirstArg).to.eql([3, 4]); // tr
expect(fourthCallFirstArg).to.eql([1, 4]); // tl
});
it('calls a truthy callback only once', function() {
var extent = [1, 2, 3, 4];
ol.extent.forEachCorner(extent, callbackTrue);
expect(callbackTrue.callCount).to.be(1);
});
it('ensures that any corner can cancel the callback execution', function() {
var extent = [1, 2, 3, 4];
var bottomLeftSpy = sinon.spy(function(corner) {
return (corner[0] === 1 && corner[1] === 2) ? true : false;
});
var bottomRightSpy = sinon.spy(function(corner) {
return (corner[0] === 3 && corner[1] === 2) ? true : false;
});
var topRightSpy = sinon.spy(function(corner) {
return (corner[0] === 3 && corner[1] === 4) ? true : false;
});
var topLeftSpy = sinon.spy(function(corner) {
return (corner[0] === 1 && corner[1] === 4) ? true : false;
});
ol.extent.forEachCorner(extent, bottomLeftSpy);
ol.extent.forEachCorner(extent, bottomRightSpy);
ol.extent.forEachCorner(extent, topRightSpy);
ol.extent.forEachCorner(extent, topLeftSpy);
expect(bottomLeftSpy.callCount).to.be(1);
expect(bottomRightSpy.callCount).to.be(2);
expect(topRightSpy.callCount).to.be(3);
expect(topLeftSpy.callCount).to.be(4);
});
it('returns false eventually, if no invocation returned a truthy value',
function() {
var extent = [1, 2, 3, 4];
var spy = sinon.spy(); // will return undefined for each corner
var got = ol.extent.forEachCorner(extent, spy);
expect(spy.callCount).to.be(4);
expect(got).to.be(false);
}
);
it('calls the callback with given scope', function() {
var extent = [1, 2, 3, 4];
var scope = {humpty: 'dumpty'};
ol.extent.forEachCorner(extent, callbackTrue, scope);
expect(callbackTrue.calledOn(scope)).to.be(true);
});
});
describe('getArea', function() {
it('returns zero for empty extents', function() {
var emptyExtent = ol.extent.createEmpty();
var areaEmpty = ol.extent.getArea(emptyExtent);
expect(areaEmpty).to.be(0);
var extentDeltaXZero = [45, 67, 45, 78];
var areaDeltaXZero = ol.extent.getArea(extentDeltaXZero);
expect(areaDeltaXZero).to.be(0);
var extentDeltaYZero = [11, 67, 45, 67];
var areaDeltaYZero = ol.extent.getArea(extentDeltaYZero);
expect(areaDeltaYZero).to.be(0);
});
it('calculates correct area for other extents', function() {
var extent = [0, 0, 10, 10];
var area = ol.extent.getArea(extent);
expect(area).to.be(100);
});
});
describe('getIntersection()', function() {
it('returns the intersection of two extents', function() {
var world = [-180, -90, 180, 90];
@@ -175,6 +436,12 @@ describe('ol.extent', function() {
expect(center[0]).to.eql(2);
expect(center[1]).to.eql(3);
});
it('returns [NaN, NaN] for empty extents', function() {
var extent = ol.extent.createEmpty();
var center = ol.extent.getCenter(extent);
expect('' + center[0]).to.be('NaN');
expect('' + center[1]).to.be('NaN');
});
});
describe('getCorner', function() {
@@ -200,6 +467,21 @@ describe('ol.extent', function() {
expect(ol.extent.getCorner(extent, corner)).to.eql([3, 4]);
});
it('throws exception for unexpected corner', function() {
expect(function() {
ol.extent.getCorner(extent, 'foobar');
}).to.throwException();
});
});
describe('getEnlargedArea', function() {
it('returns enlarged area of two extents', function() {
var extent1 = [-1, -1, 0, 0];
var extent2 = [0, 0, 1, 1];
var enlargedArea = ol.extent.getEnlargedArea(extent1, extent2);
expect(enlargedArea).to.be(4);
});
});
describe('getForViewAndSize', function() {
@@ -259,6 +541,28 @@ describe('ol.extent', function() {
});
});
describe('getIntersectionArea', function() {
it('returns correct area when extents intersect', function() {
var extent1 = [0, 0, 2, 2];
var extent2 = [1, 1, 3, 3];
var intersectionArea = ol.extent.getIntersectionArea(extent1, extent2);
expect(intersectionArea).to.be(1);
});
it('returns 0 when extents do not intersect', function() {
var extent1 = [0, 0, 1, 1];
var extent2 = [2, 2, 3, 3];
var intersectionArea = ol.extent.getIntersectionArea(extent1, extent2);
expect(intersectionArea).to.be(0);
});
});
describe('getMargin', function() {
it('returns the correct margin (sum of width and height)', function() {
var extent = [1, 2, 3, 4];
expect(ol.extent.getMargin(extent)).to.be(4);
});
});
describe('intersects', function() {
it('returns the expected value', function() {
@@ -294,6 +598,29 @@ describe('ol.extent', function() {
});
});
describe('isInfinite', function() {
it('returns true for infinite extents', function() {
var extents = [
[-Infinity, 0, 0, 0],
[0, -Infinity, 0, 0],
[0, 0, +Infinity, 0],
[0, 0, 0, +Infinity]
];
expect(ol.extent.isInfinite(extents[0])).to.be(true);
expect(ol.extent.isInfinite(extents[1])).to.be(true);
expect(ol.extent.isInfinite(extents[2])).to.be(true);
expect(ol.extent.isInfinite(extents[3])).to.be(true);
});
it('returns false for other extents', function() {
var extents = [
ol.extent.createEmpty(),
[1, 2, 3, 4]
];
expect(ol.extent.isInfinite(extents[0])).to.be(false);
expect(ol.extent.isInfinite(extents[1])).to.be(false);
});
});
describe('touches', function() {
it('returns the expected value', function() {

View File

@@ -369,6 +369,63 @@ describe('ol.format.WKT', function() {
expect(format.writeFeatures(features)).to.eql(wkt);
});
describe('scientific notation supported', function() {
it('handles scientific notation correctly', function() {
var wkt = 'POINT(3e1 1e1)';
var geom = format.readGeometry(wkt);
expect(geom.getCoordinates()).to.eql([30, 10]);
expect(format.writeGeometry(geom)).to.eql('POINT(30 10)');
});
it('works with with negative exponent', function() {
var wkt = 'POINT(3e-1 1e-1)';
var geom = format.readGeometry(wkt);
expect(geom.getCoordinates()).to.eql([0.3, 0.1]);
expect(format.writeGeometry(geom)).to.eql('POINT(0.3 0.1)');
});
it('works with with explicitly positive exponent', function() {
var wkt = 'POINT(3e+1 1e+1)';
var geom = format.readGeometry(wkt);
expect(geom.getCoordinates()).to.eql([30, 10]);
expect(format.writeGeometry(geom)).to.eql('POINT(30 10)');
});
it('handles very small numbers in scientific notation', function() {
// very small numbers keep the scientific notation, both when reading and
// writing
var wkt = 'POINT(3e-9 1e-9)';
var geom = format.readGeometry(wkt);
expect(geom.getCoordinates()).to.eql([3e-9, 1e-9]);
expect(format.writeGeometry(geom)).to.eql('POINT(3e-9 1e-9)');
});
it('handles very big numbers in scientific notation', function() {
// very big numbers keep the scientific notation, both when reading and
// writing
var wkt = 'POINT(3e25 1e25)';
var geom = format.readGeometry(wkt);
expect(geom.getCoordinates()).to.eql([3e25, 1e25]);
expect(format.writeGeometry(geom)).to.eql('POINT(3e+25 1e+25)');
});
it('works case insensitively (e / E)', function() {
var wkt = 'POINT(3E1 1E1)';
var geom = format.readGeometry(wkt);
expect(geom.getCoordinates()).to.eql([30, 10]);
expect(format.writeGeometry(geom)).to.eql('POINT(30 10)');
});
it('detects invalid scientific notation', function() {
expect(function() {
// note the double 'e'
format.readGeometry('POINT(3ee1 10)');
}).to.throwException();
});
});
});
goog.require('ol.Feature');

View File

@@ -203,6 +203,73 @@ describe('ol.geom.Circle', function() {
});
describe('#intersectsExtent', function() {
it('returns false for non-intersecting extents (wide outside own bbox)',
function() {
var wideOutsideLeftTop = [-3, 2, -2, 3];
var wideOutsideRightTop = [2, 2, 3, 3];
var wideOutsideRightBottom = [2, -3, 3, -2];
var wideOutsideLeftBottom = [-3, -3, -2, -2];
expect(circle.intersectsExtent(wideOutsideLeftTop)).to.be(false);
expect(circle.intersectsExtent(wideOutsideRightTop)).to.be(false);
expect(circle.intersectsExtent(wideOutsideRightBottom)).to.be(false);
expect(circle.intersectsExtent(wideOutsideLeftBottom)).to.be(false);
}
);
it('returns false for non-intersecting extents (inside own bbox)',
function() {
var nearOutsideLeftTop = [-1, 0.9, -0.9, 1];
var nearOutsideRightTop = [0.9, 0.9, 1, 1];
var nearOutsideRightBottom = [0.9, -1, 1, -0.9];
var nearOutsideLeftBottom = [-1, -1, -0.9, -0.9];
expect(circle.intersectsExtent(nearOutsideLeftTop)).to.be(false);
expect(circle.intersectsExtent(nearOutsideRightTop)).to.be(false);
expect(circle.intersectsExtent(nearOutsideRightBottom)).to.be(false);
expect(circle.intersectsExtent(nearOutsideLeftBottom)).to.be(false);
}
);
it('returns true for extents that intersect clearly', function() {
var intersectingLeftTop = [-1.5, 0.5, -0.5, 1.5];
var intersectingRightTop = [0.5, 0.5, 1.5, 1.5];
var intersectingRightBottom = [0.5, -1.5, 1.5, -0.5];
var intersectingLeftBottom = [-1.5, -1.5, -0.5, -0.5];
expect(circle.intersectsExtent(intersectingLeftTop)).to.be(true);
expect(circle.intersectsExtent(intersectingRightTop)).to.be(true);
expect(circle.intersectsExtent(intersectingRightBottom)).to.be(true);
expect(circle.intersectsExtent(intersectingLeftBottom)).to.be(true);
});
it('returns true for extents that touch the circumference', function() {
var touchCircumferenceLeft = [-2, 0, -1, 1];
var touchCircumferenceTop = [0, 1, 1, 2];
var touchCircumferenceRight = [1, -1, 2, 0];
var touchCircumferenceBottom = [-1, -2, 0, -1];
expect(circle.intersectsExtent(touchCircumferenceLeft)).to.be(true);
expect(circle.intersectsExtent(touchCircumferenceTop)).to.be(true);
expect(circle.intersectsExtent(touchCircumferenceRight)).to.be(true);
expect(circle.intersectsExtent(touchCircumferenceBottom)).to.be(true);
});
it('returns true for a contained extent', function() {
var containedExtent = [-0.5, -0.5, 0.5, 0.5];
expect(circle.intersectsExtent(containedExtent)).to.be(true);
});
it('returns true for a covering extent', function() {
var bigCoveringExtent = [-5, -5, 5, 5];
expect(circle.intersectsExtent(bigCoveringExtent)).to.be(true);
});
it('returns true for the geom\'s own extent', function() {
var circleExtent = circle.getExtent();
expect(circle.intersectsExtent(circleExtent)).to.be(true);
});
});
});
});

View File

@@ -1,5 +1,6 @@
goog.provide('ol.test.geom.GeometryCollection');
goog.require('ol.extent');
describe('ol.geom.GeometryCollection', function() {
@@ -114,6 +115,35 @@ describe('ol.geom.GeometryCollection', function() {
});
describe('#intersectsExtent()', function() {
beforeEach(function() {
point = new ol.geom.Point([5, 20]);
line = new ol.geom.LineString([[10, 20], [30, 40]]);
poly = new ol.geom.Polygon([outer, inner1, inner2]);
multi = new ol.geom.GeometryCollection([point, line, poly]);
});
it('returns true for intersecting point', function() {
expect(multi.intersectsExtent([5, 20, 5, 20])).to.be(true);
});
it('returns true for intersecting part of lineString', function() {
expect(multi.intersectsExtent([25, 35, 30, 40])).to.be(true);
});
it('returns true for intersecting part of polygon', function() {
expect(multi.intersectsExtent([0, 0, 5, 5])).to.be(true);
});
it('returns false for non-matching extent within own extent', function() {
var extent = [0, 35, 5, 40];
expect(poly.intersectsExtent(extent)).to.be(false);
});
});
describe('#setGeometries', function() {
var line, multi, point, poly;

View File

@@ -73,6 +73,22 @@ describe('ol.geom.LineString', function() {
expect(lineString.getStride()).to.be(2);
});
describe('#intersectsExtent', function() {
it('return false for non matching extent', function() {
expect(lineString.intersectsExtent([1, 3, 1.9, 4])).to.be(false);
});
it('return true for extent on midpoint', function() {
expect(lineString.intersectsExtent([2, 3, 4, 3])).to.be(true);
});
it('returns true for the geom\'s own extent', function() {
expect(lineString.intersectsExtent(lineString.getExtent())).to.be(true);
});
});
});
describe('construct with 3D coordinates', function() {
@@ -102,6 +118,22 @@ describe('ol.geom.LineString', function() {
expect(lineString.getStride()).to.be(3);
});
describe('#intersectsExtent', function() {
it('return false for non matching extent', function() {
expect(lineString.intersectsExtent([1, 3, 1.9, 4])).to.be(false);
});
it('return true for extent on midpoint', function() {
expect(lineString.intersectsExtent([2, 3, 4, 3])).to.be(true);
});
it('returns true for the geom\'s own extent', function() {
expect(lineString.intersectsExtent(lineString.getExtent())).to.be(true);
});
});
});
describe('construct with 3D coordinates and layout XYM', function() {
@@ -132,6 +164,22 @@ describe('ol.geom.LineString', function() {
expect(lineString.getStride()).to.be(3);
});
describe('#intersectsExtent', function() {
it('return false for non matching extent', function() {
expect(lineString.intersectsExtent([1, 3, 1.9, 4])).to.be(false);
});
it('return true for extent on midpoint', function() {
expect(lineString.intersectsExtent([2, 3, 4, 3])).to.be(true);
});
it('returns true for the geom\'s own extent', function() {
expect(lineString.intersectsExtent(lineString.getExtent())).to.be(true);
});
});
});
describe('construct with 4D coordinates', function() {
@@ -161,6 +209,22 @@ describe('ol.geom.LineString', function() {
expect(lineString.getStride()).to.be(4);
});
describe('#intersectsExtent', function() {
it('return false for non matching extent', function() {
expect(lineString.intersectsExtent([1, 3, 1.9, 4])).to.be(false);
});
it('return true for extent on midpoint', function() {
expect(lineString.intersectsExtent([2, 3, 4, 3])).to.be(true);
});
it('returns true for the geom\'s own extent', function() {
expect(lineString.intersectsExtent(lineString.getExtent())).to.be(true);
});
});
});
describe('with a simple line string', function() {

View File

@@ -88,6 +88,18 @@ describe('ol.geom.MultiLineString', function() {
});
describe('#intersectsExtent()', function() {
it('returns true for intersecting part of lineString', function() {
expect(multiLineString.intersectsExtent([1, 2, 2, 3])).to.be(true);
});
it('returns false for non-matching extent within own extent', function() {
expect(multiLineString.intersectsExtent([1, 7, 2, 8])).to.be(false);
});
});
});
describe('construct with 3D coordinates', function() {

View File

@@ -73,6 +73,18 @@ describe('ol.geom.MultiPoint', function() {
expect(multiPoint.getStride()).to.be(2);
});
describe('#intersectsExtent()', function() {
it('returns true for extent covering a point', function() {
expect(multiPoint.intersectsExtent([1, 2, 2, 2])).to.be(true);
});
it('returns false for non-matching extent within own extent', function() {
expect(multiPoint.intersectsExtent([2, 3, 2, 4])).to.be(false);
});
});
});
describe('construct with 3D coordinates', function() {

View File

@@ -115,6 +115,14 @@ describe('ol.geom.MultiPolygon', function() {
});
describe('#getExtent()', function() {
it('returns expected result', function() {
expect(multiPolygon.getExtent()).to.eql([0, 0, 5, 2]);
});
});
describe('#getSimplifiedGeometry', function() {
it('returns the expected result', function() {
@@ -127,6 +135,22 @@ describe('ol.geom.MultiPolygon', function() {
});
});
describe('#intersectsExtent()', function() {
it('returns true for extent of of each polygon', function() {
var polygons = multiPolygon.getPolygons();
for (var i = 0; i < polygons.length; i++) {
expect(multiPolygon.intersectsExtent(
polygons[i].getExtent())).to.be(true);
}
});
it('returns false for non-matching extent within own extent', function() {
expect(multiPolygon.intersectsExtent([2.1, 0, 2.9, 2])).to.be(false);
});
});
});
});

View File

@@ -37,6 +37,14 @@ describe('ol.geom.Point', function() {
expect(point.getStride()).to.be(2);
});
it('does not intersect non matching extent', function() {
expect(point.intersectsExtent([0, 0, 10, 0.5])).to.be(false);
});
it('does intersect it\'s extent', function() {
expect(point.intersectsExtent(point.getExtent())).to.be(true);
});
});
describe('construct with 3D coordinates and layout XYM', function() {
@@ -66,6 +74,14 @@ describe('ol.geom.Point', function() {
expect(point.getStride()).to.be(3);
});
it('does not intersect non matching extent', function() {
expect(point.intersectsExtent([0, 0, 10, 0.5])).to.be(false);
});
it('does intersect it\'s extent', function() {
expect(point.intersectsExtent(point.getExtent())).to.be(true);
});
});
describe('construct with 4D coordinates', function() {
@@ -95,6 +111,14 @@ describe('ol.geom.Point', function() {
expect(point.getStride()).to.be(4);
});
it('does not intersect non matching extent', function() {
expect(point.intersectsExtent([0, 0, 10, 0.5])).to.be(false);
});
it('does intersect it\'s extent', function() {
expect(point.intersectsExtent(point.getExtent())).to.be(true);
});
describe('#getClosestPoint', function() {
it('preseves extra dimensions', function() {

View File

@@ -215,6 +215,33 @@ describe('ol.geom.Polygon', function() {
expect(polygon.containsCoordinate(insideInner)).to.be(false);
});
describe('#intersectsExtent', function() {
it('does not intersect outside extent', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([outsideOuter]))).to.be(false);
});
it('does intersect inside extent', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([inside]))).to.be(true);
});
it('does intersect boundary extent', function() {
var firstMidX = (outerRing[0][0] + outerRing[1][0]) / 2;
var firstMidY = (outerRing[0][1] + outerRing[1][1]) / 2;
expect(polygon.intersectsExtent(ol.extent.boundingExtent([[firstMidX,
firstMidY]]))).to.be(true);
});
it('does not intersect extent fully contained by inner ring', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([insideInner]))).to.be(false);
});
});
describe('#getOrientedFlatCoordinates', function() {
it('reverses the outer ring if necessary', function() {
@@ -287,6 +314,33 @@ describe('ol.geom.Polygon', function() {
expect(polygon.containsCoordinate(insideInner)).to.be(false);
});
describe('#intersectsExtent', function() {
it('does not intersect outside extent', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([outsideOuter]))).to.be(false);
});
it('does intersect inside extent', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([inside]))).to.be(true);
});
it('does intersect boundary extent', function() {
var firstMidX = (outerRing[0][0] + outerRing[1][0]) / 2;
var firstMidY = (outerRing[0][1] + outerRing[1][1]) / 2;
expect(polygon.intersectsExtent(ol.extent.boundingExtent([[firstMidX,
firstMidY]]))).to.be(true);
});
it('does not intersect extent fully contained by inner ring', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([insideInner]))).to.be(false);
});
});
describe('#getOrientedFlatCoordinates', function() {
it('reverses the outer ring if necessary', function() {
@@ -367,6 +421,35 @@ describe('ol.geom.Polygon', function() {
expect(polygon.containsCoordinate(insideInner2)).to.be(false);
});
describe('#intersectsExtent', function() {
it('does not intersect outside extent', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([outsideOuter]))).to.be(false);
});
it('does intersect inside extent', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([inside]))).to.be(true);
});
it('does intersect boundary extent', function() {
var firstMidX = (outerRing[0][0] + outerRing[1][0]) / 2;
var firstMidY = (outerRing[0][1] + outerRing[1][1]) / 2;
expect(polygon.intersectsExtent(ol.extent.boundingExtent([[firstMidX,
firstMidY]]))).to.be(true);
});
it('does not intersect extent fully contained by inner ring', function() {
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([insideInner1]))).to.be(false);
expect(polygon.intersectsExtent(
ol.extent.boundingExtent([insideInner2]))).to.be(false);
});
});
describe('#getOrientedFlatCoordinates', function() {
it('reverses the outer ring if necessary', function() {
@@ -436,10 +519,44 @@ describe('ol.geom.Polygon', function() {
});
});
describe('ol.geom.Polygon.fromCircle', function() {
it('creates a regular polygon', function() {
var circle = new ol.geom.Circle([0, 0, 0], 1, ol.geom.GeometryLayout.XYZ);
var polygon = ol.geom.Polygon.fromCircle(circle);
var coordinates = polygon.getLinearRing(0).getCoordinates();
expect(coordinates[0].length).to.eql(3);
expect(coordinates[0][2]).to.eql(0);
expect(coordinates[32]).to.eql(coordinates[0]);
// east
expect(coordinates[0][0]).to.roughlyEqual(1, 1e-9);
expect(coordinates[0][1]).to.roughlyEqual(0, 1e-9);
// south
expect(coordinates[8][0]).to.roughlyEqual(0, 1e-9);
expect(coordinates[8][1]).to.roughlyEqual(1, 1e-9);
// west
expect(coordinates[16][0]).to.roughlyEqual(-1, 1e-9);
expect(coordinates[16][1]).to.roughlyEqual(0, 1e-9);
// north
expect(coordinates[24][0]).to.roughlyEqual(0, 1e-9);
expect(coordinates[24][1]).to.roughlyEqual(-1, 1e-9);
});
it('creates a regular polygon with custom sides and angle', function() {
var circle = new ol.geom.Circle([0, 0], 1);
var polygon = ol.geom.Polygon.fromCircle(circle, 4, Math.PI / 2);
var coordinates = polygon.getLinearRing(0).getCoordinates();
expect(coordinates[4]).to.eql(coordinates[0]);
expect(coordinates[0][0]).to.roughlyEqual(0, 1e-9);
expect(coordinates[0][1]).to.roughlyEqual(1, 1e-9);
});
});
});
goog.require('ol.extent');
goog.require('ol.geom.Circle');
goog.require('ol.geom.GeometryLayout');
goog.require('ol.geom.LinearRing');
goog.require('ol.geom.Polygon');

View File

@@ -136,8 +136,8 @@ describe('ol.interaction.Draw', function() {
it('triggers draw events', function() {
var ds = sinon.spy();
var de = sinon.spy();
goog.events.listen(draw, ol.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.DrawEventType.DRAWEND, de);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWEND, de);
simulateEvent('pointermove', 10, 20);
simulateEvent('pointerdown', 10, 20);
simulateEvent('pointerup', 10, 20);
@@ -151,11 +151,12 @@ describe('ol.interaction.Draw', function() {
end: 0,
addfeature: 0
};
goog.events.listen(draw, ol.DrawEventType.DRAWEND, function() {
expect(receivedEvents.end).to.be(0);
expect(receivedEvents.addfeature).to.be(0);
++receivedEvents.end;
});
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWEND,
function() {
expect(receivedEvents.end).to.be(0);
expect(receivedEvents.addfeature).to.be(0);
++receivedEvents.end;
});
source.on(ol.source.VectorEventType.ADDFEATURE, function() {
expect(receivedEvents.end).to.be(1);
expect(receivedEvents.addfeature).to.be(0);
@@ -279,8 +280,8 @@ describe('ol.interaction.Draw', function() {
it('triggers draw events', function() {
var ds = sinon.spy();
var de = sinon.spy();
goog.events.listen(draw, ol.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.DrawEventType.DRAWEND, de);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWEND, de);
// first point
simulateEvent('pointermove', 10, 20);
@@ -435,8 +436,8 @@ describe('ol.interaction.Draw', function() {
it('triggers draw events', function() {
var ds = sinon.spy();
var de = sinon.spy();
goog.events.listen(draw, ol.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.DrawEventType.DRAWEND, de);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWEND, de);
// first point
simulateEvent('pointermove', 10, 20);
@@ -573,8 +574,8 @@ describe('ol.interaction.Draw', function() {
it('triggers draw events', function() {
var ds = sinon.spy();
var de = sinon.spy();
goog.events.listen(draw, ol.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.DrawEventType.DRAWEND, de);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWSTART, ds);
goog.events.listen(draw, ol.interaction.DrawEventType.DRAWEND, de);
// first point
simulateEvent('pointermove', 10, 20);
@@ -708,13 +709,42 @@ describe('ol.interaction.Draw', function() {
});
});
describe('ol.interaction.Draw.createRegularPolygon', function() {
it('creates a regular polygon in Circle mode', function() {
var draw = new ol.interaction.Draw({
source: source,
type: ol.geom.GeometryType.CIRCLE,
geometryFunction:
ol.interaction.Draw.createRegularPolygon(4, Math.PI / 4)
});
map.addInteraction(draw);
// first point
simulateEvent('pointermove', 0, 0);
simulateEvent('pointerdown', 0, 0);
simulateEvent('pointerup', 0, 0);
// finish on second point
simulateEvent('pointermove', 20, 20);
simulateEvent('pointerdown', 20, 20);
simulateEvent('pointerup', 20, 20);
var features = source.getFeatures();
var geometry = features[0].getGeometry();
expect(geometry).to.be.a(ol.geom.Polygon);
var coordinates = geometry.getCoordinates();
expect(coordinates[0].length).to.eql(5);
expect(coordinates[0][0][0]).to.roughlyEqual(20, 1e-9);
expect(coordinates[0][0][1]).to.roughlyEqual(20, 1e-9);
});
});
});
goog.require('goog.dispose');
goog.require('goog.events');
goog.require('goog.events.BrowserEvent');
goog.require('goog.style');
goog.require('ol.DrawEventType');
goog.require('ol.Map');
goog.require('ol.MapBrowserPointerEvent');
goog.require('ol.View');
@@ -727,6 +757,7 @@ goog.require('ol.geom.MultiPolygon');
goog.require('ol.geom.Point');
goog.require('ol.geom.Polygon');
goog.require('ol.interaction.Draw');
goog.require('ol.interaction.DrawEventType');
goog.require('ol.interaction.Interaction');
goog.require('ol.layer.Vector');
goog.require('ol.pointer.PointerEvent');

View File

@@ -0,0 +1,78 @@
goog.provide('ol.test.source.TileJSON');
describe('ol.source.TileJSON', function() {
describe('tileUrlFunction', function() {
var source, tileGrid;
beforeEach(function(done) {
var googNetJsonp = goog.net.Jsonp;
// mock goog.net.Jsonp (used in the ol.source.TileJSON constructor)
goog.net.Jsonp = function() {
this.send = function() {
var callback = arguments[1];
var client = new XMLHttpRequest();
client.open('GET', 'spec/ol/data/tilejson.json', true);
client.onload = function() {
callback(JSON.parse(client.responseText));
};
client.send();
};
};
source = new ol.source.TileJSON({
url: 'http://api.tiles.mapbox.com/v3/mapbox.geography-class.jsonp'
});
goog.net.Jsonp = googNetJsonp;
var key = source.on('change', function() {
if (source.getState() === 'ready') {
source.unByKey(key);
tileGrid = source.getTileGrid();
done();
}
});
});
it('uses the correct tile coordinates', function() {
var coordinate = [829330.2064098881, 5933916.615134273];
var regex = /\/([0-9]*\/[0-9]*\/[0-9]*)\.png$/;
var tileUrl;
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 0));
expect(tileUrl.match(regex)[1]).to.eql('0/0/0');
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 1));
expect(tileUrl.match(regex)[1]).to.eql('1/1/0');
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 2));
expect(tileUrl.match(regex)[1]).to.eql('2/2/1');
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 3));
expect(tileUrl.match(regex)[1]).to.eql('3/4/2');
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 4));
expect(tileUrl.match(regex)[1]).to.eql('4/8/5');
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 5));
expect(tileUrl.match(regex)[1]).to.eql('5/16/11');
tileUrl = source.tileUrlFunction(
tileGrid.getTileCoordForCoordAndZ(coordinate, 6));
expect(tileUrl.match(regex)[1]).to.eql('6/33/22');
});
});
});
goog.require('goog.net.Jsonp');
goog.require('ol.source.TileJSON');

View File

@@ -115,22 +115,7 @@ describe('ol.source.Tile', function() {
});
describe('#getWrapXTileCoord()', function() {
it('returns the expected tile coordinate - {wrapX: undefined}', function() {
var tileSource = new ol.source.Tile({
projection: 'EPSG:3857'
});
var tileCoord = tileSource.getWrapXTileCoord([6, -31, 22]);
expect(tileCoord).to.eql([6, -31, 22]);
tileCoord = tileSource.getWrapXTileCoord([6, 33, 22]);
expect(tileCoord).to.eql([6, 33, 22]);
tileCoord = tileSource.getWrapXTileCoord([6, 97, 22]);
expect(tileCoord).to.eql([6, 97, 22]);
});
describe('#getTileCoordForTileUrlFunction()', function() {
it('returns the expected tile coordinate - {wrapX: true}', function() {
var tileSource = new ol.source.Tile({
@@ -138,13 +123,13 @@ describe('ol.source.Tile', function() {
wrapX: true
});
var tileCoord = tileSource.getWrapXTileCoord([6, -31, 22]);
var tileCoord = tileSource.getTileCoordForTileUrlFunction([6, -31, 22]);
expect(tileCoord).to.eql([6, 33, 22]);
tileCoord = tileSource.getWrapXTileCoord([6, 33, 22]);
tileCoord = tileSource.getTileCoordForTileUrlFunction([6, 33, 22]);
expect(tileCoord).to.eql([6, 33, 22]);
tileCoord = tileSource.getWrapXTileCoord([6, 97, 22]);
tileCoord = tileSource.getTileCoordForTileUrlFunction([6, 97, 22]);
expect(tileCoord).to.eql([6, 33, 22]);
});
@@ -154,13 +139,13 @@ describe('ol.source.Tile', function() {
wrapX: false
});
var tileCoord = tileSource.getWrapXTileCoord([6, -31, 22]);
var tileCoord = tileSource.getTileCoordForTileUrlFunction([6, -31, 22]);
expect(tileCoord).to.eql(null);
tileCoord = tileSource.getWrapXTileCoord([6, 33, 22]);
tileCoord = tileSource.getTileCoordForTileUrlFunction([6, 33, 22]);
expect(tileCoord).to.eql([6, 33, 22]);
tileCoord = tileSource.getWrapXTileCoord([6, 97, 22]);
tileCoord = tileSource.getTileCoordForTileUrlFunction([6, 97, 22]);
expect(tileCoord).to.eql(null);
});
});

View File

@@ -0,0 +1,35 @@
goog.provide('ol.test.source.TileVector');
describe('ol.source.TileVector', function() {
describe('#loadFeatures()', function() {
it('calls tileUrlFunction with correct tile coords', function() {
var tileCoords = [];
var source = new ol.source.TileVector({
format: new ol.format.TopoJSON(),
projection: 'EPSG:3857',
tileGrid: ol.tilegrid.createXYZ({
maxZoom: 19
}),
tileUrlFunction: function(tileCoord) {
tileCoords.push(tileCoord.slice());
return null;
}
});
source.loadFeatures(
[-8238854, 4969777, -8237854, 4970777], 4.8, source.getProjection());
expect(tileCoords[0]).to.eql([15, 9647, 12320]);
expect(tileCoords[1]).to.eql([15, 9647, 12319]);
expect(tileCoords[2]).to.eql([15, 9648, 12320]);
expect(tileCoords[3]).to.eql([15, 9648, 12319]);
});
});
});
goog.require('ol.format.TopoJSON');
goog.require('ol.source.TileVector');

View File

@@ -66,15 +66,18 @@ describe('ol.source.XYZ', function() {
it('returns the expected URL', function() {
var projection = xyzTileSource.getProjection();
var tileUrl = xyzTileSource.tileUrlFunction(
xyzTileSource.getWrapXTileCoord([6, -31, -23], projection));
xyzTileSource.getTileCoordForTileUrlFunction(
[6, -31, 41], projection));
expect(tileUrl).to.eql('6/33/22');
tileUrl = xyzTileSource.tileUrlFunction(
xyzTileSource.getWrapXTileCoord([6, 33, -23], projection));
xyzTileSource.getTileCoordForTileUrlFunction(
[6, 33, 41], projection));
expect(tileUrl).to.eql('6/33/22');
tileUrl = xyzTileSource.tileUrlFunction(
xyzTileSource.getWrapXTileCoord([6, 97, -23], projection));
xyzTileSource.getTileCoordForTileUrlFunction(
[6, 97, 41], projection));
expect(tileUrl).to.eql('6/33/22');
});
@@ -83,14 +86,20 @@ describe('ol.source.XYZ', function() {
describe('crop y', function() {
it('returns the expected URL', function() {
var projection = xyzTileSource.getProjection();
var tileUrl = xyzTileSource.tileUrlFunction(
[6, 33, -87]);
xyzTileSource.getTileCoordForTileUrlFunction(
[6, 33, 150], projection));
expect(tileUrl).to.be(undefined);
tileUrl = xyzTileSource.tileUrlFunction([6, 33, -23]);
tileUrl = xyzTileSource.tileUrlFunction(
xyzTileSource.getTileCoordForTileUrlFunction(
[6, 33, 41], projection));
expect(tileUrl).to.eql('6/33/22');
tileUrl = xyzTileSource.tileUrlFunction([6, 33, 41]);
tileUrl = xyzTileSource.tileUrlFunction(
xyzTileSource.getTileCoordForTileUrlFunction(
[6, 33, -23], projection));
expect(tileUrl).to.be(undefined);
});

View File

@@ -46,7 +46,79 @@ describe('ol.TileCoord', function() {
ol.tilecoord.hash(tileCoord2));
});
});
describe('restrictByExtentAndZ', function() {
it('restricts by z', function() {
var tileGrid = new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
tileSize: 10,
resolutions: [2, 1],
minZoom: 1
});
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, 0], tileGrid))
.to.equal(null);
expect(ol.tilecoord.restrictByExtentAndZ([1, 0, 0], tileGrid))
.to.eql([1, 0, 0]);
expect(ol.tilecoord.restrictByExtentAndZ([2, 0, 0], tileGrid))
.to.equal(null);
});
it('restricts by extent when extent defines tile ranges', function() {
var tileGrid = new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
sizes: [[3, 3]],
tileSize: 10,
resolutions: [1]
});
expect(ol.tilecoord.restrictByExtentAndZ([0, 1, 1], tileGrid))
.to.eql([0, 1, 1]);
expect(ol.tilecoord.restrictByExtentAndZ([0, 2, 0], tileGrid))
.to.equal(null);
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, 2], tileGrid))
.to.equal(null);
});
it('restricts by extent when sizes define tile ranges', function() {
var tileGrid = new ol.tilegrid.TileGrid({
origin: [10, 20],
sizes: [[3, 3]],
tileSize: 10,
resolutions: [1]
});
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, 0], tileGrid))
.to.eql([0, 0, 0]);
expect(ol.tilecoord.restrictByExtentAndZ([0, -1, 0], tileGrid))
.to.equal(null);
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, -1], tileGrid))
.to.equal(null);
expect(ol.tilecoord.restrictByExtentAndZ([0, 2, 2], tileGrid))
.to.eql([0, 2, 2]);
expect(ol.tilecoord.restrictByExtentAndZ([0, 3, 0], tileGrid))
.to.equal(null);
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, 3], tileGrid))
.to.equal(null);
});
it('does not restrict by extent with no extent or sizes', function() {
var tileGrid = new ol.tilegrid.TileGrid({
origin: [10, 20],
tileSize: 10,
resolutions: [1]
});
expect(ol.tilecoord.restrictByExtentAndZ([0, Infinity, 0], tileGrid))
.to.eql([0, Infinity, 0]);
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, Infinity], tileGrid))
.to.eql([0, 0, Infinity]);
expect(ol.tilecoord.restrictByExtentAndZ([0, -Infinity, 0], tileGrid))
.to.eql([0, -Infinity, 0]);
expect(ol.tilecoord.restrictByExtentAndZ([0, 0, Infinity], tileGrid))
.to.eql([0, 0, Infinity]);
});
});
});
goog.require('ol.TileCoord');
goog.require('ol.tilecoord');
goog.require('ol.tilegrid.TileGrid');

View File

@@ -150,6 +150,129 @@ describe('ol.tilegrid.TileGrid', function() {
});
});
describe('create with extent exceeding tile ranges', function() {
it('throws an exception', function() {
expect(function() {
return new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
sizes: [[1, 1]],
tileSize: 10,
resolutions: [1]
});
}).to.throwException();
expect(function() {
return new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
origin: [10, 40], // top-left origin
sizes: [[3, 3]], // would have to be [[3, -3]] for this to not throw
tileSize: 10,
resolutions: [1]
});
}).to.throwException();
});
});
describe('create with origin', function() {
var tileGrid;
beforeEach(function() {
tileGrid = new ol.tilegrid.TileGrid({
origin: [10, 20],
tileSize: 10,
resolutions: [1]
});
});
it('returns the configured origin', function() {
expect(tileGrid.getOrigin()).to.eql([10, 20]);
});
it('returns null for an unknown extent', function() {
expect(tileGrid.getExtent()).to.equal(null);
});
it('returns null for an unknown full tile range', function() {
expect(tileGrid.getFullTileRange(0)).to.equal(null);
});
});
describe('create with extent', function() {
var tileGrid;
beforeEach(function() {
tileGrid = new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
tileSize: 10,
resolutions: [1]
});
});
it('assumes bottom left corner of extent as origin', function() {
expect(tileGrid.getOrigin()).to.eql([10, 20]);
});
it('calculates full tile ranges from extent', function() {
var fullTileRange = tileGrid.getFullTileRange(0);
expect(fullTileRange.minX).to.equal(0);
expect(fullTileRange.maxX).to.equal(1);
expect(fullTileRange.minY).to.equal(0);
expect(fullTileRange.maxY).to.equal(1);
});
});
describe('create with extent and sizes', function() {
var tileGrid;
beforeEach(function() {
tileGrid = new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
sizes: [[3, 3]],
tileSize: 10,
resolutions: [1]
});
});
it('returns the configured extent', function() {
expect(tileGrid.getExtent()).to.eql([10, 20, 30, 40]);
});
it('calculates full tile ranges from sizes', function() {
var fullTileRange = tileGrid.getFullTileRange(0);
expect(fullTileRange.minX).to.equal(0);
expect(fullTileRange.maxX).to.equal(2);
expect(fullTileRange.minY).to.equal(0);
expect(fullTileRange.maxY).to.equal(2);
});
});
describe('create with top-left origin and sizes', function() {
var tileGrid;
beforeEach(function() {
tileGrid = new ol.tilegrid.TileGrid({
origin: [10, 40],
sizes: [[3, -3]],
tileSize: 10,
resolutions: [1]
});
});
it('calculates correct minX and maxX for negative heights', function() {
var fullTileRange = tileGrid.getFullTileRange(0);
expect(fullTileRange.minY).to.equal(-3);
expect(fullTileRange.maxY).to.equal(-1);
});
});
describe('create with extent and origin', function() {
it('uses both origin and extent', function() {
var tileGrid = new ol.tilegrid.TileGrid({
origin: [0, 0],
extent: [10, 20, 30, 40],
tileSize: 10,
resolutions: [1]
});
expect(tileGrid.getOrigin()).to.eql([0, 0]);
expect(tileGrid.getExtent()).to.eql([10, 20, 30, 40]);
});
});
describe('createForExtent', function() {
it('allows creation of tile grid from extent', function() {
var extent = ol.extent.createOrUpdate(-100, -100, 100, 100);
@@ -247,6 +370,104 @@ describe('ol.tilegrid.TileGrid', function() {
});
describe('createOriginTopLeftTileCoordTransform', function() {
it('transforms y to -y-1 for top-left origins', function() {
var tileGrid = new ol.tilegrid.TileGrid({
origin: [10, 40],
sizes: [[2, -2], [4, -4]],
resolutions: [1, 0.5],
tileSize: 10
});
var transformFn =
ol.tilegrid.createOriginTopLeftTileCoordTransform(tileGrid);
expect(transformFn([0, 0, -2])).to.eql([0, 0, 1]);
expect(transformFn([0, 0, -1])).to.eql([0, 0, 0]);
expect(transformFn([1, 0, -4])).to.eql([1, 0, 3]);
expect(transformFn([1, 0, -1])).to.eql([1, 0, 0]);
});
it('transforms y to -y-1 when origin corner is not specified', function() {
var tileGrid1 = new ol.tilegrid.TileGrid({
origin: [10, 20],
resolutions: [1, 0.5],
tileSize: 10
});
var tileGrid = new ol.tilegrid.TileGrid({
origin: [10, 40],
resolutions: [1, 0.5],
tileSize: 10
});
var transformFn1 =
ol.tilegrid.createOriginTopLeftTileCoordTransform(tileGrid);
var transformFn2 =
ol.tilegrid.createOriginTopLeftTileCoordTransform(tileGrid1);
expect(transformFn1([0, 0, -2])).to.eql([0, 0, 1]);
expect(transformFn2([0, 0, -2])).to.eql([0, 0, 1]);
expect(transformFn1([0, 0, -1])).to.eql([0, 0, 0]);
expect(transformFn2([0, 0, -1])).to.eql([0, 0, 0]);
expect(transformFn1([1, 0, -4])).to.eql([1, 0, 3]);
expect(transformFn2([1, 0, -4])).to.eql([1, 0, 3]);
expect(transformFn1([1, 0, -1])).to.eql([1, 0, 0]);
expect(transformFn2([1, 0, -1])).to.eql([1, 0, 0]);
});
it('transforms y to height-y-1 for bottom-left origins', function() {
var tileGrid1 = new ol.tilegrid.TileGrid({
extent: [10, 20, 30, 40],
resolutions: [1, 0.5],
tileSize: 10
});
var tileGrid2 = new ol.tilegrid.TileGrid({
origin: [10, 20],
sizes: [[2, 2], [4, 4]],
resolutions: [1, 0.5],
tileSize: 10
});
var transformFn1 =
ol.tilegrid.createOriginTopLeftTileCoordTransform(tileGrid1);
var transformFn2 =
ol.tilegrid.createOriginTopLeftTileCoordTransform(tileGrid2);
expect(tileGrid1.getFullTileRange(0).getHeight()).to.equal(2);
expect(transformFn1([0, 0, 0])).to.eql([0, 0, 1]);
expect(transformFn2([0, 0, 0])).to.eql([0, 0, 1]);
expect(transformFn1([0, 0, 1])).to.eql([0, 0, 0]);
expect(transformFn2([0, 0, 1])).to.eql([0, 0, 0]);
expect(tileGrid1.getFullTileRange(1).getHeight()).to.equal(4);
expect(transformFn1([1, 0, 0])).to.eql([1, 0, 3]);
expect(transformFn2([1, 0, 0])).to.eql([1, 0, 3]);
expect(transformFn1([1, 0, 3])).to.eql([1, 0, 0]);
expect(transformFn2([1, 0, 3])).to.eql([1, 0, 0]);
});
});
describe('createXYZ()', function() {
it('uses defaults', function() {
var tileGrid = ol.tilegrid.createXYZ();
expect(tileGrid.getExtent()).to.eql(
ol.proj.get('EPSG:3857').getExtent());
expect(tileGrid.getMinZoom()).to.equal(0);
expect(tileGrid.getMaxZoom()).to.equal(ol.DEFAULT_MAX_ZOOM);
expect(tileGrid.getTileSize()).to.equal(ol.DEFAULT_TILE_SIZE);
});
it('respects configuration options', function() {
var tileGrid = ol.tilegrid.createXYZ({
extent: [10, 20, 30, 40],
minZoom: 1,
maxZoom: 2,
tileSize: 128
});
expect(tileGrid.getExtent()).to.eql([10, 20, 30, 40]);
expect(tileGrid.getMinZoom()).to.equal(1);
expect(tileGrid.getMaxZoom()).to.equal(2);
expect(tileGrid.getTileSize()).to.equal(128);
});
});
describe('getForProjection', function() {
it('gets the default tile grid for a projection', function() {
@@ -269,7 +490,150 @@ describe('ol.tilegrid.TileGrid', function() {
});
describe('getTileCoordFromCoordAndZ', function() {
describe('#getTileCoordChildTileRange()', function() {
var tileGrid;
beforeEach(function() {
tileGrid = ol.tilegrid.createForExtent(
ol.proj.get('EPSG:3857').getExtent(), 22);
});
it('returns the tile range for one zoom level deeper', function() {
var range;
range = tileGrid.getTileCoordChildTileRange([0, 0, 0]);
expect(range.minX).to.be(0);
expect(range.maxX).to.be(1);
expect(range.minY).to.be(0);
expect(range.maxY).to.be(1);
range = tileGrid.getTileCoordChildTileRange([0, 1, 0]);
expect(range.minX).to.be(2);
expect(range.maxX).to.be(3);
expect(range.minY).to.be(0);
expect(range.maxY).to.be(1);
range = tileGrid.getTileCoordChildTileRange([0, 0, 1]);
expect(range.minX).to.be(0);
expect(range.maxX).to.be(1);
expect(range.minY).to.be(2);
expect(range.maxY).to.be(3);
range = tileGrid.getTileCoordChildTileRange([0, -1, 0]);
expect(range.minX).to.be(-2);
expect(range.maxX).to.be(-1);
expect(range.minY).to.be(0);
expect(range.maxY).to.be(1);
range = tileGrid.getTileCoordChildTileRange([0, 0, -1]);
expect(range.minX).to.be(0);
expect(range.maxX).to.be(1);
expect(range.minY).to.be(-2);
expect(range.maxY).to.be(-1);
});
it('returns null for z > maxZoom', function() {
var max = tileGrid.maxZoom;
var range = tileGrid.getTileCoordChildTileRange([max + 1, 0, 0]);
expect(range).to.be(null);
});
});
describe('#forEachTileCoordParentTileRange()', function() {
var tileGrid;
beforeEach(function() {
tileGrid = ol.tilegrid.createForExtent(
ol.proj.get('EPSG:3857').getExtent(), 22);
});
it('iterates as expected', function() {
var tileCoord = [5, 11, 21];
var zs = [], tileRanges = [];
tileGrid.forEachTileCoordParentTileRange(
tileCoord,
function(z, tileRange) {
zs.push(z);
tileRanges.push(new ol.TileRange(
tileRange.minX, tileRange.maxX,
tileRange.minY, tileRange.maxY));
return false;
});
expect(zs.length).to.eql(5);
expect(tileRanges.length).to.eql(5);
expect(zs[0]).to.eql(4);
expect(tileRanges[0].minX).to.eql(5);
expect(tileRanges[0].maxX).to.eql(5);
expect(tileRanges[0].minY).to.eql(10);
expect(tileRanges[0].maxY).to.eql(10);
expect(zs[1]).to.eql(3);
expect(tileRanges[1].minX).to.eql(2);
expect(tileRanges[1].maxX).to.eql(2);
expect(tileRanges[1].minY).to.eql(5);
expect(tileRanges[1].maxY).to.eql(5);
expect(zs[2]).to.eql(2);
expect(tileRanges[2].minX).to.eql(1);
expect(tileRanges[2].maxX).to.eql(1);
expect(tileRanges[2].minY).to.eql(2);
expect(tileRanges[2].maxY).to.eql(2);
expect(zs[3]).to.eql(1);
expect(tileRanges[3].minX).to.eql(0);
expect(tileRanges[3].maxX).to.eql(0);
expect(tileRanges[3].minY).to.eql(1);
expect(tileRanges[3].maxY).to.eql(1);
expect(zs[4]).to.eql(0);
expect(tileRanges[4].minX).to.eql(0);
expect(tileRanges[4].maxX).to.eql(0);
expect(tileRanges[4].minY).to.eql(0);
expect(tileRanges[4].maxY).to.eql(0);
});
});
describe('getResolution', function() {
var tileGrid;
beforeEach(function() {
tileGrid = ol.tilegrid.createForExtent(
ol.proj.get('EPSG:3857').getExtent(), 22);
});
it('returns the correct resolution at the equator', function() {
// @see http://msdn.microsoft.com/en-us/library/aa940990.aspx
expect(tileGrid.getResolution(0)).to.roughlyEqual(156543.04, 1e-2);
expect(tileGrid.getResolution(1)).to.roughlyEqual(78271.52, 1e-2);
expect(tileGrid.getResolution(2)).to.roughlyEqual(39135.76, 1e-2);
expect(tileGrid.getResolution(3)).to.roughlyEqual(19567.88, 1e-2);
expect(tileGrid.getResolution(4)).to.roughlyEqual(9783.94, 1e-2);
expect(tileGrid.getResolution(5)).to.roughlyEqual(4891.97, 1e-2);
expect(tileGrid.getResolution(6)).to.roughlyEqual(2445.98, 1e-2);
expect(tileGrid.getResolution(7)).to.roughlyEqual(1222.99, 1e-2);
expect(tileGrid.getResolution(8)).to.roughlyEqual(611.50, 1e-2);
expect(tileGrid.getResolution(9)).to.roughlyEqual(305.75, 1e-2);
expect(tileGrid.getResolution(10)).to.roughlyEqual(152.87, 1e-2);
expect(tileGrid.getResolution(11)).to.roughlyEqual(76.44, 1e-2);
expect(tileGrid.getResolution(12)).to.roughlyEqual(38.22, 1e-2);
expect(tileGrid.getResolution(13)).to.roughlyEqual(19.11, 1e-2);
expect(tileGrid.getResolution(14)).to.roughlyEqual(9.55, 1e-2);
expect(tileGrid.getResolution(15)).to.roughlyEqual(4.78, 1e-2);
expect(tileGrid.getResolution(16)).to.roughlyEqual(2.39, 1e-2);
expect(tileGrid.getResolution(17)).to.roughlyEqual(1.19, 1e-2);
expect(tileGrid.getResolution(18)).to.roughlyEqual(0.60, 1e-2);
expect(tileGrid.getResolution(19)).to.roughlyEqual(0.30, 1e-2);
});
});
describe('#getTileCoordFromCoordAndZ()', function() {
describe('Y North, X East', function() {
it('returns the expected TileCoord', function() {
@@ -696,7 +1060,7 @@ describe('ol.tilegrid.TileGrid', function() {
});
});
describe('getZForResolution (approcimate)', function() {
describe('getZForResolution (approximate)', function() {
it('returns the expected z value', function() {
var tileGrid = new ol.tilegrid.TileGrid({
resolutions: resolutions,
@@ -731,4 +1095,5 @@ goog.require('ol.proj');
goog.require('ol.proj.EPSG3857');
goog.require('ol.proj.Projection');
goog.require('ol.proj.Units');
goog.require('ol.TileRange');
goog.require('ol.tilegrid.TileGrid');

View File

@@ -42,27 +42,17 @@ describe('ol.tilegrid.WMTS', function() {
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]
]);
goog.array.repeat([-20037508.3428, 20037508.3428], 20));
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.array.repeat(256, 20));
});
});
});
goog.require('goog.array');
goog.require('ol.format.WMTSCapabilities');
goog.require('ol.tilegrid.WMTS');

View File

@@ -1,168 +0,0 @@
goog.provide('ol.test.tilegrid.XYZ');
describe('ol.tilegrid.XYZ', function() {
var xyzTileGrid;
beforeEach(function() {
xyzTileGrid = new ol.tilegrid.XYZ({
maxZoom: 22
});
});
describe('#getTileCoordChildTileRange()', function() {
it('returns the tile range for one zoom level deeper', function() {
var range;
range = xyzTileGrid.getTileCoordChildTileRange([0, 0, 0]);
expect(range.minX).to.be(0);
expect(range.maxX).to.be(1);
expect(range.minY).to.be(0);
expect(range.maxY).to.be(1);
range = xyzTileGrid.getTileCoordChildTileRange([0, 1, 0]);
expect(range.minX).to.be(2);
expect(range.maxX).to.be(3);
expect(range.minY).to.be(0);
expect(range.maxY).to.be(1);
range = xyzTileGrid.getTileCoordChildTileRange([0, 0, 1]);
expect(range.minX).to.be(0);
expect(range.maxX).to.be(1);
expect(range.minY).to.be(2);
expect(range.maxY).to.be(3);
range = xyzTileGrid.getTileCoordChildTileRange([0, -1, 0]);
expect(range.minX).to.be(-2);
expect(range.maxX).to.be(-1);
expect(range.minY).to.be(0);
expect(range.maxY).to.be(1);
range = xyzTileGrid.getTileCoordChildTileRange([0, 0, -1]);
expect(range.minX).to.be(0);
expect(range.maxX).to.be(1);
expect(range.minY).to.be(-2);
expect(range.maxY).to.be(-1);
});
it('returns null for z > maxZoom', function() {
var max = xyzTileGrid.maxZoom;
var range = xyzTileGrid.getTileCoordChildTileRange([max + 1, 0, 0]);
expect(range).to.be(null);
});
it('is like ol.tilegrid.TileGrid#getTileCoordChildTileRange()', function() {
var superMethod = ol.tilegrid.TileGrid.prototype
.getTileCoordChildTileRange.bind(xyzTileGrid);
var coord, selfRange, superRange;
coord = [0, 0, 0];
selfRange = xyzTileGrid.getTileCoordChildTileRange(coord);
superRange = superMethod(coord);
expect(selfRange.minX).to.be(superRange.minX);
expect(selfRange.maxX).to.be(superRange.maxX);
expect(selfRange.minY).to.be(superRange.minY);
expect(selfRange.maxY).to.be(superRange.maxY);
coord = [1, 2, 3];
selfRange = xyzTileGrid.getTileCoordChildTileRange(coord);
superRange = superMethod(coord);
expect(selfRange.minX).to.be(superRange.minX);
expect(selfRange.maxX).to.be(superRange.maxX);
expect(selfRange.minY).to.be(superRange.minY);
expect(selfRange.maxY).to.be(superRange.maxY);
});
});
describe('forEachTileCoordParentTileRange', function() {
it('iterates as expected', function() {
var tileCoord = [5, 11, 21];
var zs = [], tileRanges = [];
xyzTileGrid.forEachTileCoordParentTileRange(
tileCoord,
function(z, tileRange) {
zs.push(z);
tileRanges.push(new ol.TileRange(
tileRange.minX, tileRange.maxX,
tileRange.minY, tileRange.maxY));
return false;
});
expect(zs.length).to.eql(5);
expect(tileRanges.length).to.eql(5);
expect(zs[0]).to.eql(4);
expect(tileRanges[0].minX).to.eql(5);
expect(tileRanges[0].maxX).to.eql(5);
expect(tileRanges[0].minY).to.eql(10);
expect(tileRanges[0].maxY).to.eql(10);
expect(zs[1]).to.eql(3);
expect(tileRanges[1].minX).to.eql(2);
expect(tileRanges[1].maxX).to.eql(2);
expect(tileRanges[1].minY).to.eql(5);
expect(tileRanges[1].maxY).to.eql(5);
expect(zs[2]).to.eql(2);
expect(tileRanges[2].minX).to.eql(1);
expect(tileRanges[2].maxX).to.eql(1);
expect(tileRanges[2].minY).to.eql(2);
expect(tileRanges[2].maxY).to.eql(2);
expect(zs[3]).to.eql(1);
expect(tileRanges[3].minX).to.eql(0);
expect(tileRanges[3].maxX).to.eql(0);
expect(tileRanges[3].minY).to.eql(1);
expect(tileRanges[3].maxY).to.eql(1);
expect(zs[4]).to.eql(0);
expect(tileRanges[4].minX).to.eql(0);
expect(tileRanges[4].maxX).to.eql(0);
expect(tileRanges[4].minY).to.eql(0);
expect(tileRanges[4].maxY).to.eql(0);
});
});
describe('getResolution', function() {
it('returns the correct resolution at the equator', function() {
// @see http://msdn.microsoft.com/en-us/library/aa940990.aspx
expect(xyzTileGrid.getResolution(0)).to.roughlyEqual(156543.04, 1e-2);
expect(xyzTileGrid.getResolution(1)).to.roughlyEqual(78271.52, 1e-2);
expect(xyzTileGrid.getResolution(2)).to.roughlyEqual(39135.76, 1e-2);
expect(xyzTileGrid.getResolution(3)).to.roughlyEqual(19567.88, 1e-2);
expect(xyzTileGrid.getResolution(4)).to.roughlyEqual(9783.94, 1e-2);
expect(xyzTileGrid.getResolution(5)).to.roughlyEqual(4891.97, 1e-2);
expect(xyzTileGrid.getResolution(6)).to.roughlyEqual(2445.98, 1e-2);
expect(xyzTileGrid.getResolution(7)).to.roughlyEqual(1222.99, 1e-2);
expect(xyzTileGrid.getResolution(8)).to.roughlyEqual(611.50, 1e-2);
expect(xyzTileGrid.getResolution(9)).to.roughlyEqual(305.75, 1e-2);
expect(xyzTileGrid.getResolution(10)).to.roughlyEqual(152.87, 1e-2);
expect(xyzTileGrid.getResolution(11)).to.roughlyEqual(76.44, 1e-2);
expect(xyzTileGrid.getResolution(12)).to.roughlyEqual(38.22, 1e-2);
expect(xyzTileGrid.getResolution(13)).to.roughlyEqual(19.11, 1e-2);
expect(xyzTileGrid.getResolution(14)).to.roughlyEqual(9.55, 1e-2);
expect(xyzTileGrid.getResolution(15)).to.roughlyEqual(4.78, 1e-2);
expect(xyzTileGrid.getResolution(16)).to.roughlyEqual(2.39, 1e-2);
expect(xyzTileGrid.getResolution(17)).to.roughlyEqual(1.19, 1e-2);
expect(xyzTileGrid.getResolution(18)).to.roughlyEqual(0.60, 1e-2);
expect(xyzTileGrid.getResolution(19)).to.roughlyEqual(0.30, 1e-2);
});
});
});
goog.require('ol.TileCoord');
goog.require('ol.TileRange');
goog.require('ol.tilegrid.TileGrid');
goog.require('ol.tilegrid.XYZ');

View File

@@ -55,8 +55,8 @@ describe('ol.rendering.layer.Image', function() {
beforeEach(function() {
source = new ol.source.ImageStatic({
url: 'spec/ol/data/tiles/osm/5/5/12.png',
imageExtent: new ol.tilegrid.XYZ({}).getTileCoordExtent(
[5, 5, -12 - 1]),
imageExtent: ol.tilegrid.createXYZ().getTileCoordExtent(
[5, 5, 32 - 12 - 1]),
projection: ol.proj.get('EPSG:3857')
});
});
@@ -91,4 +91,3 @@ goog.require('ol.Map');
goog.require('ol.View');
goog.require('ol.layer.Image');
goog.require('ol.source.ImageStatic');
goog.require('ol.tilegrid.XYZ');