Merge branch 'master' into patch-4
This commit is contained in:
@@ -2,7 +2,7 @@ version: 2
|
||||
jobs:
|
||||
build:
|
||||
docker:
|
||||
- image: circleci/node:latest-browsers
|
||||
- image: circleci/node:current-browsers
|
||||
|
||||
working_directory: ~/repo
|
||||
|
||||
@@ -11,7 +11,7 @@ jobs:
|
||||
|
||||
- restore_cache:
|
||||
keys:
|
||||
- v1-dependencies-{{ checksum "package.json" }}
|
||||
- v1-dependencies-{{ checksum "package-lock.json" }}
|
||||
- v1-dependencies-
|
||||
|
||||
- run:
|
||||
@@ -21,7 +21,7 @@ jobs:
|
||||
- save_cache:
|
||||
paths:
|
||||
- node_modules
|
||||
key: v1-dependencies-{{ checksum "package.json" }}
|
||||
key: v1-dependencies-{{ checksum "package-lock.json" }}
|
||||
|
||||
- run:
|
||||
name: Run Tests
|
||||
|
||||
24
README.md
24
README.md
@@ -41,30 +41,6 @@ See the following examples for more detail on bundling OpenLayers with your appl
|
||||
* Using [Parcel](https://github.com/openlayers/ol-parcel)
|
||||
* Using [Browserify](https://github.com/openlayers/ol-browserify)
|
||||
|
||||
## IntelliSense support and type checking for VS Code
|
||||
|
||||
The `ol` package contains a `src/` folder with JSDoc annotated sources. TypeScript can get type definitions from these sources with a `jsconfig.json` config file in the project root:
|
||||
```js
|
||||
{
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
// Point to the JSDoc typed sources when using modules from the ol package
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"ol": ["node_modules/ol/src"],
|
||||
"ol/*": ["node_modules/ol/src/*"]
|
||||
}
|
||||
},
|
||||
"include": [
|
||||
"**/*.js",
|
||||
"node_modules/ol/**/*.js"
|
||||
]
|
||||
}
|
||||
```
|
||||
Project template with this configuration: https://gist.github.com/9a7253cb4712e8bf38d75d8ac898e36c.
|
||||
|
||||
Note that the above only works when authoring in plain JavaScript. For similar configurations with a `tsconfig.json` in TypeScript projects, your mileage may vary.
|
||||
|
||||
## Supported Browsers
|
||||
|
||||
OpenLayers runs on all modern browsers that support [HTML5](https://html.spec.whatwg.org/multipage/) and [ECMAScript 5](http://www.ecma-international.org/ecma-262/5.1/). This includes Chrome, Firefox, Safari and Edge. For older browsers and platforms like Internet Explorer (down to version 9) and Android 4.x, [polyfills](http://polyfill.io) for `requestAnimationFrame` and `Element.prototype.classList` are required, and using the KML format requires a polyfill for `URL`.
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
## Upgrade notes
|
||||
|
||||
### v6.2.0
|
||||
|
||||
### v6.1.0
|
||||
|
||||
### v6.0.0
|
||||
|
||||
#### Backwards incompatible changes
|
||||
@@ -77,7 +81,7 @@ Generally, the responsibility of applying center/rotation/resolutions constraint
|
||||
|
||||
##### The view `extent` option now applies to the whole viewport
|
||||
|
||||
Previously, this options only constrained the view *center*. This behaviour can still be obtained by specifying `constrainCenterOnly` in the view options.
|
||||
Previously, this options only constrained the view *center*. This behaviour can still be obtained by specifying `constrainOnlyCenter` in the view options.
|
||||
|
||||
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ Generally, the responsibility of applying center/rotation/resolutions constraint
|
||||
|
||||
##### The view `extent` option now applies to the whole viewport
|
||||
|
||||
Previously, this options only constrained the view *center*. This behaviour can still be obtained by specifying `constrainCenterOnly` in the view options.
|
||||
Previously, this options only constrained the view *center*. This behaviour can still be obtained by specifying `constrainOnlyCenter` in the view options.
|
||||
|
||||
As a side effect, the view `rotate` method is gone and has been replaced with `adjustRotation` which takes a delta as input.
|
||||
|
||||
|
||||
196
changelog/v6.2.0.md
Normal file
196
changelog/v6.2.0.md
Normal file
@@ -0,0 +1,196 @@
|
||||
# 6.2.0
|
||||
|
||||
With almost 90 pull requests, this release brings several new features, performance improvements and bug fixes. In addition to that, we once again improved the API documentation and the example pages.
|
||||
|
||||
## New features and improvements
|
||||
|
||||
* Mousewheel zooming now brings the same user experience as trackpad zooming. One click on the wheel no longer means a jump of a whole zoom level. Instead, depending on the speed of moving the wheel, the user has fine-grained control over zoom increments/decrements.
|
||||
* Users now have better control over the initial map viewport when the aspect ratio of the map is different from a specified initial extent.
|
||||
* Text rendering has been optimized for decluttering and improved for rotated views. This means lower memory footprint and no more blurry text when the map is rotated. **Note:** Whit this change, the label cache has been deprecated.
|
||||
* A new `displacement` option for icon, circle and regular shape styles makes positioning of point symbolizers more flexible.
|
||||
* Several improvements have been made to the KML parser for reading styles, bringing the rendered result much closer to Google Earth.
|
||||
* OpenLayers is now less aggressive on stopping events and preventing event default behavior. This means that users have more control over events, making it easier to use interactive SVGs as layers and to embed maps on scrollable pages.
|
||||
* Vector tile layers now have a `vector` render mode, which brings improved zooming experience for sources with not too much data.
|
||||
* We replaced the previous pointer events polyfill to elm-pep, which should work better in web components.
|
||||
|
||||
## List of all changes
|
||||
|
||||
* [#10613](https://github.com/openlayers/openlayers/pull/10613) - Show KML name labels for Points in MultiGeometry ([@mike-000](https://github.com/mike-000))
|
||||
* [#10632](https://github.com/openlayers/openlayers/pull/10632) - Draw interaction: Append coordinates to polygons and lines (reworked) ([@jahow](https://github.com/jahow))
|
||||
* [#9565](https://github.com/openlayers/openlayers/pull/9565) - Make mousewheel zoom behave like trackpad zoom. ([@dbrnz](https://github.com/dbrnz))
|
||||
* [#10580](https://github.com/openlayers/openlayers/pull/10580) - Fix KML Polystyle outline 0 conflict with Linestyle for linestrings ([@mike-000](https://github.com/mike-000))
|
||||
* [#10612](https://github.com/openlayers/openlayers/pull/10612) - Make examples work in Internet Explorer ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10587](https://github.com/openlayers/openlayers/pull/10587) - Adds option to View for using larger resolution value when clamping #10586 ([@jeremy-smith-maco](https://github.com/jeremy-smith-maco))
|
||||
* [#10607](https://github.com/openlayers/openlayers/pull/10607) - Update elm-pep to fix builds for IE < 11 ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10598](https://github.com/openlayers/openlayers/pull/10598) - Remove inheritDoc to work around JSDoc issue ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10574](https://github.com/openlayers/openlayers/pull/10574) - Text rendering improvements ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10591](https://github.com/openlayers/openlayers/pull/10591) - Remove obsolete license notice ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10588](https://github.com/openlayers/openlayers/pull/10588) - Sort doc navigation properly and add missing modules ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10581](https://github.com/openlayers/openlayers/pull/10581) - Use package-lock.json for the checksum calculation ([@DanielRuf](https://github.com/DanielRuf))
|
||||
* [#10584](https://github.com/openlayers/openlayers/pull/10584) - fixed issue with version throwing an error if it is null ([@MrSoUndso](https://github.com/MrSoUndso))
|
||||
* [#10575](https://github.com/openlayers/openlayers/pull/10575) - Fix ol/layer/Graticule rendercomplete problem ([@mike-000](https://github.com/mike-000))
|
||||
* [#10562](https://github.com/openlayers/openlayers/pull/10562) - Zoomify: Separate the service pixel ratio and the device pixel ratio ([@crubier](https://github.com/crubier))
|
||||
* [#10573](https://github.com/openlayers/openlayers/pull/10573) - Replace Bing layer with MapTiler in example ([@mike-000](https://github.com/mike-000))
|
||||
* [#10570](https://github.com/openlayers/openlayers/pull/10570) - Use correct extent for the vector image ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10572](https://github.com/openlayers/openlayers/pull/10572) - Assert each layer is only added to the map once ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10563](https://github.com/openlayers/openlayers/pull/10563) - More compatible way of exporting a map as pdf ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10545](https://github.com/openlayers/openlayers/pull/10545) - Make KML point feature styles compatible with declutter ([@mike-000](https://github.com/mike-000))
|
||||
* [#10542](https://github.com/openlayers/openlayers/pull/10542) - Replace Bing layer with MapTiler in KML example ([@mike-000](https://github.com/mike-000))
|
||||
* [#10543](https://github.com/openlayers/openlayers/pull/10543) - @api tag must not have a value. ([@MoonE](https://github.com/MoonE))
|
||||
* [#10547](https://github.com/openlayers/openlayers/pull/10547) - Only generate module apidoc pages when it contains api tags ([@MoonE](https://github.com/MoonE))
|
||||
* [#10502](https://github.com/openlayers/openlayers/pull/10502) - Stop events that originate with a removed target ([@walkermatt](https://github.com/walkermatt))
|
||||
* [#10527](https://github.com/openlayers/openlayers/pull/10527) - Remove label cache, render text directly to target canvas ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10534](https://github.com/openlayers/openlayers/pull/10534) - [GeoJSON] Read projection from CRS type EPSG ([@wussup](https://github.com/wussup))
|
||||
* [#10430](https://github.com/openlayers/openlayers/pull/10430) - Offset regular shape ([@Razi91](https://github.com/Razi91))
|
||||
* [#10513](https://github.com/openlayers/openlayers/pull/10513) - fixed flag-name in upgrade notes ([@fgubler](https://github.com/fgubler))
|
||||
* [#10504](https://github.com/openlayers/openlayers/pull/10504) - Fix for reset north when rotation is 360 degrees ([@mike-000](https://github.com/mike-000))
|
||||
* [#10510](https://github.com/openlayers/openlayers/pull/10510) - Remove build/apidoc before running jsdoc again ([@MoonE](https://github.com/MoonE))
|
||||
* [#10498](https://github.com/openlayers/openlayers/pull/10498) - Fixing issue #10497 on behalf of LarryHuang ([@gazza0](https://github.com/gazza0))
|
||||
* [#10496](https://github.com/openlayers/openlayers/pull/10496) - Do not stop events when dragging ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10478](https://github.com/openlayers/openlayers/pull/10478) - Do not abort and dispose of tiles ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10495](https://github.com/openlayers/openlayers/pull/10495) - typo in view.fit ([@danielklim](https://github.com/danielklim))
|
||||
* [#10473](https://github.com/openlayers/openlayers/pull/10473) - Fix for undefined source in Vector layer ([@mike-000](https://github.com/mike-000))
|
||||
* [#10484](https://github.com/openlayers/openlayers/pull/10484) - Use a function to get the value of the gradient ([@fredj](https://github.com/fredj))
|
||||
* [#10262](https://github.com/openlayers/openlayers/pull/10262) - Rework to make Document and XMLSerializer lazy and injectable ([@bjornharrtell](https://github.com/bjornharrtell))
|
||||
* [#10461](https://github.com/openlayers/openlayers/pull/10461) - Fix link in apidocs to ObjectEvent. ([@MoonE](https://github.com/MoonE))
|
||||
* [#10413](https://github.com/openlayers/openlayers/pull/10413) - Limit the ZoomSlider's range to the view's constrained resolution. ([@MoonE](https://github.com/MoonE))
|
||||
* [#10438](https://github.com/openlayers/openlayers/pull/10438) - Avoid accessing the DOM to read the viewport size too often ([@jahow](https://github.com/jahow))
|
||||
* [#10439](https://github.com/openlayers/openlayers/pull/10439) - WebGL points layer / add support for symbol rotation ([@jahow](https://github.com/jahow))
|
||||
* [#10434](https://github.com/openlayers/openlayers/pull/10434) - Disable image smoothing for the DEM source in the Sea Level example ([@mike-000](https://github.com/mike-000))
|
||||
* [#10417](https://github.com/openlayers/openlayers/pull/10417) - Replace Bing layer with MapTiler ([@mike-000](https://github.com/mike-000))
|
||||
* [#10415](https://github.com/openlayers/openlayers/pull/10415) - Control button span element pointer events ([@mike-000](https://github.com/mike-000))
|
||||
* [#10409](https://github.com/openlayers/openlayers/pull/10409) - Improve viewport computation in WebGL Postprocessing ([@jahow](https://github.com/jahow))
|
||||
* [#10119](https://github.com/openlayers/openlayers/pull/10119) - Add crossOrigin option to ol/format/KML for icons ([@mike-000](https://github.com/mike-000))
|
||||
* [#10181](https://github.com/openlayers/openlayers/pull/10181) - add tags to example docs ([@roemhildtg](https://github.com/roemhildtg))
|
||||
* [#10407](https://github.com/openlayers/openlayers/pull/10407) - Use render feature compatible extent check ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10340](https://github.com/openlayers/openlayers/pull/10340) - Draw circles and custom geometry in user coordinates ([@mike-000](https://github.com/mike-000))
|
||||
* [#10393](https://github.com/openlayers/openlayers/pull/10393) - getFeaturesInExtent function for ol/source/VectorTile ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10402](https://github.com/openlayers/openlayers/pull/10402) - Do not preventDefault on pointerdown ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10269](https://github.com/openlayers/openlayers/pull/10269) - Replace the BNG layer source in the Raster Reprojection example ([@mike-000](https://github.com/mike-000))
|
||||
* [#10394](https://github.com/openlayers/openlayers/pull/10394) - Remove map renderer element when disposing ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10391](https://github.com/openlayers/openlayers/pull/10391) - Use box-shadow css instead of filter ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10392](https://github.com/openlayers/openlayers/pull/10392) - Fix interim tile handing for vector tiles ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10380](https://github.com/openlayers/openlayers/pull/10380) - Adjust examples for layer canvas pixel ratio and rotation ([@mike-000](https://github.com/mike-000))
|
||||
* [#10384](https://github.com/openlayers/openlayers/pull/10384) - Include Transform typedef in API ([@mike-000](https://github.com/mike-000))
|
||||
* [#10385](https://github.com/openlayers/openlayers/pull/10385) - Import transpiled rbush ([@walkermatt](https://github.com/walkermatt))
|
||||
* [#10363](https://github.com/openlayers/openlayers/pull/10363) - Interactive SVG layer example ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10120](https://github.com/openlayers/openlayers/pull/10120) - Resolve constraints using anchor if following a cancelled animation ([@mike-000](https://github.com/mike-000))
|
||||
* [#10370](https://github.com/openlayers/openlayers/pull/10370) - Replace Bing layer with MapTiler ([@mike-000](https://github.com/mike-000))
|
||||
* [#10362](https://github.com/openlayers/openlayers/pull/10362) - Remove line that was accidently added with #10332 ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10309](https://github.com/openlayers/openlayers/pull/10309) - Bring back vector render mode for vector tile layers ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10332](https://github.com/openlayers/openlayers/pull/10332) - Conditional default prevention instead of touch-action: none ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10301](https://github.com/openlayers/openlayers/pull/10301) - Create hit detection data per layer and without requestAnimationFrame ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10347](https://github.com/openlayers/openlayers/pull/10347) - Set utfgrid tile as loaded after load instead of empty ([@adube](https://github.com/adube))
|
||||
* [#10344](https://github.com/openlayers/openlayers/pull/10344) - Fix lazy UTFGrid loading ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10321](https://github.com/openlayers/openlayers/pull/10321) - Support touch events for DragBox interaction ([@greggian](https://github.com/greggian))
|
||||
* [#10315](https://github.com/openlayers/openlayers/pull/10315) - Replace Bing sources in some examples ([@mike-000](https://github.com/mike-000))
|
||||
* [#10330](https://github.com/openlayers/openlayers/pull/10330) - Fix modifying circle geometries ([@greggian](https://github.com/greggian))
|
||||
* [#10318](https://github.com/openlayers/openlayers/pull/10318) - Use a minimalist pointer events polyfill ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10322](https://github.com/openlayers/openlayers/pull/10322) - Update tile grid option descriptions ([@mike-000](https://github.com/mike-000))
|
||||
* [#10308](https://github.com/openlayers/openlayers/pull/10308) - Fix feature lookup after removal of alpha ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10310](https://github.com/openlayers/openlayers/pull/10310) - Ensure that OverviewMap respects the initial rotation of attached Maps ([@brianhelba](https://github.com/brianhelba))
|
||||
* [#10302](https://github.com/openlayers/openlayers/pull/10302) - Do not use Math.sign() to support very old browsers ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10295](https://github.com/openlayers/openlayers/pull/10295) - Do not fail when hit detecting features without style ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10293](https://github.com/openlayers/openlayers/pull/10293) - Do not hit detect while tile is loading ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10292](https://github.com/openlayers/openlayers/pull/10292) - Fix typo in jsdoc in ol/source/WMTS ([@jomue](https://github.com/jomue))
|
||||
* [#10291](https://github.com/openlayers/openlayers/pull/10291) - tabindex without focus condition ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10286](https://github.com/openlayers/openlayers/pull/10286) - Use passive option to avoid Chrome warning ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10285](https://github.com/openlayers/openlayers/pull/10285) - Fix WMS GetLegendGraphic example codesandbox error ([@mike-000](https://github.com/mike-000))
|
||||
* [#10283](https://github.com/openlayers/openlayers/pull/10283) - Use the originalEvent in the targetNotEditable condition ([@fredj](https://github.com/fredj))
|
||||
* [#10282](https://github.com/openlayers/openlayers/pull/10282) - Fix documentation of Stroke.lineDash default value ([@jansule](https://github.com/jansule))
|
||||
* [#10259](https://github.com/openlayers/openlayers/pull/10259) - Remove all the sketch features in abortDrawing ([@fredj](https://github.com/fredj))
|
||||
* [#10265](https://github.com/openlayers/openlayers/pull/10265) - Update operators doc in WebGL points layer example ([@fredj](https://github.com/fredj))
|
||||
* [#10256](https://github.com/openlayers/openlayers/pull/10256) - Do not bypass measureTextWidth ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10264](https://github.com/openlayers/openlayers/pull/10264) - Remove unused variable from vertex shader ([@fredj](https://github.com/fredj))
|
||||
* [#10257](https://github.com/openlayers/openlayers/pull/10257) - Allow View.adjust* methods to take a null opt_anchor ([@brianhelba](https://github.com/brianhelba))
|
||||
* [#10261](https://github.com/openlayers/openlayers/pull/10261) - WebGL / do not throw error when shader compilation gives a warning ([@jahow](https://github.com/jahow))
|
||||
* [#10255](https://github.com/openlayers/openlayers/pull/10255) - Don't use instanceof HTMLElement in handleMapBrowserEvent ([@fredj](https://github.com/fredj))
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Dependency Updates</summary>
|
||||
|
||||
* [#10629](https://github.com/openlayers/openlayers/pull/10629) - Bump ol-mapbox-style from 6.0.0 to 6.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10628](https://github.com/openlayers/openlayers/pull/10628) - Bump puppeteer from 2.1.0 to 2.1.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10627](https://github.com/openlayers/openlayers/pull/10627) - Bump handlebars from 4.7.2 to 4.7.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10626](https://github.com/openlayers/openlayers/pull/10626) - Bump webpack-dev-server from 3.10.2 to 3.10.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10600](https://github.com/openlayers/openlayers/pull/10600) - Bump puppeteer from 2.0.0 to 2.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10606](https://github.com/openlayers/openlayers/pull/10606) - Bump @babel/core from 7.8.3 to 7.8.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10605](https://github.com/openlayers/openlayers/pull/10605) - Bump webpack-dev-server from 3.10.1 to 3.10.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10604](https://github.com/openlayers/openlayers/pull/10604) - Bump rollup from 1.29.1 to 1.31.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10603](https://github.com/openlayers/openlayers/pull/10603) - Bump @babel/preset-env from 7.8.3 to 7.8.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10602](https://github.com/openlayers/openlayers/pull/10602) - Bump url-polyfill from 1.1.7 to 1.1.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10601](https://github.com/openlayers/openlayers/pull/10601) - Bump terser-webpack-plugin from 2.3.2 to 2.3.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10578](https://github.com/openlayers/openlayers/pull/10578) - Bump sinon from 8.1.0 to 8.1.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10577](https://github.com/openlayers/openlayers/pull/10577) - Bump mocha from 7.0.0 to 7.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10576](https://github.com/openlayers/openlayers/pull/10576) - Bump rollup from 1.29.0 to 1.29.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10551](https://github.com/openlayers/openlayers/pull/10551) - Bump handlebars from 4.7.1 to 4.7.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10550](https://github.com/openlayers/openlayers/pull/10550) - Bump @babel/preset-env from 7.8.2 to 7.8.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10549](https://github.com/openlayers/openlayers/pull/10549) - Bump sinon from 8.0.4 to 8.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10548](https://github.com/openlayers/openlayers/pull/10548) - Bump @babel/core from 7.8.0 to 7.8.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10518](https://github.com/openlayers/openlayers/pull/10518) - Bump front-matter from 3.0.2 to 3.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10516](https://github.com/openlayers/openlayers/pull/10516) - Bump handlebars from 4.5.3 to 4.7.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10514](https://github.com/openlayers/openlayers/pull/10514) - Bump terser-webpack-plugin from 2.3.1 to 2.3.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10523](https://github.com/openlayers/openlayers/pull/10523) - Bump sinon from 8.0.2 to 8.0.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10515](https://github.com/openlayers/openlayers/pull/10515) - Bump @babel/preset-env from 7.7.7 to 7.8.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10517](https://github.com/openlayers/openlayers/pull/10517) - Bump karma-firefox-launcher from 1.2.0 to 1.3.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10519](https://github.com/openlayers/openlayers/pull/10519) - Bump @babel/core from 7.7.7 to 7.8.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10520](https://github.com/openlayers/openlayers/pull/10520) - Bump globby from 10.0.1 to 11.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10521](https://github.com/openlayers/openlayers/pull/10521) - Bump rollup-plugin-terser from 5.1.3 to 5.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10522](https://github.com/openlayers/openlayers/pull/10522) - Bump rollup from 1.28.0 to 1.29.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10480](https://github.com/openlayers/openlayers/pull/10480) - Bump mocha from 6.2.2 to 7.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10482](https://github.com/openlayers/openlayers/pull/10482) - Bump sinon from 8.0.1 to 8.0.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10481](https://github.com/openlayers/openlayers/pull/10481) - Bump yargs from 15.0.2 to 15.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10479](https://github.com/openlayers/openlayers/pull/10479) - Bump rollup from 1.27.14 to 1.28.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10466](https://github.com/openlayers/openlayers/pull/10466) - Bump webpack from 4.41.4 to 4.41.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10467](https://github.com/openlayers/openlayers/pull/10467) - Bump sinon from 8.0.0 to 8.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10450](https://github.com/openlayers/openlayers/pull/10450) - Bump @babel/core from 7.7.5 to 7.7.7 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10449](https://github.com/openlayers/openlayers/pull/10449) - Bump eslint from 6.7.2 to 6.8.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10448](https://github.com/openlayers/openlayers/pull/10448) - Bump rollup from 1.27.13 to 1.27.14 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10447](https://github.com/openlayers/openlayers/pull/10447) - Bump @babel/preset-env from 7.7.6 to 7.7.7 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10446](https://github.com/openlayers/openlayers/pull/10446) - Bump sinon from 7.5.0 to 8.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10445](https://github.com/openlayers/openlayers/pull/10445) - Bump webpack from 4.41.2 to 4.41.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10444](https://github.com/openlayers/openlayers/pull/10444) - Bump terser-webpack-plugin from 2.3.0 to 2.3.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10443](https://github.com/openlayers/openlayers/pull/10443) - Bump webpack-dev-server from 3.9.0 to 3.10.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10425](https://github.com/openlayers/openlayers/pull/10425) - Bump elm-pep from 1.0.2 to 1.0.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10427](https://github.com/openlayers/openlayers/pull/10427) - Bump webpack-cli from 3.3.2 to 3.3.10 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10426](https://github.com/openlayers/openlayers/pull/10426) - Bump copy-webpack-plugin from 5.0.5 to 5.1.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10424](https://github.com/openlayers/openlayers/pull/10424) - Bump eslint from 6.7.1 to 6.7.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10423](https://github.com/openlayers/openlayers/pull/10423) - Bump marked from 0.7.0 to 0.8.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10422](https://github.com/openlayers/openlayers/pull/10422) - Bump url-polyfill from 1.1.5 to 1.1.7 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10421](https://github.com/openlayers/openlayers/pull/10421) - Bump rollup-plugin-terser from 5.1.2 to 5.1.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10420](https://github.com/openlayers/openlayers/pull/10420) - Bump terser-webpack-plugin from 2.2.2 to 2.3.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10419](https://github.com/openlayers/openlayers/pull/10419) - Bump rollup from 1.27.9 to 1.27.13 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10418](https://github.com/openlayers/openlayers/pull/10418) - Bump babel-loader from 8.0.5 to 8.0.6 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10399](https://github.com/openlayers/openlayers/pull/10399) - Bump rollup from 1.25.1 to 1.27.9 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10398](https://github.com/openlayers/openlayers/pull/10398) - Bump terser-webpack-plugin from 2.2.1 to 2.2.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10397](https://github.com/openlayers/openlayers/pull/10397) - Bump @babel/core from 7.7.4 to 7.7.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10396](https://github.com/openlayers/openlayers/pull/10396) - Bump @babel/preset-env from 7.7.4 to 7.7.6 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10365](https://github.com/openlayers/openlayers/pull/10365) - Bump @babel/preset-env from 7.6.3 to 7.7.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10366](https://github.com/openlayers/openlayers/pull/10366) - Bump karma-coverage-istanbul-reporter from 2.1.0 to 2.1.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10367](https://github.com/openlayers/openlayers/pull/10367) - Bump coveralls from 3.0.7 to 3.0.9 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10368](https://github.com/openlayers/openlayers/pull/10368) - Bump sinon from 7.3.2 to 7.5.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10369](https://github.com/openlayers/openlayers/pull/10369) - Bump @babel/core from 7.7.2 to 7.7.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10337](https://github.com/openlayers/openlayers/pull/10337) - Bump fs-extra from 8.0.1 to 8.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10336](https://github.com/openlayers/openlayers/pull/10336) - Bump eslint from 6.6.0 to 6.7.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10335](https://github.com/openlayers/openlayers/pull/10335) - Bump yargs from 14.2.0 to 15.0.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10334](https://github.com/openlayers/openlayers/pull/10334) - Bump webpack-dev-middleware from 3.6.2 to 3.7.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10333](https://github.com/openlayers/openlayers/pull/10333) - Bump copy-webpack-plugin from 5.0.4 to 5.0.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10306](https://github.com/openlayers/openlayers/pull/10306) - Bump puppeteer from 1.20.0 to 2.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10307](https://github.com/openlayers/openlayers/pull/10307) - Bump @babel/core from 7.6.4 to 7.7.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10305](https://github.com/openlayers/openlayers/pull/10305) - Bump proj4 from 2.5.0 to 2.6.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10304](https://github.com/openlayers/openlayers/pull/10304) - Bump handlebars from 4.4.5 to 4.5.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10303](https://github.com/openlayers/openlayers/pull/10303) - Bump glob from 7.1.5 to 7.1.6 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10280](https://github.com/openlayers/openlayers/pull/10280) - Bump rollup-plugin-commonjs from 10.0.0 to 10.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10279](https://github.com/openlayers/openlayers/pull/10279) - Bump rollup-plugin-terser from 5.0.0 to 5.1.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10278](https://github.com/openlayers/openlayers/pull/10278) - Bump eslint from 6.0.0 to 6.6.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10277](https://github.com/openlayers/openlayers/pull/10277) - Bump karma-webpack from 4.0.0-rc.6 to 4.0.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10276](https://github.com/openlayers/openlayers/pull/10276) - Bump webpack-dev-server from 3.3.1 to 3.9.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10251](https://github.com/openlayers/openlayers/pull/10251) - Bump @babel/preset-env from 7.4.4 to 7.6.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10250](https://github.com/openlayers/openlayers/pull/10250) - Bump buble from 0.19.7 to 0.19.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10249](https://github.com/openlayers/openlayers/pull/10249) - Bump karma-firefox-launcher from 1.1.0 to 1.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10248](https://github.com/openlayers/openlayers/pull/10248) - Bump html-to-image from 0.1.0 to 0.1.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10247](https://github.com/openlayers/openlayers/pull/10247) - Bump terser-webpack-plugin from 2.0.1 to 2.2.1 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
</details>
|
||||
13
changelog/v6.2.1.md
Normal file
13
changelog/v6.2.1.md
Normal file
@@ -0,0 +1,13 @@
|
||||
# 6.2.1
|
||||
|
||||
This is a bugfix release which resolves bundler issues due to a circular dependency, and brings a few documentation and example fixes.
|
||||
|
||||
## List of all changes
|
||||
|
||||
* [#10656](https://github.com/openlayers/openlayers/pull/10656) - Fix for export PDF example compatibility issues, and layer opacity handling. ([@mike-000](https://github.com/mike-000))
|
||||
* [#10653](https://github.com/openlayers/openlayers/pull/10653) - More reliable check for module content beyond classes ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10617](https://github.com/openlayers/openlayers/pull/10617) - Improve apidoc generation performance ([@MoonE](https://github.com/MoonE))
|
||||
* [#10625](https://github.com/openlayers/openlayers/pull/10625) - Apidoc cleanup navigation html ([@MoonE](https://github.com/MoonE))
|
||||
* [#10649](https://github.com/openlayers/openlayers/pull/10649) - Remove circular dependency ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10637](https://github.com/openlayers/openlayers/pull/10637) - Develop on 6.2.1 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
@@ -34,7 +34,7 @@ Interactions for <a href="module-ol_Feature-Feature.html">vector features</a>
|
||||
<tr><th>Projections</th><th>Observable objects</th><th>Other components</th></tr>
|
||||
<tr><td><p>All coordinates and extents need to be provided in view projection (default: EPSG:3857). To transform, use <a href="module-ol_proj.html#.transform">ol/proj#transform()</a> and <a href="module-ol_proj.html#.transformExtent">ol/proj#transformExtent()</a>.</p>
|
||||
<a href="module-ol_proj.html">ol/proj</a></td>
|
||||
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
|
||||
<td><p>Changes to all <a href="module-ol_Object-BaseObject.html">ol/Object</a>s can be observed by calling the <a href="module-ol_Object-BaseObject.html#on">object.on('propertychange')</a> method. Listeners receive an <a href="module-ol_Object.ObjectEvent.html">ol/Object.ObjectEvent</a> with information on the changed property and old value.</p>
|
||||
<td>
|
||||
<a href="module-ol_Geolocation.html">ol/Geolocation</a><br>
|
||||
<a href="module-ol_Overlay-Overlay.html">ol/Overlay</a><br></td>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*/
|
||||
exports.defineTags = function(dictionary) {
|
||||
dictionary.defineTag('api', {
|
||||
mustHaveValue: false,
|
||||
mustNotHaveValue: true,
|
||||
canHaveType: false,
|
||||
canHaveName: false,
|
||||
onTagged: function(doclet, tag) {
|
||||
@@ -21,15 +21,11 @@ exports.defineTags = function(dictionary) {
|
||||
* from the documentation.
|
||||
*/
|
||||
|
||||
const api = [];
|
||||
const api = {};
|
||||
const classes = {};
|
||||
const types = {};
|
||||
const modules = {};
|
||||
|
||||
function hasApiMembers(doclet) {
|
||||
return doclet.longname.split('#')[0] == this.longname;
|
||||
}
|
||||
|
||||
function includeAugments(doclet) {
|
||||
// Make sure that `observables` and `fires` are taken from an already processed `class` doclet.
|
||||
// This is necessary because JSDoc generates multiple doclets with the same longname.
|
||||
@@ -116,10 +112,9 @@ exports.handlers = {
|
||||
const doclet = e.doclet;
|
||||
if (doclet.stability) {
|
||||
modules[doclet.longname.split(/[~\.]/).shift()] = true;
|
||||
api.push(doclet);
|
||||
api[doclet.longname.split('#')[0]] = true;
|
||||
}
|
||||
if (doclet.kind == 'class') {
|
||||
modules[doclet.longname.split(/[~\.]/).shift()] = true;
|
||||
if (!(doclet.longname in classes)) {
|
||||
classes[doclet.longname] = doclet;
|
||||
} else if ('augments' in doclet) {
|
||||
@@ -160,7 +155,7 @@ exports.handlers = {
|
||||
if (doclet.isEnum || doclet.kind == 'typedef') {
|
||||
continue;
|
||||
}
|
||||
if (doclet.kind == 'class' && api.some(hasApiMembers, doclet)) {
|
||||
if (doclet.kind == 'class' && doclet.longname in api) {
|
||||
// Mark undocumented classes with documented members as unexported.
|
||||
// This is used in ../template/tmpl/container.tmpl to hide the
|
||||
// constructor from the docs.
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
exports.defineTags = function(dictionary) {
|
||||
dictionary.defineTag('inheritDoc', {
|
||||
mustHaveValue: false,
|
||||
mustNotHaveValue: true,
|
||||
canHaveType: false,
|
||||
canHaveName: false,
|
||||
onTagged: function(doclet, tag) {
|
||||
@@ -42,15 +42,15 @@ exports.handlers = {
|
||||
|
||||
parseComplete: function(e) {
|
||||
let ancestors, candidate, candidates, doclet, i, j, k, l, key;
|
||||
let incompleteDoclet, stability, incomplete, incompletes;
|
||||
let stability, incomplete, incompletes;
|
||||
const doclets = e.doclets;
|
||||
for (i = doclets.length - 1; i >= 0; --i) {
|
||||
doclet = doclets[i];
|
||||
if (doclet.augments) {
|
||||
ancestors = [].concat(doclet.augments);
|
||||
}
|
||||
incompletes = incompleteByClass[doclet.longname];
|
||||
if (ancestors && incompletes) {
|
||||
if (!doclet.augments || !incompletes) {
|
||||
continue;
|
||||
}
|
||||
ancestors = doclet.augments.slice();
|
||||
// collect ancestors from the whole hierarchy
|
||||
for (j = 0; j < ancestors.length; ++j) {
|
||||
candidates = lookup[ancestors[j]];
|
||||
@@ -58,12 +58,13 @@ exports.handlers = {
|
||||
for (k = candidates.length - 1; k >= 0; --k) {
|
||||
candidate = candidates[k];
|
||||
if (candidate.augments) {
|
||||
ancestors = ancestors.concat(candidate.augments);
|
||||
Array.prototype.push.apply(ancestors, candidate.augments);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// walk through all inheritDoc members
|
||||
let incompleteDoclet;
|
||||
for (j = incompletes.length - 1; j >= 0; --j) {
|
||||
incomplete = incompletes[j];
|
||||
candidates = lookup[doclet.longname + '#' + incomplete];
|
||||
@@ -105,6 +106,5 @@ exports.handlers = {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@@ -188,6 +188,12 @@ function attachModuleSymbols(doclets, modules) {
|
||||
});
|
||||
}
|
||||
|
||||
function getPrettyName(longname) {
|
||||
return longname
|
||||
.split('~')[0]
|
||||
.replace('module:', '');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the navigation sidebar.
|
||||
* @param {object} members The members that will be used to create the sidebar.
|
||||
@@ -206,10 +212,12 @@ function buildNav(members) {
|
||||
// merge namespaces and classes, then sort
|
||||
const merged = members.modules.concat(members.classes);
|
||||
merged.sort(function(a, b) {
|
||||
if (a.longname > b.longname) {
|
||||
const prettyNameA = getPrettyName(a.longname).toLowerCase();
|
||||
const prettyNameB = getPrettyName(b.longname).toLowerCase();
|
||||
if (prettyNameA > prettyNameB) {
|
||||
return 1;
|
||||
}
|
||||
if (a.longname < b.longname) {
|
||||
if (prettyNameA < prettyNameB) {
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
@@ -221,9 +229,7 @@ function buildNav(members) {
|
||||
nav.push({
|
||||
type: 'class',
|
||||
longname: v.longname,
|
||||
prettyname: v.longname
|
||||
.split('~')[0]
|
||||
.replace('module:', ''),
|
||||
prettyname: getPrettyName(v.longname),
|
||||
name: v.name,
|
||||
module: find({
|
||||
kind: 'module',
|
||||
@@ -268,14 +274,13 @@ function buildNav(members) {
|
||||
kind: 'event',
|
||||
memberof: v.longname
|
||||
});
|
||||
// only add modules that have more to show than just a single class
|
||||
if (classes.length !== 1 && (classes.length + members.length + methods.length + typedefs.length + events.length > 0)) {
|
||||
// Only add modules that contain more than just classes with their
|
||||
// associated Options typedef
|
||||
if (typedefs.length > classes.length || members.length + methods.length > 0) {
|
||||
nav.push({
|
||||
type: 'module',
|
||||
longname: v.longname,
|
||||
prettyname: v.longname
|
||||
.split('~')[0]
|
||||
.replace('module:', ''),
|
||||
prettyname: getPrettyName(v.longname),
|
||||
name: v.name,
|
||||
members: members,
|
||||
methods: methods,
|
||||
@@ -472,6 +477,7 @@ exports.publish = function(taffyData, opts, tutorials) {
|
||||
// index page displays information from package.json and lists files
|
||||
const files = find({kind: 'file'});
|
||||
|
||||
view.navigationHtml = helper.resolveLinks(view.partial('navigation.tmpl'));
|
||||
generate('Index',
|
||||
[{kind: 'mainpage', readme: opts.readme, longname: (opts.mainpagetitle) ? opts.mainpagetitle : 'Main Page'}].concat(files),
|
||||
indexUrl);
|
||||
|
||||
@@ -33,7 +33,7 @@ $(function () {
|
||||
|
||||
if (value && value.length > 1) {
|
||||
var regexp = new RegExp(value, 'i');
|
||||
$el.find('li, .itemMembers').hide();
|
||||
$el.find('li, .member-list').hide();
|
||||
|
||||
$el.find('li').each(function (i, v) {
|
||||
const $item = $(v);
|
||||
@@ -41,7 +41,7 @@ $(function () {
|
||||
|
||||
if (name && regexp.test(name)) {
|
||||
const $classEntry = $item.closest('.item');
|
||||
const $members = $item.closest('.itemMembers');
|
||||
const $members = $item.closest('.member-list');
|
||||
|
||||
// Do the weight thing
|
||||
$classEntry.removeData('weight');
|
||||
@@ -60,7 +60,7 @@ $(function () {
|
||||
.appendTo(".navigation ul.list"); // append again to the list
|
||||
|
||||
} else {
|
||||
$el.find('.item, .itemMembers').show();
|
||||
$el.find('.item, .member-list').show();
|
||||
}
|
||||
|
||||
$el.find('.list').scrollTop(0);
|
||||
@@ -68,7 +68,7 @@ $(function () {
|
||||
|
||||
// Toggle when click an item element
|
||||
$('.navigation').on('click', '.toggle', function (e) {
|
||||
$(this).parent().parent().find('.itemMembers').toggle();
|
||||
$(this).parent().parent().find('.member-list').toggle();
|
||||
});
|
||||
|
||||
// Show an item related a current documentation automatically
|
||||
@@ -84,7 +84,7 @@ $(function () {
|
||||
.remove()
|
||||
.prependTo('.navigation .list')
|
||||
.show()
|
||||
.find('.itemMembers')
|
||||
.find('.member-list')
|
||||
.show();
|
||||
}
|
||||
|
||||
|
||||
@@ -183,7 +183,7 @@ li {
|
||||
padding-left: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
.navigation li.item .itemMembers {
|
||||
.navigation li.item .member-list {
|
||||
display: none;
|
||||
padding-left: 8px;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ var version = obj.packageInfo.version;
|
||||
</div>
|
||||
|
||||
<div id="wrap" class="clearfix">
|
||||
<?js= this.partial('navigation.tmpl', this) ?>
|
||||
<?js= this.navigationHtml ?>
|
||||
<div class="main">
|
||||
<h1 class="page-title" data-filename="<?js= filename ?>"><?js= title ?></h1>
|
||||
<div id="latest-check" class="alert alert-warning alert-dismissible" role="alert" style="display:none">
|
||||
|
||||
@@ -1,95 +1,59 @@
|
||||
<?js
|
||||
var self = this;
|
||||
|
||||
function toShortName(name) {
|
||||
return name.indexOf('module:') === 0 ? name.split('/').pop() : name;
|
||||
}
|
||||
|
||||
function getItemCssClass(type) {
|
||||
if (type === 'module') {
|
||||
return 'glyphicon-plus';
|
||||
} else if (type === 'class') {
|
||||
return 'glyphicon-chevron-right';
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
const printList = v => { ?>
|
||||
<li data-name="<?js= v.longname ?>"><?js
|
||||
}
|
||||
const printListWithStability = v => {
|
||||
const cls = v.stability && v.stability !== 'stable' ? ' class="unstable"' : ''; ?>
|
||||
<li data-name="<?js= v.longname ?>"<?js= cls ?>><?js
|
||||
}
|
||||
|
||||
function listContent(item, title, listItemPrinter) {
|
||||
const type = title.toLowerCase();
|
||||
if (item[type] && item[type].length) { ?>
|
||||
<div class="member-list">
|
||||
<span class="subtitle"><?js= title ?></span>
|
||||
<ul><?js
|
||||
item[type].forEach(function (v) {
|
||||
listItemPrinter(v); ?><?js= self.linkto(v.longname, toShortName(v.name)) ?><?js
|
||||
}); ?>
|
||||
</ul>
|
||||
</div><?js
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="navigation">
|
||||
<div class="search">
|
||||
<input id="search" type="text" class="form-control input-sm" placeholder="Search Documentation">
|
||||
</div>
|
||||
<ul class="list">
|
||||
<?js
|
||||
this.nav.forEach(function (item) {
|
||||
?>
|
||||
<ul class="list"><?js
|
||||
this.nav.forEach(function (item) { ?>
|
||||
<li class="item" data-name="<?js= item.longname ?>" data-shortname="<?js= item.name.toLowerCase() ?>">
|
||||
<span class="title">
|
||||
<?js if (item.type === 'module') { ?>
|
||||
<span class="glyphicon glyphicon-plus toggle"></span>
|
||||
<?js } else if (item.type === 'class') { ?>
|
||||
<span class="glyphicon glyphicon-chevron-right toggle"></span>
|
||||
<?js } ?>
|
||||
<span class="glyphicon <?js= getItemCssClass(item.type) ?> toggle"></span>
|
||||
<?js= self.linkto(item.longname, item.prettyname) ?>
|
||||
<?js if (item.type === 'namespace' &&
|
||||
(item.members.length + item.typedefs.length + item.methods.length +
|
||||
item.events.length > 0)) { ?>
|
||||
<?js } ?>
|
||||
</span>
|
||||
<ul class="members itemMembers">
|
||||
<?js
|
||||
if (item.members.length) {
|
||||
?>
|
||||
<span class="subtitle">Members</span>
|
||||
<?js
|
||||
item.members.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>"><?js= self.linkto(v.longname, toShortName(v.name)) ?></li>
|
||||
<?js
|
||||
});
|
||||
</span><?js
|
||||
listContent(item, 'Members', printList);
|
||||
listContent(item, 'Typedefs', printListWithStability);
|
||||
listContent(item, 'Methods', printListWithStability);
|
||||
if (item.fires) {
|
||||
const fires = item.fires.map(v => self.find({longname: v})[0] || {longname: v, name: v.split(/#?event:/)[1]});
|
||||
listContent({fires: fires}, 'Fires', printListWithStability)
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="typedefs itemMembers">
|
||||
<?js
|
||||
if (item.typedefs.length) {
|
||||
?>
|
||||
<span class="subtitle">Typedefs</span>
|
||||
<?js
|
||||
item.typedefs.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>" class="<?js= (v.stability && v.stability !== 'stable') ? 'unstable' : ''?>">
|
||||
<?js= self.linkto(v.longname, toShortName(v.name)) ?>
|
||||
</li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="methods itemMembers">
|
||||
<?js
|
||||
if (item.methods.length) {
|
||||
?>
|
||||
<span class="subtitle">Methods</span>
|
||||
<?js
|
||||
|
||||
item.methods.forEach(function (v) {
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>" class="<?js= (v.stability && v.stability !== 'stable') ? 'unstable' : ''?>">
|
||||
<?js= self.linkto(v.longname, toShortName(v.name)) ?>
|
||||
</li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="fires itemMembers">
|
||||
<?js
|
||||
if (item.fires && item.fires.length) {
|
||||
?>
|
||||
<span class="subtitle">Fires</span>
|
||||
<?js
|
||||
item.fires.forEach(function (v) {
|
||||
v = self.find({longname: v})[0] || {longname: v, name: v.split(/#?event:/)[1]};
|
||||
?>
|
||||
<li data-name="<?js= v.longname ?>" class="<?js= (v.stability && v.stability != 'stable') ? 'unstable' : '' ?>">
|
||||
<?js= self.linkto(v.longname, toShortName(v.name)) ?>
|
||||
</li>
|
||||
<?js
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</li>
|
||||
<?js }); ?>
|
||||
}); ?>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
<th>Name</th>
|
||||
<th>Type</th>
|
||||
<th>Settable</th>
|
||||
<th><a href="module-ol_Object-ObjectEvent.html">ol/Object.ObjectEvent</a> type</th>
|
||||
<th><a href="module-ol_Object.ObjectEvent.html">ol/Object.ObjectEvent</a> type</th>
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
@@ -6,7 +6,7 @@ exports.defineTags = function(dictionary) {
|
||||
|
||||
const classTag = dictionary.lookUp('class');
|
||||
dictionary.defineTag('interface', {
|
||||
mustHaveValue: false,
|
||||
mustNotHaveValue: true,
|
||||
onTagged: function(doclet, tag) {
|
||||
classTag.onTagged.apply(this, arguments);
|
||||
doclet.virtual = true;
|
||||
|
||||
@@ -7,8 +7,8 @@
|
||||
"allowJs": true, /* Allow javascript files to be compiled. */
|
||||
// "checkJs": true, /* Report errors in .js files. */
|
||||
// "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */
|
||||
// "declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
// "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
"declaration": true, /* Generates corresponding '.d.ts' file. */
|
||||
"declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */
|
||||
"sourceMap": true, /* Generates corresponding '.map' file. */
|
||||
// "outFile": "./", /* Concatenate and emit output to single file. */
|
||||
"outDir": "../build/ol", /* Redirect output structure to the directory. */
|
||||
|
||||
@@ -245,3 +245,7 @@ Layer opacity must be a number.
|
||||
|
||||
`forEachFeatureAtCoordinate` cannot be used on a WebGL layer if the hit detection logic has not been enabled.
|
||||
This is done by providing adequate shaders using the `hitVertexShader` and `hitFragmentShader` properties of `WebGLPointsLayerRenderer`.
|
||||
|
||||
### 67
|
||||
|
||||
A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both.
|
||||
@@ -4,10 +4,10 @@ title: Drag-and-Drop Image Vector
|
||||
shortdesc: Example of using the drag-and-drop interaction with image vector rendering.
|
||||
docs: >
|
||||
Example of using the drag-and-drop interaction with an `ol/layer/VectorImage` layer. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. Each file is rendered to an image on the client.
|
||||
tags: "drag-and-drop-image-vector, gpx, geojson, igc, kml, topojson, vector, image"
|
||||
tags: "drag-and-drop-image-vector, gpx, geojson, igc, kml, topojson, maptiler, vector, image"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div id="info"> </div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import View from '../src/ol/View.js';
|
||||
import {GPX, GeoJSON, IGC, KML, TopoJSON} from '../src/ol/format.js';
|
||||
import {defaults as defaultInteractions, DragAndDrop} from '../src/ol/interaction.js';
|
||||
import {VectorImage as VectorImageLayer, Tile as TileLayer} from '../src/ol/layer.js';
|
||||
import {BingMaps, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {XYZ, Vector as VectorSource} from '../src/ol/source.js';
|
||||
|
||||
const dragAndDropInteraction = new DragAndDrop({
|
||||
formatConstructors: [
|
||||
@@ -15,13 +15,18 @@ const dragAndDropInteraction = new DragAndDrop({
|
||||
]
|
||||
});
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const map = new Map({
|
||||
interactions: defaultInteractions().extend([dragAndDropInteraction]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
imagerySet: 'Aerial',
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
})
|
||||
],
|
||||
|
||||
@@ -4,10 +4,10 @@ title: Drag-and-Drop
|
||||
shortdesc: Example of using the drag-and-drop interaction.
|
||||
docs: >
|
||||
Example of using the drag-and-drop interaction. Drag and drop GPX, GeoJSON, IGC, KML, or TopoJSON files on to the map. There is no projection transform support, so this will only work with data in EPSG:4326 and EPSG:3857.
|
||||
tags: "drag-and-drop, gpx, geojson, igc, kml, topojson"
|
||||
tags: "drag-and-drop, gpx, geojson, igc, kml, topojson, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div id="info"> </div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import View from '../src/ol/View.js';
|
||||
import {GPX, GeoJSON, IGC, KML, TopoJSON} from '../src/ol/format.js';
|
||||
import {defaults as defaultInteractions, DragAndDrop} from '../src/ol/interaction.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {BingMaps, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {XYZ, Vector as VectorSource} from '../src/ol/source.js';
|
||||
|
||||
const dragAndDropInteraction = new DragAndDrop({
|
||||
formatConstructors: [
|
||||
@@ -15,13 +15,18 @@ const dragAndDropInteraction = new DragAndDrop({
|
||||
]
|
||||
});
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const map = new Map({
|
||||
interactions: defaultInteractions().extend([dragAndDropInteraction]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
imagerySet: 'Aerial',
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
})
|
||||
],
|
||||
|
||||
9
examples/es2015-custom-element.html
Normal file
9
examples/es2015-custom-element.html
Normal file
@@ -0,0 +1,9 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Custom map element
|
||||
shortdesc: Example of a custom element with a map.
|
||||
docs: >
|
||||
The example creates and registers a custom element, `ol-map`, which contains a simple map. **Note:** Only works in browsers that supports `ShadowRoot`.
|
||||
tags: "es2015, web-component, custom-element, shadow-dom"
|
||||
---
|
||||
<ol-map id="map" class="map"></ol-map>
|
||||
43
examples/es2015-custom-element.js
Normal file
43
examples/es2015-custom-element.js
Normal file
@@ -0,0 +1,43 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
|
||||
class OLComponent extends HTMLElement {
|
||||
|
||||
constructor() {
|
||||
super();
|
||||
this.shadow = this.attachShadow({mode: 'open'});
|
||||
const link = document.createElement('link');
|
||||
link.setAttribute('rel', 'stylesheet');
|
||||
link.setAttribute('href', 'css/ol.css');
|
||||
this.shadow.appendChild(link);
|
||||
const style = document.createElement('style');
|
||||
style.innerText = `
|
||||
:host {
|
||||
display: block;
|
||||
}
|
||||
`;
|
||||
this.shadow.appendChild(style);
|
||||
const div = document.createElement('div');
|
||||
div.style.width = '100%';
|
||||
div.style.height = '100%';
|
||||
this.shadow.appendChild(div);
|
||||
|
||||
this.map = new Map({
|
||||
target: div,
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM()
|
||||
})
|
||||
],
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2
|
||||
})
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
customElements.define('ol-map', OLComponent);
|
||||
@@ -1,6 +0,0 @@
|
||||
.overlay {
|
||||
background-color: yellow;
|
||||
border-radius: 6px;
|
||||
padding: 4px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
@@ -3,13 +3,9 @@ layout: example.html
|
||||
title: Map Export
|
||||
shortdesc: Example of exporting a map as a PNG image.
|
||||
docs: >
|
||||
Example of exporting a map as a PNG image. This example use the <a href="https://www.npmjs.com/package/html-to-image">html-to-image</a>
|
||||
library.
|
||||
Example of exporting a map as a PNG image.
|
||||
tags: "export, png, openstreetmap"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div style="display: none;">
|
||||
<div class="overlay" id="null">Null Island</div>
|
||||
</div>
|
||||
<a id="export-png" class="btn btn-default"><i class="fa fa-download"></i> Download PNG</a>
|
||||
<a id="image-download" download="map.png"></a>
|
||||
|
||||
@@ -1,12 +1,9 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import Overlay from '../src/ol/Overlay.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
|
||||
import {toPng} from 'html-to-image';
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
@@ -16,7 +13,8 @@ const map = new Map({
|
||||
source: new VectorSource({
|
||||
url: 'data/geojson/countries.geojson',
|
||||
format: new GeoJSON()
|
||||
})
|
||||
}),
|
||||
opacity: 0.5
|
||||
})
|
||||
],
|
||||
target: 'map',
|
||||
@@ -26,28 +24,33 @@ const map = new Map({
|
||||
})
|
||||
});
|
||||
|
||||
map.addOverlay(new Overlay({
|
||||
position: [0, 0],
|
||||
element: document.getElementById('null')
|
||||
}));
|
||||
|
||||
|
||||
// export options for html-to-image.
|
||||
// See: https://github.com/bubkoo/html-to-image#options
|
||||
const exportOptions = {
|
||||
filter: function(element) {
|
||||
return element.className ? element.className.indexOf('ol-control') === -1 : true;
|
||||
}
|
||||
};
|
||||
|
||||
document.getElementById('export-png').addEventListener('click', function() {
|
||||
map.once('rendercomplete', function() {
|
||||
toPng(map.getTargetElement(), exportOptions)
|
||||
.then(function(dataURL) {
|
||||
const link = document.getElementById('image-download');
|
||||
link.href = dataURL;
|
||||
link.click();
|
||||
const mapCanvas = document.createElement('canvas');
|
||||
const size = map.getSize();
|
||||
mapCanvas.width = size[0];
|
||||
mapCanvas.height = size[1];
|
||||
const mapContext = mapCanvas.getContext('2d');
|
||||
Array.prototype.forEach.call(document.querySelectorAll('.ol-layer canvas'), function(canvas) {
|
||||
if (canvas.width > 0) {
|
||||
const opacity = canvas.parentNode.style.opacity;
|
||||
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
|
||||
const transform = canvas.style.transform;
|
||||
// Get the transform parameters from the style's transform matrix
|
||||
const matrix = transform.match(/^matrix\(([^\(]*)\)$/)[1].split(',').map(Number);
|
||||
// Apply the transform to the export map context
|
||||
CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix);
|
||||
mapContext.drawImage(canvas, 0, 0);
|
||||
}
|
||||
});
|
||||
if (navigator.msSaveBlob) {
|
||||
// link download attribuute does not work on MS browsers
|
||||
navigator.msSaveBlob(mapCanvas.msToBlob(), 'map.png');
|
||||
} else {
|
||||
const link = document.getElementById('image-download');
|
||||
link.href = mapCanvas.toDataURL();
|
||||
link.click();
|
||||
}
|
||||
});
|
||||
map.renderSync();
|
||||
});
|
||||
|
||||
@@ -6,7 +6,7 @@ docs: >
|
||||
Example of exporting a map as a PDF using the <a href="https://github.com/MrRio/jsPDF" target="_blank">jsPDF</a> library.
|
||||
tags: "export, pdf, openstreetmap"
|
||||
resources:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.2.61/jspdf.min.js
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/jspdf/1.5.3/jspdf.min.js
|
||||
---
|
||||
<div class="row-fluid">
|
||||
<div class="span12">
|
||||
|
||||
@@ -4,8 +4,6 @@ import WKT from '../src/ol/format/WKT.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
|
||||
import {toJpeg} from 'html-to-image';
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new OSM()
|
||||
});
|
||||
@@ -20,7 +18,8 @@ feature.getGeometry().transform('EPSG:4326', 'EPSG:3857');
|
||||
const vector = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
features: [feature]
|
||||
})
|
||||
}),
|
||||
opacity: 0.5
|
||||
});
|
||||
|
||||
|
||||
@@ -44,14 +43,6 @@ const dims = {
|
||||
};
|
||||
|
||||
|
||||
// export options for html-to-image.
|
||||
// See: https://github.com/bubkoo/html-to-image#options
|
||||
const exportOptions = {
|
||||
filter: function(element) {
|
||||
return element.className.indexOf('ol-control') === -1;
|
||||
}
|
||||
};
|
||||
|
||||
const exportButton = document.getElementById('export-pdf');
|
||||
|
||||
exportButton.addEventListener('click', function() {
|
||||
@@ -68,11 +59,24 @@ exportButton.addEventListener('click', function() {
|
||||
const viewResolution = map.getView().getResolution();
|
||||
|
||||
map.once('rendercomplete', function() {
|
||||
exportOptions.width = width;
|
||||
exportOptions.height = height;
|
||||
toJpeg(map.getViewport(), exportOptions).then(function(dataUrl) {
|
||||
const mapCanvas = document.createElement('canvas');
|
||||
mapCanvas.width = width;
|
||||
mapCanvas.height = height;
|
||||
const mapContext = mapCanvas.getContext('2d');
|
||||
Array.prototype.forEach.call(document.querySelectorAll('.ol-layer canvas'), function(canvas) {
|
||||
if (canvas.width > 0) {
|
||||
const opacity = canvas.parentNode.style.opacity;
|
||||
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
|
||||
const transform = canvas.style.transform;
|
||||
// Get the transform parameters from the style's transform matrix
|
||||
const matrix = transform.match(/^matrix\(([^\(]*)\)$/)[1].split(',').map(Number);
|
||||
// Apply the transform to the export map context
|
||||
CanvasRenderingContext2D.prototype.setTransform.apply(mapContext, matrix);
|
||||
mapContext.drawImage(canvas, 0, 0);
|
||||
}
|
||||
});
|
||||
const pdf = new jsPDF('landscape', undefined, format);
|
||||
pdf.addImage(dataUrl, 'JPEG', 0, 0, dim[0], dim[1]);
|
||||
pdf.addImage(mapCanvas.toDataURL('image/jpeg'), 'JPEG', 0, 0, dim[0], dim[1]);
|
||||
pdf.save('map.pdf');
|
||||
// Reset original map size
|
||||
map.setSize(size);
|
||||
@@ -80,7 +84,6 @@ exportButton.addEventListener('click', function() {
|
||||
exportButton.disabled = false;
|
||||
document.body.style.cursor = 'auto';
|
||||
});
|
||||
});
|
||||
|
||||
// Set print size
|
||||
const printSize = [width, height];
|
||||
|
||||
@@ -6,10 +6,10 @@ docs: >
|
||||
<p>Layer rendering can be manipulated in <code>prerender</code> and <code>postrender</code> event listeners.
|
||||
These listeners get an event with a reference to the Canvas rendering context.
|
||||
In this example, the <code>postrender</code> listener applies a filter to the image data.</p>
|
||||
tags: "filter, image manipulation"
|
||||
tags: "filter, image manipulation, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<select id="kernel" name="kernel">
|
||||
|
||||
@@ -2,12 +2,19 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
const key = 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5';
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const imagery = new TileLayer({
|
||||
source: new BingMaps({key: key, imagerySet: 'Aerial'})
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: ''
|
||||
})
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
|
||||
@@ -4,10 +4,10 @@ title: KML
|
||||
shortdesc: Rendering KML with a vector source.
|
||||
docs: >
|
||||
This example uses the <code>ol/format/KML</code> to parse KML for rendering with a vector source.
|
||||
tags: "KML"
|
||||
tags: "KML, maptiler"
|
||||
cloak:
|
||||
- key: As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5
|
||||
value: Your Bing Maps Key from http://www.bingmapsportal.com/ here
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div id="info"> </div>
|
||||
|
||||
@@ -2,13 +2,18 @@ import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import KML from '../src/ol/format/KML.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import BingMaps from '../src/ol/source/BingMaps.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
const attributions = '<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new BingMaps({
|
||||
imagerySet: 'Aerial',
|
||||
key: 'As1HiMj1PvLPlqc_gtM7AqZfBL8ZL3VrjaS3zIb22Uvb9WKhuJObROC-qUpa81U5'
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ cloak:
|
||||
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width">
|
||||
<title>Mapbox Style objects with ol-mapbox-style</title>
|
||||
<link rel="stylesheet" href="../css/ol.css" type="text/css">
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,String.prototype.startsWith,Object.assign"></script>
|
||||
<style type="text/css">
|
||||
html, body, .map {
|
||||
margin: 0;
|
||||
|
||||
@@ -5,7 +5,9 @@ shortdesc: Example of some Regular Shape styles.
|
||||
docs: >
|
||||
This example shows how several regular shapes
|
||||
or symbols (representing `x`, `cross`, `star`,
|
||||
`triangle` and `square`) can be created.
|
||||
`triangle`, `square` and `stacked`) can be created.
|
||||
|
||||
Style `stacked` represents possility to stack multiple shapes with offset
|
||||
tags: "vector, symbol, regularshape, style, square, cross, star, triangle, x"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -59,18 +59,39 @@ const styles = {
|
||||
radius2: 0,
|
||||
angle: Math.PI / 4
|
||||
})
|
||||
}),
|
||||
'stacked': [
|
||||
new Style({
|
||||
image: new RegularShape({
|
||||
fill: fill,
|
||||
stroke: stroke,
|
||||
points: 4,
|
||||
radius: 5,
|
||||
angle: Math.PI / 4,
|
||||
displacement: [0, 10]
|
||||
})
|
||||
}),
|
||||
new Style({
|
||||
image: new RegularShape({
|
||||
fill: fill,
|
||||
stroke: stroke,
|
||||
points: 4,
|
||||
radius: 10,
|
||||
angle: Math.PI / 4
|
||||
})
|
||||
})
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
const styleKeys = ['x', 'cross', 'star', 'triangle', 'square'];
|
||||
const styleKeys = ['x', 'cross', 'star', 'triangle', 'square', 'stacked'];
|
||||
const count = 250;
|
||||
const features = new Array(count);
|
||||
const e = 4500000;
|
||||
for (let i = 0; i < count; ++i) {
|
||||
const coordinates = [2 * e * Math.random() - e, 2 * e * Math.random() - e];
|
||||
features[i] = new Feature(new Point(coordinates));
|
||||
features[i].setStyle(styles[styleKeys[Math.floor(Math.random() * 5)]]);
|
||||
features[i].setStyle(styles[styleKeys[Math.floor(Math.random() * 6)]]);
|
||||
}
|
||||
|
||||
const source = new VectorSource({
|
||||
|
||||
@@ -8,6 +8,11 @@ docs: >
|
||||
<a href="https://www.mapbox.com/blog/terrain-rgb/">Mapbox Terrain-RGB tiles</a>
|
||||
to "flood" areas below the elevation shown on the sea level slider.
|
||||
</p>
|
||||
<p>
|
||||
<code>ol/source/Raster</code> can take either a tile source or layer.
|
||||
In this case a layer is used to allow disabling at the <code>prerender</code> event
|
||||
of image smoothing which would change the precise elevation values set in the pixels.
|
||||
</p>
|
||||
tags: "raster, pixel operation, flood"
|
||||
cloak:
|
||||
- key: pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg
|
||||
|
||||
@@ -22,9 +22,15 @@ function flood(pixels, data) {
|
||||
}
|
||||
|
||||
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
|
||||
const elevation = new XYZ({
|
||||
const elevation = new TileLayer({
|
||||
source: new XYZ({
|
||||
url: 'https://api.mapbox.com/v4/mapbox.terrain-rgb/{z}/{x}/{y}.pngraw?access_token=' + key,
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
});
|
||||
elevation.on('prerender', function(evt) {
|
||||
evt.context.imageSmoothingEnabled = false;
|
||||
evt.context.msImageSmoothingEnabled = false;
|
||||
});
|
||||
|
||||
const raster = new RasterSource({
|
||||
|
||||
@@ -10,7 +10,7 @@ docs: >
|
||||
tags: "draw, edit, modify, vector, snap"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<form id="options-form" automplete="off">
|
||||
<form id="options-form" autocomplete="off">
|
||||
<div class="radio">
|
||||
<label>
|
||||
<input type="radio" name="interaction" value="draw" id="draw" checked>
|
||||
|
||||
@@ -67,9 +67,9 @@
|
||||
<link rel="stylesheet" href="./resources/prism/prism.css" type="text/css">
|
||||
<link rel="stylesheet" href="./css/ol.css" type="text/css">
|
||||
<link rel="stylesheet" href="./resources/layout.css" type="text/css">
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>
|
||||
{{{ extraHead.local }}}
|
||||
{{{ css.tag }}}
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/clipboard.js/1.7.1/clipboard.min.js"></script>
|
||||
<title>{{ title }}</title>
|
||||
</head>
|
||||
@@ -139,7 +139,7 @@
|
||||
<head>
|
||||
<title>{{ title }}</title>
|
||||
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList,URL"></script>{{#if extraHead.remote}}
|
||||
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL"></script>{{#if extraHead.remote}}
|
||||
{{ indent extraHead.remote spaces=4 }}{{/if}}
|
||||
<style>
|
||||
.map {
|
||||
|
||||
@@ -1,19 +1,5 @@
|
||||
This folder contains example templates. These templates are used to build the examples in the `examples/` folder. The resulting examples are written to the `build/examples` folder.
|
||||
|
||||
Although the main purpose of these examples is to demonstrate how to use the API, they also serve other purposes in the development cycle, and so are not exactly as they would be in normal application code:
|
||||
|
||||
* every time the library changes, they are compiled together with the library as a basic check that they remain in sync with the library
|
||||
|
||||
* they use a special loader script to enable defining at run time which build mode (raw/debug/advanced) to use
|
||||
|
||||
To enable this, examples have the following, not needed in application code:
|
||||
|
||||
* each html file loads `loader.js`; application code would not need this, but would instead load the appropriate library build file, either a hosted version or a custom build
|
||||
|
||||
* each js file starts with `goog.require` functions, used by the compiler; application code would only have these if the code is to be compiled together with the library and/or Closure library
|
||||
|
||||
* some js files use type definitions (comments with @type tags); these are also used by the compiler, and are only needed if the code is to be compiled together with the library
|
||||
|
||||
* html files load `resources/common.js` and some scripts use `common.getRendererFromQueryString()` to set the map renderer; application code would not need these
|
||||
The examples are transpiled to es5. If the name of an example starts with `es2015-`, transpilation will be bypassed. This allows for showing es2015+ features in examples.
|
||||
|
||||
At the bottom of each example generated in the `build/examples` folder, a modified version of its source code is shown. That modified version can be run standalone and is usually used as starting point for users to extend examples into their own application.
|
||||
|
||||
22
examples/tracing.html
Normal file
22
examples/tracing.html
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Tracing around a polygon
|
||||
shortdesc: Example of setting up a draw interaction to easily snap to an existing feature.
|
||||
docs: >
|
||||
This example showcases how the draw interaction API can be set up to make snapping along
|
||||
an existing geometry easier while preserving topology, which is sometimes called "tracing".
|
||||
When the user clicks on two different points on the Idaho state border,
|
||||
the part of the border comprised between these two points is added to
|
||||
the currently drawn feature.
|
||||
This leverages the `appendCoordinates` method of the `ol/interaction/Draw` interaction.
|
||||
tags: "draw, trace, snap, vector, topology"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<form class="form-inline">
|
||||
<label>Geometry type </label>
|
||||
<select id="type">
|
||||
<option value="Polygon">Polygon</option>
|
||||
<option value="LineString">LineString</option>
|
||||
<option value="None">None</option>
|
||||
</select>
|
||||
</form>
|
||||
253
examples/tracing.js
Normal file
253
examples/tracing.js
Normal file
@@ -0,0 +1,253 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import Draw from '../src/ol/interaction/Draw.js';
|
||||
import Snap from '../src/ol/interaction/Snap.js';
|
||||
import Style from '../src/ol/style/Style.js';
|
||||
import Stroke from '../src/ol/style/Stroke.js';
|
||||
import Fill from '../src/ol/style/Fill.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import LineString from '../src/ol/geom/LineString.js';
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
|
||||
// math utilities
|
||||
|
||||
// coordinates; will return the length of the [a, b] segment
|
||||
function length(a, b) {
|
||||
return Math.sqrt((b[0] - a[0]) * (b[0] - a[0]) + (b[1] - a[1]) * (b[1] - a[1]));
|
||||
}
|
||||
|
||||
// coordinates; will return true if c is on the [a, b] segment
|
||||
function isOnSegment(c, a, b) {
|
||||
const lengthAc = length(a, c);
|
||||
const lengthAb = length(a, b);
|
||||
const dot = ((c[0] - a[0]) * (b[0] - a[0]) + (c[1] - a[1]) * (b[1] - a[1])) / lengthAb;
|
||||
return Math.abs(lengthAc - dot) < 1e-6 && lengthAc < lengthAb;
|
||||
}
|
||||
|
||||
// modulo for negative values, eg: mod(-1, 4) returns 3
|
||||
function mod(a, b) {
|
||||
return ((a % b) + b) % b;
|
||||
}
|
||||
|
||||
// returns a coordinates array which contains the segments of the feature's
|
||||
// outer ring between the start and end points
|
||||
// Note: this assumes the base feature is a single polygon
|
||||
function getPartialRingCoords(feature, startPoint, endPoint) {
|
||||
let polygon = feature.getGeometry();
|
||||
if (polygon.getType() === 'MultiPolygon') {
|
||||
polygon = polygon.getPolygon(0);
|
||||
}
|
||||
const ringCoords = polygon.getLinearRing().getCoordinates();
|
||||
|
||||
let i, pointA, pointB, startSegmentIndex = -1;
|
||||
for (i = 0; i < ringCoords.length; i++) {
|
||||
pointA = ringCoords[i];
|
||||
pointB = ringCoords[mod(i + 1, ringCoords.length)];
|
||||
|
||||
// check if this is the start segment dot product
|
||||
if (isOnSegment(startPoint, pointA, pointB)) {
|
||||
startSegmentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
const cwCoordinates = [];
|
||||
let cwLength = 0;
|
||||
const ccwCoordinates = [];
|
||||
let ccwLength = 0;
|
||||
|
||||
// build clockwise coordinates
|
||||
for (i = 0; i < ringCoords.length; i++) {
|
||||
pointA = i === 0 ? startPoint : ringCoords[mod(i + startSegmentIndex, ringCoords.length)];
|
||||
pointB = ringCoords[mod(i + startSegmentIndex + 1, ringCoords.length)];
|
||||
cwCoordinates.push(pointA);
|
||||
|
||||
if (isOnSegment(endPoint, pointA, pointB)) {
|
||||
cwCoordinates.push(endPoint);
|
||||
cwLength += length(pointA, endPoint);
|
||||
break;
|
||||
} else {
|
||||
cwLength += length(pointA, pointB);
|
||||
}
|
||||
}
|
||||
|
||||
// build counter-clockwise coordinates
|
||||
for (i = 0; i < ringCoords.length; i++) {
|
||||
pointA = ringCoords[mod(startSegmentIndex - i, ringCoords.length)];
|
||||
pointB = i === 0 ? startPoint : ringCoords[mod(startSegmentIndex - i + 1, ringCoords.length)];
|
||||
ccwCoordinates.push(pointB);
|
||||
|
||||
if (isOnSegment(endPoint, pointA, pointB)) {
|
||||
ccwCoordinates.push(endPoint);
|
||||
ccwLength += length(endPoint, pointB);
|
||||
break;
|
||||
} else {
|
||||
ccwLength += length(pointA, pointB);
|
||||
}
|
||||
}
|
||||
|
||||
// keep the shortest path
|
||||
return ccwLength < cwLength ? ccwCoordinates : cwCoordinates;
|
||||
}
|
||||
|
||||
|
||||
// layers definition
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new OSM()
|
||||
});
|
||||
|
||||
// features in this layer will be snapped to
|
||||
const baseVector = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
format: new GeoJSON(),
|
||||
url: 'https://ahocevar.com/geoserver/wfs?service=wfs&request=getfeature&typename=topp:states&cql_filter=STATE_NAME=\'Idaho\'&outputformat=application/json'
|
||||
})
|
||||
});
|
||||
|
||||
// this is were the drawn features go
|
||||
const drawVector = new VectorLayer({
|
||||
source: new VectorSource(),
|
||||
style: new Style({
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(100, 255, 0, 1)',
|
||||
width: 2
|
||||
}),
|
||||
fill: new Fill({
|
||||
color: 'rgba(100, 255, 0, 0.3)'
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
// this line only appears when we're tracing a feature outer ring
|
||||
const previewLine = new Feature({
|
||||
geometry: new LineString([])
|
||||
});
|
||||
const previewVector = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
features: [previewLine]
|
||||
}),
|
||||
style: new Style({
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(255, 0, 0, 1)',
|
||||
width: 2
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [raster, baseVector, drawVector, previewVector],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [-12986427, 5678422],
|
||||
zoom: 5
|
||||
})
|
||||
});
|
||||
|
||||
let drawInteraction, tracingFeature, startPoint, endPoint;
|
||||
let drawing = false;
|
||||
|
||||
const getFeatureOptions = {
|
||||
hitTolerance: 10,
|
||||
layerFilter: (layer) => {
|
||||
return layer === baseVector;
|
||||
}
|
||||
};
|
||||
|
||||
// the click event is used to start/end tracing around a feature
|
||||
map.on('click', (event) => {
|
||||
if (!drawing) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hit = false;
|
||||
map.forEachFeatureAtPixel(
|
||||
event.pixel,
|
||||
(feature) => {
|
||||
if (tracingFeature && feature !== tracingFeature) {
|
||||
return;
|
||||
}
|
||||
|
||||
hit = true;
|
||||
const coord = map.getCoordinateFromPixel(event.pixel);
|
||||
|
||||
// second click on the tracing feature: append the ring coordinates
|
||||
if (feature === tracingFeature) {
|
||||
endPoint = tracingFeature.getGeometry().getClosestPoint(coord);
|
||||
const appendCoords = getPartialRingCoords(tracingFeature, startPoint, endPoint);
|
||||
drawInteraction.removeLastPoint();
|
||||
drawInteraction.appendCoordinates(appendCoords);
|
||||
tracingFeature = null;
|
||||
}
|
||||
|
||||
// start tracing on the feature ring
|
||||
tracingFeature = feature;
|
||||
startPoint = tracingFeature.getGeometry().getClosestPoint(coord);
|
||||
},
|
||||
getFeatureOptions
|
||||
);
|
||||
|
||||
if (!hit) {
|
||||
// clear current tracing feature & preview
|
||||
previewLine.getGeometry().setCoordinates([]);
|
||||
tracingFeature = null;
|
||||
}
|
||||
});
|
||||
|
||||
// the pointermove event is used to show a preview of the result of the tracing
|
||||
map.on('pointermove', (event) => {
|
||||
if (tracingFeature && drawing) {
|
||||
let coord = null;
|
||||
map.forEachFeatureAtPixel(
|
||||
event.pixel,
|
||||
(feature) => {
|
||||
if (tracingFeature === feature) {
|
||||
coord = map.getCoordinateFromPixel(event.pixel);
|
||||
}
|
||||
},
|
||||
getFeatureOptions
|
||||
);
|
||||
|
||||
let previewCoords = [];
|
||||
if (coord) {
|
||||
endPoint = tracingFeature.getGeometry().getClosestPoint(coord);
|
||||
previewCoords = getPartialRingCoords(tracingFeature, startPoint, endPoint);
|
||||
}
|
||||
previewLine.getGeometry().setCoordinates(previewCoords);
|
||||
}
|
||||
});
|
||||
|
||||
const snapInteraction = new Snap({
|
||||
source: baseVector.getSource()
|
||||
});
|
||||
|
||||
const typeSelect = document.getElementById('type');
|
||||
|
||||
function addInteraction() {
|
||||
const value = typeSelect.value;
|
||||
if (value !== 'None') {
|
||||
drawInteraction = new Draw({
|
||||
source: drawVector.getSource(),
|
||||
type: typeSelect.value
|
||||
});
|
||||
drawInteraction.on('drawstart', () => {
|
||||
drawing = true;
|
||||
});
|
||||
drawInteraction.on('drawend', () => {
|
||||
drawing = false;
|
||||
previewLine.getGeometry().setCoordinates([]);
|
||||
tracingFeature = null;
|
||||
});
|
||||
map.addInteraction(drawInteraction);
|
||||
map.addInteraction(snapInteraction);
|
||||
}
|
||||
}
|
||||
|
||||
typeSelect.onchange = function() {
|
||||
map.removeInteraction(drawInteraction);
|
||||
map.removeInteraction(snapInteraction);
|
||||
addInteraction();
|
||||
};
|
||||
addInteraction();
|
||||
@@ -6,6 +6,8 @@ docs: >
|
||||
Example showing vector tiles in EPSG:4326 (styled using `ol-mapbox-style`) loaded from maptiler.com.
|
||||
**Note**: Make sure to get your own API key at https://www.maptiler.com/cloud/ when using this example. No map will be visible when the API key has expired.
|
||||
tags: "vector tiles, epsg4326, mapbox style, ol-mapbox-style, maptiler"
|
||||
resources:
|
||||
- https://cdn.polyfill.io/v2/polyfill.min.js?features=String.prototype.startsWith,Object.assign"
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
|
||||
@@ -4,7 +4,7 @@ import VectorTileSource from '../src/ol/source/VectorTile.js';
|
||||
import TileGrid from '../src/ol/tilegrid/TileGrid.js';
|
||||
|
||||
import olms from 'ol-mapbox-style';
|
||||
import {defaultResolutions} from 'ol-mapbox-style/util.js';
|
||||
import {defaultResolutions} from 'ol-mapbox-style/dist/util.js';
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
|
||||
|
||||
@@ -13,6 +13,8 @@ docs: >
|
||||
Note: those will be taken from the attributes provided to the renderer
|
||||
* `['var', 'varName']` fetches a value from the style variables, or 0 if undefined
|
||||
* `['time']` returns the time in seconds since the creation of the layer
|
||||
* `['zoom']` returns the current zoom level
|
||||
* `['resolution']` returns the current resolution
|
||||
|
||||
* Math operators:
|
||||
* `['*', value1, value2]` multiplies `value1` by `value2`
|
||||
@@ -57,7 +59,6 @@ docs: >
|
||||
* `['color', red, green, blue, alpha]` creates a `color` value from `number` values; the `alpha` parameter is
|
||||
optional; if not specified, it will be set to 1.
|
||||
Note: `red`, `green` and `blue` components must be values between 0 and 255; `alpha` between 0 and 1.
|
||||
|
||||
Values can either be literals or another operator, as they will be evaluated recursively.
|
||||
Literal values can be of the following types:
|
||||
* `boolean`
|
||||
@@ -76,6 +77,7 @@ experimental: true
|
||||
<option value="triangles-latitude">Triangles, color related to latitude</option>
|
||||
<option value="circles">Circles, size related to population</option>
|
||||
<option value="circles-zoom">Circles, size related to zoom</option>
|
||||
<option value="rotating-bars">Rotating bars</option>
|
||||
</select>
|
||||
<textarea style="width: 100%; height: 20rem; font-family: monospace; font-size: small;" id="style-editor"></textarea>
|
||||
<small>
|
||||
|
||||
@@ -95,6 +95,35 @@ const predefinedStyles = {
|
||||
offset: [0, 0],
|
||||
opacity: 0.95
|
||||
}
|
||||
},
|
||||
'rotating-bars': {
|
||||
symbol: {
|
||||
symbolType: 'square',
|
||||
rotation: ['*', [
|
||||
'time'
|
||||
], 0.1],
|
||||
size: ['array', 4, [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, 4,
|
||||
300000, 28]
|
||||
],
|
||||
color: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, '#ffdc00',
|
||||
300000, '#ff5b19'
|
||||
],
|
||||
offset: ['array', 0, [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, 2,
|
||||
300000, 14]
|
||||
]
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -167,3 +196,10 @@ function onSelectChange() {
|
||||
}
|
||||
onSelectChange();
|
||||
select.addEventListener('change', onSelectChange);
|
||||
|
||||
// animate the map
|
||||
function animate() {
|
||||
map.render();
|
||||
window.requestAnimationFrame(animate);
|
||||
}
|
||||
animate();
|
||||
|
||||
@@ -22,7 +22,7 @@ module.exports = {
|
||||
stats: 'minimal',
|
||||
module: {
|
||||
rules: [{
|
||||
test: /\.js$/,
|
||||
test: /^((?!es2015-)[\s\S])*\.js$/,
|
||||
use: {
|
||||
loader: 'buble-loader'
|
||||
},
|
||||
|
||||
@@ -3,7 +3,7 @@ layout: example.html
|
||||
title: ArcGIS REST with 512x512 Tiles
|
||||
shortdesc: Example of a XYZ source in EPSG:4326 using Esri 512x512 tiles.
|
||||
docs: >
|
||||
ArcGIS REST tile services with custom tile sizes (here: 512x512 pixels) and projection (here: EPSG:4326) are supported by `ol/source/XYZ`. A custom tile url function is used to handle zoom level offsets.
|
||||
ArcGIS REST tile services with custom tile sizes (here: 512x512 pixels) and projection (here: EPSG:4326) are supported by `ol/source/XYZ`.
|
||||
tags: "xyz, esri, tilesize, custom projection"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -3,26 +3,18 @@ import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
// The tile size supported by the ArcGIS tile service.
|
||||
const tileSize = 512;
|
||||
|
||||
const urlTemplate = 'https://services.arcgisonline.com/arcgis/rest/services/' +
|
||||
'ESRI_Imagery_World_2D/MapServer/tile/{z}/{y}/{x}';
|
||||
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
attributions: 'Copyright:© 2013 ESRI, i-cubed, GeoEye',
|
||||
maxZoom: 16,
|
||||
url: 'https://services.arcgisonline.com/arcgis/rest/services/' +
|
||||
'ESRI_Imagery_World_2D/MapServer/tile/{z}/{y}/{x}',
|
||||
maxZoom: 15,
|
||||
projection: 'EPSG:4326',
|
||||
tileSize: tileSize,
|
||||
tileUrlFunction: function(tileCoord) {
|
||||
return urlTemplate.replace('{z}', (tileCoord[0] - 1).toString())
|
||||
.replace('{x}', tileCoord[1].toString())
|
||||
.replace('{y}', tileCoord[2].toString());
|
||||
},
|
||||
tileSize: 512, // the tile size supported by the ArcGIS tile service
|
||||
maxResolution: 180 / 512, // Esri's tile grid fits 180 degrees on one 512 px tile
|
||||
wrapX: true
|
||||
})
|
||||
})
|
||||
|
||||
@@ -10,7 +10,6 @@ tags: "zoomify, deep zoom, IIP, pixel, projection"
|
||||
<div class="controls">
|
||||
<select id="zoomifyProtocol">
|
||||
<option value="zoomify">Zoomify</option>
|
||||
<option value="iip">IIP</option>
|
||||
<option value="zoomifyretina">Zoomify Retina</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -3,36 +3,42 @@ import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import Zoomify from '../src/ol/source/Zoomify.js';
|
||||
|
||||
const imgWidth = 9911;
|
||||
const imgHeight = 6100;
|
||||
const imgWidth = 4000;
|
||||
const imgHeight = 3000;
|
||||
|
||||
const zoomifyUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?zoomify=' +
|
||||
'/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF/';
|
||||
const iipUrl = 'http://vips.vtech.fr/cgi-bin/iipsrv.fcgi?FIF=' + '/mnt/MD1/AD00/plan_CHU-4HD-01/FOND.TIF' + '&JTL={z},{tileIndex}';
|
||||
const zoomifyUrl = 'https://ol-zoomify.surge.sh/zoomify/';
|
||||
|
||||
const layer = new TileLayer({
|
||||
source: new Zoomify({
|
||||
tileSize: 256,
|
||||
tilePixelRatio: 1,
|
||||
const source = new Zoomify({
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
crossOrigin: 'anonymous',
|
||||
zDirection: -1 // Ensure we get a tile with the screen resolution or higher
|
||||
});
|
||||
const extent = source.getTileGrid().getExtent();
|
||||
|
||||
const retinaPixelRatio = 2;
|
||||
const retinaSource = new Zoomify({
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous',
|
||||
zDirection: -1, // Ensure we get a tile with the screen resolution or higher
|
||||
tilePixelRatio: retinaPixelRatio, // Display retina tiles
|
||||
tileSize: 256 / retinaPixelRatio // from a higher zoom level
|
||||
});
|
||||
|
||||
const extent = [0, -imgHeight, imgWidth, 0];
|
||||
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
const layer = new TileLayer({
|
||||
source: source
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [layer],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1],
|
||||
maxResolution: resolutions[0],
|
||||
resolutions: layer.getSource().getTileGrid().getResolutions(),
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
extent: extent,
|
||||
constrainOnlyCenter: true
|
||||
})
|
||||
});
|
||||
map.getView().fit(extent);
|
||||
@@ -40,74 +46,11 @@ map.getView().fit(extent);
|
||||
const control = document.getElementById('zoomifyProtocol');
|
||||
control.addEventListener('change', function(event) {
|
||||
const value = event.currentTarget.value;
|
||||
if (value === 'iip') {
|
||||
const extent = [0, -imgHeight, imgWidth, 0];
|
||||
layer.setSource(
|
||||
new Zoomify({
|
||||
tileSize: 256,
|
||||
tilePixelRatio: 1,
|
||||
url: iipUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
);
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
map.setView(
|
||||
new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1],
|
||||
maxResolution: resolutions[0],
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
);
|
||||
map.getView().fit(extent);
|
||||
} else if (value === 'zoomify') {
|
||||
const extent = [0, -imgHeight, imgWidth, 0];
|
||||
layer.setSource(
|
||||
new Zoomify({
|
||||
tileSize: 256,
|
||||
tilePixelRatio: 1,
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth, imgHeight],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
);
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
map.setView(
|
||||
new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1],
|
||||
maxResolution: resolutions[0],
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
);
|
||||
map.getView().fit(extent);
|
||||
if (value === 'zoomify') {
|
||||
layer.setSource(source);
|
||||
} else if (value === 'zoomifyretina') {
|
||||
const pixelRatio = 4;
|
||||
// Be careful! Image extent will be modified by pixel ratio
|
||||
const extent = [0, -imgHeight / pixelRatio, imgWidth / pixelRatio, 0];
|
||||
layer.setSource(
|
||||
new Zoomify({
|
||||
tileSize: 256 / pixelRatio,
|
||||
tilePixelRatio: pixelRatio,
|
||||
url: zoomifyUrl,
|
||||
size: [imgWidth / pixelRatio, imgHeight / pixelRatio],
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
);
|
||||
const resolutions = layer.getSource().getTileGrid().getResolutions();
|
||||
map.setView(
|
||||
new View({
|
||||
// adjust zoom levels to those provided by the source
|
||||
minResolution: resolutions[resolutions.length - 1] / pixelRatio,
|
||||
maxResolution: resolutions[0],
|
||||
// constrain the center: center cannot be set outside this extent
|
||||
extent: extent
|
||||
})
|
||||
);
|
||||
map.getView().fit(extent);
|
||||
layer.setSource(retinaSource);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
|
||||
|
||||
3613
package-lock.json
generated
3613
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
28
package.json
28
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.1.1",
|
||||
"version": "6.2.2",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
"map",
|
||||
@@ -22,9 +22,9 @@
|
||||
"build-index": "npm run build-package && node tasks/generate-index",
|
||||
"build-legacy": "shx rm -rf build && npm run build-index && webpack --config config/webpack-config-legacy-build.js && cleancss --source-map src/ol/ol.css -o build/legacy/ol.css",
|
||||
"copy-css": "shx cp src/ol/ol.css build/ol/ol.css",
|
||||
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && tsc --project config/tsconfig-build.json",
|
||||
"transpile": "shx rm -rf build/ol && shx mkdir -p build/ol && shx cp -rf src/ol build/ol/src && node tasks/serialize-workers && npx --package typescript@3.8.1-rc tsc --project config/tsconfig-build.json",
|
||||
"typecheck": "tsc --pretty",
|
||||
"apidoc": "jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
|
||||
"apidoc": "shx rm -rf build/apidoc && jsdoc -R config/jsdoc/api/index.md -c config/jsdoc/api/conf.json -P package.json -d build/apidoc"
|
||||
},
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
@@ -36,7 +36,7 @@
|
||||
"url": "https://github.com/openlayers/openlayers/issues"
|
||||
},
|
||||
"dependencies": {
|
||||
"elm-pep": "^1.0.2",
|
||||
"elm-pep": "^1.0.4",
|
||||
"pbf": "3.2.1",
|
||||
"pixelworks": "1.1.0",
|
||||
"rbush": "^3.0.1"
|
||||
@@ -62,9 +62,8 @@
|
||||
"front-matter": "^3.0.2",
|
||||
"fs-extra": "^8.0.0",
|
||||
"glob": "^7.1.5",
|
||||
"globby": "^10.0.0",
|
||||
"handlebars": "4.5.3",
|
||||
"html-to-image": "^0.1.0",
|
||||
"globby": "^11.0.0",
|
||||
"handlebars": "4.7.3",
|
||||
"istanbul": "0.4.5",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
"jquery": "3.4.1",
|
||||
@@ -72,20 +71,19 @@
|
||||
"jsdoc-plugin-typescript": "^2.0.5",
|
||||
"karma": "^4.4.1",
|
||||
"karma-chrome-launcher": "3.1.0",
|
||||
"karma-coverage": "^2.0.1",
|
||||
"karma-coverage-istanbul-reporter": "^2.1.0",
|
||||
"karma-coverage-istanbul-reporter": "^2.1.1",
|
||||
"karma-firefox-launcher": "^1.1.0",
|
||||
"karma-mocha": "1.3.0",
|
||||
"karma-sourcemap-loader": "^0.3.7",
|
||||
"karma-webpack": "^4.0.0-rc.2",
|
||||
"loglevelnext": "^3.0.1",
|
||||
"marked": "0.7.0",
|
||||
"mocha": "6.2.2",
|
||||
"ol-mapbox-style": "^5.0.2",
|
||||
"marked": "0.8.0",
|
||||
"mocha": "7.0.1",
|
||||
"ol-mapbox-style": "^6.0.0",
|
||||
"pixelmatch": "^5.1.0",
|
||||
"pngjs": "^3.4.0",
|
||||
"proj4": "2.6.0",
|
||||
"puppeteer": "~2.0.0",
|
||||
"puppeteer": "~2.1.0",
|
||||
"rollup": "^1.25.1",
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"rollup-plugin-commonjs": "^10.0.0",
|
||||
@@ -93,12 +91,12 @@
|
||||
"rollup-plugin-terser": "^5.0.0",
|
||||
"serve-static": "^1.14.0",
|
||||
"shx": "^0.3.2",
|
||||
"sinon": "^7.3.2",
|
||||
"sinon": "^9.0.0",
|
||||
"terser-webpack-plugin": "^2.0.1",
|
||||
"typescript": "3.5.3",
|
||||
"url-polyfill": "^1.1.5",
|
||||
"walk": "^2.3.9",
|
||||
"webpack": "4.41.2",
|
||||
"webpack": "4.41.6",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-middleware": "^3.6.2",
|
||||
"webpack-dev-server": "^3.3.1",
|
||||
|
||||
BIN
rendering/cases/icon-opacity/expected.png
Normal file
BIN
rendering/cases/icon-opacity/expected.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 119 KiB |
47
rendering/cases/icon-opacity/main.js
Normal file
47
rendering/cases/icon-opacity/main.js
Normal file
@@ -0,0 +1,47 @@
|
||||
import Map from '../../../src/ol/Map.js';
|
||||
import View from '../../../src/ol/View.js';
|
||||
import {Vector as VectorLayer, Tile as TileLayer} from '../../../src/ol/layer.js';
|
||||
import {Vector as VectorSource, XYZ} from '../../../src/ol/source.js';
|
||||
import Point from '../../../src/ol/geom/Point.js';
|
||||
import Feature from '../../../src/ol/Feature.js';
|
||||
import {fromLonLat} from '../../../src/ol/proj.js';
|
||||
import {Style, Icon} from '../../../src/ol/style.js';
|
||||
|
||||
const center = fromLonLat([8.6, 50.1]);
|
||||
|
||||
new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg'
|
||||
})
|
||||
}),
|
||||
new VectorLayer({
|
||||
style: function() {
|
||||
return new Style({
|
||||
image: new Icon({
|
||||
opacity: 0.5,
|
||||
src: '/data/icon.png',
|
||||
anchor: [0.5, 46],
|
||||
anchorXUnits: 'fraction',
|
||||
anchorYUnits: 'pixels'
|
||||
})
|
||||
});
|
||||
},
|
||||
source: new VectorSource({
|
||||
features: [
|
||||
new Feature(
|
||||
new Point(center)
|
||||
)
|
||||
]
|
||||
})
|
||||
})
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: center,
|
||||
zoom: 3
|
||||
})
|
||||
});
|
||||
|
||||
render();
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 144 KiB After Width: | Height: | Size: 134 KiB |
@@ -13,16 +13,17 @@ const vectorSource = new VectorSource();
|
||||
function createFeatures(stroke, fill, offSet = [0, 0]) {
|
||||
let feature;
|
||||
feature = new Feature({
|
||||
geometry: new Point([-15 + offSet[0], 15 + offSet[1]])
|
||||
geometry: new Point([offSet[0], offSet[1]])
|
||||
});
|
||||
// square
|
||||
// square with offset
|
||||
feature.setStyle(new Style({
|
||||
image: new RegularShape({
|
||||
fill: fill,
|
||||
stroke: stroke,
|
||||
points: 4,
|
||||
radius: 10,
|
||||
angle: Math.PI / 4
|
||||
angle: Math.PI / 4,
|
||||
displacement: [-15, 15]
|
||||
})
|
||||
}));
|
||||
vectorSource.addFeature(feature);
|
||||
|
||||
@@ -26,7 +26,7 @@ export class CollectionEvent extends Event {
|
||||
/**
|
||||
* @param {CollectionEventType} type Type.
|
||||
* @param {*=} opt_element Element.
|
||||
* @param {number} opt_index The index of the added or removed element.
|
||||
* @param {number=} opt_index The index of the added or removed element.
|
||||
*/
|
||||
constructor(type, opt_element, opt_index) {
|
||||
super(type);
|
||||
|
||||
@@ -58,20 +58,6 @@ class ImageTile extends Tile {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.state == TileState.LOADING) {
|
||||
this.unlistenImage_();
|
||||
this.image_ = getBlankImage();
|
||||
}
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML image element for this tile (may be a Canvas, Image, or Video).
|
||||
* @return {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} Image.
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/**
|
||||
* @module ol/PluggableMap
|
||||
*/
|
||||
import {getUid} from './util.js';
|
||||
import Collection from './Collection.js';
|
||||
import CollectionEventType from './CollectionEventType.js';
|
||||
import MapBrowserEvent from './MapBrowserEvent.js';
|
||||
@@ -933,12 +932,16 @@ class PluggableMap extends BaseObject {
|
||||
// coordinates so interactions cannot be used.
|
||||
return;
|
||||
}
|
||||
let target = /** @type {Node} */ (mapBrowserEvent.originalEvent.target);
|
||||
while (target) {
|
||||
if (target.parentElement === this.overlayContainerStopEvent_) {
|
||||
const target = /** @type {Node} */ (mapBrowserEvent.originalEvent.target);
|
||||
if (!mapBrowserEvent.dragging) {
|
||||
if (this.overlayContainerStopEvent_.contains(target) || !(document.body.contains(target) || this.viewport_.getRootNode && this.viewport_.getRootNode().contains(target))) {
|
||||
// Abort if the event target is a child of the container that doesn't allow
|
||||
// event propagation or is no longer in the page. It's possible for the target to no longer
|
||||
// be in the page if it has been removed in an event listener, this might happen in a Control
|
||||
// that recreates it's content based on user interaction either manually or via a render
|
||||
// in something like https://reactjs.org/
|
||||
return;
|
||||
}
|
||||
target = target.parentElement;
|
||||
}
|
||||
mapBrowserEvent.frameState = this.frameState_;
|
||||
const interactionsArray = this.getInteractions().getArray();
|
||||
@@ -1102,7 +1105,8 @@ class PluggableMap extends BaseObject {
|
||||
}
|
||||
const view = this.getView();
|
||||
if (view) {
|
||||
this.viewport_.setAttribute('data-view', getUid(view));
|
||||
this.updateViewportSize_();
|
||||
|
||||
this.viewPropertyListenerKey_ = listen(
|
||||
view, ObjectEventType.PROPERTYCHANGE,
|
||||
this.handleViewPropertyChanged_, this);
|
||||
@@ -1360,6 +1364,27 @@ class PluggableMap extends BaseObject {
|
||||
parseFloat(computedStyle['borderBottomWidth'])
|
||||
]);
|
||||
}
|
||||
|
||||
this.updateViewportSize_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Recomputes the viewport size and save it on the view object (if any)
|
||||
* @private
|
||||
*/
|
||||
updateViewportSize_() {
|
||||
const view = this.getView();
|
||||
if (view) {
|
||||
let size = undefined;
|
||||
const computedStyle = getComputedStyle(this.viewport_);
|
||||
if (computedStyle.width && computedStyle.height) {
|
||||
size = [
|
||||
parseInt(computedStyle.width, 10),
|
||||
parseInt(computedStyle.height, 10)
|
||||
];
|
||||
}
|
||||
view.setViewportSize(size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -145,10 +145,9 @@ class Tile extends EventTarget {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Called by the tile cache when the tile is removed from the cache due to expiry
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setState(TileState.ABORT);
|
||||
release() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -7,16 +7,7 @@ import {fromKey, getKey} from './tilecoord.js';
|
||||
class TileCache extends LRUCache {
|
||||
|
||||
/**
|
||||
* @param {number=} opt_highWaterMark High water mark.
|
||||
*/
|
||||
constructor(opt_highWaterMark) {
|
||||
|
||||
super(opt_highWaterMark);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {!Object<string, import("./TileRange.js").default>} usedTiles Used tiles.
|
||||
* @param {!Object<string, boolean>} usedTiles Used tiles.
|
||||
*/
|
||||
expireCache(usedTiles) {
|
||||
while (this.canExpireCache()) {
|
||||
@@ -24,7 +15,7 @@ class TileCache extends LRUCache {
|
||||
if (tile.getKey() in usedTiles) {
|
||||
break;
|
||||
} else {
|
||||
this.pop().dispose();
|
||||
this.pop().release();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,7 +33,7 @@ class TileCache extends LRUCache {
|
||||
this.forEach(function(tile) {
|
||||
if (tile.tileCoord[0] !== z) {
|
||||
this.remove(getKey(tile.tileCoord));
|
||||
tile.dispose();
|
||||
tile.release();
|
||||
}
|
||||
}.bind(this));
|
||||
}
|
||||
|
||||
@@ -84,8 +84,7 @@ class TileQueue extends PriorityQueue {
|
||||
handleTileChange(event) {
|
||||
const tile = /** @type {import("./Tile.js").default} */ (event.target);
|
||||
const state = tile.getState();
|
||||
if (tile.hifi && state === TileState.LOADED || state === TileState.ERROR ||
|
||||
state === TileState.EMPTY || state === TileState.ABORT) {
|
||||
if (tile.hifi && state === TileState.LOADED || state === TileState.ERROR || state === TileState.EMPTY) {
|
||||
tile.removeEventListener(EventType.CHANGE, this.boundHandleTileChange_);
|
||||
const tileKey = tile.getKey();
|
||||
if (tileKey in this.tilesLoadingKeys_) {
|
||||
@@ -102,27 +101,19 @@ class TileQueue extends PriorityQueue {
|
||||
*/
|
||||
loadMoreTiles(maxTotalLoading, maxNewLoads) {
|
||||
let newLoads = 0;
|
||||
let abortedTiles = false;
|
||||
let state, tile, tileKey;
|
||||
while (this.tilesLoading_ < maxTotalLoading && newLoads < maxNewLoads &&
|
||||
this.getCount() > 0) {
|
||||
tile = /** @type {import("./Tile.js").default} */ (this.dequeue()[0]);
|
||||
tileKey = tile.getKey();
|
||||
state = tile.getState();
|
||||
if (state === TileState.ABORT) {
|
||||
abortedTiles = true;
|
||||
} else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
this.tilesLoadingKeys_[tileKey] = true;
|
||||
++this.tilesLoading_;
|
||||
++newLoads;
|
||||
tile.load();
|
||||
}
|
||||
}
|
||||
if (newLoads === 0 && abortedTiles) {
|
||||
// Do not stop the render loop when all wanted tiles were aborted due to
|
||||
// a small, saturated tile cache.
|
||||
this.tileChangeCallback_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,5 @@ export default {
|
||||
* @type {number}
|
||||
*/
|
||||
ERROR: 3,
|
||||
EMPTY: 4,
|
||||
ABORT: 5
|
||||
EMPTY: 4
|
||||
};
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
import {getUid} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
import {unlistenByKey} from './events.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -19,6 +18,10 @@ import {unlistenByKey} from './events.js';
|
||||
* @property {number} renderedTileZ
|
||||
*/
|
||||
|
||||
/**
|
||||
* @type {Array<HTMLCanvasElement>}
|
||||
*/
|
||||
const canvasPool = [];
|
||||
|
||||
class VectorRenderTile extends Tile {
|
||||
|
||||
@@ -26,13 +29,10 @@ class VectorRenderTile extends Tile {
|
||||
* @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {import("./TileState.js").default} state State.
|
||||
* @param {import("./tilecoord.js").TileCoord} urlTileCoord Wrapped tile coordinate for source urls.
|
||||
* @param {import("./tilegrid/TileGrid.js").default} sourceTileGrid Tile grid of the source.
|
||||
* @param {function(VectorRenderTile):Array<import("./VectorTile").default>} getSourceTiles Function
|
||||
* to get an source tiles for this tile.
|
||||
* @param {function(VectorRenderTile):void} removeSourceTiles Function to remove this tile from its
|
||||
* source tiles's consumer count.
|
||||
* to get source tiles for this tile.
|
||||
*/
|
||||
constructor(tileCoord, state, urlTileCoord, sourceTileGrid, getSourceTiles, removeSourceTiles) {
|
||||
constructor(tileCoord, state, urlTileCoord, getSourceTiles) {
|
||||
|
||||
super(tileCoord, state, {transition: 0});
|
||||
|
||||
@@ -71,6 +71,11 @@ class VectorRenderTile extends Tile {
|
||||
*/
|
||||
this.replayState_ = {};
|
||||
|
||||
/**
|
||||
* @type {Array<import("./VectorTile.js").default>}
|
||||
*/
|
||||
this.sourceTiles = null;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
@@ -79,23 +84,7 @@ class VectorRenderTile extends Tile {
|
||||
/**
|
||||
* @type {!function():Array<import("./VectorTile.js").default>}
|
||||
*/
|
||||
this.getSourceTiles = getSourceTiles.bind(this, this);
|
||||
|
||||
/**
|
||||
* @type {!function(import("./VectorRenderTile.js").default):void}
|
||||
*/
|
||||
this.removeSourceTiles_ = removeSourceTiles;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./tilegrid/TileGrid.js").default}
|
||||
*/
|
||||
this.sourceTileGrid_ = sourceTileGrid;
|
||||
|
||||
/**
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.sourceTileListenerKeys = [];
|
||||
this.getSourceTiles = getSourceTiles.bind(undefined, this);
|
||||
|
||||
/**
|
||||
* z of the source tiles of the last getSourceTiles call.
|
||||
@@ -115,27 +104,6 @@ class VectorRenderTile extends Tile {
|
||||
this.wrappedTileCoord = urlTileCoord;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.sourceTileListenerKeys.forEach(unlistenByKey);
|
||||
this.sourceTileListenerKeys.length = 0;
|
||||
this.removeSourceTiles_(this);
|
||||
for (const key in this.context_) {
|
||||
const canvas = this.context_[key].canvas;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
for (const key in this.executorGroups) {
|
||||
const executorGroups = this.executorGroups[key];
|
||||
for (let i = 0, ii = executorGroups.length; i < ii; ++i) {
|
||||
executorGroups[i].disposeInternal();
|
||||
}
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./layer/Layer.js").default} layer Layer.
|
||||
* @return {CanvasRenderingContext2D} The rendering context.
|
||||
@@ -143,7 +111,7 @@ class VectorRenderTile extends Tile {
|
||||
getContext(layer) {
|
||||
const key = getUid(layer);
|
||||
if (!(key in this.context_)) {
|
||||
this.context_[key] = createCanvasContext2D();
|
||||
this.context_[key] = createCanvasContext2D(1, 1, canvasPool);
|
||||
}
|
||||
return this.context_[key];
|
||||
}
|
||||
@@ -192,6 +160,16 @@ class VectorRenderTile extends Tile {
|
||||
load() {
|
||||
this.getSourceTiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
release() {
|
||||
for (const key in this.context_) {
|
||||
canvasPool.push(this.context_[key].canvas);
|
||||
}
|
||||
super.release();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -18,11 +18,6 @@ class VectorTile extends Tile {
|
||||
|
||||
super(tileCoord, state, opt_options);
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
*/
|
||||
this.consumers = 0;
|
||||
|
||||
/**
|
||||
* Extent of this tile; set by the source.
|
||||
* @type {import("./extent.js").Extent}
|
||||
|
||||
100
src/ol/View.js
100
src/ol/View.js
@@ -2,7 +2,6 @@
|
||||
* @module ol/View
|
||||
*/
|
||||
import {DEFAULT_TILE_SIZE} from './tilegrid/common.js';
|
||||
import {getUid} from './util.js';
|
||||
import {VOID} from './functions.js';
|
||||
import {createExtent, none as centerNone} from './centerconstraint.js';
|
||||
import BaseObject from './Object.js';
|
||||
@@ -130,6 +129,14 @@ import {createMinMaxResolution} from './resolutionconstraint.js';
|
||||
* @property {boolean} [smoothResolutionConstraint=true] If true, the resolution
|
||||
* min/max values will be applied smoothly, i. e. allow the view to exceed slightly
|
||||
* the given resolution or zoom bounds.
|
||||
* @property {boolean} [showFullExtent=false] Allow the view to be zoomed out to
|
||||
* show the full configured extent. By default, when a view is configured with an
|
||||
* extent, users will not be able to zoom out so the viewport exceeds the extent in
|
||||
* either dimension. This means the full extent may not be visible if the viewport
|
||||
* is taller or wider than the aspect ratio of the configured extent. If
|
||||
* showFullExtent is true, the user will be able to zoom out so that the viewport
|
||||
* exceeds the height or width of the configured extent, but not both, allowing the
|
||||
* full extent to be shown.
|
||||
* @property {import("./proj.js").ProjectionLike} [projection='EPSG:3857'] The
|
||||
* projection. The default is Spherical Mercator.
|
||||
* @property {number} [resolution] The initial resolution for the view. The
|
||||
@@ -294,6 +301,12 @@ class View extends BaseObject {
|
||||
*/
|
||||
this.projection_ = createProjection(options.projection, 'EPSG:3857');
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./size.js").Size}
|
||||
*/
|
||||
this.viewportSize_ = [100, 100];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("./coordinate.js").Coordinate|undefined}
|
||||
@@ -649,7 +662,7 @@ class View extends BaseObject {
|
||||
animation.targetResolution :
|
||||
animation.sourceResolution + progress * (animation.targetResolution - animation.sourceResolution);
|
||||
if (animation.anchor) {
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
const constrainedResolution = this.constraints_.resolution(resolution, 0, size, true);
|
||||
this.targetCenter_ = this.calculateCenterZoom(constrainedResolution, animation.anchor);
|
||||
}
|
||||
@@ -722,27 +735,34 @@ class View extends BaseObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current viewport size.
|
||||
* @private
|
||||
* @param {number=} opt_rotation Take into account the rotation of the viewport when giving the size
|
||||
* @return {import("./size.js").Size} Viewport size or `[100, 100]` when no viewport is found.
|
||||
*/
|
||||
getSizeFromViewport_(opt_rotation) {
|
||||
const size = [100, 100];
|
||||
const selector = '.ol-viewport[data-view="' + getUid(this) + '"]';
|
||||
const element = document.querySelector(selector);
|
||||
if (element) {
|
||||
const metrics = getComputedStyle(element);
|
||||
size[0] = parseInt(metrics.width, 10);
|
||||
size[1] = parseInt(metrics.height, 10);
|
||||
}
|
||||
getViewportSize_(opt_rotation) {
|
||||
const size = this.viewportSize_;
|
||||
if (opt_rotation) {
|
||||
const w = size[0];
|
||||
const h = size[1];
|
||||
size[0] = Math.abs(w * Math.cos(opt_rotation)) + Math.abs(h * Math.sin(opt_rotation));
|
||||
size[1] = Math.abs(w * Math.sin(opt_rotation)) + Math.abs(h * Math.cos(opt_rotation));
|
||||
}
|
||||
return [
|
||||
Math.abs(w * Math.cos(opt_rotation)) + Math.abs(h * Math.sin(opt_rotation)),
|
||||
Math.abs(w * Math.sin(opt_rotation)) + Math.abs(h * Math.cos(opt_rotation))
|
||||
];
|
||||
} else {
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the viewport size on the view. The viewport size is not read every time from the DOM
|
||||
* to avoid performance hit and layout reflow.
|
||||
* This should be done on map size change.
|
||||
* @param {import("./size.js").Size=} opt_size Viewport size; if undefined, [100, 100] is assumed
|
||||
*/
|
||||
setViewportSize(opt_size) {
|
||||
this.viewportSize_ = Array.isArray(opt_size) ? opt_size.slice() : [100, 100];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the view center.
|
||||
@@ -773,6 +793,13 @@ class View extends BaseObject {
|
||||
return this.constraints_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {boolean} Resolution constraint is set
|
||||
*/
|
||||
getConstrainResolution() {
|
||||
return this.options_.constrainResolution;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<number>=} opt_hints Destination array.
|
||||
* @return {Array<number>} Hint.
|
||||
@@ -792,8 +819,8 @@ class View extends BaseObject {
|
||||
* The size is the pixel dimensions of the box into which the calculated extent
|
||||
* should fit. In most cases you want to get the extent of the entire map,
|
||||
* that is `map.getSize()`.
|
||||
* @param {import("./size.js").Size=} opt_size Box pixel size. If not provided, the size of the
|
||||
* first map that uses this view will be used.
|
||||
* @param {import("./size.js").Size=} opt_size Box pixel size. If not provided, the size
|
||||
* of the map that uses this view will be used.
|
||||
* @return {import("./extent.js").Extent} Extent.
|
||||
* @api
|
||||
*/
|
||||
@@ -808,7 +835,7 @@ class View extends BaseObject {
|
||||
* @return {import("./extent.js").Extent} Extent.
|
||||
*/
|
||||
calculateExtentInternal(opt_size) {
|
||||
const size = opt_size || this.getSizeFromViewport_();
|
||||
const size = opt_size || this.getViewportSize_();
|
||||
const center = /** @type {!import("./coordinate.js").Coordinate} */ (this.getCenterInternal());
|
||||
assert(center, 1); // The view center is not defined
|
||||
const resolution = /** @type {!number} */ (this.getResolution());
|
||||
@@ -931,7 +958,7 @@ class View extends BaseObject {
|
||||
* the given size.
|
||||
*/
|
||||
getResolutionForExtentInternal(extent, opt_size) {
|
||||
const size = opt_size || this.getSizeFromViewport_();
|
||||
const size = opt_size || this.getViewportSize_();
|
||||
const xResolution = getWidth(extent) / size[0];
|
||||
const yResolution = getHeight(extent) / size[1];
|
||||
return Math.max(xResolution, yResolution);
|
||||
@@ -945,7 +972,7 @@ class View extends BaseObject {
|
||||
*/
|
||||
getResolutionForValueFunction(opt_power) {
|
||||
const power = opt_power || 2;
|
||||
const maxResolution = this.maxResolution_;
|
||||
const maxResolution = this.getConstrainedResolution(this.maxResolution_);
|
||||
const minResolution = this.minResolution_;
|
||||
const max = Math.log(maxResolution / minResolution) / Math.log(power);
|
||||
return (
|
||||
@@ -976,17 +1003,17 @@ class View extends BaseObject {
|
||||
* @return {function(number): number} Value for resolution function.
|
||||
*/
|
||||
getValueForResolutionFunction(opt_power) {
|
||||
const power = opt_power || 2;
|
||||
const maxResolution = this.maxResolution_;
|
||||
const logPower = Math.log(opt_power || 2);
|
||||
const maxResolution = this.getConstrainedResolution(this.maxResolution_);
|
||||
const minResolution = this.minResolution_;
|
||||
const max = Math.log(maxResolution / minResolution) / Math.log(power);
|
||||
const max = Math.log(maxResolution / minResolution) / logPower;
|
||||
return (
|
||||
/**
|
||||
* @param {number} resolution Resolution.
|
||||
* @return {number} Value.
|
||||
*/
|
||||
function(resolution) {
|
||||
const value = (Math.log(maxResolution / resolution) / Math.log(power)) / max;
|
||||
const value = (Math.log(maxResolution / resolution) / logPower) / max;
|
||||
return value;
|
||||
});
|
||||
}
|
||||
@@ -1079,7 +1106,7 @@ class View extends BaseObject {
|
||||
* @api
|
||||
*/
|
||||
fit(geometryOrExtent, opt_options) {
|
||||
const options = assign({size: this.getSizeFromViewport_()}, opt_options || {});
|
||||
const options = assign({size: this.getViewportSize_()}, opt_options || {});
|
||||
|
||||
/** @type {import("./geom/SimpleGeometry.js").default} */
|
||||
let geometry;
|
||||
@@ -1097,7 +1124,7 @@ class View extends BaseObject {
|
||||
} else {
|
||||
const userProjection = getUserProjection();
|
||||
if (userProjection) {
|
||||
geometry = /** @type {import("./geom/SimpleGeometry.js").default} */ (geometry.clone().transform(userProjection, this.getProjection()));
|
||||
geometry = /** @type {import("./geom/SimpleGeometry.js").default} */ (geometryOrExtent.clone().transform(userProjection, this.getProjection()));
|
||||
} else {
|
||||
geometry = geometryOrExtent;
|
||||
}
|
||||
@@ -1114,7 +1141,7 @@ class View extends BaseObject {
|
||||
const options = opt_options || {};
|
||||
let size = options.size;
|
||||
if (!size) {
|
||||
size = this.getSizeFromViewport_();
|
||||
size = this.getViewportSize_();
|
||||
}
|
||||
const padding = options.padding !== undefined ? options.padding : [0, 0, 0, 0];
|
||||
const nearest = options.nearest !== undefined ? options.nearest : false;
|
||||
@@ -1261,7 +1288,7 @@ class View extends BaseObject {
|
||||
*/
|
||||
adjustResolutionInternal(ratio, opt_anchor) {
|
||||
const isMoving = this.getAnimating() || this.getInteracting();
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_ * ratio, 0, size, isMoving);
|
||||
|
||||
if (opt_anchor) {
|
||||
@@ -1385,7 +1412,7 @@ class View extends BaseObject {
|
||||
|
||||
// compute rotation
|
||||
const newRotation = this.constraints_.rotation(this.targetRotation_, isMoving);
|
||||
const size = this.getSizeFromViewport_(newRotation);
|
||||
const size = this.getViewportSize_(newRotation);
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_, 0, size, isMoving);
|
||||
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size, isMoving);
|
||||
|
||||
@@ -1419,7 +1446,7 @@ class View extends BaseObject {
|
||||
const direction = opt_resolutionDirection || 0;
|
||||
|
||||
const newRotation = this.constraints_.rotation(this.targetRotation_);
|
||||
const size = this.getSizeFromViewport_(newRotation);
|
||||
const size = this.getViewportSize_(newRotation);
|
||||
const newResolution = this.constraints_.resolution(this.targetResolution_, direction, size);
|
||||
const newCenter = this.constraints_.center(this.targetCenter_, newResolution, size);
|
||||
|
||||
@@ -1500,7 +1527,7 @@ class View extends BaseObject {
|
||||
* @return {import("./coordinate.js").Coordinate|undefined} Valid center position.
|
||||
*/
|
||||
getConstrainedCenter(targetCenter, opt_targetResolution) {
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
return this.constraints_.center(targetCenter, opt_targetResolution || this.getResolution(), size);
|
||||
}
|
||||
|
||||
@@ -1529,7 +1556,7 @@ class View extends BaseObject {
|
||||
*/
|
||||
getConstrainedResolution(targetResolution, opt_direction) {
|
||||
const direction = opt_direction || 0;
|
||||
const size = this.getSizeFromViewport_(this.getRotation());
|
||||
const size = this.getViewportSize_(this.getRotation());
|
||||
|
||||
return this.constraints_.resolution(targetResolution, direction, size);
|
||||
}
|
||||
@@ -1599,6 +1626,9 @@ export function createResolutionConstraint(options) {
|
||||
const smooth =
|
||||
options.smoothResolutionConstraint !== undefined ? options.smoothResolutionConstraint : true;
|
||||
|
||||
const showFullExtent =
|
||||
options.showFullExtent !== undefined ? options.showFullExtent : false;
|
||||
|
||||
const projection = createProjection(options.projection, 'EPSG:3857');
|
||||
const projExtent = projection.getExtent();
|
||||
let constrainOnlyCenter = options.constrainOnlyCenter;
|
||||
@@ -1616,10 +1646,10 @@ export function createResolutionConstraint(options) {
|
||||
|
||||
if (options.constrainResolution) {
|
||||
resolutionConstraint = createSnapToResolutions(resolutions, smooth,
|
||||
!constrainOnlyCenter && extent);
|
||||
!constrainOnlyCenter && extent, showFullExtent);
|
||||
} else {
|
||||
resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth,
|
||||
!constrainOnlyCenter && extent);
|
||||
!constrainOnlyCenter && extent, showFullExtent);
|
||||
}
|
||||
} else {
|
||||
// calculate the default min and max resolution
|
||||
@@ -1665,10 +1695,10 @@ export function createResolutionConstraint(options) {
|
||||
if (options.constrainResolution) {
|
||||
resolutionConstraint = createSnapToPower(
|
||||
zoomFactor, maxResolution, minResolution, smooth,
|
||||
!constrainOnlyCenter && extent);
|
||||
!constrainOnlyCenter && extent, showFullExtent);
|
||||
} else {
|
||||
resolutionConstraint = createMinMaxResolution(maxResolution, minResolution, smooth,
|
||||
!constrainOnlyCenter && extent);
|
||||
!constrainOnlyCenter && extent, showFullExtent);
|
||||
}
|
||||
}
|
||||
return {constraint: resolutionConstraint, maxResolution: maxResolution,
|
||||
|
||||
@@ -325,7 +325,6 @@ class Attribution extends Control {
|
||||
* Update the attribution element.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @this {Attribution}
|
||||
* @api
|
||||
*/
|
||||
export function render(mapEvent) {
|
||||
this.updateElement_(mapEvent.frameState);
|
||||
|
||||
@@ -79,9 +79,10 @@ class Control extends BaseObject {
|
||||
this.listenerKeys = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function(import("../MapEvent.js").default): void}
|
||||
*/
|
||||
this.render = options.render ? options.render : VOID;
|
||||
this.render_ = options.render ? options.render : VOID;
|
||||
|
||||
if (options.target) {
|
||||
this.setTarget(options.target);
|
||||
@@ -134,6 +135,16 @@ class Control extends BaseObject {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the projection. Rendering of the coordinates is done in
|
||||
* `handleMouseMove` and `handleMouseUp`.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @api
|
||||
*/
|
||||
render(mapEvent) {
|
||||
this.render_.call(this, mapEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is used to set a target element for the control. It has no
|
||||
* effect if it is called after the control has been added to the map (i.e.
|
||||
|
||||
@@ -9,6 +9,29 @@ import EventType from '../events/EventType.js';
|
||||
|
||||
const events = ['fullscreenchange', 'webkitfullscreenchange', 'MSFullscreenChange'];
|
||||
|
||||
|
||||
/**
|
||||
* @enum {string}
|
||||
*/
|
||||
const FullScreenEventType = {
|
||||
|
||||
/**
|
||||
* Triggered after the map entered fullscreen.
|
||||
* @event FullScreenEventType#enterfullscreen
|
||||
* @api
|
||||
*/
|
||||
ENTERFULLSCREEN: 'enterfullscreen',
|
||||
|
||||
/**
|
||||
* Triggered after the map leave fullscreen.
|
||||
* @event FullScreenEventType#leavefullscreen
|
||||
* @api
|
||||
*/
|
||||
LEAVEFULLSCREEN: 'leavefullscreen'
|
||||
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} [className='ol-full-screen'] CSS class name.
|
||||
@@ -38,6 +61,8 @@ const events = ['fullscreenchange', 'webkitfullscreenchange', 'MSFullscreenChang
|
||||
* The [Fullscreen API](http://www.w3.org/TR/fullscreen/) is used to
|
||||
* toggle the map in full screen mode.
|
||||
*
|
||||
* @fires FullScreenEventType#enterfullscreen
|
||||
* @fires FullScreenEventType#leavefullscreen
|
||||
* @api
|
||||
*/
|
||||
class FullScreen extends Control {
|
||||
@@ -162,9 +187,11 @@ class FullScreen extends Control {
|
||||
if (isFullScreen()) {
|
||||
this.setClassName_(this.button_, true);
|
||||
replaceNode(this.labelActiveNode_, this.labelNode_);
|
||||
this.dispatchEvent(FullScreenEventType.ENTERFULLSCREEN);
|
||||
} else {
|
||||
this.setClassName_(this.button_, false);
|
||||
replaceNode(this.labelNode_, this.labelActiveNode_);
|
||||
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
|
||||
}
|
||||
if (map) {
|
||||
map.updateSize();
|
||||
|
||||
@@ -248,7 +248,6 @@ class MousePosition extends Control {
|
||||
* `handleMouseMove` and `handleMouseUp`.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @this {MousePosition}
|
||||
* @api
|
||||
*/
|
||||
export function render(mapEvent) {
|
||||
const frameState = mapEvent.frameState;
|
||||
|
||||
@@ -17,6 +17,7 @@ import {replaceNode} from '../dom.js';
|
||||
import {listen, listenOnce} from '../events.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import {containsExtent, equals as equalsExtent, getBottomRight, getTopLeft, scaleFromCenter} from '../extent.js';
|
||||
import View from '../View.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -59,8 +60,8 @@ class ControlledMap extends PluggableMap {
|
||||
* @property {HTMLElement|string} [target] Specify a target if you want the control
|
||||
* to be rendered outside of the map's viewport.
|
||||
* @property {string} [tipLabel='Overview map'] Text label to use for the button tip.
|
||||
* @property {import("../View.js").default} [view] Custom view for the overview map. If not provided,
|
||||
* a default view with an EPSG:3857 projection will be used.
|
||||
* @property {View} [view] Custom view for the overview map (should use same projection as main map). If not provided,
|
||||
* a default view with the same projection as the main map will be used.
|
||||
*/
|
||||
|
||||
|
||||
@@ -167,6 +168,13 @@ class OverviewMap extends Control {
|
||||
this.ovmapDiv_ = document.createElement('div');
|
||||
this.ovmapDiv_.className = 'ol-overviewmap-map';
|
||||
|
||||
/**
|
||||
* Explicitly given view to be used instead of a view derived from the main map.
|
||||
* @type {View}
|
||||
* @private
|
||||
*/
|
||||
this.view_ = options.view;
|
||||
|
||||
/**
|
||||
* @type {ControlledMap}
|
||||
* @private
|
||||
@@ -303,6 +311,14 @@ class OverviewMap extends Control {
|
||||
* @private
|
||||
*/
|
||||
bindView_(view) {
|
||||
if (!this.view_) {
|
||||
// Unless an explicit view definition was given, derive default from whatever main map uses.
|
||||
const newView = new View({
|
||||
projection: view.getProjection()
|
||||
});
|
||||
this.ovmap_.setView(newView);
|
||||
}
|
||||
|
||||
view.addEventListener(getChangeEventType(ViewProperty.ROTATION), this.boundHandleRotationChanged_);
|
||||
// Sync once with the new view
|
||||
this.handleRotationChanged_();
|
||||
@@ -603,7 +619,6 @@ class OverviewMap extends Control {
|
||||
* Update the overview map element.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @this {OverviewMap}
|
||||
* @api
|
||||
*/
|
||||
export function render(mapEvent) {
|
||||
this.validateExtent_();
|
||||
|
||||
@@ -131,8 +131,9 @@ class Rotate extends Control {
|
||||
// upon it
|
||||
return;
|
||||
}
|
||||
if (view.getRotation() !== undefined) {
|
||||
if (this.duration_ > 0) {
|
||||
const rotation = view.getRotation();
|
||||
if (rotation !== undefined) {
|
||||
if (this.duration_ > 0 && rotation % (2 * Math.PI) !== 0) {
|
||||
view.animate({
|
||||
rotation: 0,
|
||||
duration: this.duration_,
|
||||
@@ -150,7 +151,6 @@ class Rotate extends Control {
|
||||
* Update the rotate control element.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @this {Rotate}
|
||||
* @api
|
||||
*/
|
||||
export function render(mapEvent) {
|
||||
const frameState = mapEvent.frameState;
|
||||
|
||||
@@ -418,7 +418,6 @@ class ScaleLine extends Control {
|
||||
* Update the scale line element.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @this {ScaleLine}
|
||||
* @api
|
||||
*/
|
||||
export function render(mapEvent) {
|
||||
const frameState = mapEvent.frameState;
|
||||
|
||||
@@ -339,7 +339,6 @@ class ZoomSlider extends Control {
|
||||
* Update the zoomslider element.
|
||||
* @param {import("../MapEvent.js").default} mapEvent Map event.
|
||||
* @this {ZoomSlider}
|
||||
* @api
|
||||
*/
|
||||
export function render(mapEvent) {
|
||||
if (!mapEvent.frameState) {
|
||||
|
||||
@@ -7,10 +7,12 @@
|
||||
* Create an html canvas element and returns its 2d context.
|
||||
* @param {number=} opt_width Canvas width.
|
||||
* @param {number=} opt_height Canvas height.
|
||||
* @param {Array<HTMLCanvasElement>=} opt_canvasPool Canvas pool to take existing canvas from.
|
||||
* @return {CanvasRenderingContext2D} The context.
|
||||
*/
|
||||
export function createCanvasContext2D(opt_width, opt_height) {
|
||||
const canvas = document.createElement('canvas');
|
||||
export function createCanvasContext2D(opt_width, opt_height, opt_canvasPool) {
|
||||
const canvas = opt_canvasPool && opt_canvasPool.length ?
|
||||
opt_canvasPool.shift() : document.createElement('canvas');
|
||||
if (opt_width) {
|
||||
canvas.width = opt_width;
|
||||
}
|
||||
|
||||
@@ -162,6 +162,8 @@ class GeoJSON extends JSONFeature {
|
||||
if (crs) {
|
||||
if (crs['type'] == 'name') {
|
||||
projection = getProjection(crs['properties']['name']);
|
||||
} else if (crs['type'] === 'EPSG') {
|
||||
projection = getProjection('EPSG:' + crs['properties']['code']);
|
||||
} else {
|
||||
assert(false, 36); // Unknown SRS type
|
||||
}
|
||||
|
||||
@@ -349,7 +349,7 @@ class IIIFInfo {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {PreferredOptions} opt_preferredOptions Optional options for preferred format and quality.
|
||||
* @param {PreferredOptions=} opt_preferredOptions Optional options for preferred format and quality.
|
||||
* @returns {import("../source/IIIF.js").Options} IIIF tile source ready constructor options.
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -378,6 +378,11 @@ function createStyleDefaults() {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {HTMLTextAreaElement}
|
||||
*/
|
||||
let TEXTAREA;
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
@@ -877,32 +882,32 @@ class KML extends XMLFeature {
|
||||
* @return {Style} style Style.
|
||||
*/
|
||||
function createNameStyleFunction(foundStyle, name) {
|
||||
let textStyle = null;
|
||||
const textOffset = [0, 0];
|
||||
let textAlign = 'start';
|
||||
if (foundStyle.getImage()) {
|
||||
let imageSize = foundStyle.getImage().getImageSize();
|
||||
const imageStyle = foundStyle.getImage();
|
||||
if (imageStyle) {
|
||||
let imageSize = imageStyle.getImageSize();
|
||||
if (imageSize === null) {
|
||||
imageSize = DEFAULT_IMAGE_STYLE_SIZE;
|
||||
}
|
||||
if (imageSize.length == 2) {
|
||||
const imageScale = foundStyle.getImage().getScale();
|
||||
// Offset the label to be centered to the right of the icon, if there is
|
||||
// one.
|
||||
const imageScale = imageStyle.getScale();
|
||||
// Offset the label to be centered to the right of the icon,
|
||||
// if there is one.
|
||||
textOffset[0] = imageScale * imageSize[0] / 2;
|
||||
textOffset[1] = -imageScale * imageSize[1] / 2;
|
||||
textAlign = 'left';
|
||||
}
|
||||
}
|
||||
if (foundStyle.getText() !== null) {
|
||||
let textStyle = foundStyle.getText();
|
||||
if (textStyle) {
|
||||
// clone the text style, customizing it with name, alignments and offset.
|
||||
// Note that kml does not support many text options that OpenLayers does (rotation, textBaseline).
|
||||
const foundText = foundStyle.getText();
|
||||
textStyle = foundText.clone();
|
||||
textStyle.setFont(foundText.getFont() || DEFAULT_TEXT_STYLE.getFont());
|
||||
textStyle.setScale(foundText.getScale() || DEFAULT_TEXT_STYLE.getScale());
|
||||
textStyle.setFill(foundText.getFill() || DEFAULT_TEXT_STYLE.getFill());
|
||||
textStyle.setStroke(foundText.getStroke() || DEFAULT_TEXT_STROKE_STYLE);
|
||||
textStyle = textStyle.clone();
|
||||
textStyle.setFont(textStyle.getFont() || DEFAULT_TEXT_STYLE.getFont());
|
||||
textStyle.setScale(textStyle.getScale() || DEFAULT_TEXT_STYLE.getScale());
|
||||
textStyle.setFill(textStyle.getFill() || DEFAULT_TEXT_STYLE.getFill());
|
||||
textStyle.setStroke(textStyle.getStroke() || DEFAULT_TEXT_STROKE_STYLE);
|
||||
} else {
|
||||
textStyle = DEFAULT_TEXT_STYLE.clone();
|
||||
}
|
||||
@@ -912,7 +917,12 @@ function createNameStyleFunction(foundStyle, name) {
|
||||
textStyle.setTextAlign(textAlign);
|
||||
|
||||
const nameStyle = new Style({
|
||||
text: textStyle
|
||||
image: imageStyle,
|
||||
text: textStyle,
|
||||
// although nameStyle will be used only for Point geometries
|
||||
// fill and stroke are included to assist writing of MultiGeometry styles
|
||||
fill: foundStyle.getFill(),
|
||||
stroke: foundStyle.getStroke()
|
||||
});
|
||||
return nameStyle;
|
||||
}
|
||||
@@ -932,45 +942,66 @@ function createFeatureStyleFunction(style, styleUrl, defaultStyle, sharedStyles,
|
||||
/**
|
||||
* @param {Feature} feature feature.
|
||||
* @param {number} resolution Resolution.
|
||||
* @return {Array<Style>} Style.
|
||||
* @return {Array<Style>|Style} Style.
|
||||
*/
|
||||
function(feature, resolution) {
|
||||
let drawName = showPointNames;
|
||||
/** @type {Style|undefined} */
|
||||
let nameStyle;
|
||||
let name = '';
|
||||
let multiGeometryPoints = [];
|
||||
if (drawName) {
|
||||
const geometry = feature.getGeometry();
|
||||
if (geometry) {
|
||||
drawName = geometry.getType() === GeometryType.POINT;
|
||||
const type = geometry.getType();
|
||||
if (type === GeometryType.GEOMETRY_COLLECTION) {
|
||||
multiGeometryPoints = geometry.getGeometriesArray().filter(function(geometry) {
|
||||
const type = geometry.getType();
|
||||
return type === GeometryType.POINT || type === GeometryType.MULTI_POINT;
|
||||
});
|
||||
drawName = multiGeometryPoints.length > 0;
|
||||
} else {
|
||||
drawName = type === GeometryType.POINT || type === GeometryType.MULTI_POINT;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (drawName) {
|
||||
name = /** @type {string} */ (feature.get('name'));
|
||||
drawName = drawName && !!name;
|
||||
// convert any html character codes
|
||||
if (drawName && name.search(/&[^&]+;/) > -1) {
|
||||
if (!TEXTAREA) {
|
||||
TEXTAREA = document.createElement('textarea');
|
||||
}
|
||||
TEXTAREA.innerHTML = name;
|
||||
name = TEXTAREA.value;
|
||||
}
|
||||
}
|
||||
|
||||
let featureStyle = defaultStyle;
|
||||
if (style) {
|
||||
if (drawName) {
|
||||
nameStyle = createNameStyleFunction(style[0], name);
|
||||
return style.concat(nameStyle);
|
||||
}
|
||||
return style;
|
||||
}
|
||||
if (styleUrl) {
|
||||
const foundStyle = findStyle(styleUrl, defaultStyle, sharedStyles);
|
||||
if (drawName) {
|
||||
nameStyle = createNameStyleFunction(foundStyle[0], name);
|
||||
return foundStyle.concat(nameStyle);
|
||||
}
|
||||
return foundStyle;
|
||||
featureStyle = style;
|
||||
} else if (styleUrl) {
|
||||
featureStyle = findStyle(styleUrl, defaultStyle, sharedStyles);
|
||||
}
|
||||
if (drawName) {
|
||||
nameStyle = createNameStyleFunction(defaultStyle[0], name);
|
||||
return defaultStyle.concat(nameStyle);
|
||||
const nameStyle = createNameStyleFunction(featureStyle[0], name);
|
||||
if (multiGeometryPoints.length > 0) {
|
||||
// in multigeometries restrict the name style to points and create a
|
||||
// style without image or text for geometries requiring fill or stroke
|
||||
// including any polygon specific style if there is one
|
||||
nameStyle.setGeometry(new GeometryCollection(multiGeometryPoints));
|
||||
const baseStyle = new Style({
|
||||
geometry: featureStyle[0].getGeometry(),
|
||||
image: null,
|
||||
fill: featureStyle[0].getFill(),
|
||||
stroke: featureStyle[0].getStroke(),
|
||||
text: null
|
||||
});
|
||||
return [nameStyle, baseStyle].concat(featureStyle.slice(1));
|
||||
}
|
||||
return defaultStyle;
|
||||
return nameStyle;
|
||||
}
|
||||
return featureStyle;
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -1759,13 +1790,57 @@ function readStyle(node, objectStack) {
|
||||
const textStyle = /** @type {Text} */
|
||||
('textStyle' in styleObject ?
|
||||
styleObject['textStyle'] : DEFAULT_TEXT_STYLE);
|
||||
let strokeStyle = /** @type {Stroke} */
|
||||
const strokeStyle = /** @type {Stroke} */
|
||||
('strokeStyle' in styleObject ?
|
||||
styleObject['strokeStyle'] : DEFAULT_STROKE_STYLE);
|
||||
const outline = /** @type {boolean|undefined} */
|
||||
(styleObject['outline']);
|
||||
if (outline !== undefined && !outline) {
|
||||
strokeStyle = null;
|
||||
// if the polystyle specifies no outline two styles are needed,
|
||||
// one for non-polygon geometries where linestrings require a stroke
|
||||
// and one for polygons where there should be no stroke
|
||||
return [
|
||||
new Style({
|
||||
geometry: function(feature) {
|
||||
const geometry = feature.getGeometry();
|
||||
const type = geometry.getType();
|
||||
if (type === GeometryType.GEOMETRY_COLLECTION) {
|
||||
return new GeometryCollection(
|
||||
geometry.getGeometriesArray().filter(function(geometry) {
|
||||
const type = geometry.getType();
|
||||
return type !== GeometryType.POLYGON && type !== GeometryType.MULTI_POLYGON;
|
||||
})
|
||||
);
|
||||
} else if (type !== GeometryType.POLYGON && type !== GeometryType.MULTI_POLYGON) {
|
||||
return geometry;
|
||||
}
|
||||
},
|
||||
fill: fillStyle,
|
||||
image: imageStyle,
|
||||
stroke: strokeStyle,
|
||||
text: textStyle,
|
||||
zIndex: undefined // FIXME
|
||||
}),
|
||||
new Style({
|
||||
geometry: function(feature) {
|
||||
const geometry = feature.getGeometry();
|
||||
const type = geometry.getType();
|
||||
if (type === GeometryType.GEOMETRY_COLLECTION) {
|
||||
return new GeometryCollection(
|
||||
geometry.getGeometriesArray().filter(function(geometry) {
|
||||
const type = geometry.getType();
|
||||
return type === GeometryType.POLYGON || type === GeometryType.MULTI_POLYGON;
|
||||
})
|
||||
);
|
||||
} else if (type === GeometryType.POLYGON || type === GeometryType.MULTI_POLYGON) {
|
||||
return geometry;
|
||||
}
|
||||
},
|
||||
fill: fillStyle,
|
||||
stroke: null,
|
||||
zIndex: undefined // FIXME
|
||||
})
|
||||
];
|
||||
}
|
||||
return [new Style({
|
||||
fill: fillStyle,
|
||||
@@ -2527,7 +2602,7 @@ function writeLineStyle(node, style, objectStack) {
|
||||
const /** @type {import("../xml.js").NodeStackItem} */ context = {node: node};
|
||||
const properties = {
|
||||
'color': style.getColor(),
|
||||
'width': style.getWidth()
|
||||
'width': Number(style.getWidth()) || 1
|
||||
};
|
||||
const parentNode = objectStack[objectStack.length - 1].node;
|
||||
const orderedKeys = LINE_STYLE_SEQUENCE[parentNode.namespaceURI];
|
||||
|
||||
@@ -74,7 +74,10 @@ class WMTSCapabilities extends XML {
|
||||
* @inheritDoc
|
||||
*/
|
||||
readFromNode(node) {
|
||||
const version = node.getAttribute('version').trim();
|
||||
let version = node.getAttribute('version');
|
||||
if (version) {
|
||||
version = version.trim();
|
||||
}
|
||||
let WMTSCapabilityObject = this.owsParser_.readFromNode(node);
|
||||
if (!WMTSCapabilityObject) {
|
||||
return null;
|
||||
|
||||
@@ -5,7 +5,7 @@ import {abstract} from '../util.js';
|
||||
import {extend} from '../array.js';
|
||||
import FeatureFormat from '../format/Feature.js';
|
||||
import FormatType from '../format/FormatType.js';
|
||||
import {isDocument, parse} from '../xml.js';
|
||||
import {isDocument, parse, getXMLSerializer} from '../xml.js';
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -23,7 +23,7 @@ class XMLFeature extends FeatureFormat {
|
||||
* @type {XMLSerializer}
|
||||
* @private
|
||||
*/
|
||||
this.xmlSerializer_ = new XMLSerializer();
|
||||
this.xmlSerializer_ = getXMLSerializer();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @module ol/format/xsd
|
||||
*/
|
||||
import {getAllTextContent, DOCUMENT} from '../xml.js';
|
||||
import {getAllTextContent, getDocument} from '../xml.js';
|
||||
import {padNumber} from '../string.js';
|
||||
|
||||
|
||||
@@ -112,7 +112,7 @@ export function writeBooleanTextNode(node, bool) {
|
||||
* @param {string} string String.
|
||||
*/
|
||||
export function writeCDATASection(node, string) {
|
||||
node.appendChild(DOCUMENT.createCDATASection(string));
|
||||
node.appendChild(getDocument().createCDATASection(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -128,7 +128,7 @@ export function writeDateTimeTextNode(node, dateTime) {
|
||||
padNumber(date.getUTCHours(), 2) + ':' +
|
||||
padNumber(date.getUTCMinutes(), 2) + ':' +
|
||||
padNumber(date.getUTCSeconds(), 2) + 'Z';
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@ export function writeDateTimeTextNode(node, dateTime) {
|
||||
*/
|
||||
export function writeDecimalTextNode(node, decimal) {
|
||||
const string = decimal.toPrecision();
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +148,7 @@ export function writeDecimalTextNode(node, decimal) {
|
||||
*/
|
||||
export function writeNonNegativeIntegerTextNode(node, nonNegativeInteger) {
|
||||
const string = nonNegativeInteger.toString();
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
|
||||
@@ -157,5 +157,5 @@ export function writeNonNegativeIntegerTextNode(node, nonNegativeInteger) {
|
||||
* @param {string} string String.
|
||||
*/
|
||||
export function writeStringTextNode(node, string) {
|
||||
node.appendChild(DOCUMENT.createTextNode(string));
|
||||
node.appendChild(getDocument().createTextNode(string));
|
||||
}
|
||||
|
||||
@@ -13,6 +13,8 @@ import PointerInteraction, {centroid as centroidFromPointers} from './Pointer.js
|
||||
* @property {import("../events/condition.js").Condition} [condition] A function that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a boolean
|
||||
* to indicate whether that event should be handled.
|
||||
* Default is {@link module:ol/events/condition~noModifierKeys} and {@link module:ol/events/condition~primaryAction}.
|
||||
* In addition, if there is a `tabindex` attribute on the map element,
|
||||
* {@link module:ol/events/condition~focus} will also be applied.
|
||||
* @property {import("../Kinetic.js").default} [kinetic] Kinetic inertia to apply to the pan.
|
||||
*/
|
||||
|
||||
|
||||
@@ -143,7 +143,13 @@ const DrawEventType = {
|
||||
* @event DrawEvent#drawend
|
||||
* @api
|
||||
*/
|
||||
DRAWEND: 'drawend'
|
||||
DRAWEND: 'drawend',
|
||||
/**
|
||||
* Triggered upon feature draw abortion
|
||||
* @event DrawEvent#drawabort
|
||||
* @api
|
||||
*/
|
||||
DRAWABORT: 'drawabort'
|
||||
};
|
||||
|
||||
|
||||
@@ -505,7 +511,7 @@ class Draw extends PointerInteraction {
|
||||
if (this.freehand_ &&
|
||||
event.type === MapBrowserEventType.POINTERDRAG &&
|
||||
this.sketchFeature_ !== null) {
|
||||
this.addToDrawing_(event);
|
||||
this.addToDrawing_(event.coordinate);
|
||||
pass = false;
|
||||
} else if (this.freehand_ &&
|
||||
event.type === MapBrowserEventType.POINTERDOWN) {
|
||||
@@ -580,12 +586,11 @@ class Draw extends PointerInteraction {
|
||||
this.finishDrawing();
|
||||
}
|
||||
} else {
|
||||
this.addToDrawing_(event);
|
||||
this.addToDrawing_(event.coordinate);
|
||||
}
|
||||
pass = false;
|
||||
} else if (this.freehand_) {
|
||||
this.finishCoordinate_ = null;
|
||||
this.abortDrawing_();
|
||||
this.abortDrawing();
|
||||
}
|
||||
if (!pass && this.stopClick_) {
|
||||
event.stopPropagation();
|
||||
@@ -764,13 +769,12 @@ class Draw extends PointerInteraction {
|
||||
|
||||
/**
|
||||
* Add a new coordinate to the drawing.
|
||||
* @param {import("../MapBrowserEvent.js").default} event Event.
|
||||
* @param {!PointCoordType} coordinate Coordinate
|
||||
* @private
|
||||
*/
|
||||
addToDrawing_(event) {
|
||||
const coordinate = event.coordinate;
|
||||
addToDrawing_(coordinate) {
|
||||
const geometry = this.sketchFeature_.getGeometry();
|
||||
const projection = event.map.getView().getProjection();
|
||||
const projection = this.getMap().getView().getProjection();
|
||||
let done;
|
||||
let coordinates;
|
||||
if (this.mode_ === Mode.LINE_STRING) {
|
||||
@@ -835,7 +839,7 @@ class Draw extends PointerInteraction {
|
||||
}
|
||||
|
||||
if (coordinates.length === 0) {
|
||||
this.finishCoordinate_ = null;
|
||||
this.abortDrawing();
|
||||
}
|
||||
|
||||
this.updateSketchFeatures_();
|
||||
@@ -903,9 +907,56 @@ class Draw extends PointerInteraction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extend an existing geometry by adding additional points. This only works
|
||||
* on features with `LineString` geometries, where the interaction will
|
||||
* extend lines by adding points to the end of the coordinates array.
|
||||
* Stop drawing without adding the sketch feature to the target layer.
|
||||
* @api
|
||||
*/
|
||||
abortDrawing() {
|
||||
const sketchFeature = this.abortDrawing_();
|
||||
if (sketchFeature) {
|
||||
this.dispatchEvent(new DrawEvent(DrawEventType.DRAWABORT, sketchFeature));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Append coordinates to the end of the geometry that is currently being drawn.
|
||||
* This can be used when drawing LineStrings or Polygons. Coordinates will
|
||||
* either be appended to the current LineString or the outer ring of the current
|
||||
* Polygon.
|
||||
* @param {!LineCoordType} coordinates Linear coordinates to be appended into
|
||||
* the coordinate array.
|
||||
* @api
|
||||
*/
|
||||
appendCoordinates(coordinates) {
|
||||
const mode = this.mode_;
|
||||
let sketchCoords = [];
|
||||
if (mode === Mode.LINE_STRING) {
|
||||
sketchCoords = /** @type {LineCoordType} */ this.sketchCoords_;
|
||||
} else if (mode === Mode.POLYGON) {
|
||||
sketchCoords = this.sketchCoords_ && this.sketchCoords_.length ? /** @type {PolyCoordType} */ (this.sketchCoords_)[0] : [];
|
||||
}
|
||||
|
||||
// Remove last coordinate from sketch drawing (this coordinate follows cursor position)
|
||||
const ending = sketchCoords.pop();
|
||||
|
||||
// Append coordinate list
|
||||
for (let i = 0; i < coordinates.length; i++) {
|
||||
this.addToDrawing_(coordinates[i]);
|
||||
}
|
||||
|
||||
// Duplicate last coordinate for sketch drawing
|
||||
this.addToDrawing_(ending);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate draw mode by starting from an existing geometry which will
|
||||
* receive new additional points. This only works on features with
|
||||
* `LineString` geometries, where the interaction will extend lines by adding
|
||||
* points to the end of the coordinates array.
|
||||
* This will change the original feature, instead of drawing a copy.
|
||||
*
|
||||
* The function will dispatch a `drawstart` event.
|
||||
*
|
||||
* @param {!Feature<LineString>} feature Feature to be extended.
|
||||
* @api
|
||||
*/
|
||||
@@ -948,7 +999,7 @@ class Draw extends PointerInteraction {
|
||||
const map = this.getMap();
|
||||
const active = this.getActive();
|
||||
if (!map || !active) {
|
||||
this.abortDrawing_();
|
||||
this.abortDrawing();
|
||||
}
|
||||
this.overlay_.setMap(active ? map : null);
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ export const Mode = {
|
||||
* takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
|
||||
* boolean to indicate whether that event should be handled. Default is
|
||||
* {@link module:ol/events/condition~always}.
|
||||
* In addition, if there is a `tabindex` attribute on the map element,
|
||||
* {@link module:ol/events/condition~focus} will also be applied.
|
||||
* @property {number} [maxDelta=1] Maximum mouse wheel delta.
|
||||
* @property {number} [duration=250] Animation duration in milliseconds.
|
||||
* @property {number} [timeout=80] Mouse wheel timeout duration in milliseconds.
|
||||
@@ -130,7 +132,7 @@ class MouseWheelZoom extends Interaction {
|
||||
* @private
|
||||
* @type {number}
|
||||
*/
|
||||
this.trackpadDeltaPerZoom_ = 300;
|
||||
this.deltaPerZoom_ = 300;
|
||||
|
||||
}
|
||||
|
||||
@@ -212,15 +214,18 @@ class MouseWheelZoom extends Interaction {
|
||||
Mode.WHEEL;
|
||||
}
|
||||
|
||||
if (this.mode_ === Mode.TRACKPAD) {
|
||||
const view = map.getView();
|
||||
if (this.mode_ === Mode.TRACKPAD && !view.getConstrainResolution()) {
|
||||
if (this.trackpadTimeoutId_) {
|
||||
clearTimeout(this.trackpadTimeoutId_);
|
||||
} else {
|
||||
if (view.getAnimating()) {
|
||||
view.cancelAnimations();
|
||||
}
|
||||
view.beginInteraction();
|
||||
}
|
||||
this.trackpadTimeoutId_ = setTimeout(this.endInteraction_.bind(this), this.trackpadEventGap_);
|
||||
view.adjustZoom(-delta / this.trackpadDeltaPerZoom_, this.lastAnchor_);
|
||||
this.trackpadTimeoutId_ = setTimeout(this.endInteraction_.bind(this), this.timeout_);
|
||||
view.adjustZoom(-delta / this.deltaPerZoom_, this.lastAnchor_);
|
||||
this.startTime_ = now;
|
||||
return false;
|
||||
}
|
||||
@@ -244,8 +249,13 @@ class MouseWheelZoom extends Interaction {
|
||||
if (view.getAnimating()) {
|
||||
view.cancelAnimations();
|
||||
}
|
||||
const delta = clamp(this.totalDelta_, -this.maxDelta_, this.maxDelta_);
|
||||
zoomByDelta(view, -delta, this.lastAnchor_, this.duration_);
|
||||
let delta = -clamp(this.totalDelta_, -this.maxDelta_ * this.deltaPerZoom_, this.maxDelta_ * this.deltaPerZoom_) / this.deltaPerZoom_;
|
||||
if (view.getConstrainResolution()) {
|
||||
// view has a zoom constraint, zoom by 1
|
||||
delta = delta ? delta > 0 ? 1 : -1 : 0;
|
||||
}
|
||||
zoomByDelta(view, delta, this.lastAnchor_, this.duration_);
|
||||
|
||||
this.mode_ = undefined;
|
||||
this.totalDelta_ = 0;
|
||||
this.lastAnchor_ = null;
|
||||
|
||||
@@ -61,7 +61,7 @@ const SelectEventType = {
|
||||
* @property {import("../style/Style.js").StyleLike} [style]
|
||||
* Style for the selected features. By default the default edit style is used
|
||||
* (see {@link module:ol/style}).
|
||||
* If set to `false` the selected feature's style will not change.
|
||||
* If set to a falsey value, the selected feature's style will not change.
|
||||
* @property {import("../events/condition.js").Condition} [removeCondition] A function
|
||||
* that takes an {@link module:ol/MapBrowserEvent~MapBrowserEvent} and returns a
|
||||
* boolean to indicate whether that event should be handled.
|
||||
@@ -133,6 +133,12 @@ class SelectEvent extends Event {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Original feature styles to reset to when features are no longer selected.
|
||||
* @type {Object.<number, import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction>}
|
||||
*/
|
||||
const originalFeatureStyles = {};
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
@@ -209,14 +215,6 @@ class Select extends Interaction {
|
||||
*/
|
||||
this.style_ = options.style !== undefined ? options.style : getDefaultStyleFunction();
|
||||
|
||||
/**
|
||||
* An association between selected feature (key)
|
||||
* and original style (value)
|
||||
* @private
|
||||
* @type {Object.<number, import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction>}
|
||||
*/
|
||||
this.featureStyleAssociation_ = {};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../Collection.js").default}
|
||||
@@ -319,11 +317,11 @@ class Select extends Interaction {
|
||||
setMap(map) {
|
||||
const currentMap = this.getMap();
|
||||
if (currentMap && this.style_) {
|
||||
this.features_.forEach(this.removeSelectedStyle_.bind(this));
|
||||
this.features_.forEach(this.restorePreviousStyle_.bind(this));
|
||||
}
|
||||
super.setMap(map);
|
||||
if (map && this.style_) {
|
||||
this.features_.forEach(this.giveSelectedStyle_.bind(this));
|
||||
this.features_.forEach(this.applySelectedStyle_.bind(this));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -334,7 +332,7 @@ class Select extends Interaction {
|
||||
addFeature_(evt) {
|
||||
const feature = evt.element;
|
||||
if (this.style_) {
|
||||
this.giveSelectedStyle_(feature);
|
||||
this.applySelectedStyle_(feature);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -345,17 +343,26 @@ class Select extends Interaction {
|
||||
removeFeature_(evt) {
|
||||
const feature = evt.element;
|
||||
if (this.style_) {
|
||||
this.removeSelectedStyle_(feature);
|
||||
this.restorePreviousStyle_(feature);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction|null} Select style.
|
||||
*/
|
||||
getStyle() {
|
||||
return this.style_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../Feature.js").default} feature Feature
|
||||
* @private
|
||||
*/
|
||||
giveSelectedStyle_(feature) {
|
||||
applySelectedStyle_(feature) {
|
||||
const key = getUid(feature);
|
||||
this.featureStyleAssociation_[key] = feature.getStyle();
|
||||
if (!(key in originalFeatureStyles)) {
|
||||
originalFeatureStyles[key] = feature.getStyle();
|
||||
}
|
||||
feature.setStyle(this.style_);
|
||||
}
|
||||
|
||||
@@ -363,10 +370,17 @@ class Select extends Interaction {
|
||||
* @param {import("../Feature.js").default} feature Feature
|
||||
* @private
|
||||
*/
|
||||
removeSelectedStyle_(feature) {
|
||||
restorePreviousStyle_(feature) {
|
||||
const key = getUid(feature);
|
||||
feature.setStyle(this.featureStyleAssociation_[key]);
|
||||
delete this.featureStyleAssociation_[key];
|
||||
const selectInteractions = /** @type {Array<Select>} */ (this.getMap().getInteractions().getArray().filter(function(interaction) {
|
||||
return interaction instanceof Select && interaction.getStyle() && interaction.getFeatures().getArray().indexOf(feature) !== -1;
|
||||
}));
|
||||
if (selectInteractions.length > 0) {
|
||||
feature.setStyle(selectInteractions[selectInteractions.length - 1].getStyle());
|
||||
} else {
|
||||
feature.setStyle(originalFeatureStyles[key]);
|
||||
delete originalFeatureStyles[key];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,10 @@ import Layer from './Layer.js';
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {import("../PluggableMap.js").default} [map] Sets the layer as overlay on a map. The map will not manage
|
||||
* this layer in its layers collection, and the layer will be rendered on top. This is useful for
|
||||
* temporary layers. The standard way to add a layer to a map and have it managed by the map is to
|
||||
|
||||
@@ -21,6 +21,10 @@ import {assign} from '../obj.js';
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {number} [preload=0] Preload. Load low-resolution tiles up to `preload` levels. `0`
|
||||
* means no preloading.
|
||||
* @property {import("../source/Tile.js").default} [source] Source for this layer.
|
||||
|
||||
@@ -21,6 +21,10 @@ import {createDefaultStyle, toFunction as toStyleFunction} from '../style/Style.
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting
|
||||
* features before rendering. By default features are drawn in the order that they are created. Use
|
||||
* `null` to avoid the sort, but get an undefined draw order.
|
||||
|
||||
@@ -15,15 +15,16 @@ import {
|
||||
getTransform,
|
||||
transformExtent
|
||||
} from '../proj.js';
|
||||
import {getCenter, intersects, equals, getIntersection, isEmpty} from '../extent.js';
|
||||
import {getCenter, getHeight, getWidth, intersects, equals, getIntersection, isEmpty} from '../extent.js';
|
||||
import {clamp} from '../math.js';
|
||||
import Style from '../style/Style.js';
|
||||
import Feature from '../Feature.js';
|
||||
import {bbox} from '../loadingstrategy.js';
|
||||
import {meridian, parallel} from '../geom/flat/geodesic.js';
|
||||
import GeometryLayout from '../geom/GeometryLayout.js';
|
||||
import Point from '../geom/Point.js';
|
||||
import Collection from '../Collection.js';
|
||||
import {getVectorContext} from '../render.js';
|
||||
import EventType from '../render/EventType.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -65,6 +66,10 @@ const INTERVALS = [
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {number} [maxLines=100] The maximum number of meridians and
|
||||
* parallels from the center of the map. The default value of 100 means that at
|
||||
* most 200 meridians and 200 parallels will be displayed. The default value is
|
||||
@@ -379,6 +384,8 @@ class Graticule extends VectorLayer {
|
||||
|
||||
this.meridiansLabels_ = [];
|
||||
this.parallelsLabels_ = [];
|
||||
|
||||
this.addEventListener(EventType.POSTRENDER, this.drawLabels_.bind(this));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -391,7 +398,7 @@ class Graticule extends VectorLayer {
|
||||
this.setSource(
|
||||
new VectorSource({
|
||||
loader: this.loaderFunction.bind(this),
|
||||
strategy: bbox,
|
||||
strategy: this.strategyFunction.bind(this),
|
||||
features: new Collection(),
|
||||
overlaps: false,
|
||||
useSpatialIndex: false,
|
||||
@@ -414,6 +421,12 @@ class Graticule extends VectorLayer {
|
||||
stroke: this.strokeStyle_
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {?import("../extent.js").Extent}
|
||||
* @private
|
||||
*/
|
||||
this.loadedExtent_ = null;
|
||||
|
||||
/**
|
||||
* @type {?import("../extent.js").Extent}
|
||||
*/
|
||||
@@ -421,7 +434,21 @@ class Graticule extends VectorLayer {
|
||||
|
||||
this.setRenderOrder(null);
|
||||
|
||||
this.tmpExtent_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Strategy function for loading features based on the view's extent and
|
||||
* resolution.
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @return {Array<import("../extent.js").Extent>} Extents.
|
||||
*/
|
||||
strategyFunction(extent, resolution) {
|
||||
if (this.loadedExtent_ && !equals(this.loadedExtent_, extent)) {
|
||||
// we should not keep track of loaded extents
|
||||
this.getSource().removeLoadedExtent(this.loadedExtent_);
|
||||
}
|
||||
return [extent];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -431,16 +458,12 @@ class Graticule extends VectorLayer {
|
||||
* @param {import("../proj/Projection.js").default} projection Projection
|
||||
*/
|
||||
loaderFunction(extent, resolution, projection) {
|
||||
this.loadedExtent_ = extent;
|
||||
const source = this.getSource();
|
||||
|
||||
// only consider the intersection between our own extent & the requested one
|
||||
const layerExtent = this.getExtent() || [-Infinity, -Infinity, Infinity, Infinity];
|
||||
const renderExtent = getIntersection(layerExtent, extent, this.tmpExtent_);
|
||||
|
||||
// we should not keep track of loaded extents
|
||||
setTimeout(function() {
|
||||
source.removeLoadedExtent(extent);
|
||||
}, 0);
|
||||
const renderExtent = getIntersection(layerExtent, extent);
|
||||
|
||||
if (this.renderedExtent_ && equals(this.renderedExtent_, renderExtent)) {
|
||||
return;
|
||||
@@ -468,10 +491,10 @@ class Graticule extends VectorLayer {
|
||||
// first make sure we have enough features in the pool
|
||||
let featureCount = this.meridians_.length + this.parallels_.length;
|
||||
if (this.meridiansLabels_) {
|
||||
featureCount += this.meridiansLabels_.length;
|
||||
featureCount += this.meridians_.length;
|
||||
}
|
||||
if (this.parallelsLabels_) {
|
||||
featureCount += this.parallelsLabels_.length;
|
||||
featureCount += this.parallels_.length;
|
||||
}
|
||||
|
||||
let feature;
|
||||
@@ -498,27 +521,6 @@ class Graticule extends VectorLayer {
|
||||
feature.setStyle(this.lineStyle_);
|
||||
featuresColl.push(feature);
|
||||
}
|
||||
let labelData;
|
||||
if (this.meridiansLabels_) {
|
||||
for (i = 0, l = this.meridiansLabels_.length; i < l; ++i) {
|
||||
labelData = this.meridiansLabels_[i];
|
||||
feature = this.featurePool_[poolIndex++];
|
||||
feature.setGeometry(labelData.geom);
|
||||
feature.setStyle(this.lonLabelStyle_);
|
||||
feature.set('graticule_label', labelData.text);
|
||||
featuresColl.push(feature);
|
||||
}
|
||||
}
|
||||
if (this.parallelsLabels_) {
|
||||
for (i = 0, l = this.parallelsLabels_.length; i < l; ++i) {
|
||||
labelData = this.parallelsLabels_[i];
|
||||
feature = this.featurePool_[poolIndex++];
|
||||
feature.setGeometry(labelData.geom);
|
||||
feature.setStyle(this.latLabelStyle_);
|
||||
feature.set('graticule_label', labelData.text);
|
||||
featuresColl.push(feature);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -535,12 +537,16 @@ class Graticule extends VectorLayer {
|
||||
const lineString = this.getMeridian_(lon, minLat, maxLat, squaredTolerance, index);
|
||||
if (intersects(lineString.getExtent(), extent)) {
|
||||
if (this.meridiansLabels_) {
|
||||
const textPoint = this.getMeridianPoint_(lineString, extent, index);
|
||||
const text = this.lonLabelFormatter_(lon);
|
||||
if (index in this.meridiansLabels_) {
|
||||
this.meridiansLabels_[index].text = text;
|
||||
} else {
|
||||
this.meridiansLabels_[index] = {
|
||||
geom: textPoint,
|
||||
text: this.lonLabelFormatter_(lon)
|
||||
geom: new Point([]),
|
||||
text: text
|
||||
};
|
||||
}
|
||||
}
|
||||
this.meridians_[index++] = lineString;
|
||||
}
|
||||
return index;
|
||||
@@ -560,17 +566,83 @@ class Graticule extends VectorLayer {
|
||||
const lineString = this.getParallel_(lat, minLon, maxLon, squaredTolerance, index);
|
||||
if (intersects(lineString.getExtent(), extent)) {
|
||||
if (this.parallelsLabels_) {
|
||||
const textPoint = this.getParallelPoint_(lineString, extent, index);
|
||||
const text = this.latLabelFormatter_(lat);
|
||||
if (index in this.parallelsLabels_) {
|
||||
this.parallelsLabels_[index].text = text;
|
||||
} else {
|
||||
this.parallelsLabels_[index] = {
|
||||
geom: textPoint,
|
||||
text: this.latLabelFormatter_(lat)
|
||||
geom: new Point([]),
|
||||
text: text
|
||||
};
|
||||
}
|
||||
}
|
||||
this.parallels_[index++] = lineString;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../render/Event.js").default} event Render event.
|
||||
* @private
|
||||
*/
|
||||
drawLabels_(event) {
|
||||
const rotation = event.frameState.viewState.rotation;
|
||||
const extent = event.frameState.extent;
|
||||
let rotationCenter, rotationExtent;
|
||||
if (rotation) {
|
||||
rotationCenter = getCenter(extent);
|
||||
const width = getWidth(extent);
|
||||
const height = getHeight(extent);
|
||||
const cr = Math.abs(Math.cos(rotation));
|
||||
const sr = Math.abs(Math.sin(rotation));
|
||||
const unrotatedWidth = (sr * height - cr * width) / (sr * sr - cr * cr);
|
||||
const unrotatedHeight = (sr * width - cr * height) / (sr * sr - cr * cr);
|
||||
rotationExtent = [
|
||||
rotationCenter[0] - unrotatedWidth / 2, rotationCenter[1] - unrotatedHeight / 2,
|
||||
rotationCenter[0] + unrotatedWidth / 2, rotationCenter[1] + unrotatedHeight / 2
|
||||
];
|
||||
}
|
||||
|
||||
const vectorContext = getVectorContext(event);
|
||||
let poolIndex = this.meridians_.length + this.parallels_.length;
|
||||
let feature, index, l, textPoint;
|
||||
|
||||
if (this.meridiansLabels_) {
|
||||
for (index = 0, l = this.meridiansLabels_.length; index < l; ++index) {
|
||||
const lineString = this.meridians_[index];
|
||||
if (!rotation) {
|
||||
textPoint = this.getMeridianPoint_(lineString, extent, index);
|
||||
} else {
|
||||
const clone = lineString.clone();
|
||||
clone.rotate(-rotation, rotationCenter);
|
||||
textPoint = this.getMeridianPoint_(clone, rotationExtent, index);
|
||||
textPoint.rotate(rotation, rotationCenter);
|
||||
}
|
||||
feature = this.featurePool_[poolIndex++];
|
||||
feature.setGeometry(textPoint);
|
||||
feature.set('graticule_label', this.meridiansLabels_[index].text);
|
||||
vectorContext.drawFeature(feature, this.lonLabelStyle_(feature));
|
||||
}
|
||||
}
|
||||
if (this.parallelsLabels_) {
|
||||
for (index = 0, l = this.parallels_.length; index < l; ++index) {
|
||||
const lineString = this.parallels_[index];
|
||||
if (!rotation) {
|
||||
textPoint = this.getParallelPoint_(lineString, extent, index);
|
||||
} else {
|
||||
const clone = lineString.clone();
|
||||
clone.rotate(-rotation, rotationCenter);
|
||||
textPoint = this.getParallelPoint_(clone, rotationExtent, index);
|
||||
textPoint.rotate(rotation, rotationCenter);
|
||||
}
|
||||
feature = this.featurePool_[poolIndex++];
|
||||
feature.setGeometry(textPoint);
|
||||
feature.set('graticule_label', this.parallelsLabels_[index].text);
|
||||
vectorContext.drawFeature(feature, this.latLabelStyle_(feature));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../extent.js").Extent} extent Extent.
|
||||
* @param {import("../coordinate.js").Coordinate} center Center.
|
||||
@@ -727,19 +799,23 @@ class Graticule extends VectorLayer {
|
||||
*/
|
||||
getMeridianPoint_(lineString, extent, index) {
|
||||
const flatCoordinates = lineString.getFlatCoordinates();
|
||||
const clampedBottom = Math.max(extent[1], flatCoordinates[1]);
|
||||
const clampedTop = Math.min(extent[3], flatCoordinates[flatCoordinates.length - 1]);
|
||||
let bottom = 1;
|
||||
let top = flatCoordinates.length - 1;
|
||||
if (flatCoordinates[bottom] > flatCoordinates[top]) {
|
||||
bottom = top;
|
||||
top = 1;
|
||||
}
|
||||
const clampedBottom = Math.max(extent[1], flatCoordinates[bottom]);
|
||||
const clampedTop = Math.min(extent[3], flatCoordinates[top]);
|
||||
const lat = clamp(
|
||||
extent[1] + Math.abs(extent[1] - extent[3]) * this.lonLabelPosition_,
|
||||
clampedBottom, clampedTop);
|
||||
const coordinate = [flatCoordinates[0], lat];
|
||||
let point;
|
||||
if (index in this.meridiansLabels_) {
|
||||
point = this.meridiansLabels_[index].geom;
|
||||
const coordinate0 = flatCoordinates[bottom - 1] +
|
||||
(flatCoordinates[top - 1] - flatCoordinates[bottom - 1]) * (lat - flatCoordinates[bottom]) /
|
||||
(flatCoordinates[top] - flatCoordinates[bottom]);
|
||||
const coordinate = [coordinate0, lat];
|
||||
const point = this.meridiansLabels_[index].geom;
|
||||
point.setCoordinates(coordinate);
|
||||
} else {
|
||||
point = new Point(coordinate);
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
@@ -783,19 +859,23 @@ class Graticule extends VectorLayer {
|
||||
*/
|
||||
getParallelPoint_(lineString, extent, index) {
|
||||
const flatCoordinates = lineString.getFlatCoordinates();
|
||||
const clampedLeft = Math.max(extent[0], flatCoordinates[0]);
|
||||
const clampedRight = Math.min(extent[2], flatCoordinates[flatCoordinates.length - 2]);
|
||||
let left = 0;
|
||||
let right = flatCoordinates.length - 2;
|
||||
if (flatCoordinates[left] > flatCoordinates[right]) {
|
||||
left = right;
|
||||
right = 0;
|
||||
}
|
||||
const clampedLeft = Math.max(extent[0], flatCoordinates[left]);
|
||||
const clampedRight = Math.min(extent[2], flatCoordinates[right]);
|
||||
const lon = clamp(
|
||||
extent[0] + Math.abs(extent[0] - extent[2]) * this.latLabelPosition_,
|
||||
clampedLeft, clampedRight);
|
||||
const coordinate = [lon, flatCoordinates[1]];
|
||||
let point;
|
||||
if (index in this.parallelsLabels_) {
|
||||
point = this.parallelsLabels_[index].geom;
|
||||
const coordinate1 = flatCoordinates[left + 1] +
|
||||
(flatCoordinates[right + 1] - flatCoordinates[left + 1]) * (lon - flatCoordinates[left]) /
|
||||
(flatCoordinates[right] - flatCoordinates[left]);
|
||||
const coordinate = [lon, coordinate1];
|
||||
const point = this.parallelsLabels_[index].geom;
|
||||
point.setCoordinates(coordinate);
|
||||
} else {
|
||||
point = new Point(coordinate);
|
||||
}
|
||||
return point;
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,10 @@ import SourceState from '../source/State.js';
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {Array<import("./Base.js").default>|import("../Collection.js").default<import("./Base.js").default>} [layers] Child layers.
|
||||
*/
|
||||
|
||||
|
||||
@@ -24,6 +24,10 @@ import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {Array<string>} [gradient=['#00f', '#0ff', '#0f0', '#ff0', '#f00']] The color gradient
|
||||
* of the heatmap, specified as an array of CSS color strings.
|
||||
* @property {number} [radius=8] Radius size in pixels.
|
||||
@@ -294,7 +298,9 @@ class Heatmap extends VectorLayer {
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
}`,
|
||||
uniforms: {
|
||||
u_gradientTexture: this.gradient_
|
||||
u_gradientTexture: function() {
|
||||
return this.gradient_;
|
||||
}.bind(this)
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -9,6 +9,7 @@ import LayerProperty from './Property.js';
|
||||
import {assign} from '../obj.js';
|
||||
import RenderEventType from '../render/EventType.js';
|
||||
import SourceState from '../source/State.js';
|
||||
import {assert} from '../asserts.js';
|
||||
|
||||
/**
|
||||
* @typedef {function(import("../PluggableMap.js").FrameState):HTMLElement} RenderFunction
|
||||
@@ -30,6 +31,10 @@ import SourceState from '../source/State.js';
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {import("../source/Source.js").default} [source] Source for this layer. If not provided to the constructor,
|
||||
* the source can be set by calling {@link module:ol/layer/Layer#setSource layer.setSource(source)} after
|
||||
* construction.
|
||||
@@ -243,7 +248,13 @@ class Layer extends BaseLayer {
|
||||
if (map) {
|
||||
this.mapPrecomposeKey_ = listen(map, RenderEventType.PRECOMPOSE, function(evt) {
|
||||
const renderEvent = /** @type {import("../render/Event.js").default} */ (evt);
|
||||
renderEvent.frameState.layerStatesArray.push(this.getLayerState(false));
|
||||
const layerStatesArray = renderEvent.frameState.layerStatesArray;
|
||||
const layerState = this.getLayerState(false);
|
||||
// A layer can only be added to the map once. Use either `layer.setMap()` or `map.addLayer()`, not both.
|
||||
assert(!layerStatesArray.some(function(arrayLayerState) {
|
||||
return arrayLayerState.layer === layerState.layer;
|
||||
}), 67);
|
||||
layerStatesArray.push(layerState);
|
||||
}, this);
|
||||
this.mapRenderKey_ = listen(this, EventType.CHANGE, map.render, map);
|
||||
this.changed();
|
||||
|
||||
@@ -20,6 +20,10 @@ import CanvasVectorImageLayerRenderer from '../renderer/canvas/VectorImageLayer.
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting
|
||||
* features before rendering. By default features are drawn in the order that they are created. Use
|
||||
* `null` to avoid the sort, but get an undefined draw order.
|
||||
|
||||
@@ -24,6 +24,10 @@ import {assign} from '../obj.js';
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {import("../render.js").OrderFunction} [renderOrder] Render order. Function to be used when sorting
|
||||
* features before rendering. By default features are drawn in the order that they are created. Use
|
||||
* `null` to avoid the sort, but get an undefined draw order.
|
||||
|
||||
@@ -23,6 +23,10 @@ import Layer from './Layer.js';
|
||||
* visible.
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {number} [minZoom] The minimum view zoom level (exclusive) above which this layer will be
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {import("../source/Vector.js").default} [source] Source.
|
||||
* @property {boolean} [disableHitDetection=false] Setting this to true will provide a slight performance boost, but will
|
||||
* prevent all hit detection on the layer.
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
import {getFontParameters} from '../css.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import {clear} from '../obj.js';
|
||||
import {create as createTransform} from '../transform.js';
|
||||
import LabelCache from './canvas/LabelCache.js';
|
||||
import BaseObject from '../Object.js';
|
||||
import EventTarget from '../events/Target.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -13,6 +13,12 @@ import LabelCache from './canvas/LabelCache.js';
|
||||
* @property {import("../colorlike.js").ColorLike} fillStyle
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Label
|
||||
* @property {number} width
|
||||
* @property {number} height
|
||||
* @property {Array<string|number>} contextInstructions
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} FillStrokeState
|
||||
@@ -164,21 +170,23 @@ export const defaultPadding = [0, 0, 0, 0];
|
||||
*/
|
||||
export const defaultLineWidth = 1;
|
||||
|
||||
/**
|
||||
* @type {BaseObject}
|
||||
*/
|
||||
export const checkedFonts = new BaseObject();
|
||||
|
||||
/**
|
||||
* The label cache for text rendering. To change the default cache size of 2048
|
||||
* entries, use {@link module:ol/structs/LRUCache#setSize}.
|
||||
* @type {LabelCache}
|
||||
* Deprecated - there is no label cache any more.
|
||||
* @type {?}
|
||||
* @api
|
||||
* @deprecated
|
||||
*/
|
||||
export const labelCache = new LabelCache();
|
||||
|
||||
|
||||
/**
|
||||
* @type {!Object<string, number>}
|
||||
*/
|
||||
export const checkedFonts = {};
|
||||
|
||||
export const labelCache = new EventTarget();
|
||||
labelCache.setSize = function() {
|
||||
console.warn('labelCache is deprecated.'); //eslint-disable-line
|
||||
};
|
||||
|
||||
/**
|
||||
* @type {CanvasRenderingContext2D}
|
||||
@@ -200,9 +208,8 @@ export const textHeights = {};
|
||||
* Clears the label cache when a font becomes available.
|
||||
* @param {string} fontSpec CSS font spec.
|
||||
*/
|
||||
export const checkFont = (function() {
|
||||
export const registerFont = (function() {
|
||||
const retries = 100;
|
||||
const checked = checkedFonts;
|
||||
const size = '32px ';
|
||||
const referenceFonts = ['monospace', 'serif'];
|
||||
const len = referenceFonts.length;
|
||||
@@ -235,19 +242,18 @@ export const checkFont = (function() {
|
||||
|
||||
function check() {
|
||||
let done = true;
|
||||
for (const font in checked) {
|
||||
if (checked[font] < retries) {
|
||||
const fonts = checkedFonts.getKeys();
|
||||
for (let i = 0, ii = fonts.length; i < ii; ++i) {
|
||||
const font = fonts[i];
|
||||
if (checkedFonts.get(font) < retries) {
|
||||
if (isAvailable.apply(this, font.split('\n'))) {
|
||||
checked[font] = retries;
|
||||
clear(textHeights);
|
||||
// Make sure that loaded fonts are picked up by Safari
|
||||
measureContext = null;
|
||||
measureFont = undefined;
|
||||
if (labelCache.getCount()) {
|
||||
labelCache.clear();
|
||||
}
|
||||
checkedFonts.set(font, retries);
|
||||
} else {
|
||||
++checked[font];
|
||||
checkedFonts.set(font, checkedFonts.get(font) + 1, true);
|
||||
done = false;
|
||||
}
|
||||
}
|
||||
@@ -267,10 +273,10 @@ export const checkFont = (function() {
|
||||
for (let i = 0, ii = families.length; i < ii; ++i) {
|
||||
const family = families[i];
|
||||
const key = font.style + '\n' + font.weight + '\n' + family;
|
||||
if (!(key in checked)) {
|
||||
checked[key] = retries;
|
||||
if (checkedFonts.get(key) === undefined) {
|
||||
checkedFonts.set(key, retries, true);
|
||||
if (!isAvailable(font.style, font.weight, family)) {
|
||||
checked[key] = 0;
|
||||
checkedFonts.set(key, 0, true);
|
||||
if (interval === undefined) {
|
||||
interval = setInterval(check, 32);
|
||||
}
|
||||
@@ -381,14 +387,11 @@ export function rotateAtOffset(context, rotation, offsetX, offsetY) {
|
||||
}
|
||||
|
||||
|
||||
export const resetTransform = createTransform();
|
||||
|
||||
|
||||
/**
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {import("../transform.js").Transform|null} transform Transform.
|
||||
* @param {number} opacity Opacity.
|
||||
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.
|
||||
* @param {Label|HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} labelOrImage Label.
|
||||
* @param {number} originX Origin X.
|
||||
* @param {number} originY Origin Y.
|
||||
* @param {number} w Width.
|
||||
@@ -397,23 +400,41 @@ export const resetTransform = createTransform();
|
||||
* @param {number} y Y.
|
||||
* @param {number} scale Scale.
|
||||
*/
|
||||
export function drawImage(context,
|
||||
transform, opacity, image, originX, originY, w, h, x, y, scale) {
|
||||
let alpha;
|
||||
if (opacity != 1) {
|
||||
alpha = context.globalAlpha;
|
||||
context.globalAlpha = alpha * opacity;
|
||||
export function drawImageOrLabel(context,
|
||||
transform, opacity, labelOrImage, originX, originY, w, h, x, y, scale) {
|
||||
context.save();
|
||||
|
||||
if (opacity !== 1) {
|
||||
context.globalAlpha *= opacity;
|
||||
}
|
||||
if (transform) {
|
||||
context.setTransform.apply(context, transform);
|
||||
}
|
||||
|
||||
context.drawImage(image, originX, originY, w, h, x, y, w * scale, h * scale);
|
||||
if ((/** @type {*} */ (labelOrImage).contextInstructions)) {
|
||||
// label
|
||||
context.translate(x, y);
|
||||
context.scale(scale, scale);
|
||||
executeLabelInstructions(/** @type {Label} */ (labelOrImage), context);
|
||||
} else {
|
||||
// image
|
||||
context.drawImage(/** @type {HTMLCanvasElement|HTMLImageElement|HTMLVideoElement} */ (labelOrImage), originX, originY, w, h, x, y, w * scale, h * scale);
|
||||
}
|
||||
|
||||
if (opacity != 1) {
|
||||
context.globalAlpha = alpha;
|
||||
context.restore();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Label} label Label.
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
*/
|
||||
function executeLabelInstructions(label, context) {
|
||||
const contextInstructions = label.contextInstructions;
|
||||
for (let i = 0, ii = contextInstructions.length; i < ii; i += 2) {
|
||||
if (Array.isArray(contextInstructions[i + 1])) {
|
||||
CanvasRenderingContext2D.prototype[contextInstructions[i]].apply(context, contextInstructions[i + 1]);
|
||||
} else {
|
||||
context[contextInstructions[i]] = contextInstructions[i + 1];
|
||||
}
|
||||
if (transform) {
|
||||
context.setTransform.apply(context, resetTransform);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import {createEmpty, createOrUpdate,
|
||||
import {lineStringLength} from '../../geom/flat/length.js';
|
||||
import {drawTextOnPath} from '../../geom/flat/textpath.js';
|
||||
import {transform2D} from '../../geom/flat/transform.js';
|
||||
import {drawImage, defaultPadding, defaultTextBaseline} from '../canvas.js';
|
||||
import {drawImageOrLabel, defaultPadding, defaultTextBaseline} from '../canvas.js';
|
||||
import CanvasInstruction from './Instruction.js';
|
||||
import {TEXT_ALIGN} from './TextBuilder.js';
|
||||
import {
|
||||
@@ -16,9 +16,7 @@ import {
|
||||
apply as applyTransform,
|
||||
setFromArray as transformSetFromArray
|
||||
} from '../../transform.js';
|
||||
import {createCanvasContext2D} from '../../dom.js';
|
||||
import {labelCache, defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||
import Disposable from '../../Disposable.js';
|
||||
import {defaultTextAlign, measureTextHeight, measureAndCacheTextWidth, measureTextWidths} from '../canvas.js';
|
||||
import RBush from 'rbush/rbush.js';
|
||||
|
||||
|
||||
@@ -52,7 +50,7 @@ const p3 = [];
|
||||
const p4 = [];
|
||||
|
||||
|
||||
class Executor extends Disposable {
|
||||
class Executor {
|
||||
/**
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
@@ -60,7 +58,6 @@ class Executor extends Disposable {
|
||||
* @param {SerializableInstructions} instructions The serializable instructions
|
||||
*/
|
||||
constructor(resolution, pixelRatio, overlaps, instructions) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @protected
|
||||
@@ -154,29 +151,26 @@ class Executor extends Disposable {
|
||||
* @type {Object<string, Object<string, number>>}
|
||||
*/
|
||||
this.widths_ = {};
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @private
|
||||
* @type {Object<string, import("../canvas.js").Label>}
|
||||
*/
|
||||
disposeInternal() {
|
||||
labelCache.release(this);
|
||||
super.disposeInternal();
|
||||
this.labels_ = {};
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param {string} text Text.
|
||||
* @param {string} textKey Text style key.
|
||||
* @param {string} fillKey Fill style key.
|
||||
* @param {string} strokeKey Stroke style key.
|
||||
* @return {HTMLCanvasElement} Image.
|
||||
* @return {import("../canvas.js").Label} Label.
|
||||
*/
|
||||
getTextImage(text, textKey, fillKey, strokeKey) {
|
||||
let label;
|
||||
const key = strokeKey + textKey + text + fillKey + this.pixelRatio;
|
||||
|
||||
if (!labelCache.containsKey(key)) {
|
||||
createLabel(text, textKey, fillKey, strokeKey) {
|
||||
const key = text + textKey + fillKey + strokeKey;
|
||||
if (this.labels_[key]) {
|
||||
return this.labels_[key];
|
||||
}
|
||||
const strokeState = strokeKey ? this.strokeStates[strokeKey] : null;
|
||||
const fillState = fillKey ? this.fillStates[fillKey] : null;
|
||||
const textState = this.textStates[textKey];
|
||||
@@ -192,47 +186,49 @@ class Executor extends Disposable {
|
||||
const lineHeight = measureTextHeight(textState.font);
|
||||
const height = lineHeight * numLines;
|
||||
const renderWidth = width + strokeWidth;
|
||||
const context = createCanvasContext2D(
|
||||
const contextInstructions = [];
|
||||
/** @type {import("../canvas.js").Label} */
|
||||
const label = {
|
||||
// make canvas 2 pixels wider to account for italic text width measurement errors
|
||||
Math.ceil((renderWidth + 2) * scale),
|
||||
Math.ceil((height + strokeWidth) * scale));
|
||||
label = context.canvas;
|
||||
labelCache.set(key, label);
|
||||
width: Math.ceil((renderWidth + 2) * scale),
|
||||
height: Math.ceil((height + strokeWidth) * scale),
|
||||
contextInstructions: contextInstructions
|
||||
};
|
||||
if (scale != 1) {
|
||||
context.scale(scale, scale);
|
||||
contextInstructions.push('scale', [scale, scale]);
|
||||
}
|
||||
context.font = textState.font;
|
||||
contextInstructions.push('font', textState.font);
|
||||
if (strokeKey) {
|
||||
context.strokeStyle = strokeState.strokeStyle;
|
||||
context.lineWidth = strokeWidth;
|
||||
context.lineCap = strokeState.lineCap;
|
||||
context.lineJoin = strokeState.lineJoin;
|
||||
context.miterLimit = strokeState.miterLimit;
|
||||
if (context.setLineDash && strokeState.lineDash.length) {
|
||||
context.setLineDash(strokeState.lineDash);
|
||||
context.lineDashOffset = strokeState.lineDashOffset;
|
||||
contextInstructions.push('strokeStyle', strokeState.strokeStyle);
|
||||
contextInstructions.push('lineWidth', strokeWidth);
|
||||
contextInstructions.push('lineCap', strokeState.lineCap);
|
||||
contextInstructions.push('lineJoin', strokeState.lineJoin);
|
||||
contextInstructions.push('miterLimit', strokeState.miterLimit);
|
||||
if (CanvasRenderingContext2D.prototype.setLineDash) {
|
||||
contextInstructions.push('setLineDash', [strokeState.lineDash]);
|
||||
contextInstructions.push('lineDashOffset', strokeState.lineDashOffset);
|
||||
}
|
||||
}
|
||||
if (fillKey) {
|
||||
context.fillStyle = fillState.fillStyle;
|
||||
contextInstructions.push('fillStyle', fillState.fillStyle);
|
||||
}
|
||||
context.textBaseline = 'middle';
|
||||
context.textAlign = 'center';
|
||||
contextInstructions.push('textBaseline', 'middle');
|
||||
contextInstructions.push('textAlign', 'center');
|
||||
const leftRight = (0.5 - align);
|
||||
const x = align * renderWidth + leftRight * strokeWidth;
|
||||
let i;
|
||||
if (strokeKey) {
|
||||
for (i = 0; i < numLines; ++i) {
|
||||
context.strokeText(lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight);
|
||||
contextInstructions.push('strokeText', [lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight]);
|
||||
}
|
||||
}
|
||||
if (fillKey) {
|
||||
for (i = 0; i < numLines; ++i) {
|
||||
context.fillText(lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight);
|
||||
contextInstructions.push('fillText', [lines[i], x + leftRight * widths[i], 0.5 * (strokeWidth + lineHeight) + i * lineHeight]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return labelCache.get(key, this);
|
||||
this.labels_[key] = label;
|
||||
return label;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -265,7 +261,7 @@ class Executor extends Disposable {
|
||||
* @param {CanvasRenderingContext2D} context Context.
|
||||
* @param {number} x X.
|
||||
* @param {number} y Y.
|
||||
* @param {HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} image Image.
|
||||
* @param {import("../canvas.js").Label|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement} imageOrLabel Image.
|
||||
* @param {number} anchorX Anchor X.
|
||||
* @param {number} anchorY Anchor Y.
|
||||
* @param {import("../canvas.js").DeclutterGroup} declutterGroup Declutter group.
|
||||
@@ -281,11 +277,11 @@ class Executor extends Disposable {
|
||||
* @param {Array<*>} fillInstruction Fill instruction.
|
||||
* @param {Array<*>} strokeInstruction Stroke instruction.
|
||||
*/
|
||||
replayImage_(
|
||||
replayImageOrLabel_(
|
||||
context,
|
||||
x,
|
||||
y,
|
||||
image,
|
||||
imageOrLabel,
|
||||
anchorX,
|
||||
anchorY,
|
||||
declutterGroup,
|
||||
@@ -307,8 +303,8 @@ class Executor extends Disposable {
|
||||
x -= anchorX;
|
||||
y -= anchorY;
|
||||
|
||||
const w = (width + originX > image.width) ? image.width - originX : width;
|
||||
const h = (height + originY > image.height) ? image.height - originY : height;
|
||||
const w = (width + originX > imageOrLabel.width) ? imageOrLabel.width - originX : width;
|
||||
const h = (height + originY > imageOrLabel.height) ? imageOrLabel.height - originY : height;
|
||||
const boxW = padding[3] + w * scale + padding[1];
|
||||
const boxH = padding[0] + h * scale + padding[2];
|
||||
const boxX = x - padding[3];
|
||||
@@ -362,11 +358,11 @@ class Executor extends Disposable {
|
||||
}
|
||||
extend(declutterGroup, tmpExtent);
|
||||
const declutterArgs = intersects ?
|
||||
[context, transform ? transform.slice(0) : null, opacity, image, originX, originY, w, h, x, y, scale] :
|
||||
[context, transform ? transform.slice(0) : null, opacity, imageOrLabel, originX, originY, w, h, x, y, scale] :
|
||||
null;
|
||||
if (declutterArgs) {
|
||||
if (fillStroke) {
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1, p2, p3, p4);
|
||||
declutterArgs.push(fillInstruction, strokeInstruction, p1.slice(0), p2.slice(0), p3.slice(0), p4.slice(0));
|
||||
}
|
||||
declutterGroup.push(declutterArgs);
|
||||
}
|
||||
@@ -376,7 +372,7 @@ class Executor extends Disposable {
|
||||
/** @type {Array<*>} */ (fillInstruction),
|
||||
/** @type {Array<*>} */ (strokeInstruction));
|
||||
}
|
||||
drawImage(context, transform, opacity, image, originX, originY, w, h, x, y, scale);
|
||||
drawImageOrLabel(context, transform, opacity, imageOrLabel, originX, originY, w, h, x, y, scale);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,7 +447,7 @@ class Executor extends Disposable {
|
||||
declutterData[13], declutterData[14], declutterData[15], declutterData[16],
|
||||
declutterData[11], declutterData[12]);
|
||||
}
|
||||
drawImage.apply(undefined, declutterData);
|
||||
drawImageOrLabel.apply(undefined, declutterData);
|
||||
if (currentAlpha !== opacity) {
|
||||
context.globalAlpha = currentAlpha;
|
||||
}
|
||||
@@ -470,12 +466,12 @@ class Executor extends Disposable {
|
||||
* @param {string} textKey The key of the text state.
|
||||
* @param {string} strokeKey The key for the stroke state.
|
||||
* @param {string} fillKey The key for the fill state.
|
||||
* @return {{label: HTMLCanvasElement, anchorX: number, anchorY: number}} The text image and its anchor.
|
||||
* @return {{label: import("../canvas.js").Label, anchorX: number, anchorY: number}} The text image and its anchor.
|
||||
*/
|
||||
drawTextImageWithPointPlacement_(text, textKey, strokeKey, fillKey) {
|
||||
drawLabelWithPointPlacement_(text, textKey, strokeKey, fillKey) {
|
||||
const textState = this.textStates[textKey];
|
||||
|
||||
const label = this.getTextImage(text, textKey, fillKey, strokeKey);
|
||||
const label = this.createLabel(text, textKey, fillKey, strokeKey);
|
||||
|
||||
const strokeState = this.strokeStates[strokeKey];
|
||||
const pixelRatio = this.pixelRatio;
|
||||
@@ -483,7 +479,7 @@ class Executor extends Disposable {
|
||||
const baseline = TEXT_ALIGN[textState.textBaseline || defaultTextBaseline];
|
||||
const strokeWidth = strokeState && strokeState.lineWidth ? strokeState.lineWidth : 0;
|
||||
|
||||
// Remove the 2 pixels we added in getTextImage() for the anchor
|
||||
// Remove the 2 pixels we added in createLabel() for the anchor
|
||||
const width = label.width / pixelRatio - 2 * textState.scale;
|
||||
const anchorX = align * width + 2 * (0.5 - align) * strokeWidth;
|
||||
const anchorY = baseline * label.height / pixelRatio + 2 * (0.5 - baseline) * strokeWidth;
|
||||
@@ -648,7 +644,7 @@ class Executor extends Disposable {
|
||||
textKey = /** @type {string} */ (instruction[19]);
|
||||
strokeKey = /** @type {string} */ (instruction[20]);
|
||||
fillKey = /** @type {string} */ (instruction[21]);
|
||||
const labelWithAnchor = this.drawTextImageWithPointPlacement_(text, textKey, strokeKey, fillKey);
|
||||
const labelWithAnchor = this.drawLabelWithPointPlacement_(text, textKey, strokeKey, fillKey);
|
||||
image = labelWithAnchor.label;
|
||||
instruction[3] = image;
|
||||
const textOffsetX = /** @type {number} */ (instruction[22]);
|
||||
@@ -701,7 +697,7 @@ class Executor extends Disposable {
|
||||
}
|
||||
declutterGroup = declutterGroups[index];
|
||||
}
|
||||
this.replayImage_(context,
|
||||
this.replayImageOrLabel_(context,
|
||||
pixelCoordinates[d], pixelCoordinates[d + 1], image, anchorX, anchorY,
|
||||
declutterGroup, height, opacity, originX, originY, rotation, scale,
|
||||
snapToPixel, width, padding,
|
||||
@@ -758,10 +754,10 @@ class Executor extends Disposable {
|
||||
for (c = 0, cc = parts.length; c < cc; ++c) {
|
||||
part = parts[c]; // x, y, anchorX, rotation, chunk
|
||||
chars = /** @type {string} */ (part[4]);
|
||||
label = this.getTextImage(chars, textKey, '', strokeKey);
|
||||
label = this.createLabel(chars, textKey, '', strokeKey);
|
||||
anchorX = /** @type {number} */ (part[2]) + strokeWidth;
|
||||
anchorY = baseline * label.height + (0.5 - baseline) * 2 * strokeWidth - offsetY;
|
||||
this.replayImage_(context,
|
||||
this.replayImageOrLabel_(context,
|
||||
/** @type {number} */ (part[0]), /** @type {number} */ (part[1]), label,
|
||||
anchorX, anchorY, declutterGroup, label.height, 1, 0, 0,
|
||||
/** @type {number} */ (part[3]), pixelRatioScale, false, label.width,
|
||||
@@ -772,10 +768,10 @@ class Executor extends Disposable {
|
||||
for (c = 0, cc = parts.length; c < cc; ++c) {
|
||||
part = parts[c]; // x, y, anchorX, rotation, chunk
|
||||
chars = /** @type {string} */ (part[4]);
|
||||
label = this.getTextImage(chars, textKey, fillKey, '');
|
||||
label = this.createLabel(chars, textKey, fillKey, '');
|
||||
anchorX = /** @type {number} */ (part[2]);
|
||||
anchorY = baseline * label.height - offsetY;
|
||||
this.replayImage_(context,
|
||||
this.replayImageOrLabel_(context,
|
||||
/** @type {number} */ (part[0]), /** @type {number} */ (part[1]), label,
|
||||
anchorX, anchorY, declutterGroup, label.height, 1, 0, 0,
|
||||
/** @type {number} */ (part[3]), pixelRatioScale, false, label.width,
|
||||
|
||||
@@ -10,7 +10,6 @@ import {isEmpty} from '../../obj.js';
|
||||
import BuilderType from './BuilderType.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../../transform.js';
|
||||
import Executor from './Executor.js';
|
||||
import Disposable from '../../Disposable.js';
|
||||
|
||||
/**
|
||||
* @const
|
||||
@@ -26,7 +25,7 @@ const ORDER = [
|
||||
];
|
||||
|
||||
|
||||
class ExecutorGroup extends Disposable {
|
||||
class ExecutorGroup {
|
||||
/**
|
||||
* @param {import("../../extent.js").Extent} maxExtent Max extent for clipping. When a
|
||||
* `maxExtent` was set on the Buillder for this executor group, the same `maxExtent`
|
||||
@@ -40,7 +39,6 @@ class ExecutorGroup extends Disposable {
|
||||
* @param {number=} opt_renderBuffer Optional rendering buffer.
|
||||
*/
|
||||
constructor(maxExtent, resolution, pixelRatio, overlaps, allInstructions, opt_renderBuffer) {
|
||||
super();
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -128,24 +126,6 @@ class ExecutorGroup extends Disposable {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
for (const z in this.executorsByZIndex_) {
|
||||
const executors = this.executorsByZIndex_[z];
|
||||
for (const key in executors) {
|
||||
executors[key].disposeInternal();
|
||||
}
|
||||
}
|
||||
if (this.hitDetectionContext_) {
|
||||
const canvas = this.hitDetectionContext_.canvas;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Array<BuilderType>} executors Executors.
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user