Compare commits
318 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4be8309f7 | ||
|
|
39a5511073 | ||
|
|
396f07bea1 | ||
|
|
33980d0ba8 | ||
|
|
7da86ae71f | ||
|
|
af15cfb815 | ||
|
|
600e1a4647 | ||
|
|
43010c8934 | ||
|
|
f7b0f6750b | ||
|
|
e5e03d46a0 | ||
|
|
e78c14c061 | ||
|
|
21f99e01c3 | ||
|
|
8098572346 | ||
|
|
ac50cc3460 | ||
|
|
06ae419db6 | ||
|
|
43d6247671 | ||
|
|
442213f85b | ||
|
|
2a96b6a8e3 | ||
|
|
89f92a53b4 | ||
|
|
9c26d9d7dd | ||
|
|
3de05c249b | ||
|
|
bb2bdb17aa | ||
|
|
b8c70bcbe7 | ||
|
|
c23d59e3a8 | ||
|
|
5dec336f94 | ||
|
|
e3f83f3601 | ||
|
|
3d0f7e4af8 | ||
|
|
4b13c6dae0 | ||
|
|
7097a4c6ba | ||
|
|
79ea5bf9cd | ||
|
|
97d0d277fb | ||
|
|
025b27bdec | ||
|
|
00af5a87be | ||
|
|
53f6359f8f | ||
|
|
bac3a8e9d8 | ||
|
|
66eedbfed2 | ||
|
|
7d7228d45c | ||
|
|
459efede60 | ||
|
|
b0ed775bc6 | ||
|
|
43ebfc4653 | ||
|
|
49c1486e06 | ||
|
|
3902759595 | ||
|
|
d71c733d9b | ||
|
|
90e1819d76 | ||
|
|
f84fae8f70 | ||
|
|
6c0dd6152d | ||
|
|
b96e70e952 | ||
|
|
501c90b0a2 | ||
|
|
2a2783c086 | ||
|
|
2f49876180 | ||
|
|
c7161acb6a | ||
|
|
db6314b6b2 | ||
|
|
65eb24da68 | ||
|
|
6652192647 | ||
|
|
bc34fe5b71 | ||
|
|
80b4473180 | ||
|
|
cd3b222467 | ||
|
|
6e4259359b | ||
|
|
a2e6119da1 | ||
|
|
c992cea9a4 | ||
|
|
ced327e9a0 | ||
|
|
df1fcc0d90 | ||
|
|
b13cbe8cb8 | ||
|
|
2abc88d41c | ||
|
|
3e0494aa9e | ||
|
|
aa5487b67b | ||
|
|
76333f72ba | ||
|
|
3ac08bcbef | ||
|
|
15a64e657d | ||
|
|
4f0431edd5 | ||
|
|
0f87df0ade | ||
|
|
1c21853269 | ||
|
|
1cd9256771 | ||
|
|
fcb95ced5f | ||
|
|
ffab886964 | ||
|
|
27cbbaf97b | ||
|
|
c0831cc64b | ||
|
|
c40263c38b | ||
|
|
daaf9695ff | ||
|
|
5d358a7367 | ||
|
|
80abb8fb15 | ||
|
|
e63bb45e6f | ||
|
|
edc02dbde2 | ||
|
|
4462608991 | ||
|
|
ff3cc9b4d0 | ||
|
|
a844691d7b | ||
|
|
acf973751b | ||
|
|
e843b2cfc0 | ||
|
|
719495587c | ||
|
|
9e010631c1 | ||
|
|
a64f2eb720 | ||
|
|
d643951a74 | ||
|
|
a39f751981 | ||
|
|
fc98704bcb | ||
|
|
27c530ec64 | ||
|
|
e3f7d29bb2 | ||
|
|
44347a9ed3 | ||
|
|
31dae929f5 | ||
|
|
5712792772 | ||
|
|
bcf7649b9a | ||
|
|
7e4119d580 | ||
|
|
72903d6454 | ||
|
|
35af80b433 | ||
|
|
ad6d91b9ae | ||
|
|
37cbb8e43e | ||
|
|
e0329febc4 | ||
|
|
cff00f1c3b | ||
|
|
61c4fa8cd6 | ||
|
|
cc24ec1be6 | ||
|
|
2b0256140e | ||
|
|
88bbb8c1ae | ||
|
|
e60dc93e0e | ||
|
|
599835e818 | ||
|
|
afa688273b | ||
|
|
6b4e00e6ac | ||
|
|
10379920d2 | ||
|
|
ebae0386bd | ||
|
|
bf7af07657 | ||
|
|
327fe11344 | ||
|
|
319efedb14 | ||
|
|
4fe16d0281 | ||
|
|
ce8b63a67e | ||
|
|
6b25f713cd | ||
|
|
4b79818797 | ||
|
|
062614388c | ||
|
|
8c5be52462 | ||
|
|
b6d694050e | ||
|
|
fc555241ea | ||
|
|
33b0f88771 | ||
|
|
1fe5a68e16 | ||
|
|
948003ff27 | ||
|
|
d837166a1b | ||
|
|
c659c05de8 | ||
|
|
485ade42b5 | ||
|
|
85c3aae454 | ||
|
|
a29fc016f5 | ||
|
|
19eadaea24 | ||
|
|
b8e8d30df0 | ||
|
|
f43637cc33 | ||
|
|
56faf4c3ad | ||
|
|
a0b271a812 | ||
|
|
a1c00744d1 | ||
|
|
94b8cf6af3 | ||
|
|
0c0c8c5d56 | ||
|
|
fef4d4e9b7 | ||
|
|
8e4fbe3e74 | ||
|
|
110c17cf9e | ||
|
|
e38250ee14 | ||
|
|
39012a58f8 | ||
|
|
7b66b294a8 | ||
|
|
9ee93cd2cf | ||
|
|
ed18310136 | ||
|
|
a3c137cff1 | ||
|
|
9eb4816b27 | ||
|
|
ee653a8e0d | ||
|
|
7edd10d66f | ||
|
|
e0cab3d3ba | ||
|
|
34ed3c684e | ||
|
|
d0811ea286 | ||
|
|
54c5330203 | ||
|
|
09768c6634 | ||
|
|
dfdb498d0d | ||
|
|
d1aec83ca2 | ||
|
|
2937513cb3 | ||
|
|
b46e985af0 | ||
|
|
e50662f0a1 | ||
|
|
bcdb191de2 | ||
|
|
775bf82631 | ||
|
|
fc9123947d | ||
|
|
636c65da69 | ||
|
|
adcbd0bb50 | ||
|
|
89c0eaef8d | ||
|
|
889eef66c1 | ||
|
|
de851e9b29 | ||
|
|
cb6b716b98 | ||
|
|
2980a0a168 | ||
|
|
829aac1860 | ||
|
|
3d351a53e6 | ||
|
|
a0ceebfb2f | ||
|
|
a9d93fe151 | ||
|
|
b4257779f1 | ||
|
|
0f3778ce00 | ||
|
|
36a366bfeb | ||
|
|
95bcb574b7 | ||
|
|
bd5510b62a | ||
|
|
a34e7ddd99 | ||
|
|
1de0d09acb | ||
|
|
2b1417df3f | ||
|
|
cfac31799b | ||
|
|
61fc71c30f | ||
|
|
9f3052211b | ||
|
|
4450981b0d | ||
|
|
54884314ee | ||
|
|
a75ea2cc6b | ||
|
|
aba93e7b9c | ||
|
|
90d6a6f441 | ||
|
|
7454df0c2f | ||
|
|
a126702e95 | ||
|
|
dd788b406c | ||
|
|
c97a26ae26 | ||
|
|
f475387d39 | ||
|
|
5af4dfa623 | ||
|
|
e3666f18da | ||
|
|
046b78cca7 | ||
|
|
b349058c58 | ||
|
|
8a53947f44 | ||
|
|
9acba8f82a | ||
|
|
0cb9d73848 | ||
|
|
7069e2688d | ||
|
|
0c72fce1ff | ||
|
|
87414256e2 | ||
|
|
9e7e15ed5c | ||
|
|
68850c7ddc | ||
|
|
f277206631 | ||
|
|
2a2cc40d42 | ||
|
|
395b59c01e | ||
|
|
58b4b6eeea | ||
|
|
5b1106ac23 | ||
|
|
2483fbd26b | ||
|
|
736ef88473 | ||
|
|
873999ec7d | ||
|
|
cbf0ecfd75 | ||
|
|
97ded06ee4 | ||
|
|
782ff6e9f5 | ||
|
|
dc2137b622 | ||
|
|
c5eb80e610 | ||
|
|
d1ee300968 | ||
|
|
b44a6ab26a | ||
|
|
3cb0aae796 | ||
|
|
490bef8d40 | ||
|
|
f477fc18f2 | ||
|
|
3c243b0236 | ||
|
|
e9785317eb | ||
|
|
315695eeb8 | ||
|
|
f20db28901 | ||
|
|
2ce14a50a1 | ||
|
|
057cc92716 | ||
|
|
5786121cd5 | ||
|
|
b727e4f45e | ||
|
|
fb9673465a | ||
|
|
babdce4819 | ||
|
|
684e305bc8 | ||
|
|
deb541791a | ||
|
|
db49842f63 | ||
|
|
8fe8302dc2 | ||
|
|
b1a9f765fc | ||
|
|
db583be0f9 | ||
|
|
d0cd1064ff | ||
|
|
b4a996e760 | ||
|
|
dee114d4c4 | ||
|
|
db34a338d6 | ||
|
|
0eac5007e8 | ||
|
|
c1921a6b16 | ||
|
|
dc28590cff | ||
|
|
3ab32ff744 | ||
|
|
daaaff5ac7 | ||
|
|
fa0258a323 | ||
|
|
4f83392b76 | ||
|
|
8a04f5059d | ||
|
|
92f70c225f | ||
|
|
41b7893523 | ||
|
|
89becd4c6d | ||
|
|
7eb60fae23 | ||
|
|
d7acbc40d5 | ||
|
|
176dccd6df | ||
|
|
526679433e | ||
|
|
b64ab8a6b2 | ||
|
|
6c6c4ab1df | ||
|
|
d3b47c794e | ||
|
|
8aa4a59fcf | ||
|
|
61e8b39626 | ||
|
|
8c7aafd4df | ||
|
|
37f9a6a6e9 | ||
|
|
2e1dee1994 | ||
|
|
ec9dcbee88 | ||
|
|
211c2ee531 | ||
|
|
e1d3560dbf | ||
|
|
1d6284725d | ||
|
|
c69201d5ad | ||
|
|
92e025b8e5 | ||
|
|
7c8b2215d4 | ||
|
|
d2b25533c2 | ||
|
|
733b883ac0 | ||
|
|
eaa5af2c7a | ||
|
|
1260dfc153 | ||
|
|
76df721b98 | ||
|
|
a55fec2759 | ||
|
|
c984b28752 | ||
|
|
3b02f5597e | ||
|
|
40f8510083 | ||
|
|
7f8fdd6219 | ||
|
|
ea0e1bff29 | ||
|
|
9b2089bc8f | ||
|
|
32644c7ba9 | ||
|
|
80b4f51d6e | ||
|
|
c8456868bd | ||
|
|
239f5745c1 | ||
|
|
70706443f5 | ||
|
|
47dd60104d | ||
|
|
d08c0baff9 | ||
|
|
80cf76e783 | ||
|
|
b045e4ee5b | ||
|
|
a7605c7447 | ||
|
|
76af2b6466 | ||
|
|
a996d62d46 | ||
|
|
f67476dd8f | ||
|
|
0e402073da | ||
|
|
07678d960a | ||
|
|
a47025b9c9 | ||
|
|
99c56a1f08 | ||
|
|
701dc3b54a | ||
|
|
ea88e6cbd4 | ||
|
|
b40709ea5b | ||
|
|
20de880d2b | ||
|
|
1827d7a0d9 | ||
|
|
400667fe95 | ||
|
|
d0a1fdc1d2 | ||
|
|
dd1243db73 |
7
.dependabot/config.yml
Normal file
@@ -0,0 +1,7 @@
|
||||
# See https://dependabot.com/docs/config-file/
|
||||
version: 1
|
||||
update_configs:
|
||||
- package_manager: "javascript"
|
||||
directory: "/"
|
||||
update_schedule: "weekly"
|
||||
version_requirement_updates: "increase_versions_if_necessary"
|
||||
4
.github/stale.yml
vendored
@@ -6,6 +6,10 @@ daysUntilClose: 7
|
||||
exemptLabels:
|
||||
- blocker
|
||||
- regression
|
||||
- bug
|
||||
- 'pull request accepted'
|
||||
# Issues assigned to a milestone will not go stale
|
||||
exemptMilestones: true
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
|
||||
34
changelog/v6.0.1.md
Normal file
@@ -0,0 +1,34 @@
|
||||
# 6.0.1
|
||||
|
||||
Hot on the heels of the 6.0 release, this patch release includes a few fixes for existing functionality. There should be nothing special needed to upgrade an application from 6.0.0 to 6.0.1. See the 6.0.0 release notes for details on upgrading from an older version.
|
||||
|
||||
## Changes
|
||||
|
||||
* [#10060](https://github.com/openlayers/openlayers/pull/10060) - Ensure zoom level is not less than minimum integer zoom level for extent ([@mike-000](https://github.com/mike-000))
|
||||
* [#10045](https://github.com/openlayers/openlayers/pull/10045) - Make the immediate API work with a user projection ([@tschaub](https://github.com/tschaub))
|
||||
* [#10068](https://github.com/openlayers/openlayers/pull/10068) - Update jsdoc-plugin-typescript to 2.0.3 ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10063](https://github.com/openlayers/openlayers/pull/10063) - Use the same spelling used elsewhere ([@tschaub](https://github.com/tschaub))
|
||||
* [#10067](https://github.com/openlayers/openlayers/pull/10067) - fixed jsdoc type annotations ([@KlausBenndorf](https://github.com/KlausBenndorf))
|
||||
* [#10057](https://github.com/openlayers/openlayers/pull/10057) - Remove unused test extensions ([@tschaub](https://github.com/tschaub))
|
||||
* [#10056](https://github.com/openlayers/openlayers/pull/10056) - Remove called assert extension ([@tschaub](https://github.com/tschaub))
|
||||
* [#10055](https://github.com/openlayers/openlayers/pull/10055) - Ensure proper tile load sequence ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10051](https://github.com/openlayers/openlayers/pull/10051) - Simplify the assertion ([@tschaub](https://github.com/tschaub))
|
||||
* [#10050](https://github.com/openlayers/openlayers/pull/10050) - Use expect().fail() instead of expect.fail() ([@tschaub](https://github.com/tschaub))
|
||||
* [#10048](https://github.com/openlayers/openlayers/pull/10048) - Early EMPTY state for VectorRenderTile ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10043](https://github.com/openlayers/openlayers/pull/10043) - User coordinates during snapping ([@tschaub](https://github.com/tschaub))
|
||||
* [#10042](https://github.com/openlayers/openlayers/pull/10042) - Better typing ([@fredj](https://github.com/fredj))
|
||||
* [#10040](https://github.com/openlayers/openlayers/pull/10040) - Additional tests for LineString ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10038](https://github.com/openlayers/openlayers/pull/10038) - do not stale issues with `bug` or `pull request accepted` labels ([@KlausBenndorf](https://github.com/KlausBenndorf))
|
||||
* [#10039](https://github.com/openlayers/openlayers/pull/10039) - 🚀 Release 6 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Dependency Updates</summary>
|
||||
|
||||
* [#10065](https://github.com/openlayers/openlayers/pull/10065) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10064](https://github.com/openlayers/openlayers/pull/10064) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10052](https://github.com/openlayers/openlayers/pull/10052) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10041](https://github.com/openlayers/openlayers/pull/10041) - Update handlebars to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
</details>
|
||||
86
changelog/v6.1.0.md
Normal file
@@ -0,0 +1,86 @@
|
||||
# 6.1.0
|
||||
|
||||
With 47 pull requests, this release keeps up the momentum of the v6.x effort and brings several bug fixes, performance improvements and new features. In addition to that, we added some missing documentation to our API docs and gave them some usability improvements.
|
||||
|
||||
## New features
|
||||
|
||||
* A new, performance optimized hit detection API on the layer level, `Layer#getFeatures(pixel)` has been introduced. At this point it is implemented for vector, vector tile and image vector layers, and is recommended when performance is critical, e.g. for hit detection on mouseover.
|
||||
* For the WebGLPoints layer, we made several additions to the style expressions system. This includes a `case` operator, support for array and string types, and type checking.
|
||||
|
||||
## List of all changes
|
||||
|
||||
* [#10214](https://github.com/openlayers/openlayers/pull/10214) - WebGL / Add 'case' operator for style expressions ([@jahow](https://github.com/jahow))
|
||||
* [#10198](https://github.com/openlayers/openlayers/pull/10198) - WebGL renderer / use the specified loading strategy for the vector data ([@jahow](https://github.com/jahow))
|
||||
* [#10212](https://github.com/openlayers/openlayers/pull/10212) - Add config file for dependabot ([@fredj](https://github.com/fredj))
|
||||
* [#10187](https://github.com/openlayers/openlayers/pull/10187) - Set touch-action to allow native touch gestures ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10194](https://github.com/openlayers/openlayers/pull/10194) - Added check to make sure extent array has four objects. ([@MrSoUndso](https://github.com/MrSoUndso))
|
||||
* [#10204](https://github.com/openlayers/openlayers/pull/10204) - Avoid scrolling over navigation ([@tschaub](https://github.com/tschaub))
|
||||
* [#10205](https://github.com/openlayers/openlayers/pull/10205) - Add the default to the type column ([@tschaub](https://github.com/tschaub))
|
||||
* [#10178](https://github.com/openlayers/openlayers/pull/10178) - Make ol/interaction/Select#handleEvent return always true. ([@TieSKey](https://github.com/TieSKey))
|
||||
* [#10203](https://github.com/openlayers/openlayers/pull/10203) - Keep issues assigned to a milestone from going stale ([@tschaub](https://github.com/tschaub))
|
||||
* [#10200](https://github.com/openlayers/openlayers/pull/10200) - Carbon add on API docs ([@tschaub](https://github.com/tschaub))
|
||||
* [#10196](https://github.com/openlayers/openlayers/pull/10196) - Webgl / add support for string and arrays in style expressions ([@jahow](https://github.com/jahow))
|
||||
* [#10197](https://github.com/openlayers/openlayers/pull/10197) - Restore node v8 compatibility ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10195](https://github.com/openlayers/openlayers/pull/10195) - Treat hsl/hsla as named colors ([@mike-000](https://github.com/mike-000))
|
||||
* [#10188](https://github.com/openlayers/openlayers/pull/10188) - Document that map render events do not have a context set ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10184](https://github.com/openlayers/openlayers/pull/10184) - Clamp the weight value between 0 and 1 ([@fredj](https://github.com/fredj))
|
||||
* [#10175](https://github.com/openlayers/openlayers/pull/10175) - Remove description from type tag ([@tschaub](https://github.com/tschaub))
|
||||
* [#10176](https://github.com/openlayers/openlayers/pull/10176) - Avoid toggling when clicking the title ([@tschaub](https://github.com/tschaub))
|
||||
* [#10172](https://github.com/openlayers/openlayers/pull/10172) - Ensure inherited docs are shown ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10171](https://github.com/openlayers/openlayers/pull/10171) - Open default attributions links in a new tab or window ([@mike-000](https://github.com/mike-000))
|
||||
* [#10047](https://github.com/openlayers/openlayers/pull/10047) - Apidoc changes ([@KaiVolland](https://github.com/KaiVolland))
|
||||
* [#10161](https://github.com/openlayers/openlayers/pull/10161) - Implement getFeatures() for ol/layer/VectorImage ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10168](https://github.com/openlayers/openlayers/pull/10168) - Webgl / Add support for filtering and color interpolation in style expressions ([@jahow](https://github.com/jahow))
|
||||
* [#10170](https://github.com/openlayers/openlayers/pull/10170) - Add back html from select-features example ([@openlayers](https://github.com/openlayers))
|
||||
* [#10093](https://github.com/openlayers/openlayers/pull/10093) - Set label text for Graticule option styles ([@mike-000](https://github.com/mike-000))
|
||||
* [#10160](https://github.com/openlayers/openlayers/pull/10160) - Improve test in case of async call ([@ejn](https://github.com/ejn))
|
||||
* [#10159](https://github.com/openlayers/openlayers/pull/10159) - Fix target name collision in event.Target and Control ([@ejn](https://github.com/ejn))
|
||||
* [#10142](https://github.com/openlayers/openlayers/pull/10142) - Fix tilechange events ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10138](https://github.com/openlayers/openlayers/pull/10138) - Should be able to ovveride defaultvalue of style in selection. ([@wirdehall](https://github.com/wirdehall))
|
||||
* [#10135](https://github.com/openlayers/openlayers/pull/10135) - Revise the description of applyTransform for geometries ([@mike-000](https://github.com/mike-000))
|
||||
* [#10133](https://github.com/openlayers/openlayers/pull/10133) - Properly unregister source tile change listeners ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10094](https://github.com/openlayers/openlayers/pull/10094) - New Layer#getFeatures method with fast hit detection ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10104](https://github.com/openlayers/openlayers/pull/10104) - Remove font sizing from the attribution control ([@openlayers](https://github.com/openlayers))
|
||||
* [#10108](https://github.com/openlayers/openlayers/pull/10108) - Fix documentation for handleMoveEvent ([@notnotse](https://github.com/notnotse))
|
||||
* [#10118](https://github.com/openlayers/openlayers/pull/10118) - Document the OSM crossOrigin default ([@mike-000](https://github.com/mike-000))
|
||||
* [#10112](https://github.com/openlayers/openlayers/pull/10112) - No ERROR state for render tiles ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10115](https://github.com/openlayers/openlayers/pull/10115) - Improve Heatmap hit detection test ([@jahow](https://github.com/jahow))
|
||||
* [#10111](https://github.com/openlayers/openlayers/pull/10111) - Correct the defaulting of ol/source/VectorTile maxZoom ([@mike-000](https://github.com/mike-000))
|
||||
* [#10102](https://github.com/openlayers/openlayers/pull/10102) - Cosmetic type fixes ([@KlausBenndorf](https://github.com/KlausBenndorf))
|
||||
* [#10107](https://github.com/openlayers/openlayers/pull/10107) - Update Vector Tile Info example test for no features ([@mike-000](https://github.com/mike-000))
|
||||
* [#10097](https://github.com/openlayers/openlayers/pull/10097) - Align layer canvas to the left ([@fredj](https://github.com/fredj))
|
||||
* [#10101](https://github.com/openlayers/openlayers/pull/10101) - Add hit detection support on the Heatmap layer ([@jahow](https://github.com/jahow))
|
||||
* [#10087](https://github.com/openlayers/openlayers/pull/10087) - Add example showing vector tiles in EPSG:4326 ([@petrsloup](https://github.com/petrsloup))
|
||||
* [#10086](https://github.com/openlayers/openlayers/pull/10086) - Update mapbox-style example ([@petrsloup](https://github.com/petrsloup))
|
||||
* [#10083](https://github.com/openlayers/openlayers/pull/10083) - webgl points layer example fixes ([@MoonE](https://github.com/MoonE))
|
||||
* [#10076](https://github.com/openlayers/openlayers/pull/10076) - Remove unnecessary typecast ([@fredj](https://github.com/fredj))
|
||||
* [#10074](https://github.com/openlayers/openlayers/pull/10074) - Remove offsets from mouse position calculation ([@mike-000](https://github.com/mike-000))
|
||||
* [#10072](https://github.com/openlayers/openlayers/pull/10072) - Better typing ([@fredj](https://github.com/fredj))
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Dependency Updates</summary>
|
||||
|
||||
* [#10208](https://github.com/openlayers/openlayers/pull/10208) - Bump pixelmatch from 5.0.2 to 5.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10210](https://github.com/openlayers/openlayers/pull/10210) - Bump glob from 7.1.4 to 7.1.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10209](https://github.com/openlayers/openlayers/pull/10209) - Bump karma from 4.1.0 to 4.4.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10207](https://github.com/openlayers/openlayers/pull/10207) - Bump ol-mapbox-style from 5.0.0-beta.3 to 5.0.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10157](https://github.com/openlayers/openlayers/pull/10157) - Bump karma-coverage-istanbul-reporter from 2.0.5 to 2.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10155](https://github.com/openlayers/openlayers/pull/10155) - Bump @types/pbf from 3.0.1 to 3.0.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10153](https://github.com/openlayers/openlayers/pull/10153) - Bump yargs from 14.0.0 to 14.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10154](https://github.com/openlayers/openlayers/pull/10154) - Bump @babel/core from 7.4.4 to 7.6.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10151](https://github.com/openlayers/openlayers/pull/10151) - Bump rollup-plugin-babel from 4.3.2 to 4.3.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10148](https://github.com/openlayers/openlayers/pull/10148) - Bump rollup-plugin-node-resolve from 5.0.0 to 5.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10150](https://github.com/openlayers/openlayers/pull/10150) - Bump copy-webpack-plugin from 5.0.3 to 5.0.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10149](https://github.com/openlayers/openlayers/pull/10149) - Bump rbush from 3.0.0 to 3.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10147](https://github.com/openlayers/openlayers/pull/10147) - Bump rollup from 1.12.0 to 1.25.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10145](https://github.com/openlayers/openlayers/pull/10145) - Greenkeeper/handlebars 4.4.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10132](https://github.com/openlayers/openlayers/pull/10132) - Update webpack to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10143](https://github.com/openlayers/openlayers/pull/10143) - Update mocha to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10117](https://github.com/openlayers/openlayers/pull/10117) - Update pbf to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10114](https://github.com/openlayers/openlayers/pull/10114) - Update coveralls to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10116](https://github.com/openlayers/openlayers/pull/10116) - Update webpack to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
* [#10105](https://github.com/openlayers/openlayers/pull/10105) - Update jsdoc-plugin-typescript to the latest version 🚀 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
</details>
|
||||
17
changelog/v6.1.1.md
Normal file
@@ -0,0 +1,17 @@
|
||||
# 6.1.1
|
||||
|
||||
Hot on the heels of OpenLayers 6.x, this patch release includes a few fixes for existing functionality. There should be nothing special needed to upgrade an application from 6.x to 6.1.1. See the 6.0.0 release notes for details on upgrading from an older version.
|
||||
|
||||
## Changes
|
||||
|
||||
* [#10235](https://github.com/openlayers/openlayers/pull/10235) - Various optimizations and fixes for the WebGL points renderer ([@jahow](https://github.com/jahow))
|
||||
* [#10244](https://github.com/openlayers/openlayers/pull/10244) - Update to new eslint config with no-multi-assign ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10243](https://github.com/openlayers/openlayers/pull/10243) - Store correct font value ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10239](https://github.com/openlayers/openlayers/pull/10239) - Simpler container reuse ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10237](https://github.com/openlayers/openlayers/pull/10237) - Fix layer zIndex test with falsy values ([@fredj](https://github.com/fredj))
|
||||
* [#10221](https://github.com/openlayers/openlayers/pull/10221) - Fix for undefined Source ([@Kai-W](https://github.com/Kai-W))
|
||||
* [#10228](https://github.com/openlayers/openlayers/pull/10228) - Use render tiles instead of source tiles for hit detection ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10226](https://github.com/openlayers/openlayers/pull/10226) - ABORT reproj tiles properly ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10224](https://github.com/openlayers/openlayers/pull/10224) - Vector tile hit detection fixes ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#10218](https://github.com/openlayers/openlayers/pull/10218) - Documentation fixes in ol/style/expressions ([@fredj](https://github.com/fredj))
|
||||
* [#10216](https://github.com/openlayers/openlayers/pull/10216) - Update changelog script to recognize dependabot instead of greenkeeper ([@ahocevar](https://github.com/ahocevar))
|
||||
@@ -1,9 +0,0 @@
|
||||
@navWidth: 250px;
|
||||
@colorSubtitle: rgb(119, 156, 52);
|
||||
@colorRed: rgb(238, 125, 125);
|
||||
@colorLink: #2a6496;
|
||||
@colorBgNavi: #2a2a2a;
|
||||
|
||||
.font-description () {
|
||||
font-family: "freight-text-pro",Georgia,Cambria,"Times New Roman",Times,serif
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
@import "common.less";
|
||||
|
||||
footer {
|
||||
margin: 15px 0;
|
||||
padding-top: 15px;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
.font-description();
|
||||
font-size: 0.8em;
|
||||
color: gray;
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
@import "common.less";
|
||||
|
||||
// normalize
|
||||
html, body {
|
||||
font: 1em "jaf-bernino-sans","Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif;
|
||||
background-color: #fff;
|
||||
}
|
||||
ul, ol {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
li {
|
||||
list-style-type: none;
|
||||
}
|
||||
|
||||
#wrap {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
@import "navigation.less";
|
||||
@import "main.less";
|
||||
@import "footer.less";
|
||||
@@ -1,288 +0,0 @@
|
||||
@import "common.less";
|
||||
|
||||
.main {
|
||||
padding: 20px 20px;
|
||||
margin-left: @navWidth;
|
||||
.page-title {
|
||||
display: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-weight: bold;
|
||||
font-size: 1.6em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-weight: bold;
|
||||
font-size: 1.5em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-weight: bold;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-weight: bold;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
dd {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
h4.name {
|
||||
span.type-signature {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: gray;
|
||||
color: #fff;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
span.type {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
span.glyphicon {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
color: #e1e1e1;
|
||||
margin-left: 7px;
|
||||
}
|
||||
|
||||
span.returnType {
|
||||
margin-left: 3px;
|
||||
background-color: transparent!important;
|
||||
color: gray!important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
span.static {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: @colorSubtitle!important;
|
||||
color: #fff;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
span.number {
|
||||
background-color: #ccc!important;
|
||||
color: #2fa2b1!important;
|
||||
}
|
||||
|
||||
span.string {
|
||||
background-color: #ccc!important;
|
||||
color: #2fa2b1!important;
|
||||
}
|
||||
|
||||
span.object {
|
||||
background-color: #ccc!important;
|
||||
color: #2fa2b1!important;
|
||||
}
|
||||
|
||||
span.array {
|
||||
background-color: #ccc!important;
|
||||
color: #2fa2b1!important;
|
||||
}
|
||||
|
||||
span.boolean {
|
||||
background-color: #ccc!important;
|
||||
color: #2fa2b1!important;
|
||||
}
|
||||
|
||||
.subsection-title {
|
||||
font-size: 14px;
|
||||
margin-top: 30px;
|
||||
color: @colorSubtitle;
|
||||
}
|
||||
|
||||
.description {
|
||||
margin-top: 10px;
|
||||
// .font-description();
|
||||
font-size: 13px;
|
||||
|
||||
p {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-source {
|
||||
font-size: 12px;
|
||||
}
|
||||
dt.tag-source {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
dt.tag-todo {
|
||||
font-size: 10px;
|
||||
display: inline-block;
|
||||
background-color: @colorLink;
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.type-signature {
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.tag-deprecated {
|
||||
display: inline-block;
|
||||
font-size: 10px;
|
||||
}
|
||||
|
||||
.important {
|
||||
background-color: @colorRed;
|
||||
color: #fff;
|
||||
padding: 2px 4px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
|
||||
.nameContainer {
|
||||
position: relative;
|
||||
margin-top: 20px;
|
||||
padding-top: 5px;
|
||||
border-top: 1px solid #e1e1e1;
|
||||
|
||||
.inherited {
|
||||
display: inline-block;
|
||||
border-radius: 3px;
|
||||
background-color: #888!important;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 5px;
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.tag-source {
|
||||
position: absolute;
|
||||
top: 17px;
|
||||
right: 0;
|
||||
font-size: 10px;
|
||||
a {
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
&.inherited {
|
||||
color: gray;
|
||||
}
|
||||
|
||||
h4 {
|
||||
margin-right: 150px;
|
||||
line-height: 1.3;
|
||||
|
||||
.signature {
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
font-family: Menlo,Monaco,Consolas,"Courier New",monospace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
margin-bottom: 15px;
|
||||
|
||||
th {
|
||||
padding: 3px 3px;
|
||||
}
|
||||
|
||||
td {
|
||||
vertical-align: top;
|
||||
padding: 5px 3px;
|
||||
}
|
||||
|
||||
.name {
|
||||
width: 110px;
|
||||
}
|
||||
|
||||
.type {
|
||||
width: 60px;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.attributes {
|
||||
width: 80px;
|
||||
color: #aaa;
|
||||
font-size: 11px;
|
||||
}
|
||||
|
||||
.description {
|
||||
font-size: 12px;
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.optional {
|
||||
float: left;
|
||||
border-radius: 3px;
|
||||
background-color: #ddd!important;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
margin-right: 5px;
|
||||
color: gray;
|
||||
}
|
||||
}
|
||||
|
||||
.readme {
|
||||
p {
|
||||
margin-top: 15px;
|
||||
line-height: 1.2;
|
||||
font-size: 0.85em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 1.7em;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 10px;
|
||||
padding-bottom: 10px;
|
||||
border-bottom: 1px solid #e1e1e1;
|
||||
}
|
||||
|
||||
li {
|
||||
font-size: 0.9em;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
article {
|
||||
ol, ul {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
ol > li {
|
||||
list-style-type: decimal;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
ul > li {
|
||||
margin-bottom: 5px;
|
||||
list-style-type: disc;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,103 +0,0 @@
|
||||
@import "common.less";
|
||||
|
||||
::-webkit-scrollbar {
|
||||
width: 8px;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
::-webkit-scrollbar-thumb {
|
||||
background-color: gray;
|
||||
border-radius: 4px;
|
||||
}
|
||||
|
||||
.navigation {
|
||||
position: fixed;
|
||||
float: left;
|
||||
width: @navWidth;
|
||||
height: 100%;
|
||||
background-color: @colorBgNavi;
|
||||
|
||||
.applicationName {
|
||||
margin: 0;
|
||||
margin-top: 15px;
|
||||
padding: 10px 15px;
|
||||
font: bold 1.25em Helvetica;
|
||||
color: #fff;
|
||||
|
||||
a {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
|
||||
.search {
|
||||
padding: 10px 15px;
|
||||
|
||||
input {
|
||||
background-color: #333;
|
||||
color: #fff;
|
||||
border-color: #555;
|
||||
}
|
||||
}
|
||||
|
||||
.list {
|
||||
padding: 10px 15px 0 15px;
|
||||
position: relative;
|
||||
overflow: auto;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
li.item {
|
||||
margin-bottom: 8px;
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #333;
|
||||
|
||||
a {
|
||||
color: #bbb;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
.title {
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
a {
|
||||
color: #e1e1e1;
|
||||
&:hover {
|
||||
color: #fff;
|
||||
}
|
||||
}
|
||||
display: block;
|
||||
font-size: 0.8em;
|
||||
|
||||
.static {
|
||||
display: block;
|
||||
border-radius: 3px;
|
||||
background-color: @colorSubtitle;
|
||||
color: #000;
|
||||
font-size: 0.7em;
|
||||
padding: 2px 4px;
|
||||
float: right;
|
||||
}
|
||||
}
|
||||
|
||||
.subtitle {
|
||||
margin-top: 10px;
|
||||
font: bold 0.65em Helvetica;
|
||||
color: @colorSubtitle;
|
||||
display: block;
|
||||
}
|
||||
|
||||
|
||||
ul {
|
||||
& > li {
|
||||
font-size: 0.7em;
|
||||
padding-left: 8px;
|
||||
margin-top: 2px;
|
||||
}
|
||||
}
|
||||
|
||||
.itemMembers {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -215,38 +215,74 @@ function buildNav(members) {
|
||||
return 0;
|
||||
});
|
||||
|
||||
function createEntry(type, v) {
|
||||
return {
|
||||
type: type,
|
||||
longname: v.longname,
|
||||
name: v.name,
|
||||
classes: find({
|
||||
kind: 'class',
|
||||
memberof: v.longname
|
||||
}).map(createEntry.bind(this, 'class')),
|
||||
members: find({
|
||||
kind: 'member',
|
||||
memberof: v.longname
|
||||
}),
|
||||
methods: find({
|
||||
kind: 'function',
|
||||
memberof: v.longname
|
||||
}),
|
||||
typedefs: find({
|
||||
kind: 'typedef',
|
||||
memberof: v.longname
|
||||
}),
|
||||
events: find({
|
||||
kind: 'event',
|
||||
memberof: v.longname
|
||||
})
|
||||
};
|
||||
}
|
||||
_.each(merged, function(v) {
|
||||
// exclude interfaces from sidebar
|
||||
if (v.interface !== true) {
|
||||
if (v.kind == 'module') {
|
||||
nav.push(createEntry('module', v));
|
||||
if (v.interface !== true && v.kind === 'class') {
|
||||
nav.push({
|
||||
type: 'class',
|
||||
longname: v.longname,
|
||||
prettyname: v.longname
|
||||
.split('~')[0]
|
||||
.replace('module:', ''),
|
||||
name: v.name,
|
||||
module: find({
|
||||
kind: 'module',
|
||||
longname: v.memberof
|
||||
})[0],
|
||||
members: find({
|
||||
kind: 'member',
|
||||
memberof: v.longname
|
||||
}),
|
||||
methods: find({
|
||||
kind: 'function',
|
||||
memberof: v.longname
|
||||
}),
|
||||
typedefs: find({
|
||||
kind: 'typedef',
|
||||
memberof: v.longname
|
||||
}),
|
||||
fires: v.fires,
|
||||
events: find({
|
||||
kind: 'event',
|
||||
memberof: v.longname
|
||||
})
|
||||
});
|
||||
} else if (v.kind == 'module') {
|
||||
const classes = find({
|
||||
kind: 'class',
|
||||
memberof: v.longname
|
||||
});
|
||||
const members = find({
|
||||
kind: 'member',
|
||||
memberof: v.longname
|
||||
});
|
||||
const methods = find({
|
||||
kind: 'function',
|
||||
memberof: v.longname
|
||||
});
|
||||
const typedefs = find({
|
||||
kind: 'typedef',
|
||||
memberof: v.longname
|
||||
});
|
||||
const events = find({
|
||||
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)) {
|
||||
nav.push({
|
||||
type: 'module',
|
||||
longname: v.longname,
|
||||
prettyname: v.longname
|
||||
.split('~')[0]
|
||||
.replace('module:', ''),
|
||||
name: v.name,
|
||||
members: members,
|
||||
methods: methods,
|
||||
typedefs: typedefs,
|
||||
fires: v.fires,
|
||||
events: events
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,121 +1,158 @@
|
||||
$(function () {
|
||||
// Search Items
|
||||
$('#search').on('keyup', function (e) {
|
||||
var value = $(this).val();
|
||||
var $el = $('.navigation');
|
||||
// Search Items
|
||||
$('#include_modules').change(function (e) {
|
||||
console.log('change');
|
||||
if ($(this).is(':checked')) {
|
||||
|
||||
if (value) {
|
||||
var regexp = new RegExp(value, 'i');
|
||||
$el.find('li, .itemMembers').hide();
|
||||
} else {
|
||||
|
||||
$el.find('li').each(function (i, v) {
|
||||
var $item = $(v);
|
||||
}
|
||||
});
|
||||
|
||||
if ($item.data('name') && regexp.test($item.data('name'))) {
|
||||
const container = $item.parent().parent().parent();
|
||||
container.show();
|
||||
container.closest('.itemMembers').show();
|
||||
container.closest('.item').show();
|
||||
$item.show();
|
||||
$item.closest('.itemMembers').show();
|
||||
$item.closest('.item').show();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
$el.find('.item, .itemMembers').hide();
|
||||
$('.navigation>ul>li').show();
|
||||
var getSearchWeight = function (searchTerm, $matchedItem) {
|
||||
let weight = 0;
|
||||
// We could get smarter on the weight here
|
||||
if ($matchedItem.data('shortname')
|
||||
&& $matchedItem.data('shortname').toLowerCase() === searchTerm.toLowerCase()) {
|
||||
weight++;
|
||||
}
|
||||
return weight;
|
||||
};
|
||||
|
||||
// sort function callback
|
||||
var weightSorter = function (a, b) {
|
||||
var aW = $(a).data('weight') || 0;
|
||||
var bW = $(b).data('weight') || 0;
|
||||
return bW - aW;
|
||||
};
|
||||
|
||||
// Search Items
|
||||
$('#search').on('keyup', function (e) {
|
||||
var value = $(this).val();
|
||||
var $el = $('.navigation');
|
||||
|
||||
if (value && value.length > 1) {
|
||||
var regexp = new RegExp(value, 'i');
|
||||
$el.find('li, .itemMembers').hide();
|
||||
|
||||
$el.find('li').each(function (i, v) {
|
||||
const $item = $(v);
|
||||
const name = $item.data('name');
|
||||
|
||||
if (name && regexp.test(name)) {
|
||||
const $classEntry = $item.closest('.item');
|
||||
const $members = $item.closest('.itemMembers');
|
||||
|
||||
// Do the weight thing
|
||||
$classEntry.removeData('weight');
|
||||
$classEntry.show();
|
||||
const weight = getSearchWeight(value, $classEntry);
|
||||
$classEntry.data('weight', weight);
|
||||
|
||||
$members.show();
|
||||
$classEntry.show();
|
||||
$item.show();
|
||||
}
|
||||
});
|
||||
|
||||
$el.find('.list').scrollTop(0);
|
||||
});
|
||||
$(".navigation ul.list li.item:visible")
|
||||
.sort(weightSorter) // sort elements
|
||||
.appendTo(".navigation ul.list"); // append again to the list
|
||||
|
||||
// Toggle when click an item element
|
||||
$('.navigation').on('click', '.title', function (e) {
|
||||
$(this).parent().find('.itemMembers').toggle();
|
||||
});
|
||||
|
||||
// Show an item related a current documentation automatically
|
||||
var filename = $('.page-title').data('filename')
|
||||
.replace(/\.[a-z]+$/, '')
|
||||
.replace('module-', 'module:')
|
||||
.replace(/_/g, '/')
|
||||
.replace(/-/g, '~');
|
||||
var $currentItem = $('.navigation .item[data-name*="' + filename + '"]:eq(0)');
|
||||
|
||||
if ($currentItem.length) {
|
||||
$currentItem
|
||||
.remove()
|
||||
.prependTo('.navigation .list')
|
||||
.show()
|
||||
.find('.itemMembers')
|
||||
.show();
|
||||
} else {
|
||||
$el.find('.item, .itemMembers').show();
|
||||
}
|
||||
|
||||
// Auto resizing on navigation
|
||||
var _onResize = function () {
|
||||
var height = $(window).height();
|
||||
var $el = $('.navigation');
|
||||
$el.find('.list').scrollTop(0);
|
||||
});
|
||||
|
||||
$el.height(height).find('.list').height(height - 133);
|
||||
};
|
||||
// Toggle when click an item element
|
||||
$('.navigation').on('click', '.toggle', function (e) {
|
||||
$(this).parent().parent().find('.itemMembers').toggle();
|
||||
});
|
||||
|
||||
$(window).on('resize', _onResize);
|
||||
_onResize();
|
||||
// Show an item related a current documentation automatically
|
||||
var filename = $('.page-title').data('filename')
|
||||
.replace(/\.[a-z]+$/, '')
|
||||
.replace('module-', 'module:')
|
||||
.replace(/_/g, '/')
|
||||
.replace(/-/g, '~');
|
||||
var $currentItem = $('.navigation .item[data-name*="' + filename + '"]:eq(0)');
|
||||
|
||||
var currentVersion = document.getElementById('package-version').innerHTML;
|
||||
if ($currentItem.length) {
|
||||
$currentItem
|
||||
.remove()
|
||||
.prependTo('.navigation .list')
|
||||
.show()
|
||||
.find('.itemMembers')
|
||||
.show();
|
||||
}
|
||||
|
||||
// warn about outdated version
|
||||
var packageUrl = 'https://raw.githubusercontent.com/openlayers/openlayers.github.io/build/package.json';
|
||||
fetch(packageUrl).then(function(response) {
|
||||
return response.json();
|
||||
}).then(function(json) {
|
||||
var latestVersion = json.version;
|
||||
document.getElementById('latest-version').innerHTML = latestVersion;
|
||||
var url = window.location.href;
|
||||
var branchSearch = url.match(/\/([^\/]*)\/apidoc\//);
|
||||
var cookieText = 'dismissed=-' + latestVersion + '-';
|
||||
var dismissed = document.cookie.indexOf(cookieText) != -1;
|
||||
if (!dismissed && /^v[0-9\.]*$/.test(branchSearch[1]) && currentVersion != latestVersion) {
|
||||
var link = url.replace(branchSearch[0], '/latest/apidoc/');
|
||||
fetch(link, {method: 'head'}).then(function(response) {
|
||||
var a = document.getElementById('latest-link');
|
||||
a.href = response.status == 200 ? link : '../../latest/apidoc/';
|
||||
});
|
||||
var latestCheck = document.getElementById('latest-check');
|
||||
latestCheck.style.display = '';
|
||||
document.getElementById('latest-dismiss').onclick = function() {
|
||||
latestCheck.style.display = 'none';
|
||||
document.cookie = cookieText;
|
||||
}
|
||||
// Auto resizing on navigation
|
||||
var _onResize = function () {
|
||||
var height = $(window).height();
|
||||
var $el = $('.navigation');
|
||||
|
||||
$el.height(height).find('.list').height(height - 133);
|
||||
};
|
||||
|
||||
$(window).on('resize', _onResize);
|
||||
_onResize();
|
||||
|
||||
var currentVersion = document.getElementById('package-version').innerHTML;
|
||||
|
||||
// warn about outdated version
|
||||
var packageUrl = 'https://raw.githubusercontent.com/openlayers/openlayers.github.io/build/package.json';
|
||||
fetch(packageUrl).then(function(response) {
|
||||
return response.json();
|
||||
}).then(function(json) {
|
||||
var latestVersion = json.version;
|
||||
document.getElementById('latest-version').innerHTML = latestVersion;
|
||||
var url = window.location.href;
|
||||
var branchSearch = url.match(/\/([^\/]*)\/apidoc\//);
|
||||
var cookieText = 'dismissed=-' + latestVersion + '-';
|
||||
var dismissed = document.cookie.indexOf(cookieText) != -1;
|
||||
if (branchSearch && !dismissed && /^v[0-9\.]*$/.test(branchSearch[1]) && currentVersion != latestVersion) {
|
||||
var link = url.replace(branchSearch[0], '/latest/apidoc/');
|
||||
fetch(link, {method: 'head'}).then(function(response) {
|
||||
var a = document.getElementById('latest-link');
|
||||
a.href = response.status == 200 ? link : '../../latest/apidoc/';
|
||||
});
|
||||
var latestCheck = document.getElementById('latest-check');
|
||||
latestCheck.style.display = '';
|
||||
document.getElementById('latest-dismiss').onclick = function() {
|
||||
latestCheck.style.display = 'none';
|
||||
document.cookie = cookieText;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// create source code links to github
|
||||
var srcLinks = $('div.tag-source');
|
||||
srcLinks.each(function(i, el) {
|
||||
var textParts = el.innerHTML.trim().split(', ');
|
||||
var link = 'https://github.com/openlayers/openlayers/blob/v' + currentVersion + '/src/ol/' +
|
||||
textParts[0];
|
||||
el.innerHTML = '<a href="' + link + '">' + textParts[0] + '</a>, ' +
|
||||
'<a href="' + link + textParts[1].replace('line ', '#L') + '">' +
|
||||
textParts[1] + '</a>';
|
||||
});
|
||||
// create source code links to github
|
||||
var srcLinks = $('div.tag-source');
|
||||
srcLinks.each(function(i, el) {
|
||||
var textParts = el.innerHTML.trim().split(', ');
|
||||
var link = 'https://github.com/openlayers/openlayers/blob/v' + currentVersion + '/src/ol/' +
|
||||
textParts[0];
|
||||
el.innerHTML = '<a href="' + link + '">' + textParts[0] + '</a>, ' +
|
||||
'<a href="' + link + textParts[1].replace('line ', '#L') + '">' +
|
||||
textParts[1] + '</a>';
|
||||
});
|
||||
|
||||
// Highlighting current anchor
|
||||
// Highlighting current anchor
|
||||
|
||||
var anchors = $('.anchor');
|
||||
var _onHashChange = function () {
|
||||
var activeHash = window.document.location.hash
|
||||
.replace(/\./g, '\\.') // Escape dot in element id
|
||||
.replace(/\~/g, '\\~'); // Escape tilde in element id
|
||||
var anchors = $('.anchor');
|
||||
var _onHashChange = function () {
|
||||
var activeHash = window.document.location.hash
|
||||
.replace(/\./g, '\\.') // Escape dot in element id
|
||||
.replace(/\~/g, '\\~'); // Escape tilde in element id
|
||||
|
||||
anchors.removeClass('highlighted');
|
||||
anchors.removeClass('highlighted');
|
||||
|
||||
if (activeHash.length > 0) {
|
||||
anchors.filter(activeHash).addClass('highlighted');
|
||||
}
|
||||
};
|
||||
if (activeHash.length > 0) {
|
||||
anchors.filter(activeHash).addClass('highlighted');
|
||||
}
|
||||
};
|
||||
|
||||
$(window).on('hashchange', _onHashChange);
|
||||
_onHashChange();
|
||||
$(window).on('hashchange', _onHashChange);
|
||||
_onHashChange();
|
||||
});
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
.navbar-inverse .navbar-nav>li>a:hover,
|
||||
.navbar-inverse .navbar-nav>li>a:focus,
|
||||
.navbar-inverse .navbar-nav>li>a.active
|
||||
{
|
||||
{
|
||||
outline:0;
|
||||
color: #fff;
|
||||
background-color: #268591;
|
||||
@@ -106,6 +106,15 @@ li {
|
||||
.navigation .applicationName a {
|
||||
color: #fff;
|
||||
}
|
||||
.navigation .include-modules {
|
||||
color: #e1e1e1;
|
||||
float: right;
|
||||
font-size: 0.75em;
|
||||
padding: 5px 15px;
|
||||
}
|
||||
.navigation .include-modules input {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
.navigation .search {
|
||||
padding: 10px 15px;
|
||||
}
|
||||
@@ -125,6 +134,11 @@ li {
|
||||
padding-bottom: 8px;
|
||||
border-bottom: 1px solid #333;
|
||||
}
|
||||
|
||||
.navigation li.perfect-match {
|
||||
border: 5px solid orange;
|
||||
}
|
||||
|
||||
.navigation li.item a {
|
||||
color: #bbb;
|
||||
}
|
||||
@@ -158,6 +172,12 @@ li {
|
||||
color: #1F6B75;
|
||||
display: block;
|
||||
}
|
||||
.navigation li.item .modulelink {
|
||||
position: relative;
|
||||
font-size: 0.75em;
|
||||
padding-left: 5px;
|
||||
top: -5px;
|
||||
}
|
||||
.navigation li.item ul > li {
|
||||
font-size: 0.75em;
|
||||
padding-left: 8px;
|
||||
@@ -165,6 +185,7 @@ li {
|
||||
}
|
||||
.navigation li.item .itemMembers {
|
||||
display: none;
|
||||
padding-left: 8px;
|
||||
}
|
||||
.main {
|
||||
padding: 20px 20px;
|
||||
|
||||
81
config/jsdoc/api/template/static/styles/site.css
Normal file
@@ -0,0 +1,81 @@
|
||||
/* Carbon adds (see https://sell.buysellads.com) */
|
||||
|
||||
#ad {
|
||||
margin-left: 1em;
|
||||
float: right;
|
||||
width: 330px;
|
||||
min-height: 125px;
|
||||
}
|
||||
|
||||
#carbonads {
|
||||
font-family: "Quattrocento Sans", "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
|
||||
}
|
||||
|
||||
#carbonads {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
#carbonads a {
|
||||
color: inherit;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
#carbonads a:hover {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
#carbonads span {
|
||||
position: relative;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#carbonads .carbon-wrap {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.carbon-img {
|
||||
display: block;
|
||||
margin: 0;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
.carbon-img img {
|
||||
display: block;
|
||||
}
|
||||
|
||||
.carbon-text {
|
||||
font-size: 13px;
|
||||
padding: 10px;
|
||||
line-height: 1.5;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.carbon-poweredby {
|
||||
display: block;
|
||||
padding: 8px 10px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
letter-spacing: .5px;
|
||||
font-weight: 600;
|
||||
font-size: 9px;
|
||||
line-height: 1;
|
||||
}
|
||||
|
||||
#carbonads a.carbon-poweredby {
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
/* Clear the float after the advertisement. */
|
||||
|
||||
.container-overview {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
pre.source {
|
||||
clear: both;
|
||||
}
|
||||
|
||||
section.content {
|
||||
overflow-y: auto;
|
||||
}
|
||||
@@ -9,7 +9,7 @@
|
||||
<?js= self.partial('source.tmpl', doc) ?>
|
||||
<?js } else { ?>
|
||||
|
||||
<section>
|
||||
<section class="content">
|
||||
|
||||
<header>
|
||||
<h2><?js if (doc.ancestors && doc.ancestors.length) { ?>
|
||||
@@ -41,6 +41,9 @@
|
||||
<pre class="prettyprint source"><code>import <?js= doc.name ?> from '<?js= importPath ?>';</code></pre>
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
<div id="ad">
|
||||
<script async type="text/javascript" src="https://cdn.carbonads.com/carbon.js?serve=CE7DV53U&placement=openlayersorg" id="_carbonads_js"></script>
|
||||
</div>
|
||||
<?js if (doc.classdesc) { ?>
|
||||
<div class="class-description"><?js= doc.classdesc ?></div>
|
||||
<?js } ?>
|
||||
|
||||
@@ -73,6 +73,7 @@ var version = obj.packageInfo.version;
|
||||
<link type="text/css" rel="stylesheet" href="styles/prettify-tomorrow.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/bootstrap.min.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/jaguar.css">
|
||||
<link type="text/css" rel="stylesheet" href="styles/site.css">
|
||||
</head>
|
||||
<body>
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?js
|
||||
var self = this;
|
||||
function toShortName(name) {
|
||||
return name.indexOf('module:') === 0 ? name.split('/').pop() : name;
|
||||
return name.indexOf('module:') === 0 ? name.split('/').pop() : name;
|
||||
}
|
||||
?>
|
||||
<div class="navigation">
|
||||
@@ -10,31 +10,23 @@ function toShortName(name) {
|
||||
</div>
|
||||
<ul class="list">
|
||||
<?js
|
||||
let navbuilder;
|
||||
this.nav.forEach(navbuilder = function (item) {
|
||||
this.nav.forEach(function (item) {
|
||||
?>
|
||||
<li class="item" data-name="<?js= item.longname ?>">
|
||||
<li class="item" data-name="<?js= item.longname ?>" data-shortname="<?js= item.name.toLowerCase() ?>">
|
||||
<span class="title">
|
||||
<?js= self.linkto(item.longname, item.type === 'module' ? item.longname.replace('module:', '') : item.name) ?>
|
||||
<?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 } ?>
|
||||
<?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)) { ?>
|
||||
item.events.length > 0)) { ?>
|
||||
<?js } ?>
|
||||
</span>
|
||||
<ul class="members itemMembers">
|
||||
<?js
|
||||
if (item.classes.length) {
|
||||
?>
|
||||
<span class="subtitle">Classes</span>
|
||||
<?js
|
||||
item.classes.forEach(function (v) {
|
||||
navbuilder(v);
|
||||
});
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
<ul class="members itemMembers">
|
||||
<?js
|
||||
if (item.members.length) {
|
||||
?>
|
||||
<span class="subtitle">Members</span>
|
||||
|
||||
@@ -16,9 +16,8 @@
|
||||
}
|
||||
});
|
||||
|
||||
/* determine if we need extra columns, "attributes" and "default" */
|
||||
/* determine if we need extra "attributes" column */
|
||||
params.hasAttributes = false;
|
||||
params.hasDefault = false;
|
||||
params.hasName = false;
|
||||
|
||||
var colspan = 2;
|
||||
@@ -40,10 +39,6 @@
|
||||
params.hasName = true;
|
||||
}
|
||||
|
||||
if (typeof param.defaultvalue !== 'undefined') {
|
||||
++colspan;
|
||||
params.hasDefault = true;
|
||||
}
|
||||
});
|
||||
?>
|
||||
|
||||
@@ -56,10 +51,6 @@
|
||||
|
||||
<th>Type</th>
|
||||
|
||||
<?js if (params.hasDefault) {?>
|
||||
<th>Default</th>
|
||||
<?js } ?>
|
||||
|
||||
<th class="last">Description</th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -80,18 +71,14 @@
|
||||
<td class="type">
|
||||
<?js if (param.type && param.type.names) {?>
|
||||
<?js= self.partial('type.tmpl', param.type.names) ?>
|
||||
<?js if (typeof param.defaultvalue !== 'undefined') { ?>
|
||||
(defaults to <?js= self.htmlsafe(param.defaultvalue) ?>)
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
</td>
|
||||
|
||||
<?js if (params.hasDefault) {?>
|
||||
<td class="default">
|
||||
<?js if (typeof param.defaultvalue !== 'undefined') { ?>
|
||||
<?js= self.htmlsafe(param.defaultvalue) ?>
|
||||
<?js } ?>
|
||||
</td>
|
||||
|
||||
<?js } ?>
|
||||
<?js } ?>
|
||||
|
||||
|
||||
<td<?js= (param.subparams ? ' colspan=' + colspan : ' ') ?> class="description last">
|
||||
<?js if (param.stability) { ?>
|
||||
<?js= self.partial('stability.tmpl', param) ?>
|
||||
|
||||
@@ -241,10 +241,6 @@ Support for the `OES_element_index_uint` WebGL extension is mandatory for WebGL
|
||||
|
||||
Layer opacity must be a number.
|
||||
|
||||
### 65
|
||||
|
||||
A symbol literal representation must be defined on the style supplied to a `WebGLPointsLayer` instance.
|
||||
|
||||
### 66
|
||||
|
||||
`forEachFeatureAtCoordinate` cannot be used on a WebGL layer if the hit detection logic has not been enabled.
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import {Map, View} from '../src/ol/index.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import {Modify, Select, Draw} from '../src/ol/interaction.js';
|
||||
import {Modify, Select, Draw, Snap} from '../src/ol/interaction.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {useGeographic} from '../src/ol/proj.js';
|
||||
@@ -39,19 +39,30 @@ const draw = new Draw({
|
||||
source: source
|
||||
});
|
||||
|
||||
const snap = new Snap({
|
||||
source: source
|
||||
});
|
||||
|
||||
function removeInteractions() {
|
||||
map.removeInteraction(modify);
|
||||
map.removeInteraction(select);
|
||||
map.removeInteraction(draw);
|
||||
map.removeInteraction(select);
|
||||
}
|
||||
|
||||
const mode = document.getElementById('mode');
|
||||
function onChange() {
|
||||
removeInteractions();
|
||||
switch (mode.value) {
|
||||
case 'draw': {
|
||||
map.removeInteraction(modify);
|
||||
map.removeInteraction(select);
|
||||
map.addInteraction(draw);
|
||||
map.addInteraction(snap);
|
||||
break;
|
||||
}
|
||||
case 'modify': {
|
||||
map.removeInteraction(draw);
|
||||
map.addInteraction(select);
|
||||
map.addInteraction(modify);
|
||||
map.addInteraction(snap);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
@@ -3,14 +3,14 @@ layout: example.html
|
||||
title: Filtering features with WebGL
|
||||
shortdesc: Using WebGL to filter large quantities of features
|
||||
docs: >
|
||||
This example shows how to use `ol/renderer/webgl/PointsLayer` to dynamically filter a large amount
|
||||
This example shows how to use `ol/layer/WebGLPoints` with a literal style to dynamically filter a large amount
|
||||
of point geometries. The above map is based on a dataset from the NASA containing 45k recorded meteorite
|
||||
landing sites. Each meteorite is marked by a circle on the map (the bigger the circle, the heavier
|
||||
the object). A pulse effect has been added, which is slightly offset by the year of the impact.
|
||||
|
||||
Adjusting the sliders causes the objects outside of the date range to be filtered out of the map. This is done using
|
||||
a custom fragment shader on the layer renderer, and by using the `v_opacity` attribute of the rendered objects
|
||||
to store the year of impact.
|
||||
Adjusting the sliders causes the objects outside of the date range to be filtered out of the map. This is done
|
||||
by mutating the variables in the `style` object provided to the WebGL layer. Also note that the last snippet
|
||||
of code is necessary to make sure the map refreshes itself every frame.
|
||||
|
||||
tags: "webgl, icon, sprite, filter, feature"
|
||||
experimental: true
|
||||
|
||||
@@ -3,162 +3,115 @@ import View from '../src/ol/View.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import Point from '../src/ol/geom/Point.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import {Vector} from '../src/ol/source.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
||||
import {clamp} from '../src/ol/math.js';
|
||||
import Stamen from '../src/ol/source/Stamen.js';
|
||||
import {formatColor} from '../src/ol/webgl/ShaderBuilder.js';
|
||||
import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
|
||||
|
||||
const vectorSource = new Vector({
|
||||
attributions: 'NASA'
|
||||
});
|
||||
|
||||
const oldColor = [180, 140, 140];
|
||||
const newColor = [255, 80, 80];
|
||||
const oldColor = 'rgba(242,56,22,0.61)';
|
||||
const newColor = '#ffe52c';
|
||||
const period = 12; // animation period in seconds
|
||||
const animRatio =
|
||||
['^',
|
||||
['/',
|
||||
['%',
|
||||
['+',
|
||||
['time'],
|
||||
[
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'year'],
|
||||
1850, 0,
|
||||
2015, period
|
||||
]
|
||||
],
|
||||
period
|
||||
],
|
||||
period
|
||||
],
|
||||
0.5
|
||||
];
|
||||
|
||||
const startTime = Date.now() * 0.001;
|
||||
const style = {
|
||||
variables: {
|
||||
minYear: 1850,
|
||||
maxYear: 2015
|
||||
},
|
||||
filter: ['between', ['get', 'year'], ['var', 'minYear'], ['var', 'maxYear']],
|
||||
symbol: {
|
||||
symbolType: 'circle',
|
||||
size: ['*',
|
||||
['interpolate', ['linear'], ['get', 'mass'], 0, 8, 200000, 26],
|
||||
['-', 1.75, ['*', animRatio, 0.75]]
|
||||
],
|
||||
color: ['interpolate',
|
||||
['linear'],
|
||||
animRatio,
|
||||
0, newColor,
|
||||
1, oldColor
|
||||
],
|
||||
opacity: ['-', 1.0, ['*', animRatio, 0.75]]
|
||||
}
|
||||
};
|
||||
|
||||
// hanle input values & events
|
||||
// handle input values & events
|
||||
const minYearInput = document.getElementById('min-year');
|
||||
const maxYearInput = document.getElementById('max-year');
|
||||
|
||||
function updateMinYear() {
|
||||
style.variables.minYear = parseInt(minYearInput.value);
|
||||
updateStatusText();
|
||||
}
|
||||
function updateMaxYear() {
|
||||
style.variables.maxYear = parseInt(maxYearInput.value);
|
||||
updateStatusText();
|
||||
}
|
||||
function updateStatusText() {
|
||||
const div = document.getElementById('status');
|
||||
div.querySelector('span.min-year').textContent = minYearInput.value;
|
||||
div.querySelector('span.max-year').textContent = maxYearInput.value;
|
||||
}
|
||||
minYearInput.addEventListener('input', updateStatusText);
|
||||
minYearInput.addEventListener('change', updateStatusText);
|
||||
maxYearInput.addEventListener('input', updateStatusText);
|
||||
maxYearInput.addEventListener('change', updateStatusText);
|
||||
|
||||
minYearInput.addEventListener('input', updateMinYear);
|
||||
minYearInput.addEventListener('change', updateMinYear);
|
||||
maxYearInput.addEventListener('input', updateMaxYear);
|
||||
maxYearInput.addEventListener('change', updateMaxYear);
|
||||
updateStatusText();
|
||||
|
||||
class WebglPointsLayer extends VectorLayer {
|
||||
createRenderer() {
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
attributes: [
|
||||
{
|
||||
name: 'size',
|
||||
callback: function(feature) {
|
||||
return 18 * clamp(feature.get('mass') / 200000, 0, 1) + 8;
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'year',
|
||||
callback: function(feature) {
|
||||
return feature.get('year');
|
||||
}
|
||||
}
|
||||
],
|
||||
vertexShader: [
|
||||
'precision mediump float;',
|
||||
// load data
|
||||
const client = new XMLHttpRequest();
|
||||
client.open('GET', 'data/csv/meteorite_landings.csv');
|
||||
client.onload = function() {
|
||||
const csv = client.responseText;
|
||||
const features = [];
|
||||
|
||||
'uniform mat4 u_projectionMatrix;',
|
||||
'uniform mat4 u_offsetScaleMatrix;',
|
||||
'uniform mat4 u_offsetRotateMatrix;',
|
||||
'attribute vec2 a_position;',
|
||||
'attribute float a_index;',
|
||||
'attribute float a_size;',
|
||||
'attribute float a_year;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'varying float v_year;',
|
||||
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||
|
||||
'void main(void) {',
|
||||
' mat4 offsetMatrix = u_offsetScaleMatrix;',
|
||||
' float offsetX = a_index == 0.0 || a_index == 3.0 ? -a_size / 2.0 : a_size / 2.0;',
|
||||
' float offsetY = a_index == 0.0 || a_index == 1.0 ? -a_size / 2.0 : a_size / 2.0;',
|
||||
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
|
||||
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
|
||||
' float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;',
|
||||
' float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;',
|
||||
' v_texCoord = vec2(u, v);',
|
||||
' v_year = a_year;',
|
||||
'}'
|
||||
].join(' '),
|
||||
fragmentShader: [
|
||||
'precision mediump float;',
|
||||
let curIndex;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
prevIndex = curIndex + 1;
|
||||
|
||||
'uniform float u_time;',
|
||||
'uniform float u_minYear;',
|
||||
'uniform float u_maxYear;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'varying float v_year;',
|
||||
|
||||
'void main(void) {',
|
||||
|
||||
// filter out pixels if the year is outside of the given range
|
||||
' if (v_year < u_minYear || v_year > u_maxYear) {',
|
||||
' discard;',
|
||||
' }',
|
||||
|
||||
' vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);',
|
||||
' float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;',
|
||||
' float value = 2.0 * (1.0 - sqRadius);',
|
||||
' float alpha = smoothstep(0.0, 1.0, value);',
|
||||
|
||||
// color is interpolated based on year
|
||||
' float ratio = clamp((v_year - 1800.0) / (2013.0 - 1800.0), 0.0, 1.1);',
|
||||
' vec3 color = mix(vec3(' + formatColor(oldColor) + '),',
|
||||
' vec3(' + formatColor(newColor) + '), ratio);',
|
||||
|
||||
' float period = 8.0;',
|
||||
' color.g *= 2.0 * (1.0 - sqrt(mod(u_time + v_year * 0.025, period) / period));',
|
||||
|
||||
' gl_FragColor = vec4(color, 1.0);',
|
||||
' gl_FragColor.a *= alpha;',
|
||||
' gl_FragColor.rgb *= gl_FragColor.a;',
|
||||
'}'
|
||||
].join(' '),
|
||||
uniforms: {
|
||||
u_time: function() {
|
||||
return Date.now() * 0.001 - startTime;
|
||||
},
|
||||
u_minYear: function() {
|
||||
return parseInt(minYearInput.value);
|
||||
},
|
||||
u_maxYear: function() {
|
||||
return parseInt(maxYearInput.value);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadData() {
|
||||
const client = new XMLHttpRequest();
|
||||
client.open('GET', 'data/csv/meteorite_landings.csv');
|
||||
client.onload = function() {
|
||||
const csv = client.responseText;
|
||||
const features = [];
|
||||
|
||||
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||
|
||||
let curIndex;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
prevIndex = curIndex + 1;
|
||||
|
||||
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
||||
if (isNaN(coords[0]) || isNaN(coords[1])) {
|
||||
// guard against bad data
|
||||
continue;
|
||||
}
|
||||
|
||||
features.push(new Feature({
|
||||
mass: parseFloat(line[1]) || 0,
|
||||
year: parseInt(line[2]) || 0,
|
||||
geometry: new Point(coords)
|
||||
}));
|
||||
const coords = fromLonLat([parseFloat(line[4]), parseFloat(line[3])]);
|
||||
if (isNaN(coords[0]) || isNaN(coords[1])) {
|
||||
// guard against bad data
|
||||
continue;
|
||||
}
|
||||
|
||||
vectorSource.addFeatures(features);
|
||||
};
|
||||
client.send();
|
||||
}
|
||||
features.push(new Feature({
|
||||
mass: parseFloat(line[1]) || 0,
|
||||
year: parseInt(line[2]) || 0,
|
||||
geometry: new Point(coords)
|
||||
}));
|
||||
}
|
||||
|
||||
loadData();
|
||||
vectorSource.addFeatures(features);
|
||||
};
|
||||
client.send();
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
@@ -167,8 +120,10 @@ const map = new Map({
|
||||
layer: 'toner'
|
||||
})
|
||||
}),
|
||||
new WebglPointsLayer({
|
||||
source: vectorSource
|
||||
new WebGLPointsLayer({
|
||||
style: style,
|
||||
source: vectorSource,
|
||||
disableHitDetection: true
|
||||
})
|
||||
],
|
||||
target: document.getElementById('map'),
|
||||
|
||||
@@ -16,16 +16,15 @@ const vector = new HeatmapLayer({
|
||||
})
|
||||
}),
|
||||
blur: parseInt(blur.value, 10),
|
||||
radius: parseInt(radius.value, 10)
|
||||
});
|
||||
|
||||
vector.getSource().on('addfeature', function(event) {
|
||||
// 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a
|
||||
// standards-violating <magnitude> tag in each Placemark. We extract it from
|
||||
// the Placemark's name instead.
|
||||
const name = event.feature.get('name');
|
||||
const magnitude = parseFloat(name.substr(2));
|
||||
event.feature.set('weight', magnitude - 5);
|
||||
radius: parseInt(radius.value, 10),
|
||||
weight: function(feature) {
|
||||
// 2012_Earthquakes_Mag5.kml stores the magnitude of each earthquake in a
|
||||
// standards-violating <magnitude> tag in each Placemark. We extract it from
|
||||
// the Placemark's name instead.
|
||||
const name = feature.get('name');
|
||||
const magnitude = parseFloat(name.substr(2));
|
||||
return magnitude - 5;
|
||||
}
|
||||
});
|
||||
|
||||
const raster = new TileLayer({
|
||||
@@ -34,7 +33,7 @@ const raster = new TileLayer({
|
||||
})
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
new Map({
|
||||
layers: [raster, vector],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
|
||||
15
examples/hitdetect-vector.html
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Vector Layer Hit Detection
|
||||
shortdesc: Example of hit detection on a countries vector layer with country information.
|
||||
docs: >
|
||||
The countries are loaded from a GeoJSON file. Information about countries is
|
||||
on hover and click is retrieved using the layer's `getFeatures()` method. For
|
||||
vector layers, this function resolves with an array of only the topmost
|
||||
feature. It uses a very efficient hit detection algorithm, at the cost of
|
||||
accuracy. For pixel exact hit detection, when performance is not a concern,
|
||||
use the map's `getFeaturesAtPixel()` or `forEachFeatureAtPixel()` methods.
|
||||
tags: "vector, geojson, click, hover, hit detection"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div id="info"> </div>
|
||||
113
examples/hitdetect-vector.js
Normal file
@@ -0,0 +1,113 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
import {Fill, Stroke, Style, Text} from '../src/ol/style.js';
|
||||
|
||||
|
||||
const style = new Style({
|
||||
fill: new Fill({
|
||||
color: 'rgba(255, 255, 255, 0.6)'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: '#319FD3',
|
||||
width: 1
|
||||
}),
|
||||
text: new Text({
|
||||
font: '12px Calibri,sans-serif',
|
||||
fill: new Fill({
|
||||
color: '#000'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: '#fff',
|
||||
width: 3
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const vectorLayer = new VectorLayer({
|
||||
source: new VectorSource({
|
||||
url: 'data/geojson/countries.geojson',
|
||||
format: new GeoJSON()
|
||||
}),
|
||||
style: function(feature) {
|
||||
style.getText().setText(feature.get('name'));
|
||||
return style;
|
||||
}
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [vectorLayer],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 1
|
||||
})
|
||||
});
|
||||
|
||||
const highlightStyle = new Style({
|
||||
stroke: new Stroke({
|
||||
color: '#f00',
|
||||
width: 1
|
||||
}),
|
||||
fill: new Fill({
|
||||
color: 'rgba(255,0,0,0.1)'
|
||||
}),
|
||||
text: new Text({
|
||||
font: '12px Calibri,sans-serif',
|
||||
fill: new Fill({
|
||||
color: '#000'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: '#f00',
|
||||
width: 3
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
const featureOverlay = new VectorLayer({
|
||||
source: new VectorSource(),
|
||||
map: map,
|
||||
style: function(feature) {
|
||||
highlightStyle.getText().setText(feature.get('name'));
|
||||
return highlightStyle;
|
||||
}
|
||||
});
|
||||
|
||||
let highlight;
|
||||
const displayFeatureInfo = function(pixel) {
|
||||
|
||||
vectorLayer.getFeatures(pixel).then(function(features) {
|
||||
const feature = features.length ? features[0] : undefined;
|
||||
const info = document.getElementById('info');
|
||||
if (features.length) {
|
||||
info.innerHTML = feature.getId() + ': ' + feature.get('name');
|
||||
} else {
|
||||
info.innerHTML = ' ';
|
||||
}
|
||||
|
||||
if (feature !== highlight) {
|
||||
if (highlight) {
|
||||
featureOverlay.getSource().removeFeature(highlight);
|
||||
}
|
||||
if (feature) {
|
||||
featureOverlay.getSource().addFeature(feature);
|
||||
}
|
||||
highlight = feature;
|
||||
}
|
||||
});
|
||||
|
||||
};
|
||||
|
||||
map.on('pointermove', function(evt) {
|
||||
if (evt.dragging) {
|
||||
return;
|
||||
}
|
||||
const pixel = map.getEventPixel(evt.originalEvent);
|
||||
displayFeatureInfo(pixel);
|
||||
});
|
||||
|
||||
map.on('click', function(evt) {
|
||||
displayFeatureInfo(evt.pixel);
|
||||
});
|
||||
@@ -3,13 +3,13 @@ layout: example.html
|
||||
title: Icon Sprites with WebGL
|
||||
shortdesc: Rendering many icons with WebGL
|
||||
docs: >
|
||||
This example shows how to use `ol/renderer/webgl/PointsLayer` to render
|
||||
This example shows how to use `ol/layer/WebGLPoints` to render
|
||||
a very large amount of sprites. The above map is based on a dataset from the National UFO Reporting Center: each
|
||||
icon marks a UFO sighting according to its reported shape (disk, light, fireball...). The older the sighting, the redder
|
||||
the icon.
|
||||
|
||||
A very simple sprite atlas is used in the form of a PNG file containing all icons on a grid. Then, the `texCoordCallback`
|
||||
option of the `ol/renderer/webgl/PointsLayer` constructor is used to specify which sprite to use according to the sighting shape.
|
||||
A very simple sprite atlas is used in the form of a PNG file containing all icons on a grid. Then, the `style` object
|
||||
given to the `ol/layer/WebGLPoints` constructor is used to specify which sprite to use according to the sighting shape.
|
||||
|
||||
The dataset contains around 80k points and can be found here: https://www.kaggle.com/NUFORC/ufo-sightings
|
||||
tags: "webgl, icon, sprite, point, ufo"
|
||||
@@ -20,3 +20,7 @@ cloak:
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div>Current sighting: <span id="info"></span></div>
|
||||
<div>
|
||||
Filter by UFO shape:
|
||||
<select id="shape-filter"></select>
|
||||
</div>
|
||||
|
||||
@@ -4,211 +4,12 @@ import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import TileJSON from '../src/ol/source/TileJSON.js';
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import Point from '../src/ol/geom/Point.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import {Vector} from '../src/ol/source.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
import WebGLPointsLayerRenderer from '../src/ol/renderer/webgl/PointsLayer.js';
|
||||
import {formatColor, formatNumber} from '../src/ol/webgl/ShaderBuilder.js';
|
||||
import WebGLPointsLayer from '../src/ol/layer/WebGLPoints.js';
|
||||
|
||||
const key = 'pk.eyJ1IjoidHNjaGF1YiIsImEiOiJjaW5zYW5lNHkxMTNmdWttM3JyOHZtMmNtIn0.CDIBD8H-G2Gf-cPkIuWtRg';
|
||||
|
||||
const vectorSource = new Vector({
|
||||
features: [],
|
||||
attributions: 'National UFO Reporting Center'
|
||||
});
|
||||
|
||||
const texture = new Image();
|
||||
texture.src = 'data/ufo_shapes.png';
|
||||
|
||||
// This describes the content of the associated sprite sheet
|
||||
// coords are u0, v0 for a given shape (all icons have a size of 0.25 x 0.5)
|
||||
const shapeTextureCoords = {
|
||||
'light': [0, 0],
|
||||
'sphere': [0.25, 0],
|
||||
'circle': [0.25, 0],
|
||||
'disc': [0.5, 0],
|
||||
'oval': [0.5, 0],
|
||||
'triangle': [0.75, 0],
|
||||
'fireball': [0, 0.5],
|
||||
'default': [0.75, 0.5]
|
||||
};
|
||||
|
||||
const oldColor = [255, 160, 110];
|
||||
const newColor = [180, 255, 200];
|
||||
const size = 16;
|
||||
|
||||
class WebglPointsLayer extends VectorLayer {
|
||||
createRenderer() {
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
attributes: [
|
||||
{
|
||||
name: 'year',
|
||||
callback: function(feature) {
|
||||
return feature.get('year');
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'texCoordU',
|
||||
callback: function(feature) {
|
||||
let coords = shapeTextureCoords[feature.get('shape')];
|
||||
if (!coords) {
|
||||
coords = shapeTextureCoords['default'];
|
||||
}
|
||||
return coords[0];
|
||||
}
|
||||
},
|
||||
{
|
||||
name: 'texCoordV',
|
||||
callback: function(feature) {
|
||||
let coords = shapeTextureCoords[feature.get('shape')];
|
||||
if (!coords) {
|
||||
coords = shapeTextureCoords['default'];
|
||||
}
|
||||
return coords[1];
|
||||
}
|
||||
}
|
||||
],
|
||||
uniforms: {
|
||||
u_texture: texture
|
||||
},
|
||||
vertexShader: [
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform mat4 u_projectionMatrix;',
|
||||
'uniform mat4 u_offsetScaleMatrix;',
|
||||
'uniform mat4 u_offsetRotateMatrix;',
|
||||
'attribute vec2 a_position;',
|
||||
'attribute float a_index;',
|
||||
'attribute float a_year;',
|
||||
'attribute float a_texCoordU;',
|
||||
'attribute float a_texCoordV;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'varying float v_year;',
|
||||
|
||||
'void main(void) {',
|
||||
' mat4 offsetMatrix = u_offsetScaleMatrix;',
|
||||
' float offsetX = a_index == 0.0 || a_index == 3.0 ? ',
|
||||
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
|
||||
' float offsetY = a_index == 0.0 || a_index == 1.0 ? ',
|
||||
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
|
||||
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
|
||||
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
|
||||
' float u = a_index == 0.0 || a_index == 3.0 ? a_texCoordU : a_texCoordU + 0.25;',
|
||||
' float v = a_index == 2.0 || a_index == 3.0 ? a_texCoordV : a_texCoordV + 0.5;',
|
||||
' v_texCoord = vec2(u, v);',
|
||||
' v_year = a_year;',
|
||||
'}'
|
||||
].join(' '),
|
||||
fragmentShader: [
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform float u_time;',
|
||||
'uniform float u_minYear;',
|
||||
'uniform float u_maxYear;',
|
||||
'uniform sampler2D u_texture;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'varying float v_year;',
|
||||
|
||||
'void main(void) {',
|
||||
' vec4 textureColor = texture2D(u_texture, v_texCoord);',
|
||||
' if (textureColor.a < 0.1) {',
|
||||
' discard;',
|
||||
' }',
|
||||
|
||||
// color is interpolated based on year
|
||||
' float ratio = clamp((v_year - 1950.0) / (2013.0 - 1950.0), 0.0, 1.1);',
|
||||
' vec3 color = mix(vec3(' + formatColor(oldColor) + '),',
|
||||
' vec3(' + formatColor(newColor) + '), ratio);',
|
||||
|
||||
' gl_FragColor = vec4(color, 1.0) * textureColor;',
|
||||
' gl_FragColor.rgb *= gl_FragColor.a;',
|
||||
'}'
|
||||
].join(' '),
|
||||
hitVertexShader: [
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform mat4 u_projectionMatrix;',
|
||||
'uniform mat4 u_offsetScaleMatrix;',
|
||||
'uniform mat4 u_offsetRotateMatrix;',
|
||||
'attribute vec2 a_position;',
|
||||
'attribute float a_index;',
|
||||
'attribute vec4 a_hitColor;',
|
||||
'attribute float a_texCoordU;',
|
||||
'attribute float a_texCoordV;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'varying vec4 v_hitColor;',
|
||||
|
||||
'void main(void) {',
|
||||
' mat4 offsetMatrix = u_offsetScaleMatrix;',
|
||||
' float offsetX = a_index == 0.0 || a_index == 3.0 ? ',
|
||||
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
|
||||
' float offsetY = a_index == 0.0 || a_index == 1.0 ? ',
|
||||
' ' + formatNumber(-size / 2) + ' : ' + formatNumber(size / 2) + ';',
|
||||
' vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);',
|
||||
' gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;',
|
||||
' float u = a_index == 0.0 || a_index == 3.0 ? a_texCoordU : a_texCoordU + 0.25;',
|
||||
' float v = a_index == 2.0 || a_index == 3.0 ? a_texCoordV : a_texCoordV + 0.5;',
|
||||
' v_texCoord = vec2(u, v);',
|
||||
' v_hitColor = a_hitColor;',
|
||||
'}'
|
||||
].join(' '),
|
||||
hitFragmentShader: [
|
||||
'precision mediump float;',
|
||||
|
||||
'uniform sampler2D u_texture;',
|
||||
'varying vec2 v_texCoord;',
|
||||
'varying vec4 v_hitColor;',
|
||||
|
||||
'void main(void) {',
|
||||
' vec4 textureColor = texture2D(u_texture, v_texCoord);',
|
||||
' if (textureColor.a < 0.1) {',
|
||||
' discard;',
|
||||
' }',
|
||||
|
||||
' gl_FragColor = v_hitColor;',
|
||||
'}'
|
||||
].join(' ')
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadData() {
|
||||
const client = new XMLHttpRequest();
|
||||
client.open('GET', 'data/csv/ufo_sighting_data.csv');
|
||||
client.onload = function() {
|
||||
const csv = client.responseText;
|
||||
const features = [];
|
||||
|
||||
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||
|
||||
let curIndex;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
prevIndex = curIndex + 1;
|
||||
|
||||
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
|
||||
|
||||
// only keep valid points
|
||||
if (isNaN(coords[0]) || isNaN(coords[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
features.push(new Feature({
|
||||
datetime: line[0],
|
||||
year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int
|
||||
shape: line[2],
|
||||
duration: line[3],
|
||||
geometry: new Point(coords)
|
||||
}));
|
||||
}
|
||||
vectorSource.addFeatures(features);
|
||||
};
|
||||
client.send();
|
||||
}
|
||||
|
||||
loadData();
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
@@ -216,9 +17,6 @@ const map = new Map({
|
||||
url: 'https://api.tiles.mapbox.com/v4/mapbox.world-dark.json?secure&access_token=' + key,
|
||||
crossOrigin: 'anonymous'
|
||||
})
|
||||
}),
|
||||
new WebglPointsLayer({
|
||||
source: vectorSource
|
||||
})
|
||||
],
|
||||
target: document.getElementById('map'),
|
||||
@@ -228,9 +26,125 @@ const map = new Map({
|
||||
})
|
||||
});
|
||||
|
||||
const vectorSource = new Vector({
|
||||
features: [],
|
||||
attributions: 'National UFO Reporting Center'
|
||||
});
|
||||
|
||||
const oldColor = [255, 160, 110];
|
||||
const newColor = [180, 255, 200];
|
||||
const size = 16;
|
||||
|
||||
const style = {
|
||||
variables: {
|
||||
filterShape: 'all'
|
||||
},
|
||||
filter: [
|
||||
'case',
|
||||
['!=', ['var', 'filterShape'], 'all'],
|
||||
['==', ['get', 'shape'], ['var', 'filterShape']],
|
||||
true
|
||||
],
|
||||
symbol: {
|
||||
symbolType: 'image',
|
||||
src: 'data/ufo_shapes.png',
|
||||
size: size,
|
||||
color: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'year'],
|
||||
1950, oldColor,
|
||||
2013, newColor
|
||||
],
|
||||
rotateWithView: false,
|
||||
offset: [
|
||||
0,
|
||||
0
|
||||
],
|
||||
textureCoord: [
|
||||
'match',
|
||||
['get', 'shape'],
|
||||
'light', [0, 0, 0.25, 0.5],
|
||||
'sphere', [0.25, 0, 0.5, 0.5],
|
||||
'circle', [0.25, 0, 0.5, 0.5],
|
||||
'disc', [0.5, 0, 0.75, 0.5],
|
||||
'oval', [0.5, 0, 0.75, 0.5],
|
||||
'triangle', [0.75, 0, 1, 0.5],
|
||||
'fireball', [0, 0.5, 0.25, 1],
|
||||
[0.75, 0.5, 1, 1]
|
||||
]
|
||||
}
|
||||
};
|
||||
|
||||
// key is shape name, value is sightings count
|
||||
const shapeTypes = {
|
||||
all: 0
|
||||
};
|
||||
const shapeSelect = document.getElementById('shape-filter');
|
||||
shapeSelect.addEventListener('input', function() {
|
||||
style.variables.filterShape = shapeSelect.options[shapeSelect.selectedIndex].value;
|
||||
map.render();
|
||||
});
|
||||
function fillShapeSelect() {
|
||||
Object.keys(shapeTypes)
|
||||
.sort(function(a, b) {
|
||||
return shapeTypes[b] - shapeTypes[a];
|
||||
})
|
||||
.forEach(function(shape) {
|
||||
const option = document.createElement('option');
|
||||
option.text = `${shape} (${shapeTypes[shape]} sightings)`;
|
||||
option.value = shape;
|
||||
shapeSelect.appendChild(option);
|
||||
});
|
||||
}
|
||||
|
||||
const client = new XMLHttpRequest();
|
||||
client.open('GET', 'data/csv/ufo_sighting_data.csv');
|
||||
client.onload = function() {
|
||||
const csv = client.responseText;
|
||||
const features = [];
|
||||
|
||||
let prevIndex = csv.indexOf('\n') + 1; // scan past the header line
|
||||
|
||||
let curIndex;
|
||||
while ((curIndex = csv.indexOf('\n', prevIndex)) != -1) {
|
||||
const line = csv.substr(prevIndex, curIndex - prevIndex).split(',');
|
||||
prevIndex = curIndex + 1;
|
||||
|
||||
const coords = fromLonLat([parseFloat(line[5]), parseFloat(line[4])]);
|
||||
|
||||
// only keep valid points
|
||||
if (isNaN(coords[0]) || isNaN(coords[1])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const shape = line[2];
|
||||
shapeTypes[shape] = (shapeTypes[shape] ? shapeTypes[shape] : 0) + 1;
|
||||
shapeTypes['all']++;
|
||||
|
||||
features.push(new Feature({
|
||||
datetime: line[0],
|
||||
year: parseInt(/[0-9]{4}/.exec(line[0])[0]), // extract the year as int
|
||||
shape: shape,
|
||||
duration: line[3],
|
||||
geometry: new Point(coords)
|
||||
}));
|
||||
}
|
||||
vectorSource.addFeatures(features);
|
||||
fillShapeSelect();
|
||||
};
|
||||
client.send();
|
||||
|
||||
map.addLayer(
|
||||
new WebGLPointsLayer({
|
||||
source: vectorSource,
|
||||
style: style
|
||||
})
|
||||
);
|
||||
|
||||
const info = document.getElementById('info');
|
||||
map.on('pointermove', function(evt) {
|
||||
if (map.getView().getInteracting()) {
|
||||
if (map.getView().getInteracting() || map.getView().getAnimating()) {
|
||||
return;
|
||||
}
|
||||
const pixel = evt.pixel;
|
||||
@@ -242,7 +156,3 @@ map.on('pointermove', function(evt) {
|
||||
info.innerText = 'On ' + datetime + ', lasted ' + duration + ' seconds and had a "' + shape + '" shape.';
|
||||
});
|
||||
});
|
||||
|
||||
texture.addEventListener('load', function() {
|
||||
map.render();
|
||||
});
|
||||
|
||||
@@ -56,35 +56,32 @@ const featureOverlay = new VectorLayer({
|
||||
let highlight;
|
||||
const displayFeatureInfo = function(pixel) {
|
||||
|
||||
const feature = map.forEachFeatureAtPixel(pixel, function(feature) {
|
||||
return feature;
|
||||
});
|
||||
map.getLayers().item(0).getFeatures(pixel).then(function(features) {
|
||||
const feature = features.length > 0 ? features[0] : undefined;
|
||||
|
||||
const info = document.getElementById('info');
|
||||
if (feature) {
|
||||
info.innerHTML = feature.getId() + ': ' + feature.get('name');
|
||||
} else {
|
||||
info.innerHTML = ' ';
|
||||
}
|
||||
|
||||
if (feature !== highlight) {
|
||||
if (highlight) {
|
||||
featureOverlay.getSource().removeFeature(highlight);
|
||||
}
|
||||
const info = document.getElementById('info');
|
||||
if (feature) {
|
||||
featureOverlay.getSource().addFeature(feature);
|
||||
info.innerHTML = feature.getId() + ': ' + feature.get('name');
|
||||
} else {
|
||||
info.innerHTML = ' ';
|
||||
}
|
||||
highlight = feature;
|
||||
}
|
||||
|
||||
if (feature !== highlight) {
|
||||
if (highlight) {
|
||||
featureOverlay.getSource().removeFeature(highlight);
|
||||
}
|
||||
if (feature) {
|
||||
featureOverlay.getSource().addFeature(feature);
|
||||
}
|
||||
highlight = feature;
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
map.on('pointermove', function(evt) {
|
||||
if (evt.dragging) {
|
||||
return;
|
||||
if (!evt.dragging) {
|
||||
displayFeatureInfo(evt.pixel);
|
||||
}
|
||||
const pixel = map.getEventPixel(evt.originalEvent);
|
||||
displayFeatureInfo(pixel);
|
||||
});
|
||||
|
||||
map.on('click', function(evt) {
|
||||
|
||||
15
examples/immediate-geographic.html
Normal file
@@ -0,0 +1,15 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Immediate Rendering (Geographic)
|
||||
shortdesc: Using the immediate rendering API with geometries in geographic coordinates.
|
||||
docs: >
|
||||
This example uses the "immediate" rendering API with geometries in geographic coordinates.
|
||||
The immediate rendering API lets you draw styled geometries without adding them to a layer first.
|
||||
Use the `getVectorContext` function to create a rendering context from a render event. Using the
|
||||
`context.drawGeometry()` and `context.setStyle()` methods on this rendering context, you can draw
|
||||
any geometry on each render frame. The `useGeographic` function is used in this example so that
|
||||
geometries can be in geographic coordinates.
|
||||
tags: "immediate, geographic"
|
||||
experimental: true
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
64
examples/immediate-geographic.js
Normal file
@@ -0,0 +1,64 @@
|
||||
import {Map, View} from '../src/ol/index.js';
|
||||
import {Point} from '../src/ol/geom.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import Stamen from '../src/ol/source/Stamen.js';
|
||||
import {Circle, Fill, Style} from '../src/ol/style.js';
|
||||
import {getVectorContext} from '../src/ol/render.js';
|
||||
import {useGeographic} from '../src/ol/proj.js';
|
||||
import {upAndDown} from '../src/ol/easing.js';
|
||||
|
||||
useGeographic();
|
||||
|
||||
const layer = new TileLayer({
|
||||
source: new Stamen({
|
||||
layer: 'toner'
|
||||
})
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [layer],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2
|
||||
})
|
||||
});
|
||||
|
||||
const image = new Circle({
|
||||
radius: 8,
|
||||
fill: new Fill({color: 'rgb(255, 153, 0)'})
|
||||
});
|
||||
|
||||
const style = new Style({
|
||||
image: image
|
||||
});
|
||||
|
||||
const n = 1000;
|
||||
const geometries = new Array(n);
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const lon = 360 * Math.random() - 180;
|
||||
const lat = 180 * Math.random() - 90;
|
||||
geometries[i] = new Point([lon, lat]);
|
||||
}
|
||||
|
||||
layer.on('postrender', function(event) {
|
||||
const vectorContext = getVectorContext(event);
|
||||
|
||||
for (let i = 0; i < n; ++i) {
|
||||
const importance = upAndDown(Math.pow((n - i) / n, 0.15));
|
||||
if (importance < 0.1) {
|
||||
continue;
|
||||
}
|
||||
image.setOpacity(importance);
|
||||
image.setScale(importance);
|
||||
vectorContext.setStyle(style);
|
||||
vectorContext.drawGeometry(geometries[i]);
|
||||
}
|
||||
|
||||
const lon = 360 * Math.random() - 180;
|
||||
const lat = 180 * Math.random() - 90;
|
||||
geometries.push(new Point([lon, lat]));
|
||||
geometries.shift();
|
||||
map.render();
|
||||
});
|
||||
@@ -1,7 +1,10 @@
|
||||
---
|
||||
layout: example-verbatim.html
|
||||
title: Vector tiles created from a Mapbox Style object
|
||||
shortdesc: Example of using ol-mapbox-style with tiles from tilehosting.com.
|
||||
shortdesc: Example of using ol-mapbox-style with tiles from maptiler.com.
|
||||
docs: >
|
||||
Example of using `ol-mapbox-style` with tiles 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, mapbox style, ol-mapbox-style, maptiler"
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
|
||||
@@ -74,13 +74,9 @@ ol.inline>li {
|
||||
.ol-attribution.ol-logo-only,
|
||||
.ol-attribution.ol-uncollapsible {
|
||||
max-width: calc(100% - 3em);
|
||||
height: 1.5em;
|
||||
}
|
||||
.ol-attribution ul {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.ol-control button, .ol-attribution, .ol-scale-line-inner {
|
||||
font-family: 'Lucida Grande',Verdana,Geneva,Lucida,Arial,Helvetica,sans-serif;
|
||||
font-size: 14px;
|
||||
}
|
||||
.iframe-info iframe {
|
||||
width: 100%;
|
||||
|
||||
22
examples/select-features.html
Normal file
@@ -0,0 +1,22 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Select Features
|
||||
shortdesc: Example of using the Select interaction.
|
||||
docs: >
|
||||
Choose between <code>Single-click</code>, <code>Click</code>, <code>Hover</code> and <code>Alt+Click</code> as the event type for selection in the combobox below. When using <code>Single-click</code> or <code>Click</code> you can hold do <code>Shift</code> key to toggle the feature in the selection.</p>
|
||||
<p>Note: when <code>Single-click</code> is used double-clicks won't select features. This in contrast to <code>Click</code>, where a double-click will both select the feature and zoom the map (because of the <code>DoubleClickZoom</code> interaction). Note that <code>Single-click</code> is less responsive than <code>Click</code> because of the delay it uses to detect double-clicks.</p>
|
||||
<p>In this example, a listener is registered for the Select interaction's <code>select</code> event in order to update the selection status above.
|
||||
tags: "select, vector"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<form class="form-inline">
|
||||
<label>Action type </label>
|
||||
<select id="type" class="form-control">
|
||||
<option value="click" selected>Click</option>
|
||||
<option value="singleclick">Single-click</option>
|
||||
<option value="pointermove">Hover</option>
|
||||
<option value="altclick">Alt+Click</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
<span id="status"> 0 selected features</span>
|
||||
</form>
|
||||
@@ -23,7 +23,7 @@ map.on('pointermove', showInfo);
|
||||
const info = document.getElementById('info');
|
||||
function showInfo(event) {
|
||||
const features = map.getFeaturesAtPixel(event.pixel);
|
||||
if (!features) {
|
||||
if (features.length == 0) {
|
||||
info.innerText = '';
|
||||
info.style.opacity = 0;
|
||||
return;
|
||||
|
||||
@@ -7,18 +7,19 @@ import {Fill, Stroke, Style} from '../src/ol/style.js';
|
||||
|
||||
// lookup for selection objects
|
||||
let selection = {};
|
||||
// feature property to act as identifier
|
||||
const idProp = 'iso_a3';
|
||||
|
||||
const vtLayer = new VectorTileLayer({
|
||||
declutter: true,
|
||||
source: new VectorTileSource({
|
||||
format: new MVT(),
|
||||
maxZoom: 15,
|
||||
format: new MVT({
|
||||
idProperty: 'iso_a3'
|
||||
}),
|
||||
url: 'https://ahocevar.com/geoserver/gwc/service/tms/1.0.0/' +
|
||||
'ne:ne_10m_admin_0_countries@EPSG%3A900913@pbf/{z}/{x}/{-y}.pbf'
|
||||
}),
|
||||
style: function(feature) {
|
||||
const selected = !!selection[feature.get(idProp)];
|
||||
const selected = !!selection[feature.getId()];
|
||||
return new Style({
|
||||
stroke: new Stroke({
|
||||
color: selected ? 'rgba(200,20,20,0.8)' : 'gray',
|
||||
@@ -45,26 +46,27 @@ const map = new Map({
|
||||
const selectElement = document.getElementById('type');
|
||||
|
||||
map.on('click', function(event) {
|
||||
const features = map.getFeaturesAtPixel(event.pixel);
|
||||
if (!features) {
|
||||
selection = {};
|
||||
vtLayer.getFeatures(event.pixel).then(function(features) {
|
||||
if (!features.length) {
|
||||
selection = {};
|
||||
// force redraw of layer style
|
||||
vtLayer.setStyle(vtLayer.getStyle());
|
||||
return;
|
||||
}
|
||||
const feature = features[0];
|
||||
if (!feature) {
|
||||
return;
|
||||
}
|
||||
const fid = feature.getId();
|
||||
|
||||
if (selectElement.value === 'singleselect') {
|
||||
selection = {};
|
||||
}
|
||||
// add selected feature to lookup
|
||||
selection[fid] = feature;
|
||||
|
||||
// force redraw of layer style
|
||||
vtLayer.setStyle(vtLayer.getStyle());
|
||||
return;
|
||||
}
|
||||
const feature = features[0];
|
||||
if (!feature) {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
const fid = feature.get(idProp);
|
||||
|
||||
if (selectElement.value === 'singleselect') {
|
||||
selection = {};
|
||||
}
|
||||
// add selected feature to lookup
|
||||
selection[fid] = feature;
|
||||
|
||||
// force redraw of layer style
|
||||
vtLayer.setStyle(vtLayer.getStyle());
|
||||
});
|
||||
|
||||
13
examples/vector-tiles-4326.html
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Vector tiles in EPSG:4326
|
||||
shortdesc: Example showing vector tiles in EPSG:4326 (styled using ol-mapbox-style)
|
||||
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"
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map" style="background:none;"></div>
|
||||
50
examples/vector-tiles-4326.js
Normal file
@@ -0,0 +1,50 @@
|
||||
import View from '../src/ol/View.js';
|
||||
import MVT from '../src/ol/format/MVT.js';
|
||||
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';
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
|
||||
// Match the server resolutions
|
||||
const maxResolution = 360 / 512;
|
||||
defaultResolutions.length = 14;
|
||||
for (let i = 0; i < 14; ++i) {
|
||||
defaultResolutions[i] = maxResolution / Math.pow(2, i + 1);
|
||||
}
|
||||
|
||||
olms('map', 'https://api.maptiler.com/maps/basic-4326/style.json?key=' + key).then(function(map) {
|
||||
|
||||
// Custom tile grid for the EPSG:4326 projection
|
||||
const tileGrid = new TileGrid({
|
||||
extent: [-180, -90, 180, 90],
|
||||
tileSize: 512,
|
||||
resolutions: defaultResolutions
|
||||
});
|
||||
|
||||
const mapboxStyle = map.get('mapbox-style');
|
||||
|
||||
// Replace the source with a EPSG:4326 projection source for each vector tile layer
|
||||
map.getLayers().forEach(function(layer) {
|
||||
const mapboxSource = layer.get('mapbox-source');
|
||||
if (mapboxSource && mapboxStyle.sources[mapboxSource].type === 'vector') {
|
||||
const source = layer.getSource();
|
||||
layer.setSource(new VectorTileSource({
|
||||
format: new MVT(),
|
||||
projection: 'EPSG:4326',
|
||||
urls: source.getUrls(),
|
||||
tileGrid: tileGrid
|
||||
}));
|
||||
}
|
||||
});
|
||||
|
||||
// Configure the map with a view with EPSG:4326 projection
|
||||
map.setView(new View({
|
||||
projection: 'EPSG:4326',
|
||||
zoom: mapboxStyle.zoom,
|
||||
center: mapboxStyle.center
|
||||
}));
|
||||
|
||||
});
|
||||
@@ -24,15 +24,15 @@ experimental: true
|
||||
<div id="map" class="map"></div>
|
||||
<label>Choose a predefined style from the list below or edit it as JSON manually.</label><br>
|
||||
<select id="style-select">
|
||||
<option>Predefined styles</option>
|
||||
<option value="icons">Icons</option>
|
||||
<option value="triangles">Triangles, color related to population</option>
|
||||
<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>
|
||||
</select>
|
||||
<textarea style="width: 100%; height: 20rem; font-family: monospace; font-size: small;" id="style-editor"></textarea>
|
||||
<small id="style-valid" style="display: none; color: forestgreen">
|
||||
✓ style is valid
|
||||
</small>
|
||||
<small id="style-invalid" style="display: none; color: grey">
|
||||
✗ style not yet valid...
|
||||
<small>
|
||||
<span id="style-valid" style="display: none; color: forestgreen">✓ style is valid</span>
|
||||
<span id="style-invalid" style="display: none; color: grey">✗ <span>style not yet valid...</span></span>
|
||||
|
||||
</small>
|
||||
|
||||
@@ -27,27 +27,76 @@ const predefinedStyles = {
|
||||
symbolType: 'triangle',
|
||||
size: 18,
|
||||
color: [
|
||||
['stretch', ['get', 'population'], 20000, 300000, 0.1, 1.0],
|
||||
['stretch', ['get', 'population'], 20000, 300000, 0.6, 0.3],
|
||||
0.6,
|
||||
1.0
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
20000, '#5aca5b',
|
||||
300000, '#ff6a19'
|
||||
],
|
||||
rotateWithView: true
|
||||
}
|
||||
},
|
||||
'triangles-latitude': {
|
||||
symbol: {
|
||||
symbolType: 'triangle',
|
||||
size: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
40000, 12,
|
||||
2000000, 24
|
||||
],
|
||||
color: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'latitude'],
|
||||
-60, '#ff14c3',
|
||||
-20, '#ff621d',
|
||||
20, '#ffed02',
|
||||
60, '#00ff67'
|
||||
],
|
||||
offset: [0, 0],
|
||||
opacity: 0.95
|
||||
}
|
||||
},
|
||||
'circles': {
|
||||
symbol: {
|
||||
symbolType: 'circle',
|
||||
size: ['stretch', ['get', 'population'], 40000, 2000000, 8, 28],
|
||||
size: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
40000, 8,
|
||||
2000000, 28
|
||||
],
|
||||
color: '#006688',
|
||||
rotateWithView: false,
|
||||
offset: [0, 0],
|
||||
opacity: ['stretch', ['get', 'population'], 40000, 2000000, 0.6, 0.92]
|
||||
opacity: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['get', 'population'],
|
||||
40000, 0.6,
|
||||
2000000, 0.92
|
||||
]
|
||||
}
|
||||
},
|
||||
'circles-zoom': {
|
||||
symbol: {
|
||||
symbolType: 'circle',
|
||||
size: [
|
||||
'interpolate',
|
||||
['exponential', 2.5],
|
||||
['zoom'],
|
||||
2, 1,
|
||||
14, 32
|
||||
],
|
||||
color: '#240572',
|
||||
offset: [0, 0],
|
||||
opacity: 0.95
|
||||
}
|
||||
}
|
||||
};
|
||||
let literalStyle = predefinedStyles['circles'];
|
||||
let pointsLayer;
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
@@ -62,45 +111,59 @@ const map = new Map({
|
||||
})
|
||||
});
|
||||
|
||||
const editor = document.getElementById('style-editor');
|
||||
editor.value = JSON.stringify(literalStyle, null, 2);
|
||||
|
||||
function refreshLayer() {
|
||||
if (pointsLayer) {
|
||||
map.removeLayer(pointsLayer);
|
||||
}
|
||||
let literalStyle;
|
||||
let pointsLayer;
|
||||
function refreshLayer(newStyle) {
|
||||
const previousLayer = pointsLayer;
|
||||
pointsLayer = new WebGLPointsLayer({
|
||||
source: vectorSource,
|
||||
style: literalStyle
|
||||
style: newStyle,
|
||||
disableHitDetection: true
|
||||
});
|
||||
map.addLayer(pointsLayer);
|
||||
|
||||
if (previousLayer) {
|
||||
map.removeLayer(previousLayer);
|
||||
previousLayer.dispose();
|
||||
}
|
||||
literalStyle = newStyle;
|
||||
}
|
||||
|
||||
function setStyleStatus(valid) {
|
||||
document.getElementById('style-valid').style.display = valid ? 'initial' : 'none';
|
||||
document.getElementById('style-invalid').style.display = !valid ? 'initial' : 'none';
|
||||
const spanValid = document.getElementById('style-valid');
|
||||
const spanInvalid = document.getElementById('style-invalid');
|
||||
function setStyleStatus(errorMsg) {
|
||||
const isError = typeof errorMsg === 'string';
|
||||
spanValid.style.display = errorMsg === null ? 'initial' : 'none';
|
||||
spanInvalid.firstElementChild.innerText = isError ? errorMsg : '';
|
||||
spanInvalid.style.display = isError ? 'initial' : 'none';
|
||||
}
|
||||
|
||||
const editor = document.getElementById('style-editor');
|
||||
editor.addEventListener('input', function() {
|
||||
const textStyle = editor.value;
|
||||
if (JSON.stringify(JSON.parse(textStyle)) === JSON.stringify(literalStyle)) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
literalStyle = JSON.parse(textStyle);
|
||||
refreshLayer();
|
||||
setStyleStatus(true);
|
||||
const newLiteralStyle = JSON.parse(textStyle);
|
||||
if (JSON.stringify(newLiteralStyle) !== JSON.stringify(literalStyle)) {
|
||||
refreshLayer(newLiteralStyle);
|
||||
}
|
||||
setStyleStatus(null);
|
||||
} catch (e) {
|
||||
setStyleStatus(false);
|
||||
setStyleStatus(e.message);
|
||||
}
|
||||
});
|
||||
refreshLayer();
|
||||
|
||||
const select = document.getElementById('style-select');
|
||||
select.addEventListener('change', function() {
|
||||
select.value = 'circles';
|
||||
function onSelectChange() {
|
||||
const style = select.value;
|
||||
literalStyle = predefinedStyles[style];
|
||||
editor.value = JSON.stringify(literalStyle, null, 2);
|
||||
refreshLayer();
|
||||
});
|
||||
const newLiteralStyle = predefinedStyles[style];
|
||||
editor.value = JSON.stringify(newLiteralStyle, null, 2);
|
||||
try {
|
||||
refreshLayer(newLiteralStyle);
|
||||
setStyleStatus();
|
||||
} catch (e) {
|
||||
setStyleStatus(e.message);
|
||||
}
|
||||
}
|
||||
onSelectChange();
|
||||
select.addEventListener('change', onSelectChange);
|
||||
|
||||
896
package-lock.json
generated
42
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.0.0",
|
||||
"version": "6.1.1",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
"map",
|
||||
@@ -37,59 +37,59 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@openlayers/pepjs": "^0.5.3",
|
||||
"pbf": "3.2.0",
|
||||
"pbf": "3.2.1",
|
||||
"pixelworks": "1.1.0",
|
||||
"rbush": "^3.0.0"
|
||||
"rbush": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.4.0",
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/preset-env": "^7.4.4",
|
||||
"@openlayers/eslint-plugin": "^4.0.0",
|
||||
"@types/arcgis-rest-api": "^10.4.4",
|
||||
"@types/geojson": "^7946.0.7",
|
||||
"@types/pbf": "^3.0.1",
|
||||
"@types/pbf": "^3.0.2",
|
||||
"@types/topojson-specification": "^1.0.1",
|
||||
"babel-loader": "^8.0.5",
|
||||
"buble": "^0.19.7",
|
||||
"buble-loader": "^0.5.1",
|
||||
"chaikin-smooth": "^1.0.4",
|
||||
"clean-css-cli": "4.3.0",
|
||||
"copy-webpack-plugin": "^5.0.3",
|
||||
"coveralls": "3.0.6",
|
||||
"copy-webpack-plugin": "^5.0.4",
|
||||
"coveralls": "3.0.7",
|
||||
"eslint": "^6.0.0",
|
||||
"eslint-config-openlayers": "^12.0.0",
|
||||
"eslint-config-openlayers": "^13.0.0",
|
||||
"expect.js": "0.3.1",
|
||||
"front-matter": "^3.0.2",
|
||||
"fs-extra": "^8.0.0",
|
||||
"glob": "^7.1.4",
|
||||
"glob": "^7.1.5",
|
||||
"globby": "^10.0.0",
|
||||
"handlebars": "4.3.1",
|
||||
"handlebars": "4.4.5",
|
||||
"html-to-image": "^0.1.0",
|
||||
"istanbul": "0.4.5",
|
||||
"istanbul-instrumenter-loader": "^3.0.1",
|
||||
"jquery": "3.4.1",
|
||||
"jsdoc": "3.6.3",
|
||||
"jsdoc-plugin-typescript": "^2.0.2",
|
||||
"karma": "^4.1.0",
|
||||
"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.0.5",
|
||||
"karma-coverage-istanbul-reporter": "^2.1.0",
|
||||
"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.0",
|
||||
"ol-mapbox-style": "^5.0.0-beta.3",
|
||||
"pixelmatch": "^5.0.0",
|
||||
"mocha": "6.2.2",
|
||||
"ol-mapbox-style": "^5.0.2",
|
||||
"pixelmatch": "^5.1.0",
|
||||
"pngjs": "^3.4.0",
|
||||
"proj4": "2.5.0",
|
||||
"puppeteer": "~1.20.0",
|
||||
"rollup": "^1.12.0",
|
||||
"rollup-plugin-babel": "^4.3.2",
|
||||
"rollup": "^1.25.1",
|
||||
"rollup-plugin-babel": "^4.3.3",
|
||||
"rollup-plugin-commonjs": "^10.0.0",
|
||||
"rollup-plugin-node-resolve": "^5.0.0",
|
||||
"rollup-plugin-node-resolve": "^5.2.0",
|
||||
"rollup-plugin-terser": "^5.0.0",
|
||||
"serve-static": "^1.14.0",
|
||||
"shx": "^0.3.2",
|
||||
@@ -98,11 +98,11 @@
|
||||
"typescript": "3.5.3",
|
||||
"url-polyfill": "^1.1.5",
|
||||
"walk": "^2.3.9",
|
||||
"webpack": "4.41.0",
|
||||
"webpack": "4.41.2",
|
||||
"webpack-cli": "^3.3.2",
|
||||
"webpack-dev-middleware": "^3.6.2",
|
||||
"webpack-dev-server": "^3.3.1",
|
||||
"yargs": "^14.0.0"
|
||||
"yargs": "^14.2.0"
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "openlayers",
|
||||
|
||||
BIN
rendering/cases/immediate-geographic/expected.png
Normal file
|
After Width: | Height: | Size: 118 KiB |
40
rendering/cases/immediate-geographic/main.js
Normal file
@@ -0,0 +1,40 @@
|
||||
import {Map, View} from '../../../src/ol/index.js';
|
||||
import {Point} from '../../../src/ol/geom.js';
|
||||
import TileLayer from '../../../src/ol/layer/Tile.js';
|
||||
import {useGeographic} from '../../../src/ol/proj.js';
|
||||
import XYZ from '../../../src/ol/source/XYZ.js';
|
||||
import {Style, Circle, Fill} from '../../../src/ol/style.js';
|
||||
import {getVectorContext} from '../../../src/ol/render.js';
|
||||
|
||||
useGeographic();
|
||||
|
||||
const center = [8.6, 50.1];
|
||||
|
||||
const layer = new TileLayer({
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg',
|
||||
transition: 0
|
||||
})
|
||||
});
|
||||
|
||||
layer.on('postrender', event => {
|
||||
const context = getVectorContext(event);
|
||||
context.setStyle(new Style({
|
||||
image: new Circle({
|
||||
radius: 5,
|
||||
fill: new Fill({color: 'red'})
|
||||
})
|
||||
}));
|
||||
context.drawGeometry(new Point(center));
|
||||
});
|
||||
|
||||
new Map({
|
||||
target: 'map',
|
||||
layers: [layer],
|
||||
view: new View({
|
||||
center: center,
|
||||
zoom: 3
|
||||
})
|
||||
});
|
||||
|
||||
render();
|
||||
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
|
Before Width: | Height: | Size: 138 KiB After Width: | Height: | Size: 138 KiB |
BIN
rendering/cases/map-text-align/expected.png
Normal file
|
After Width: | Height: | Size: 112 KiB |
26
rendering/cases/map-text-align/index.html
Normal file
@@ -0,0 +1,26 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<style>
|
||||
html, body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
#map {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
.ol-control {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map"></div>
|
||||
<script src="main.js"></script>
|
||||
</body>
|
||||
</script>
|
||||
</html>
|
||||
24
rendering/cases/map-text-align/main.js
Normal file
@@ -0,0 +1,24 @@
|
||||
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 XYZ from '../../../src/ol/source/XYZ.js';
|
||||
|
||||
|
||||
new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new XYZ({
|
||||
url: '/data/tiles/satellite/{z}/{x}/{y}.jpg'
|
||||
})
|
||||
})
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
rotation: Math.PI / 3,
|
||||
center: fromLonLat([8.6, 50.1]),
|
||||
zoom: 3
|
||||
})
|
||||
});
|
||||
|
||||
render();
|
||||
|
Before Width: | Height: | Size: 7.7 KiB After Width: | Height: | Size: 7.5 KiB |
@@ -65,6 +65,22 @@ feature.setStyle(new Style({
|
||||
}));
|
||||
vectorSource.addFeature(feature);
|
||||
|
||||
// align left
|
||||
feature = new Feature({
|
||||
geometry: new Point([50, 50])
|
||||
});
|
||||
feature.setStyle(new Style({
|
||||
text: new Text({
|
||||
font: 'Ubuntu',
|
||||
text: 'align left',
|
||||
textAlign: 'left',
|
||||
stroke: new Stroke({
|
||||
color: [10, 10, 10, 0.5]
|
||||
})
|
||||
})
|
||||
}));
|
||||
vectorSource.addFeature(feature);
|
||||
|
||||
// background and padding
|
||||
feature = new Feature({
|
||||
geometry: new Point([-10, 0])
|
||||
|
||||
@@ -231,7 +231,7 @@ class Feature extends BaseObject {
|
||||
* styles. If it is `null` the feature has no style (a `null` style).
|
||||
* @param {import("./style/Style.js").StyleLike} style Style for this feature.
|
||||
* @api
|
||||
* @fires module:ol/events/Event~Event#event:change
|
||||
* @fires module:ol/events/Event~BaseEvent#event:change
|
||||
*/
|
||||
setStyle(style) {
|
||||
this.style_ = style;
|
||||
@@ -246,7 +246,7 @@ class Feature extends BaseObject {
|
||||
* {@link module:ol/source/Vector~VectorSource#getFeatureById} method.
|
||||
* @param {number|string|undefined} id The feature id.
|
||||
* @api
|
||||
* @fires module:ol/events/Event~Event#event:change
|
||||
* @fires module:ol/events/Event~BaseEvent#event:change
|
||||
*/
|
||||
setId(id) {
|
||||
this.id_ = id;
|
||||
|
||||
@@ -81,7 +81,7 @@ class GeolocationError extends BaseEvent {
|
||||
* window.console.log(geolocation.getPosition());
|
||||
* });
|
||||
*
|
||||
* @fires module:ol/events/Event~Event#event:error
|
||||
* @fires module:ol/events/Event~BaseEvent#event:error
|
||||
* @api
|
||||
*/
|
||||
class Geolocation extends BaseObject {
|
||||
@@ -98,7 +98,7 @@ class Geolocation extends BaseObject {
|
||||
/**
|
||||
* The unprojected (EPSG:4326) device position.
|
||||
* @private
|
||||
* @type {import("./coordinate.js").Coordinate}
|
||||
* @type {?import("./coordinate.js").Coordinate}
|
||||
*/
|
||||
this.position_ = null;
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ class ImageWrapper extends ImageBase {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function():void}
|
||||
* @type {?function():void}
|
||||
*/
|
||||
this.unlisten_ = null;
|
||||
|
||||
|
||||
@@ -46,7 +46,7 @@ class ImageCanvas extends ImageBase {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Error}
|
||||
* @type {?Error}
|
||||
*/
|
||||
this.error_ = null;
|
||||
|
||||
@@ -54,7 +54,7 @@ class ImageCanvas extends ImageBase {
|
||||
|
||||
/**
|
||||
* Get any error associated with asynchronous rendering.
|
||||
* @return {Error} Any error that occurred during rendering.
|
||||
* @return {?Error} Any error that occurred during rendering.
|
||||
*/
|
||||
getError() {
|
||||
return this.error_;
|
||||
|
||||
@@ -46,7 +46,7 @@ class ImageTile extends Tile {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {function():void}
|
||||
* @type {?function():void}
|
||||
*/
|
||||
this.unlisten_ = null;
|
||||
|
||||
@@ -69,8 +69,6 @@ class ImageTile extends Tile {
|
||||
if (this.interimTile) {
|
||||
this.interimTile.dispose();
|
||||
}
|
||||
this.state = TileState.ABORT;
|
||||
this.changed();
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
|
||||
@@ -31,13 +31,13 @@ class MapBrowserEvent extends MapEvent {
|
||||
|
||||
/**
|
||||
* The map pixel relative to the viewport corresponding to the original browser event.
|
||||
* @type {import("./pixel.js").Pixel}
|
||||
* @type {?import("./pixel.js").Pixel}
|
||||
*/
|
||||
this.pixel_ = null;
|
||||
|
||||
/**
|
||||
* The coordinate in the user projection corresponding to the original browser event.
|
||||
* @type {import("./coordinate.js").Coordinate}
|
||||
* @type {?import("./coordinate.js").Coordinate}
|
||||
*/
|
||||
this.coordinate_ = null;
|
||||
|
||||
|
||||
@@ -61,7 +61,6 @@ class MapBrowserEventHandler extends EventTarget {
|
||||
this.down_ = null;
|
||||
|
||||
const element = this.map_.getViewport();
|
||||
element.setAttribute('touch-action', 'none');
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
|
||||
@@ -13,7 +13,7 @@ import EventType from './events/EventType.js';
|
||||
* and unregistration. A generic `change` event is always available through
|
||||
* {@link module:ol/Observable~Observable#changed}.
|
||||
*
|
||||
* @fires import("./events/Event.js").Event
|
||||
* @fires import("./events/Event.js").default
|
||||
* @api
|
||||
*/
|
||||
class Observable extends EventTarget {
|
||||
|
||||
@@ -436,8 +436,8 @@ class Overlay extends BaseObject {
|
||||
|
||||
/**
|
||||
* Get the extent of an element relative to the document
|
||||
* @param {HTMLElement|undefined} element The element.
|
||||
* @param {import("./size.js").Size|undefined} size The size of the element.
|
||||
* @param {HTMLElement} element The element.
|
||||
* @param {import("./size.js").Size} size The size of the element.
|
||||
* @return {import("./extent.js").Extent} The extent.
|
||||
* @protected
|
||||
*/
|
||||
@@ -512,15 +512,18 @@ class Overlay extends BaseObject {
|
||||
positioning == OverlayPositioning.CENTER_RIGHT ||
|
||||
positioning == OverlayPositioning.TOP_RIGHT) {
|
||||
if (this.rendered.left_ !== '') {
|
||||
this.rendered.left_ = style.left = '';
|
||||
this.rendered.left_ = '';
|
||||
style.left = '';
|
||||
}
|
||||
const right = Math.round(mapSize[0] - pixel[0] - offsetX) + 'px';
|
||||
if (this.rendered.right_ != right) {
|
||||
this.rendered.right_ = style.right = right;
|
||||
this.rendered.right_ = right;
|
||||
style.right = right;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.right_ !== '') {
|
||||
this.rendered.right_ = style.right = '';
|
||||
this.rendered.right_ = '';
|
||||
style.right = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
@@ -529,22 +532,26 @@ class Overlay extends BaseObject {
|
||||
}
|
||||
const left = Math.round(pixel[0] + offsetX) + 'px';
|
||||
if (this.rendered.left_ != left) {
|
||||
this.rendered.left_ = style.left = left;
|
||||
this.rendered.left_ = left;
|
||||
style.left = left;
|
||||
}
|
||||
}
|
||||
if (positioning == OverlayPositioning.BOTTOM_LEFT ||
|
||||
positioning == OverlayPositioning.BOTTOM_CENTER ||
|
||||
positioning == OverlayPositioning.BOTTOM_RIGHT) {
|
||||
if (this.rendered.top_ !== '') {
|
||||
this.rendered.top_ = style.top = '';
|
||||
this.rendered.top_ = '';
|
||||
style.top = '';
|
||||
}
|
||||
const bottom = Math.round(mapSize[1] - pixel[1] - offsetY) + 'px';
|
||||
if (this.rendered.bottom_ != bottom) {
|
||||
this.rendered.bottom_ = style.bottom = bottom;
|
||||
this.rendered.bottom_ = bottom;
|
||||
style.bottom = bottom;
|
||||
}
|
||||
} else {
|
||||
if (this.rendered.bottom_ !== '') {
|
||||
this.rendered.bottom_ = style.bottom = '';
|
||||
this.rendered.bottom_ = '';
|
||||
style.bottom = '';
|
||||
}
|
||||
if (positioning == OverlayPositioning.CENTER_LEFT ||
|
||||
positioning == OverlayPositioning.CENTER_CENTER ||
|
||||
@@ -553,7 +560,8 @@ class Overlay extends BaseObject {
|
||||
}
|
||||
const top = Math.round(pixel[1] + offsetY) + 'px';
|
||||
if (this.rendered.top_ != top) {
|
||||
this.rendered.top_ = style.top = top;
|
||||
this.rendered.top_ = 'top';
|
||||
style.top = top;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,6 +131,17 @@ import {toUserCoordinate, fromUserCoordinate} from './proj.js';
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @param {HTMLElement} element Element.
|
||||
* @param {string} touchAction Value for `touch-action'.
|
||||
*/
|
||||
function setTouchAction(element, touchAction) {
|
||||
element.style.msTouchAction = touchAction;
|
||||
element.style.touchAction = touchAction;
|
||||
element.setAttribute('touch-action', touchAction);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @fires import("./MapBrowserEvent.js").MapBrowserEvent
|
||||
* @fires import("./MapEvent.js").MapEvent
|
||||
@@ -232,7 +243,7 @@ class PluggableMap extends BaseObject {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
* @type {?Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.layerGroupPropertyListenerKeys_ = null;
|
||||
|
||||
@@ -246,9 +257,7 @@ class PluggableMap extends BaseObject {
|
||||
this.viewport_.style.overflow = 'hidden';
|
||||
this.viewport_.style.width = '100%';
|
||||
this.viewport_.style.height = '100%';
|
||||
// prevent page zoom on IE >= 10 browsers
|
||||
this.viewport_.style.msTouchAction = 'none';
|
||||
this.viewport_.style.touchAction = 'none';
|
||||
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -292,10 +301,16 @@ class PluggableMap extends BaseObject {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
* @type {?Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.keyHandlerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {?Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.focusHandlerKeys_ = null;
|
||||
|
||||
const handleBrowserEvent = this.handleBrowserEvent.bind(this);
|
||||
this.viewport_.addEventListener(EventType.CONTEXTMENU, handleBrowserEvent, false);
|
||||
this.viewport_.addEventListener(EventType.WHEEL, handleBrowserEvent, false);
|
||||
@@ -312,16 +327,6 @@ class PluggableMap extends BaseObject {
|
||||
*/
|
||||
this.interactions = optionsInternal.interactions || new Collection();
|
||||
|
||||
/**
|
||||
* @type {import("./events/Target.js").default}
|
||||
*/
|
||||
this.labelCache_ = null;
|
||||
|
||||
/**
|
||||
* @type {import("./events.js").EventsKey}
|
||||
*/
|
||||
this.labelCacheListenerKey_;
|
||||
|
||||
/**
|
||||
* @type {Collection<import("./Overlay.js").default>}
|
||||
* @private
|
||||
@@ -342,7 +347,7 @@ class PluggableMap extends BaseObject {
|
||||
this.renderer_ = null;
|
||||
|
||||
/**
|
||||
* @type {function(Event): void|undefined}
|
||||
* @type {undefined|function(Event): void}
|
||||
* @private
|
||||
*/
|
||||
this.handleResize_;
|
||||
@@ -375,9 +380,9 @@ class PluggableMap extends BaseObject {
|
||||
* @param {import("./control/Control.js").default} control Control.
|
||||
* @this {PluggableMap}
|
||||
*/
|
||||
(function(control) {
|
||||
function(control) {
|
||||
control.setMap(this);
|
||||
}).bind(this));
|
||||
}.bind(this));
|
||||
|
||||
this.controls.addEventListener(CollectionEventType.ADD,
|
||||
/**
|
||||
@@ -400,9 +405,9 @@ class PluggableMap extends BaseObject {
|
||||
* @param {import("./interaction/Interaction.js").default} interaction Interaction.
|
||||
* @this {PluggableMap}
|
||||
*/
|
||||
(function(interaction) {
|
||||
function(interaction) {
|
||||
interaction.setMap(this);
|
||||
}).bind(this));
|
||||
}.bind(this));
|
||||
|
||||
this.interactions.addEventListener(CollectionEventType.ADD,
|
||||
/**
|
||||
@@ -549,8 +554,7 @@ class PluggableMap extends BaseObject {
|
||||
return;
|
||||
}
|
||||
const coordinate = this.getCoordinateFromPixelInternal(pixel);
|
||||
opt_options = opt_options !== undefined ? opt_options :
|
||||
/** @type {AtPixelOptions} */ ({});
|
||||
opt_options = opt_options !== undefined ? opt_options : {};
|
||||
const hitTolerance = opt_options.hitTolerance !== undefined ?
|
||||
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
||||
const layerFilter = opt_options.layerFilter !== undefined ?
|
||||
@@ -602,9 +606,9 @@ class PluggableMap extends BaseObject {
|
||||
if (!this.frameState_) {
|
||||
return;
|
||||
}
|
||||
const options = opt_options || /** @type {AtPixelOptions} */ ({});
|
||||
const options = opt_options || {};
|
||||
const hitTolerance = options.hitTolerance !== undefined ?
|
||||
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
||||
options.hitTolerance * this.frameState_.pixelRatio : 0;
|
||||
const layerFilter = options.layerFilter || TRUE;
|
||||
return this.renderer_.forEachLayerAtPixel(pixel, this.frameState_, hitTolerance, callback, layerFilter);
|
||||
}
|
||||
@@ -622,8 +626,7 @@ class PluggableMap extends BaseObject {
|
||||
return false;
|
||||
}
|
||||
const coordinate = this.getCoordinateFromPixelInternal(pixel);
|
||||
opt_options = opt_options !== undefined ? opt_options :
|
||||
/** @type {AtPixelOptions} */ ({});
|
||||
opt_options = opt_options !== undefined ? opt_options : {};
|
||||
const layerFilter = opt_options.layerFilter !== undefined ? opt_options.layerFilter : TRUE;
|
||||
const hitTolerance = opt_options.hitTolerance !== undefined ?
|
||||
opt_options.hitTolerance * this.frameState_.pixelRatio : 0;
|
||||
@@ -1040,6 +1043,12 @@ class PluggableMap extends BaseObject {
|
||||
targetElement = this.getTargetElement();
|
||||
}
|
||||
|
||||
if (this.focusHandlerKeys_) {
|
||||
for (let i = 0, ii = this.focusHandlerKeys_.length; i < ii; ++i) {
|
||||
unlistenByKey(this.focusHandlerKeys_[i]);
|
||||
}
|
||||
this.focusHandlerKeys_ = null;
|
||||
}
|
||||
if (this.keyHandlerKeys_) {
|
||||
for (let i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
|
||||
unlistenByKey(this.keyHandlerKeys_[i]);
|
||||
@@ -1068,6 +1077,15 @@ class PluggableMap extends BaseObject {
|
||||
if (!this.renderer_) {
|
||||
this.renderer_ = this.createRenderer();
|
||||
}
|
||||
let hasFocus = true;
|
||||
if (targetElement.hasAttribute('tabindex')) {
|
||||
hasFocus = document.activeElement === targetElement;
|
||||
this.focusHandlerKeys_ = [
|
||||
listen(targetElement, EventType.FOCUS, setTouchAction.bind(this, this.viewport_, 'none')),
|
||||
listen(targetElement, EventType.BLUR, setTouchAction.bind(this, this.viewport_, 'auto'))
|
||||
];
|
||||
}
|
||||
setTouchAction(this.viewport_, hasFocus ? 'none' : 'auto');
|
||||
|
||||
const keyboardEventTarget = !this.keyboardEventTarget_ ?
|
||||
targetElement : this.keyboardEventTarget_;
|
||||
|
||||
@@ -144,6 +144,13 @@ class Tile extends EventTarget {
|
||||
this.dispatchEvent(EventType.CHANGE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setState(TileState.ABORT);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} Key.
|
||||
*/
|
||||
@@ -241,6 +248,9 @@ class Tile extends EventTarget {
|
||||
* @api
|
||||
*/
|
||||
setState(state) {
|
||||
if (this.state !== TileState.ERROR && this.state > state) {
|
||||
throw new Error('Tile load sequence violation');
|
||||
}
|
||||
this.state = state;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
@@ -112,12 +112,10 @@ class TileQueue extends PriorityQueue {
|
||||
if (state === TileState.ABORT) {
|
||||
abortedTiles = true;
|
||||
} else if (state === TileState.IDLE && !(tileKey in this.tilesLoadingKeys_)) {
|
||||
this.tilesLoadingKeys_[tileKey] = true;
|
||||
++this.tilesLoading_;
|
||||
++newLoads;
|
||||
tile.load();
|
||||
if (tile.getState() === TileState.LOADING) {
|
||||
this.tilesLoadingKeys_[tileKey] = true;
|
||||
++this.tilesLoading_;
|
||||
++newLoads;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newLoads === 0 && abortedTiles) {
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
*/
|
||||
import {getUid} from './util.js';
|
||||
import Tile from './Tile.js';
|
||||
import TileState from './TileState.js';
|
||||
import {createCanvasContext2D} from './dom.js';
|
||||
import {unlistenByKey} from './events.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -24,7 +24,7 @@ class VectorRenderTile extends Tile {
|
||||
|
||||
/**
|
||||
* @param {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @param {TileState} state State.
|
||||
* @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
|
||||
@@ -60,6 +60,11 @@ class VectorRenderTile extends Tile {
|
||||
*/
|
||||
this.errorSourceTileKeys = {};
|
||||
|
||||
/**
|
||||
* @type {ImageData}
|
||||
*/
|
||||
this.hitDetectionImageData = null;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Object<string, ReplayState>}
|
||||
@@ -72,9 +77,9 @@ class VectorRenderTile extends Tile {
|
||||
this.wantedResolution;
|
||||
|
||||
/**
|
||||
* @type {!function(import("./VectorRenderTile.js").default):Array<import("./VectorTile.js").default>}
|
||||
* @type {!function():Array<import("./VectorTile.js").default>}
|
||||
*/
|
||||
this.getSourceTiles_ = getSourceTiles;
|
||||
this.getSourceTiles = getSourceTiles.bind(this, this);
|
||||
|
||||
/**
|
||||
* @type {!function(import("./VectorRenderTile.js").default):void}
|
||||
@@ -87,6 +92,11 @@ class VectorRenderTile extends Tile {
|
||||
*/
|
||||
this.sourceTileGrid_ = sourceTileGrid;
|
||||
|
||||
/**
|
||||
* @type {Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.sourceTileListenerKeys = [];
|
||||
|
||||
/**
|
||||
* z of the source tiles of the last getSourceTiles call.
|
||||
* @type {number}
|
||||
@@ -109,10 +119,13 @@ class VectorRenderTile extends Tile {
|
||||
* @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 = canvas.height = 0;
|
||||
canvas.width = 0;
|
||||
canvas.height = 0;
|
||||
}
|
||||
for (const key in this.executorGroups) {
|
||||
const executorGroups = this.executorGroups[key];
|
||||
@@ -120,7 +133,6 @@ class VectorRenderTile extends Tile {
|
||||
executorGroups[i].disposeInternal();
|
||||
}
|
||||
}
|
||||
this.setState(TileState.ABORT);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
@@ -178,7 +190,7 @@ class VectorRenderTile extends Tile {
|
||||
* @inheritDoc
|
||||
*/
|
||||
load() {
|
||||
this.getSourceTiles_(this);
|
||||
this.getSourceTiles();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -73,14 +73,6 @@ class VectorTile extends Tile {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setState(TileState.ABORT);
|
||||
super.disposeInternal();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the feature format assigned for reading this tile's features.
|
||||
* @return {import("./format/Feature.js").default} Feature format.
|
||||
|
||||
@@ -37,10 +37,12 @@ export function createExtent(extent, onlyCenter, smooth) {
|
||||
// note: when zooming out of bounds, min and max values for x and y may
|
||||
// end up inverted (min > max); this has to be accounted for
|
||||
if (minX > maxX) {
|
||||
minX = maxX = (maxX + minX) / 2;
|
||||
minX = (maxX + minX) / 2;
|
||||
maxX = minX;
|
||||
}
|
||||
if (minY > maxY) {
|
||||
minY = maxY = (maxY + minY) / 2;
|
||||
minY = (maxY + minY) / 2;
|
||||
maxY = minY;
|
||||
}
|
||||
|
||||
let x = clamp(center[0], minX, maxX);
|
||||
|
||||
@@ -30,7 +30,7 @@ const HEX_COLOR_RE_ = /^#([a-f0-9]{3}|[a-f0-9]{4}(?:[a-f0-9]{2}){0,2})$/i;
|
||||
* @type {RegExp}
|
||||
* @private
|
||||
*/
|
||||
const NAMED_COLOR_RE_ = /^([a-z]*)$/i;
|
||||
const NAMED_COLOR_RE_ = /^([a-z]*)$|^hsla?\(.*\)$/i;
|
||||
|
||||
|
||||
/**
|
||||
@@ -223,3 +223,14 @@ export function toString(color) {
|
||||
const a = color[3] === undefined ? 1 : color[3];
|
||||
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} s String.
|
||||
* @return {boolean} Whether the string is actually a valid color
|
||||
*/
|
||||
export function isStringColor(s) {
|
||||
if (NAMED_COLOR_RE_.test(s)) {
|
||||
s = fromNamed(s);
|
||||
}
|
||||
return HEX_COLOR_RE_.test(s) || s.indexOf('rgba(') === 0 || s.indexOf('rgb(') === 0;
|
||||
}
|
||||
|
||||
@@ -97,7 +97,7 @@ class MousePosition extends Control {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../proj/Projection.js").default}
|
||||
* @type {?import("../proj/Projection.js").default}
|
||||
*/
|
||||
this.mapProjection_ = null;
|
||||
|
||||
|
||||
@@ -216,8 +216,8 @@ class OverviewMap extends Control {
|
||||
|
||||
const computeDesiredMousePosition = function(mousePosition) {
|
||||
return {
|
||||
clientX: mousePosition.clientX - (overlayBox.offsetWidth / 2),
|
||||
clientY: mousePosition.clientY + (overlayBox.offsetHeight / 2)
|
||||
clientX: mousePosition.clientX,
|
||||
clientY: mousePosition.clientY
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
@@ -126,7 +126,7 @@ class ScaleLine extends Control {
|
||||
|
||||
this.addEventListener(getChangeEventType(UNITS_PROP), this.handleUnitsChanged_);
|
||||
|
||||
this.setUnits(/** @type {Units} */ (options.units) || Units.METRIC);
|
||||
this.setUnits(options.units || Units.METRIC);
|
||||
|
||||
/**
|
||||
* @private
|
||||
|
||||
@@ -41,7 +41,7 @@ class ZoomToExtent extends Control {
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {import("../extent.js").Extent}
|
||||
* @type {?import("../extent.js").Extent}
|
||||
* @protected
|
||||
*/
|
||||
this.extent = options.extent ? options.extent : null;
|
||||
|
||||
@@ -72,6 +72,9 @@ export const CLASS_COLLAPSED = 'ol-collapsed';
|
||||
* @return {FontParameters} The font families (or null if the input spec is invalid).
|
||||
*/
|
||||
export const getFontParameters = (function() {
|
||||
/**
|
||||
* @type {CSSStyleDeclaration}
|
||||
*/
|
||||
let style;
|
||||
/**
|
||||
* @type {Object<string, FontParameters>}
|
||||
|
||||
@@ -9,18 +9,19 @@
|
||||
export default {
|
||||
/**
|
||||
* Generic change event. Triggered when the revision counter is increased.
|
||||
* @event module:ol/events/Event~Event#change
|
||||
* @event module:ol/events/Event~BaseEvent#change
|
||||
* @api
|
||||
*/
|
||||
CHANGE: 'change',
|
||||
|
||||
/**
|
||||
* Generic error event. Triggered when an error occurs.
|
||||
* @event module:ol/events/Event~Event#error
|
||||
* @event module:ol/events/Event~BaseEvent#error
|
||||
* @api
|
||||
*/
|
||||
ERROR: 'error',
|
||||
|
||||
BLUR: 'blur',
|
||||
CLEAR: 'clear',
|
||||
CONTEXTMENU: 'contextmenu',
|
||||
CLICK: 'click',
|
||||
@@ -28,6 +29,7 @@ export default {
|
||||
DRAGENTER: 'dragenter',
|
||||
DRAGOVER: 'dragover',
|
||||
DROP: 'drop',
|
||||
FOCUS: 'focus',
|
||||
KEYDOWN: 'keydown',
|
||||
KEYPRESS: 'keypress',
|
||||
LOAD: 'load',
|
||||
|
||||
@@ -40,7 +40,7 @@ class Target extends Disposable {
|
||||
* @private
|
||||
* @type {*}
|
||||
*/
|
||||
this.target_ = opt_target;
|
||||
this.eventTarget_ = opt_target;
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -72,7 +72,8 @@ class Target extends Disposable {
|
||||
}
|
||||
let listeners = this.listeners_[type];
|
||||
if (!listeners) {
|
||||
listeners = this.listeners_[type] = [];
|
||||
listeners = [];
|
||||
this.listeners_[type] = listeners;
|
||||
}
|
||||
if (listeners.indexOf(listener) === -1) {
|
||||
listeners.push(listener);
|
||||
@@ -96,7 +97,7 @@ class Target extends Disposable {
|
||||
const evt = typeof event === 'string' ? new Event(event) : event;
|
||||
const type = evt.type;
|
||||
if (!evt.target) {
|
||||
evt.target = this.target_ || this;
|
||||
evt.target = this.eventTarget_ || this;
|
||||
}
|
||||
const listeners = this.listeners_[type];
|
||||
let propagate;
|
||||
|
||||
@@ -1777,7 +1777,9 @@ function setCommonGeometryProperties(multiGeometry, geometries) {
|
||||
const tessellates = new Array(geometries.length);
|
||||
const altitudeModes = new Array(geometries.length);
|
||||
let hasExtrude, hasTessellate, hasAltitudeMode;
|
||||
hasExtrude = hasTessellate = hasAltitudeMode = false;
|
||||
hasExtrude = false;
|
||||
hasTessellate = false;
|
||||
hasAltitudeMode = false;
|
||||
for (let i = 0; i < ii; ++i) {
|
||||
const geometry = geometries[i];
|
||||
extrudes[i] = geometry.get('extrude');
|
||||
|
||||
@@ -73,7 +73,7 @@ class TopoJSON extends JSONFeature {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<string>}
|
||||
* @type {?Array<string>}
|
||||
*/
|
||||
this.layers_ = options.layers ? options.layers : null;
|
||||
|
||||
|
||||
@@ -31,6 +31,9 @@ class Bbox extends Filter {
|
||||
* @type {import("../../extent.js").Extent}
|
||||
*/
|
||||
this.extent = extent;
|
||||
if (extent.length !== 4) {
|
||||
throw new Error('Expected an extent with four values ([minX, minY, maxX, maxY])');
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {string|undefined}
|
||||
|
||||
@@ -39,10 +39,10 @@ export function VOID() {}
|
||||
export function memoizeOne(fn) {
|
||||
let called = false;
|
||||
|
||||
/** @type ReturnType */
|
||||
/** @type {ReturnType} */
|
||||
let lastResult;
|
||||
|
||||
/** @type Array<any> */
|
||||
/** @type {Array<any>} */
|
||||
let lastArgs;
|
||||
|
||||
let lastThis;
|
||||
|
||||
@@ -5,7 +5,7 @@ import {abstract} from '../util.js';
|
||||
import BaseObject from '../Object.js';
|
||||
import {createEmpty, getHeight, returnOrUpdate} from '../extent.js';
|
||||
import {transform2D} from './flat/transform.js';
|
||||
import {get as getProjection, getTransform, getTransformFromProjections} from '../proj.js';
|
||||
import {get as getProjection, getTransform} from '../proj.js';
|
||||
import Units from '../proj/Units.js';
|
||||
import {create as createTransform, compose as composeTransform} from '../transform.js';
|
||||
import {memoizeOne} from '../functions.js';
|
||||
@@ -62,17 +62,15 @@ class Geometry extends BaseObject {
|
||||
* @abstract
|
||||
* @param {number} revision The geometry revision.
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @param {import("../proj/Projection.js").default} [sourceProjection] The source projection.
|
||||
* @param {import("../proj/Projection.js").default} [destProjection] The destination projection.
|
||||
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
|
||||
* @return {Geometry} Simplified geometry.
|
||||
*/
|
||||
this.simplifyTransformedInternal = memoizeOne(function(revision, squaredTolerance, sourceProjection, destProjection) {
|
||||
if (!sourceProjection || !destProjection) {
|
||||
this.simplifyTransformedInternal = memoizeOne(function(revision, squaredTolerance, opt_transform) {
|
||||
if (!opt_transform) {
|
||||
return this.getSimplifiedGeometry(squaredTolerance);
|
||||
}
|
||||
const transform = getTransformFromProjections(sourceProjection, destProjection);
|
||||
const clone = this.clone();
|
||||
clone.applyTransform(transform);
|
||||
clone.applyTransform(opt_transform);
|
||||
return clone.getSimplifiedGeometry(squaredTolerance);
|
||||
});
|
||||
|
||||
@@ -82,12 +80,11 @@ class Geometry extends BaseObject {
|
||||
* Get a transformed and simplified version of the geometry.
|
||||
* @abstract
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @param {import("../proj/Projection.js").default} sourceProjection The source projection.
|
||||
* @param {import("../proj/Projection.js").default} destProjection The destination projection.
|
||||
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
|
||||
* @return {Geometry} Simplified geometry.
|
||||
*/
|
||||
simplifyTransformed(squaredTolerance, sourceProjection, destProjection) {
|
||||
return this.simplifyTransformedInternal(this.getRevision(), squaredTolerance, sourceProjection, destProjection);
|
||||
simplifyTransformed(squaredTolerance, opt_transform) {
|
||||
return this.simplifyTransformedInternal(this.getRevision(), squaredTolerance, opt_transform);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -232,12 +229,13 @@ class Geometry extends BaseObject {
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply a transform function to each coordinate of the geometry.
|
||||
* Apply a transform function to the coordinates of the geometry.
|
||||
* The geometry is modified in place.
|
||||
* If you do not want the geometry modified in place, first `clone()` it and
|
||||
* then use this function on the clone.
|
||||
* @abstract
|
||||
* @param {import("../proj.js").TransformFunction} transformFn Transform.
|
||||
* @param {import("../proj.js").TransformFunction} transformFn Transform function.
|
||||
* Called with a flat array of geometry coordinates.
|
||||
*/
|
||||
applyTransform(transformFn) {
|
||||
abstract();
|
||||
|
||||
@@ -187,7 +187,12 @@ class SimpleGeometry extends Geometry {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Apply a transform function to the coordinates of the geometry.
|
||||
* The geometry is modified in place.
|
||||
* If you do not want the geometry modified in place, first `clone()` it and
|
||||
* then use this function on the clone.
|
||||
* @param {import("../proj.js").TransformFunction} transformFn Transform function.
|
||||
* Called with a flat array of geometry coordinates.
|
||||
* @api
|
||||
*/
|
||||
applyTransform(transformFn) {
|
||||
@@ -198,7 +203,10 @@ class SimpleGeometry extends Geometry {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Rotate the geometry around a given coordinate. This modifies the geometry
|
||||
* coordinates in place.
|
||||
* @param {number} angle Rotation angle in radians.
|
||||
* @param {import("../coordinate.js").Coordinate} anchor The rotation center.
|
||||
* @api
|
||||
*/
|
||||
rotate(angle, anchor) {
|
||||
@@ -213,7 +221,13 @@ class SimpleGeometry extends Geometry {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Scale the geometry (with an optional origin). This modifies the geometry
|
||||
* coordinates in place.
|
||||
* @param {number} sx The scaling factor in the x-direction.
|
||||
* @param {number=} opt_sy The scaling factor in the y-direction (defaults to
|
||||
* sx).
|
||||
* @param {import("../coordinate.js").Coordinate=} opt_anchor The scale origin (defaults to the center
|
||||
* of the geometry extent).
|
||||
* @api
|
||||
*/
|
||||
scale(sx, opt_sy, opt_anchor) {
|
||||
@@ -236,7 +250,10 @@ class SimpleGeometry extends Geometry {
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* Translate the geometry. This modifies the geometry coordinates in place. If
|
||||
* instead you want a new geometry, first `clone()` this geometry.
|
||||
* @param {number} deltaX Delta X.
|
||||
* @param {number} deltaY Delta Y.
|
||||
* @api
|
||||
*/
|
||||
translate(deltaX, deltaY) {
|
||||
|
||||
@@ -115,7 +115,7 @@ class DragAndDrop extends Interaction {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<import("../events.js").EventsKey>}
|
||||
* @type {?Array<import("../events.js").EventsKey>}
|
||||
*/
|
||||
this.dropListenKeys_ = null;
|
||||
|
||||
|
||||
@@ -654,7 +654,8 @@ class Modify extends PointerInteraction {
|
||||
};
|
||||
|
||||
const featureSegments = [centerSegmentData, circumferenceSegmentData];
|
||||
centerSegmentData.featureSegments = circumferenceSegmentData.featureSegments = featureSegments;
|
||||
centerSegmentData.featureSegments = featureSegments;
|
||||
circumferenceSegmentData.featureSegments = featureSegments;
|
||||
this.rBush_.insert(createExtent(coordinates), centerSegmentData);
|
||||
this.rBush_.insert(geometry.getExtent(), circumferenceSegmentData);
|
||||
}
|
||||
@@ -746,12 +747,14 @@ class Modify extends PointerInteraction {
|
||||
switch (geometry.getType()) {
|
||||
case GeometryType.POINT:
|
||||
coordinates = vertex;
|
||||
segment[0] = segment[1] = vertex;
|
||||
segment[0] = vertex;
|
||||
segment[1] = vertex;
|
||||
break;
|
||||
case GeometryType.MULTI_POINT:
|
||||
coordinates = geometry.getCoordinates();
|
||||
coordinates[segmentData.index] = vertex;
|
||||
segment[0] = segment[1] = vertex;
|
||||
segment[0] = vertex;
|
||||
segment[1] = vertex;
|
||||
break;
|
||||
case GeometryType.LINE_STRING:
|
||||
coordinates = geometry.getCoordinates();
|
||||
@@ -774,7 +777,8 @@ class Modify extends PointerInteraction {
|
||||
segment[index] = vertex;
|
||||
break;
|
||||
case GeometryType.CIRCLE:
|
||||
segment[0] = segment[1] = vertex;
|
||||
segment[0] = vertex;
|
||||
segment[1] = vertex;
|
||||
if (segmentData.index === CIRCLE_CENTER_INDEX) {
|
||||
this.changingFeature_ = true;
|
||||
geometry.setCenter(vertex);
|
||||
@@ -889,8 +893,10 @@ class Modify extends PointerInteraction {
|
||||
const coordinates = geometry.getCenter();
|
||||
const centerSegmentData = segmentData.featureSegments[0];
|
||||
const circumferenceSegmentData = segmentData.featureSegments[1];
|
||||
centerSegmentData.segment[0] = centerSegmentData.segment[1] = coordinates;
|
||||
circumferenceSegmentData.segment[0] = circumferenceSegmentData.segment[1] = coordinates;
|
||||
centerSegmentData.segment[0] = coordinates;
|
||||
centerSegmentData.segment[1] = coordinates;
|
||||
circumferenceSegmentData.segment[0] = coordinates;
|
||||
circumferenceSegmentData.segment[1] = coordinates;
|
||||
this.rBush_.update(createExtent(coordinates), centerSegmentData);
|
||||
this.rBush_.update(geometry.getExtent(), circumferenceSegmentData);
|
||||
} else {
|
||||
@@ -920,12 +926,12 @@ class Modify extends PointerInteraction {
|
||||
*/
|
||||
handlePointerAtPixel_(pixel, map) {
|
||||
const pixelCoordinate = map.getCoordinateFromPixel(pixel);
|
||||
const projection = map.getView().getProjection();
|
||||
const sortByDistance = function(a, b) {
|
||||
return pointDistanceToSegmentDataSquared(pixelCoordinate, a) -
|
||||
pointDistanceToSegmentDataSquared(pixelCoordinate, b);
|
||||
return projectedDistanceToSegmentDataSquared(pixelCoordinate, a, projection) -
|
||||
projectedDistanceToSegmentDataSquared(pixelCoordinate, b, projection);
|
||||
};
|
||||
|
||||
const projection = map.getView().getProjection();
|
||||
const viewExtent = fromUserExtent(createExtent(pixelCoordinate, tempExtent), projection);
|
||||
const buffer = map.getView().getResolution() * this.pixelTolerance_;
|
||||
const box = toUserExtent(bufferExtent(viewExtent, buffer, tempExtent), projection);
|
||||
@@ -1235,9 +1241,10 @@ function compareIndexes(a, b) {
|
||||
* which to calculate the distance.
|
||||
* @param {SegmentData} segmentData The object describing the line
|
||||
* segment we are calculating the distance to.
|
||||
* @param {import("../proj/Projection.js").default} projection The view projection.
|
||||
* @return {number} The square of the distance between a point and a line segment.
|
||||
*/
|
||||
function pointDistanceToSegmentDataSquared(pointCoordinates, segmentData) {
|
||||
function projectedDistanceToSegmentDataSquared(pointCoordinates, segmentData, projection) {
|
||||
const geometry = segmentData.geometry;
|
||||
|
||||
if (geometry.getType() === GeometryType.CIRCLE) {
|
||||
@@ -1251,7 +1258,11 @@ function pointDistanceToSegmentDataSquared(pointCoordinates, segmentData) {
|
||||
return distanceToCircumference * distanceToCircumference;
|
||||
}
|
||||
}
|
||||
return squaredDistanceToSegment(pointCoordinates, segmentData.segment);
|
||||
|
||||
const coordinate = fromUserCoordinate(pointCoordinates, projection);
|
||||
tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
|
||||
tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
|
||||
return squaredDistanceToSegment(coordinate, tempSegment);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,9 +20,11 @@ import {getValues} from '../obj.js';
|
||||
* propagation of the event to other interactions in the map's interactions
|
||||
* chain.
|
||||
* @property {function(import("../MapBrowserPointerEvent.js").default)} [handleMoveEvent]
|
||||
* Function handling "move" events. This function is called on "move" events,
|
||||
* also during a drag sequence (so during a drag sequence both the
|
||||
* `handleDragEvent` function and this function are called).
|
||||
* Function handling "move" events. This function is called on "move" events.
|
||||
* This functions is also called during a drag sequence, so during a drag
|
||||
* sequence both the `handleDragEvent` function and this function are called.
|
||||
* If `handleDownEvent` is defined and it returns true this function will not
|
||||
* be called during a drag sequence.
|
||||
* @property {function(import("../MapBrowserPointerEvent.js").default):boolean} [handleUpEvent]
|
||||
* Function handling "up" events. If the function returns `false` then the
|
||||
* current drag sequence is stopped.
|
||||
|
||||
@@ -5,7 +5,7 @@ import {getUid} from '../util.js';
|
||||
import CollectionEventType from '../CollectionEventType.js';
|
||||
import {extend, includes} from '../array.js';
|
||||
import Event from '../events/Event.js';
|
||||
import {singleClick, never, shiftKeyOnly, pointerMove} from '../events/condition.js';
|
||||
import {singleClick, never, shiftKeyOnly} from '../events/condition.js';
|
||||
import {TRUE} from '../functions.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
import Interaction from './Interaction.js';
|
||||
@@ -61,6 +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.
|
||||
* @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.
|
||||
@@ -206,7 +207,7 @@ class Select extends Interaction {
|
||||
* @private
|
||||
* @type {import("../style/Style.js").default|Array.<import("../style/Style.js").default>|import("../style/Style.js").StyleFunction|null}
|
||||
*/
|
||||
this.style_ = options.style ? options.style : getDefaultStyleFunction();
|
||||
this.style_ = options.style !== undefined ? options.style : getDefaultStyleFunction();
|
||||
|
||||
/**
|
||||
* An association between selected feature (key)
|
||||
@@ -467,7 +468,7 @@ function handleEvent(mapBrowserEvent) {
|
||||
new SelectEvent(SelectEventType.SELECT,
|
||||
selected, deselected, mapBrowserEvent));
|
||||
}
|
||||
return pointerMove(mapBrowserEvent);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -14,6 +14,7 @@ import PointerInteraction from './Pointer.js';
|
||||
import {getValues} from '../obj.js';
|
||||
import VectorEventType from '../source/VectorEventType.js';
|
||||
import RBush from '../structs/RBush.js';
|
||||
import {fromUserCoordinate, toUserCoordinate} from '../proj.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -52,9 +53,10 @@ function getFeatureFromEvent(evt) {
|
||||
} else if (/** @type {import("../Collection.js").CollectionEvent} */ (evt).element) {
|
||||
return /** @type {import("../Feature.js").default} */ (/** @type {import("../Collection.js").CollectionEvent} */ (evt).element);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const tempSegment = [];
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Handles snapping of vector features while modifying or drawing them. The
|
||||
@@ -70,10 +72,12 @@ function getFeatureFromEvent(evt) {
|
||||
*
|
||||
* import Snap from 'ol/interaction/Snap';
|
||||
*
|
||||
* var snap = new Snap({
|
||||
* const snap = new Snap({
|
||||
* source: source
|
||||
* });
|
||||
*
|
||||
* map.addInteraction(snap);
|
||||
*
|
||||
* @api
|
||||
*/
|
||||
class Snap extends PointerInteraction {
|
||||
@@ -149,13 +153,6 @@ class Snap extends PointerInteraction {
|
||||
*/
|
||||
this.pendingFeatures_ = {};
|
||||
|
||||
/**
|
||||
* Used for distance sorting in sortByDistance_
|
||||
* @type {import("../coordinate.js").Coordinate}
|
||||
* @private
|
||||
*/
|
||||
this.pixelCoordinate_ = null;
|
||||
|
||||
/**
|
||||
* @type {number}
|
||||
* @private
|
||||
@@ -163,13 +160,6 @@ class Snap extends PointerInteraction {
|
||||
this.pixelTolerance_ = options.pixelTolerance !== undefined ?
|
||||
options.pixelTolerance : 10;
|
||||
|
||||
/**
|
||||
* @type {function(SegmentData, SegmentData): number}
|
||||
* @private
|
||||
*/
|
||||
this.sortByDistance_ = sortByDistance.bind(this);
|
||||
|
||||
|
||||
/**
|
||||
* Segment RTree for each layer
|
||||
* @type {import("../structs/RBush.js").default<SegmentData>}
|
||||
@@ -177,22 +167,21 @@ class Snap extends PointerInteraction {
|
||||
*/
|
||||
this.rBush_ = new RBush();
|
||||
|
||||
|
||||
/**
|
||||
* @const
|
||||
* @private
|
||||
* @type {Object<string, function(import("../Feature.js").default, import("../geom/Geometry.js").default): void>}
|
||||
*/
|
||||
this.SEGMENT_WRITERS_ = {
|
||||
'Point': this.writePointGeometry_,
|
||||
'LineString': this.writeLineStringGeometry_,
|
||||
'LinearRing': this.writeLineStringGeometry_,
|
||||
'Polygon': this.writePolygonGeometry_,
|
||||
'MultiPoint': this.writeMultiPointGeometry_,
|
||||
'MultiLineString': this.writeMultiLineStringGeometry_,
|
||||
'MultiPolygon': this.writeMultiPolygonGeometry_,
|
||||
'GeometryCollection': this.writeGeometryCollectionGeometry_,
|
||||
'Circle': this.writeCircleGeometry_
|
||||
'Point': this.writePointGeometry_.bind(this),
|
||||
'LineString': this.writeLineStringGeometry_.bind(this),
|
||||
'LinearRing': this.writeLineStringGeometry_.bind(this),
|
||||
'Polygon': this.writePolygonGeometry_.bind(this),
|
||||
'MultiPoint': this.writeMultiPointGeometry_.bind(this),
|
||||
'MultiLineString': this.writeMultiLineStringGeometry_.bind(this),
|
||||
'MultiPolygon': this.writeMultiPolygonGeometry_.bind(this),
|
||||
'GeometryCollection': this.writeGeometryCollectionGeometry_.bind(this),
|
||||
'Circle': this.writeCircleGeometry_.bind(this)
|
||||
};
|
||||
}
|
||||
|
||||
@@ -211,7 +200,7 @@ class Snap extends PointerInteraction {
|
||||
const segmentWriter = this.SEGMENT_WRITERS_[geometry.getType()];
|
||||
if (segmentWriter) {
|
||||
this.indexedFeaturesExtents_[feature_uid] = geometry.getExtent(createEmpty());
|
||||
segmentWriter.call(this, feature, geometry);
|
||||
segmentWriter(feature, geometry);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -383,10 +372,9 @@ class Snap extends PointerInteraction {
|
||||
* @return {Result} Snap result
|
||||
*/
|
||||
snapTo(pixel, pixelCoordinate, map) {
|
||||
|
||||
const lowerLeft = map.getCoordinateFromPixelInternal(
|
||||
const lowerLeft = map.getCoordinateFromPixel(
|
||||
[pixel[0] - this.pixelTolerance_, pixel[1] + this.pixelTolerance_]);
|
||||
const upperRight = map.getCoordinateFromPixelInternal(
|
||||
const upperRight = map.getCoordinateFromPixel(
|
||||
[pixel[0] + this.pixelTolerance_, pixel[1] - this.pixelTolerance_]);
|
||||
const box = boundingExtent([lowerLeft, upperRight]);
|
||||
|
||||
@@ -400,57 +388,78 @@ class Snap extends PointerInteraction {
|
||||
});
|
||||
}
|
||||
|
||||
let snappedToVertex = false;
|
||||
let snapped = false;
|
||||
let vertex = null;
|
||||
let vertexPixel = null;
|
||||
let dist, pixel1, pixel2, squaredDist1, squaredDist2;
|
||||
if (segments.length > 0) {
|
||||
this.pixelCoordinate_ = pixelCoordinate;
|
||||
segments.sort(this.sortByDistance_);
|
||||
const closestSegment = segments[0].segment;
|
||||
const isCircle = segments[0].feature.getGeometry().getType() ===
|
||||
GeometryType.CIRCLE;
|
||||
if (this.vertex_ && !this.edge_) {
|
||||
pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]);
|
||||
pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]);
|
||||
squaredDist1 = squaredCoordinateDistance(pixel, pixel1);
|
||||
squaredDist2 = squaredCoordinateDistance(pixel, pixel2);
|
||||
dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
||||
snappedToVertex = dist <= this.pixelTolerance_;
|
||||
if (snappedToVertex) {
|
||||
snapped = true;
|
||||
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
|
||||
vertexPixel = map.getPixelFromCoordinateInternal(vertex);
|
||||
}
|
||||
} else if (this.edge_) {
|
||||
if (isCircle) {
|
||||
vertex = closestOnCircle(pixelCoordinate,
|
||||
/** @type {import("../geom/Circle.js").default} */ (segments[0].feature.getGeometry()));
|
||||
} else {
|
||||
vertex = closestOnSegment(pixelCoordinate, closestSegment);
|
||||
}
|
||||
vertexPixel = map.getPixelFromCoordinateInternal(vertex);
|
||||
if (coordinateDistance(pixel, vertexPixel) <= this.pixelTolerance_) {
|
||||
snapped = true;
|
||||
if (this.vertex_ && !isCircle) {
|
||||
pixel1 = map.getPixelFromCoordinateInternal(closestSegment[0]);
|
||||
pixel2 = map.getPixelFromCoordinateInternal(closestSegment[1]);
|
||||
squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
|
||||
squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
|
||||
dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
||||
snappedToVertex = dist <= this.pixelTolerance_;
|
||||
if (snappedToVertex) {
|
||||
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
|
||||
vertexPixel = map.getPixelFromCoordinateInternal(vertex);
|
||||
}
|
||||
|
||||
if (segments.length === 0) {
|
||||
return {
|
||||
snapped: snapped,
|
||||
vertex: vertex,
|
||||
vertexPixel: vertexPixel
|
||||
};
|
||||
}
|
||||
|
||||
const projection = map.getView().getProjection();
|
||||
const projectedCoordinate = fromUserCoordinate(pixelCoordinate, projection);
|
||||
|
||||
let closestSegmentData;
|
||||
let minSquaredDistance = Infinity;
|
||||
for (let i = 0; i < segments.length; ++i) {
|
||||
const segmentData = segments[i];
|
||||
tempSegment[0] = fromUserCoordinate(segmentData.segment[0], projection);
|
||||
tempSegment[1] = fromUserCoordinate(segmentData.segment[1], projection);
|
||||
const delta = squaredDistanceToSegment(projectedCoordinate, tempSegment);
|
||||
if (delta < minSquaredDistance) {
|
||||
closestSegmentData = segmentData;
|
||||
minSquaredDistance = delta;
|
||||
}
|
||||
}
|
||||
const closestSegment = closestSegmentData.segment;
|
||||
|
||||
if (this.vertex_ && !this.edge_) {
|
||||
const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
|
||||
const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
|
||||
const squaredDist1 = squaredCoordinateDistance(pixel, pixel1);
|
||||
const squaredDist2 = squaredCoordinateDistance(pixel, pixel2);
|
||||
const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
||||
if (dist <= this.pixelTolerance_) {
|
||||
snapped = true;
|
||||
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
|
||||
vertexPixel = map.getPixelFromCoordinate(vertex);
|
||||
}
|
||||
} else if (this.edge_) {
|
||||
const isCircle = closestSegmentData.feature.getGeometry().getType() === GeometryType.CIRCLE;
|
||||
if (isCircle) {
|
||||
vertex = closestOnCircle(pixelCoordinate,
|
||||
/** @type {import("../geom/Circle.js").default} */ (closestSegmentData.feature.getGeometry()));
|
||||
} else {
|
||||
tempSegment[0] = fromUserCoordinate(closestSegment[0], projection);
|
||||
tempSegment[1] = fromUserCoordinate(closestSegment[1], projection);
|
||||
vertex = toUserCoordinate(closestOnSegment(projectedCoordinate, tempSegment), projection);
|
||||
}
|
||||
vertexPixel = map.getPixelFromCoordinate(vertex);
|
||||
|
||||
if (coordinateDistance(pixel, vertexPixel) <= this.pixelTolerance_) {
|
||||
snapped = true;
|
||||
if (this.vertex_ && !isCircle) {
|
||||
const pixel1 = map.getPixelFromCoordinate(closestSegment[0]);
|
||||
const pixel2 = map.getPixelFromCoordinate(closestSegment[1]);
|
||||
const squaredDist1 = squaredCoordinateDistance(vertexPixel, pixel1);
|
||||
const squaredDist2 = squaredCoordinateDistance(vertexPixel, pixel2);
|
||||
const dist = Math.sqrt(Math.min(squaredDist1, squaredDist2));
|
||||
if (dist <= this.pixelTolerance_) {
|
||||
vertex = squaredDist1 > squaredDist2 ? closestSegment[1] : closestSegment[0];
|
||||
vertexPixel = map.getPixelFromCoordinate(vertex);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (snapped) {
|
||||
vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
|
||||
}
|
||||
}
|
||||
|
||||
if (snapped) {
|
||||
vertexPixel = [Math.round(vertexPixel[0]), Math.round(vertexPixel[1])];
|
||||
}
|
||||
|
||||
return {
|
||||
snapped: snapped,
|
||||
vertex: vertex,
|
||||
@@ -495,7 +504,7 @@ class Snap extends PointerInteraction {
|
||||
for (let i = 0; i < geometries.length; ++i) {
|
||||
const segmentWriter = this.SEGMENT_WRITERS_[geometries[i].getType()];
|
||||
if (segmentWriter) {
|
||||
segmentWriter.call(this, feature, geometries[i]);
|
||||
segmentWriter(feature, geometries[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -613,17 +622,4 @@ class Snap extends PointerInteraction {
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sort segments by distance, helper function
|
||||
* @param {SegmentData} a The first segment data.
|
||||
* @param {SegmentData} b The second segment data.
|
||||
* @return {number} The difference in distance.
|
||||
* @this {Snap}
|
||||
*/
|
||||
function sortByDistance(a, b) {
|
||||
const deltaA = squaredDistanceToSegment(this.pixelCoordinate_, a.segment);
|
||||
const deltaB = squaredDistanceToSegment(this.pixelCoordinate_, b.segment);
|
||||
return deltaA - deltaB;
|
||||
}
|
||||
|
||||
export default Snap;
|
||||
|
||||
@@ -198,7 +198,7 @@ class Translate extends PointerInteraction {
|
||||
handleDownEvent(event) {
|
||||
this.lastFeature_ = this.featuresAtPixel_(event.pixel, event.map);
|
||||
if (!this.lastCoordinate_ && this.lastFeature_) {
|
||||
this.startCoordinate_ =
|
||||
this.startCoordinate_ = event.coordinate;
|
||||
this.lastCoordinate_ = event.coordinate;
|
||||
this.handleMoveEvent(event);
|
||||
|
||||
|
||||
@@ -105,14 +105,14 @@ class BaseLayer extends BaseObject {
|
||||
/** @type {import("./Layer.js").State} */
|
||||
const state = this.state_ || /** @type {?} */ ({
|
||||
layer: this,
|
||||
managed: opt_managed === undefined ? true : opt_managed,
|
||||
hasOverlay: false
|
||||
managed: opt_managed === undefined ? true : opt_managed
|
||||
});
|
||||
const zIndex = this.getZIndex();
|
||||
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
|
||||
state.sourceState = this.getSourceState();
|
||||
state.visible = this.getVisible();
|
||||
state.extent = this.getExtent();
|
||||
state.zIndex = this.getZIndex() || (state.managed === false ? Infinity : 0);
|
||||
state.zIndex = zIndex !== undefined ? zIndex : (state.managed === false ? Infinity : 0);
|
||||
state.maxResolution = this.getMaxResolution();
|
||||
state.minResolution = Math.max(this.getMinResolution(), 0);
|
||||
state.minZoom = this.getMinZoom();
|
||||
@@ -320,6 +320,17 @@ class BaseLayer extends BaseObject {
|
||||
setZIndex(zindex) {
|
||||
this.set(LayerProperty.Z_INDEX, zindex);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.state_) {
|
||||
this.state_.layer = null;
|
||||
this.state_ = null;
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -135,6 +135,24 @@ class BaseVectorLayer extends Layer {
|
||||
return this.declutter_;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the topmost feature that intersects the given pixel on the viewport. Returns a promise
|
||||
* that resolves with an array of features. The array will either contain the topmost feature
|
||||
* when a hit was detected, or it will be empty.
|
||||
*
|
||||
* The hit detection algorithm used for this method is optimized for performance, but is less
|
||||
* accurate than the one used in {@link import("../PluggableMap.js").default#getFeaturesAtPixel}: Text
|
||||
* is not considered, and icons are only represented by their bounding box instead of the exact
|
||||
* image.
|
||||
*
|
||||
* @param {import("../pixel.js").Pixel} pixel Pixel.
|
||||
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with an array of features.
|
||||
* @api
|
||||
*/
|
||||
getFeatures(pixel) {
|
||||
return super.getFeatures(pixel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {number|undefined} Render buffer.
|
||||
*/
|
||||
|
||||
@@ -318,10 +318,23 @@ class Graticule extends VectorLayer {
|
||||
options.latLabelPosition;
|
||||
|
||||
/**
|
||||
* @type {Object.<string,Style>}
|
||||
* @type {Style}
|
||||
* @private
|
||||
*/
|
||||
this.lonLabelStyleCache_ = {};
|
||||
this.lonLabelStyleBase_ = new Style({
|
||||
text: options.lonLabelStyle !== undefined ? options.lonLabelStyle.clone() :
|
||||
new Text({
|
||||
font: '12px Calibri,sans-serif',
|
||||
textBaseline: 'bottom',
|
||||
fill: new Fill({
|
||||
color: 'rgba(0,0,0,1)'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(255,255,255,1)',
|
||||
width: 3
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -330,31 +343,28 @@ class Graticule extends VectorLayer {
|
||||
*/
|
||||
this.lonLabelStyle_ = function(feature) {
|
||||
const label = feature.get('graticule_label');
|
||||
if (!this.lonLabelStyleCache_[label]) {
|
||||
this.lonLabelStyleCache_[label] = new Style({
|
||||
text: options.lonLabelStyle !== undefined ? options.lonLabelStyle :
|
||||
new Text({
|
||||
text: label,
|
||||
font: '12px Calibri,sans-serif',
|
||||
textBaseline: 'bottom',
|
||||
fill: new Fill({
|
||||
color: 'rgba(0,0,0,1)'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(255,255,255,1)',
|
||||
width: 3
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
return this.lonLabelStyleCache_[label];
|
||||
this.lonLabelStyleBase_.getText().setText(label);
|
||||
return this.lonLabelStyleBase_;
|
||||
}.bind(this);
|
||||
|
||||
/**
|
||||
* @type {Object.<string,Style>}
|
||||
* @type {Style}
|
||||
* @private
|
||||
*/
|
||||
this.latLabelStyleCache_ = {};
|
||||
this.latLabelStyleBase_ = new Style({
|
||||
text: options.latLabelStyle !== undefined ? options.latLabelStyle.clone() :
|
||||
new Text({
|
||||
font: '12px Calibri,sans-serif',
|
||||
textAlign: 'right',
|
||||
fill: new Fill({
|
||||
color: 'rgba(0,0,0,1)'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(255,255,255,1)',
|
||||
width: 3
|
||||
})
|
||||
})
|
||||
});
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -363,24 +373,8 @@ class Graticule extends VectorLayer {
|
||||
*/
|
||||
this.latLabelStyle_ = function(feature) {
|
||||
const label = feature.get('graticule_label');
|
||||
if (!this.latLabelStyleCache_[label]) {
|
||||
this.latLabelStyleCache_[label] = new Style({
|
||||
text: options.latLabelStyle !== undefined ? options.latLabelStyle :
|
||||
new Text({
|
||||
text: label,
|
||||
font: '12px Calibri,sans-serif',
|
||||
textAlign: 'right',
|
||||
fill: new Fill({
|
||||
color: 'rgba(0,0,0,1)'
|
||||
}),
|
||||
stroke: new Stroke({
|
||||
color: 'rgba(255,255,255,1)',
|
||||
width: 3
|
||||
})
|
||||
})
|
||||
});
|
||||
}
|
||||
return this.latLabelStyleCache_[label];
|
||||
this.latLabelStyleBase_.getText().setText(label);
|
||||
return this.latLabelStyleBase_;
|
||||
}.bind(this);
|
||||
|
||||
this.meridiansLabels_ = [];
|
||||
@@ -421,7 +415,7 @@ class Graticule extends VectorLayer {
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {import("../extent.js").Extent}
|
||||
* @type {?import("../extent.js").Extent}
|
||||
*/
|
||||
this.renderedExtent_ = null;
|
||||
|
||||
@@ -587,7 +581,8 @@ class Graticule extends VectorLayer {
|
||||
createGraticule_(extent, center, resolution, squaredTolerance) {
|
||||
const interval = this.getInterval_(resolution);
|
||||
if (interval == -1) {
|
||||
this.meridians_.length = this.parallels_.length = 0;
|
||||
this.meridians_.length = 0;
|
||||
this.parallels_.length = 0;
|
||||
if (this.meridiansLabels_) {
|
||||
this.meridiansLabels_.length = 0;
|
||||
}
|
||||
@@ -714,7 +709,8 @@ class Graticule extends VectorLayer {
|
||||
const flatCoordinates = meridian(lon, minLat, maxLat, this.projection_, squaredTolerance);
|
||||
let lineString = this.meridians_[index];
|
||||
if (!lineString) {
|
||||
lineString = this.meridians_[index] = new LineString(flatCoordinates, GeometryLayout.XY);
|
||||
lineString = new LineString(flatCoordinates, GeometryLayout.XY);
|
||||
this.meridians_[index] = lineString;
|
||||
} else {
|
||||
lineString.setFlatCoordinates(GeometryLayout.XY, flatCoordinates);
|
||||
lineString.changed();
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import {getChangeEventType} from '../Object.js';
|
||||
import {createCanvasContext2D} from '../dom.js';
|
||||
import VectorLayer from './Vector.js';
|
||||
import {clamp} from '../math.js';
|
||||
import {assign} from '../obj.js';
|
||||
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
|
||||
|
||||
@@ -180,7 +181,10 @@ class Heatmap extends VectorLayer {
|
||||
attributes: [
|
||||
{
|
||||
name: 'weight',
|
||||
callback: this.weightFunction_
|
||||
callback: function(feature) {
|
||||
const weight = this.weightFunction_(feature);
|
||||
return weight !== undefined ? clamp(weight, 0, 1) : 1;
|
||||
}.bind(this)
|
||||
}
|
||||
],
|
||||
vertexShader: `
|
||||
@@ -220,6 +224,51 @@ class Heatmap extends VectorLayer {
|
||||
float alpha = smoothstep(0.0, 1.0, value) * v_weight;
|
||||
gl_FragColor = vec4(alpha, alpha, alpha, alpha);
|
||||
}`,
|
||||
hitVertexShader: `
|
||||
precision mediump float;
|
||||
uniform mat4 u_projectionMatrix;
|
||||
uniform mat4 u_offsetScaleMatrix;
|
||||
uniform float u_size;
|
||||
attribute vec2 a_position;
|
||||
attribute float a_index;
|
||||
attribute float a_weight;
|
||||
attribute vec4 a_hitColor;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying float v_weight;
|
||||
varying vec4 v_hitColor;
|
||||
|
||||
void main(void) {
|
||||
mat4 offsetMatrix = u_offsetScaleMatrix;
|
||||
float offsetX = a_index == 0.0 || a_index == 3.0 ? -u_size / 2.0 : u_size / 2.0;
|
||||
float offsetY = a_index == 0.0 || a_index == 1.0 ? -u_size / 2.0 : u_size / 2.0;
|
||||
vec4 offsets = offsetMatrix * vec4(offsetX, offsetY, 0.0, 0.0);
|
||||
gl_Position = u_projectionMatrix * vec4(a_position, 0.0, 1.0) + offsets;
|
||||
float u = a_index == 0.0 || a_index == 3.0 ? 0.0 : 1.0;
|
||||
float v = a_index == 0.0 || a_index == 1.0 ? 0.0 : 1.0;
|
||||
v_texCoord = vec2(u, v);
|
||||
v_hitColor = a_hitColor;
|
||||
v_weight = a_weight;
|
||||
}`,
|
||||
hitFragmentShader: `
|
||||
precision mediump float;
|
||||
uniform float u_blurSlope;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
varying float v_weight;
|
||||
varying vec4 v_hitColor;
|
||||
|
||||
void main(void) {
|
||||
vec2 texCoord = v_texCoord * 2.0 - vec2(1.0, 1.0);
|
||||
float sqRadius = texCoord.x * texCoord.x + texCoord.y * texCoord.y;
|
||||
float value = (1.0 - sqrt(sqRadius)) * u_blurSlope;
|
||||
float alpha = smoothstep(0.0, 1.0, value) * v_weight;
|
||||
if (alpha < 0.05) {
|
||||
discard;
|
||||
}
|
||||
|
||||
gl_FragColor = v_hitColor;
|
||||
}`,
|
||||
uniforms: {
|
||||
u_size: function() {
|
||||
return (this.get(Property.RADIUS) + this.get(Property.BLUR)) * 2;
|
||||
|
||||
@@ -5,11 +5,6 @@ import BaseImageLayer from './BaseImage.js';
|
||||
import CanvasImageLayerRenderer from '../renderer/canvas/ImageLayer.js';
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {import("./BaseImage.js").Options} Options
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* Server-rendered images that are available for arbitrary extents and
|
||||
@@ -23,7 +18,7 @@ import CanvasImageLayerRenderer from '../renderer/canvas/ImageLayer.js';
|
||||
class ImageLayer extends BaseImageLayer {
|
||||
|
||||
/**
|
||||
* @param {Options=} opt_options Layer options.
|
||||
* @param {import("./BaseImage.js").Options=} opt_options Layer options.
|
||||
*/
|
||||
constructor(opt_options) {
|
||||
super(opt_options);
|
||||
|
||||
@@ -46,7 +46,6 @@ import SourceState from '../source/State.js';
|
||||
* @property {SourceState} sourceState
|
||||
* @property {boolean} visible
|
||||
* @property {boolean} managed
|
||||
* @property {boolean} hasOverlay Set by the renderer when an overlay for points and text is used.
|
||||
* @property {import("../extent.js").Extent} [extent]
|
||||
* @property {number} zIndex
|
||||
* @property {number} maxResolution
|
||||
@@ -192,6 +191,15 @@ class Layer extends BaseLayer {
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("../pixel").Pixel} pixel Pixel.
|
||||
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with
|
||||
* an array of features.
|
||||
*/
|
||||
getFeatures(pixel) {
|
||||
return this.renderer_.getFeatures(pixel);
|
||||
}
|
||||
|
||||
/**
|
||||
* In charge to manage the rendering of the layer. One layer type is
|
||||
* bounded with one layer renderer.
|
||||
@@ -279,6 +287,13 @@ class Layer extends BaseLayer {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.setSource(null);
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -116,6 +116,24 @@ class VectorTileLayer extends BaseVectorLayer {
|
||||
return new CanvasVectorTileLayerRenderer(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the topmost feature that intersects the given pixel on the viewport. Returns a promise
|
||||
* that resolves with an array of features. The array will either contain the topmost feature
|
||||
* when a hit was detected, or it will be empty.
|
||||
*
|
||||
* The hit detection algorithm used for this method is optimized for performance, but is less
|
||||
* accurate than the one used in {@link import("../PluggableMap.js").default#getFeaturesAtPixel}: Text
|
||||
* is not considered, and icons are only represented by their bounding box instead of the exact
|
||||
* image.
|
||||
*
|
||||
* @param {import("../pixel.js").Pixel} pixel Pixel.
|
||||
* @return {Promise<Array<import("../Feature").default>>} Promise that resolves with an array of features.
|
||||
* @api
|
||||
*/
|
||||
getFeatures(pixel) {
|
||||
return super.getFeatures(pixel);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {VectorTileRenderType} The render mode.
|
||||
*/
|
||||
|
||||
@@ -3,8 +3,7 @@
|
||||
*/
|
||||
import {assign} from '../obj.js';
|
||||
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
|
||||
import {getSymbolFragmentShader, getSymbolVertexShader, parseSymbolStyle} from '../webgl/ShaderBuilder.js';
|
||||
import {assert} from '../asserts.js';
|
||||
import {parseLiteralStyle} from '../webgl/ShaderBuilder.js';
|
||||
import Layer from './Layer.js';
|
||||
|
||||
|
||||
@@ -25,6 +24,8 @@ import Layer from './Layer.js';
|
||||
* @property {number} [maxResolution] The maximum resolution (exclusive) below which this layer will
|
||||
* be visible.
|
||||
* @property {import("../source/Vector.js").default} [source] Source.
|
||||
* @property {boolean} [disableHitDetection] Setting this to true will provide a slight performance boost, but will
|
||||
* prevent all hit detection on the layer.
|
||||
*/
|
||||
|
||||
|
||||
@@ -56,6 +57,9 @@ import Layer from './Layer.js';
|
||||
* }
|
||||
* ```
|
||||
*
|
||||
* **Important: a `WebGLPoints` layer must be manually disposed when removed, otherwise the underlying WebGL context
|
||||
* will not be garbage collected.**
|
||||
*
|
||||
* Note that any property set in the options is set as a {@link module:ol/Object~BaseObject}
|
||||
* property on the layer object; for example, setting `title: 'My Title'` in the
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
@@ -72,26 +76,42 @@ class WebGLPointsLayer extends Layer {
|
||||
super(baseOptions);
|
||||
|
||||
/**
|
||||
* @type {import('../style/LiteralStyle.js').LiteralStyle}
|
||||
* @private
|
||||
* @type {import('../webgl/ShaderBuilder.js').StyleParseResult}
|
||||
*/
|
||||
this.style = options.style;
|
||||
this.parseResult_ = parseLiteralStyle(options.style);
|
||||
|
||||
assert(this.style.symbol !== undefined, 65);
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.hitDetectionDisabled_ = !!options.disableHitDetection;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
createRenderer() {
|
||||
const parseResult = parseSymbolStyle(this.style.symbol);
|
||||
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
vertexShader: getSymbolVertexShader(parseResult.params),
|
||||
fragmentShader: getSymbolFragmentShader(parseResult.params),
|
||||
uniforms: parseResult.uniforms,
|
||||
attributes: parseResult.attributes
|
||||
vertexShader: this.parseResult_.builder.getSymbolVertexShader(),
|
||||
fragmentShader: this.parseResult_.builder.getSymbolFragmentShader(),
|
||||
hitVertexShader: !this.hitDetectionDisabled_ &&
|
||||
this.parseResult_.builder.getSymbolVertexShader(true),
|
||||
hitFragmentShader: !this.hitDetectionDisabled_ &&
|
||||
this.parseResult_.builder.getSymbolFragmentShader(true),
|
||||
uniforms: this.parseResult_.uniforms,
|
||||
attributes: this.parseResult_.attributes
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @inheritDoc
|
||||
*/
|
||||
disposeInternal() {
|
||||
this.renderer_.dispose();
|
||||
super.disposeInternal();
|
||||
}
|
||||
}
|
||||
|
||||
export default WebGLPointsLayer;
|
||||
|
||||
@@ -182,15 +182,12 @@
|
||||
.ol-attribution ul {
|
||||
margin: 0;
|
||||
padding: 0 .5em;
|
||||
font-size: .7rem;
|
||||
line-height: 1.375em;
|
||||
color: #000;
|
||||
text-shadow: 0 0 2px #fff;
|
||||
}
|
||||
.ol-attribution li {
|
||||
display: inline;
|
||||
list-style: none;
|
||||
line-height: inherit;
|
||||
}
|
||||
.ol-attribution li:not(:last-child):after {
|
||||
content: " ";
|
||||
@@ -213,8 +210,6 @@
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
border-radius: 4px 0 0;
|
||||
height: 1.1em;
|
||||
line-height: 1em;
|
||||
}
|
||||
.ol-attribution.ol-uncollapsible img {
|
||||
margin-top: -.2em;
|
||||
|
||||
@@ -499,7 +499,7 @@ export function transformWithProjections(point, sourceProjection, destinationPro
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Projection}
|
||||
* @type {?Projection}
|
||||
*/
|
||||
let userProjection = null;
|
||||
|
||||
@@ -526,7 +526,7 @@ export function clearUserProjection() {
|
||||
* Get the projection for coordinates supplied from and returned by API methods.
|
||||
* Note that this method is not yet a part of the stable API. Support for user
|
||||
* projections is not yet complete and should be considered experimental.
|
||||
* @returns {Projection} The user projection (or null if not set).
|
||||
* @returns {?Projection} The user projection (or null if not set).
|
||||
*/
|
||||
export function getUserProjection() {
|
||||
return userProjection;
|
||||
|
||||
@@ -9,6 +9,8 @@ import {
|
||||
scale as scaleTransform
|
||||
} from './transform.js';
|
||||
import CanvasImmediateRenderer from './render/canvas/Immediate.js';
|
||||
import {getSquaredTolerance} from './renderer/vector.js';
|
||||
import {getUserProjection, getTransformFromProjections} from './proj.js';
|
||||
|
||||
|
||||
/**
|
||||
@@ -92,9 +94,15 @@ export function toContext(context, opt_options) {
|
||||
export function getVectorContext(event) {
|
||||
const frameState = event.frameState;
|
||||
const transform = multiplyTransform(event.inversePixelTransform.slice(), frameState.coordinateToPixelTransform);
|
||||
const squaredTolerance = getSquaredTolerance(frameState.viewState.resolution, frameState.pixelRatio);
|
||||
let userTransform;
|
||||
const userProjection = getUserProjection();
|
||||
if (userProjection) {
|
||||
userTransform = getTransformFromProjections(userProjection, frameState.viewState.projection);
|
||||
}
|
||||
return new CanvasImmediateRenderer(
|
||||
event.context, frameState.pixelRatio, frameState.extent, transform,
|
||||
frameState.viewState.rotation);
|
||||
frameState.viewState.rotation, squaredTolerance, userTransform);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -74,7 +74,10 @@ class RenderBox extends Disposable {
|
||||
if (this.map_) {
|
||||
this.map_.getOverlayContainer().removeChild(this.element_);
|
||||
const style = this.element_.style;
|
||||
style.left = style.top = style.width = style.height = 'inherit';
|
||||
style.left = 'inherit';
|
||||
style.top = 'inherit';
|
||||
style.width = 'inherit';
|
||||
style.height = 'inherit';
|
||||
}
|
||||
this.map_ = map;
|
||||
if (this.map_) {
|
||||
|
||||
@@ -33,8 +33,8 @@ class RenderEvent extends Event {
|
||||
this.frameState = opt_frameState;
|
||||
|
||||
/**
|
||||
* Canvas context. Only available when a Canvas renderer is used, null
|
||||
* otherwise.
|
||||
* Canvas context. Not available when the event is dispatched by the map. Only available
|
||||
* when a Canvas renderer is used, null otherwise.
|
||||
* @type {CanvasRenderingContext2D|null|undefined}
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -23,6 +23,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Triggered before layers are rendered.
|
||||
* The event object will not have a `context` set.
|
||||
* @event module:ol/render/Event~RenderEvent#precompose
|
||||
* @api
|
||||
*/
|
||||
@@ -30,6 +31,7 @@ export default {
|
||||
|
||||
/**
|
||||
* Triggered after all layers are rendered.
|
||||
* The event object will not have a `context` set.
|
||||
* @event module:ol/render/Event~RenderEvent#postcompose
|
||||
* @api
|
||||
*/
|
||||
@@ -38,6 +40,7 @@ export default {
|
||||
/**
|
||||
* Triggered when rendering is complete, i.e. all sources and tiles have
|
||||
* finished loading for the current viewport, and all tiles are faded in.
|
||||
* The event object will not have a `context` set.
|
||||
* @event module:ol/render/Event~RenderEvent#rendercomplete
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -204,11 +204,10 @@ class RenderFeature {
|
||||
* Get a transformed and simplified version of the geometry.
|
||||
* @abstract
|
||||
* @param {number} squaredTolerance Squared tolerance.
|
||||
* @param {import("../proj/Projection.js").default} sourceProjection The source projection.
|
||||
* @param {import("../proj/Projection.js").default} destProjection The destination projection.
|
||||
* @param {import("../proj.js").TransformFunction} [opt_transform] Optional transform function.
|
||||
* @return {RenderFeature} Simplified geometry.
|
||||
*/
|
||||
simplifyTransformed(squaredTolerance, sourceProjection, destProjection) {
|
||||
simplifyTransformed(squaredTolerance, opt_transform) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -269,10 +268,10 @@ class RenderFeature {
|
||||
/**
|
||||
* @return {Array<number>|Array<Array<number>>} Ends or endss.
|
||||
*/
|
||||
RenderFeature.prototype.getEnds =
|
||||
RenderFeature.prototype.getEndss = function() {
|
||||
RenderFeature.prototype.getEnds = function() {
|
||||
return this.ends_;
|
||||
};
|
||||
RenderFeature.prototype.getEndss = RenderFeature.prototype.getEnds;
|
||||
|
||||
|
||||
/**
|
||||
|
||||