Compare commits
464 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
02c1f4914a | ||
|
|
f0d488c549 | ||
|
|
e2883fb658 | ||
|
|
bec4b3028a | ||
|
|
8d8632bff7 | ||
|
|
3edb5d6ddc | ||
|
|
6e8ae4a714 | ||
|
|
8ab025a77d | ||
|
|
c5ce37b484 | ||
|
|
dabebdf9ff | ||
|
|
0058ea021a | ||
|
|
5c848eb697 | ||
|
|
46a630eb9a | ||
|
|
e03366feb2 | ||
|
|
a48f50b249 | ||
|
|
d0741d628d | ||
|
|
6ac4b66655 | ||
|
|
2d510e71a9 | ||
|
|
45c38eabc4 | ||
|
|
a4ee7eee10 | ||
|
|
f4906b83c9 | ||
|
|
71fc4be2eb | ||
|
|
59186f2afd | ||
|
|
0c11a7514d | ||
|
|
351ca5866b | ||
|
|
bdb7b9740b | ||
|
|
61f05fae74 | ||
|
|
4fe091c02d | ||
|
|
792f937aa5 | ||
|
|
4acb45dc78 | ||
|
|
4f7cadd17d | ||
|
|
5267e30d6d | ||
|
|
abdb313ad7 | ||
|
|
ff22f9ace9 | ||
|
|
e5a32f533e | ||
|
|
28bc9650d7 | ||
|
|
bb3140550d | ||
|
|
2e03069440 | ||
|
|
dbd4dda0cd | ||
|
|
76e294566e | ||
|
|
1f2ce78567 | ||
|
|
1413a13385 | ||
|
|
c307df47fa | ||
|
|
386671f5ef | ||
|
|
dbe7358b52 | ||
|
|
2e2bfeb708 | ||
|
|
7fbe54686c | ||
|
|
bb0470ef8b | ||
|
|
74c7e21c6f | ||
|
|
d53ce74027 | ||
|
|
6e4f862a3d | ||
|
|
2664733ea8 | ||
|
|
89bcfd068c | ||
|
|
c33adb1035 | ||
|
|
4700e8a17b | ||
|
|
34c84cf107 | ||
|
|
568327e693 | ||
|
|
c75e127734 | ||
|
|
7efb9e3ba7 | ||
|
|
0cc3bae8fe | ||
|
|
c8cfbfccf8 | ||
|
|
ae637bf683 | ||
|
|
0e3477ec24 | ||
|
|
a8baab7561 | ||
|
|
628e5c1c90 | ||
|
|
68ea485e69 | ||
|
|
f6cb4c296d | ||
|
|
848965b25c | ||
|
|
3f73a2f04f | ||
|
|
3643144108 | ||
|
|
6958ca3101 | ||
|
|
35a6825f74 | ||
|
|
4f6f66f966 | ||
|
|
288411f86c | ||
|
|
056f6c30fb | ||
|
|
2494bee7c8 | ||
|
|
96b2e88c5f | ||
|
|
427317fa42 | ||
|
|
14e9b83954 | ||
|
|
d4e057bc10 | ||
|
|
fc2cb2e876 | ||
|
|
d6e47de6ea | ||
|
|
15a6eda515 | ||
|
|
c1fc7db3f7 | ||
|
|
762d0768b4 | ||
|
|
fc4a05ccf4 | ||
|
|
78bf0a3679 | ||
|
|
fafcb65fff | ||
|
|
01c81373b3 | ||
|
|
6dff267272 | ||
|
|
fa80e2d064 | ||
|
|
e79d9d386b | ||
|
|
1cb6465702 | ||
|
|
db99de6903 | ||
|
|
8de93330b5 | ||
|
|
c59047c965 | ||
|
|
238695a107 | ||
|
|
5db09b3817 | ||
|
|
431a054a7d | ||
|
|
9e8ee1c05d | ||
|
|
3f4f922106 | ||
|
|
30ecf117ac | ||
|
|
7f6a479805 | ||
|
|
0326447611 | ||
|
|
ce751f26dc | ||
|
|
be205b325d | ||
|
|
3ebd1d7f1d | ||
|
|
72c78e3e92 | ||
|
|
6c7d8f6af9 | ||
|
|
28fc19e6ae | ||
|
|
f5803ad6ca | ||
|
|
67c183958a | ||
|
|
3638df90f8 | ||
|
|
4ed1226411 | ||
|
|
60c4268569 | ||
|
|
747967e797 | ||
|
|
d86464a812 | ||
|
|
acea9dc822 | ||
|
|
686a6f147d | ||
|
|
c2fc800fc1 | ||
|
|
d95e507af3 | ||
|
|
b24f0c9f1b | ||
|
|
9d94485b48 | ||
|
|
f73a891797 | ||
|
|
004f429ee2 | ||
|
|
bad0105352 | ||
|
|
cea1c79803 | ||
|
|
8e8d8598b9 | ||
|
|
ed07d60314 | ||
|
|
2d92756f84 | ||
|
|
eb76d072a9 | ||
|
|
544e55fe1a | ||
|
|
04ac30009b | ||
|
|
38bff05e43 | ||
|
|
43c40eb6d6 | ||
|
|
3a57a873bc | ||
|
|
3ef40f8e22 | ||
|
|
3bf1aef8e2 | ||
|
|
a788c9bd1e | ||
|
|
eaea5b3bdc | ||
|
|
b678c51234 | ||
|
|
2e755764ec | ||
|
|
dbec83b8d9 | ||
|
|
ad21ed7840 | ||
|
|
68332c48b5 | ||
|
|
7d8afea8a7 | ||
|
|
6432a16a98 | ||
|
|
7fa8081226 | ||
|
|
dcc7c27ec0 | ||
|
|
8e6f451553 | ||
|
|
b9b1b535dd | ||
|
|
cafba311de | ||
|
|
e00d005088 | ||
|
|
87d37937c5 | ||
|
|
243d466ece | ||
|
|
104e3364bd | ||
|
|
a9bd6cd00e | ||
|
|
2960668698 | ||
|
|
9636e4ddd7 | ||
|
|
d684cb01e6 | ||
|
|
5853dc2d19 | ||
|
|
100c4a2baf | ||
|
|
e2daac9c4e | ||
|
|
14b254aeb6 | ||
|
|
7c59869549 | ||
|
|
b91f8398d2 | ||
|
|
ce3b1dc371 | ||
|
|
c10af22f27 | ||
|
|
a6c869f8f2 | ||
|
|
c96ce1d9c3 | ||
|
|
3058b3730a | ||
|
|
e4cb2aae12 | ||
|
|
9e7d3fd07b | ||
|
|
ea2e87c563 | ||
|
|
8665cee8cc | ||
|
|
f6f34f82e5 | ||
|
|
332672ca1e | ||
|
|
89baa4aa01 | ||
|
|
b88a466601 | ||
|
|
fcb39c84ce | ||
|
|
5ccea03e04 | ||
|
|
036d9bf310 | ||
|
|
611d455708 | ||
|
|
dc7303967c | ||
|
|
6665b3325b | ||
|
|
f2023cda96 | ||
|
|
a715b1f5c6 | ||
|
|
6f80ba93c8 | ||
|
|
224f4c5c7f | ||
|
|
d4cc76f3f1 | ||
|
|
26d5b2163a | ||
|
|
6f2afe0088 | ||
|
|
79285ab7dd | ||
|
|
871dd0c3c6 | ||
|
|
f336cf30b0 | ||
|
|
71020bb5e4 | ||
|
|
996a6af6a3 | ||
|
|
088ba698ee | ||
|
|
aa2b55aefe | ||
|
|
0d0808fda1 | ||
|
|
45c8ad37c8 | ||
|
|
1160b4f720 | ||
|
|
3b12f1456e | ||
|
|
92c7e6e9e8 | ||
|
|
adf814a99c | ||
|
|
82ae25e008 | ||
|
|
c864de9fd1 | ||
|
|
fc40e87f89 | ||
|
|
f9365d5a8e | ||
|
|
55e14cff55 | ||
|
|
d2939fa9e7 | ||
|
|
00ac4b60b7 | ||
|
|
2e6f55f83f | ||
|
|
7ae3d34859 | ||
|
|
281841eeb6 | ||
|
|
ec6ad7d2d6 | ||
|
|
e709095b18 | ||
|
|
c8da29cdec | ||
|
|
a2f3c02ac5 | ||
|
|
a1b8f08bca | ||
|
|
c47fac19b5 | ||
|
|
03efc13357 | ||
|
|
d366d283b1 | ||
|
|
ba6a769917 | ||
|
|
92826bd0fc | ||
|
|
0dfbedb099 | ||
|
|
12cdaed2c5 | ||
|
|
883f22d6fe | ||
|
|
1d94477ed3 | ||
|
|
371bb85350 | ||
|
|
080fe8ca67 | ||
|
|
70dbe21520 | ||
|
|
924b85f4ca | ||
|
|
e5dc6588ad | ||
|
|
bc0ad8e8c9 | ||
|
|
fff8506e35 | ||
|
|
b86f9df8bd | ||
|
|
4e8736d9f0 | ||
|
|
0f5102b249 | ||
|
|
32a3ef78aa | ||
|
|
656014dbc4 | ||
|
|
0209827b90 | ||
|
|
ceb7192a63 | ||
|
|
4a80ebe1fc | ||
|
|
f4134b873b | ||
|
|
55af918a0e | ||
|
|
f0c6dff14e | ||
|
|
d4eb473252 | ||
|
|
7679128245 | ||
|
|
5addb14e60 | ||
|
|
e9d0323e90 | ||
|
|
6a0d0c1eeb | ||
|
|
10aa3d16ab | ||
|
|
2ec760d9a5 | ||
|
|
57eaf69c1a | ||
|
|
58806aaec1 | ||
|
|
6e5e94a447 | ||
|
|
655a49de7b | ||
|
|
fa2f730442 | ||
|
|
6bfef64e89 | ||
|
|
1697d1b647 | ||
|
|
07fa1adfe8 | ||
|
|
12de93b397 | ||
|
|
cbac16e21f | ||
|
|
a10bc713f2 | ||
|
|
ca9fc92f70 | ||
|
|
46d9e8db8e | ||
|
|
8cff620691 | ||
|
|
50dc9f1f88 | ||
|
|
9a6bb4d751 | ||
|
|
f74cd62827 | ||
|
|
7bed63bf3f | ||
|
|
5149224354 | ||
|
|
f2f9f68840 | ||
|
|
f353d52da3 | ||
|
|
f4739df907 | ||
|
|
8f24467ea4 | ||
|
|
770f53b5e3 | ||
|
|
a807af75f1 | ||
|
|
c799cf0cfd | ||
|
|
d1560176ba | ||
|
|
86801d1151 | ||
|
|
7a74ba606a | ||
|
|
bc064aba36 | ||
|
|
b51d16b575 | ||
|
|
7d3abbd5ca | ||
|
|
d1930d4a3f | ||
|
|
9da64fd73b | ||
|
|
37ddae4349 | ||
|
|
0645ea909e | ||
|
|
166175b4ed | ||
|
|
b0312b7bc9 | ||
|
|
e9bf7ccc61 | ||
|
|
2e9f41ce34 | ||
|
|
2feb88cd20 | ||
|
|
01bf4c32d9 | ||
|
|
f9db2c3845 | ||
|
|
e4baee4c0c | ||
|
|
b7cd60a7d4 | ||
|
|
c2877d56cb | ||
|
|
0e19c9aa2b | ||
|
|
fdba3ecf0e | ||
|
|
2adf74ece4 | ||
|
|
26c6538531 | ||
|
|
aff751bdf0 | ||
|
|
1b17f347c0 | ||
|
|
3bc28f2125 | ||
|
|
f1c0781eb2 | ||
|
|
d742c38163 | ||
|
|
687cffb5d9 | ||
|
|
dc8c9cfabb | ||
|
|
660f646d1a | ||
|
|
30054879e8 | ||
|
|
856066d05c | ||
|
|
380cfd12cb | ||
|
|
bfdd566bef | ||
|
|
bf20ab4367 | ||
|
|
06a083adda | ||
|
|
062096b641 | ||
|
|
0064b3c18e | ||
|
|
8703ddfab6 | ||
|
|
cbc2fd2997 | ||
|
|
74e8522509 | ||
|
|
96565935f8 | ||
|
|
0c8821a01a | ||
|
|
a169aaab37 | ||
|
|
6ae34e6590 | ||
|
|
bc1f1773fe | ||
|
|
a1166fe9a8 | ||
|
|
7d4b931909 | ||
|
|
6640d2d069 | ||
|
|
f16482b420 | ||
|
|
eb0bfc970e | ||
|
|
a0da16e4e9 | ||
|
|
9267d2994d | ||
|
|
1249ecee45 | ||
|
|
855fc6f5bc | ||
|
|
658f55d03f | ||
|
|
fc03078e2a | ||
|
|
c72101ff2e | ||
|
|
2c757bc8fa | ||
|
|
635a236ab8 | ||
|
|
ac65eed669 | ||
|
|
5ac9dbeb89 | ||
|
|
cc30a38d7d | ||
|
|
ba6d6f3bb4 | ||
|
|
36f94f57ce | ||
|
|
f849595dfd | ||
|
|
c55f882e49 | ||
|
|
106c114914 | ||
|
|
5faf95b9fb | ||
|
|
b0bb7846db | ||
|
|
243629510d | ||
|
|
2f713775d0 | ||
|
|
94a125357e | ||
|
|
895749707f | ||
|
|
b39f403641 | ||
|
|
ed379f4c0e | ||
|
|
52576a4485 | ||
|
|
d8686598df | ||
|
|
d52392dabe | ||
|
|
a2291abf1d | ||
|
|
bbc99e729b | ||
|
|
d3138e4e98 | ||
|
|
f86bad7459 | ||
|
|
2e531377e2 | ||
|
|
deb523f6f5 | ||
|
|
4718ec500b | ||
|
|
5b4c682f2a | ||
|
|
9224678627 | ||
|
|
df7a911687 | ||
|
|
72cb135aff | ||
|
|
5293efc6e2 | ||
|
|
4cbf04d029 | ||
|
|
bc04e96556 | ||
|
|
6a03e1c34f | ||
|
|
f7efb60843 | ||
|
|
9ee1768a1d | ||
|
|
4e5a7fba77 | ||
|
|
f26130ee54 | ||
|
|
cb6a00e13a | ||
|
|
60c259df02 | ||
|
|
aa110486a1 | ||
|
|
33bffbcdad | ||
|
|
c4e10a34c8 | ||
|
|
c1be8cf618 | ||
|
|
1872b56355 | ||
|
|
6bc8d0cd96 | ||
|
|
d4bc7d3f39 | ||
|
|
60790fea18 | ||
|
|
77ca0c2de5 | ||
|
|
c0009d5985 | ||
|
|
c85a6016c4 | ||
|
|
d5a27dae4f | ||
|
|
0186ca74f1 | ||
|
|
9834f683b9 | ||
|
|
4f5e59d7f0 | ||
|
|
940011fb56 | ||
|
|
974fdebafa | ||
|
|
fb0550ea5c | ||
|
|
b55f8e8f40 | ||
|
|
d8d4f21437 | ||
|
|
7c556951c8 | ||
|
|
b15de51344 | ||
|
|
4822589e26 | ||
|
|
00e880f534 | ||
|
|
f4c2cbdb9b | ||
|
|
1be2c459c4 | ||
|
|
84729e985f | ||
|
|
6506efab0c | ||
|
|
243b21a2e1 | ||
|
|
9d709cb3d9 | ||
|
|
ba444117bb | ||
|
|
78a4efab8c | ||
|
|
54871b6c52 | ||
|
|
709139c657 | ||
|
|
9e37182649 | ||
|
|
d7b0191c78 | ||
|
|
5f118b0244 | ||
|
|
e74d15659f | ||
|
|
1942f3f91b | ||
|
|
2d3d6cae31 | ||
|
|
f2f5a51455 | ||
|
|
1c4bcd7ceb | ||
|
|
fd178c71e6 | ||
|
|
aee95cf690 | ||
|
|
a32dc03a78 | ||
|
|
17b8e80f0a | ||
|
|
b3c417d1c2 | ||
|
|
06884c1f35 | ||
|
|
13da248cbf | ||
|
|
2274598ea3 | ||
|
|
c5a4e842a3 | ||
|
|
b929e02f78 | ||
|
|
a4186fae3c | ||
|
|
bfb6c0ffb5 | ||
|
|
9d167413e7 | ||
|
|
bec5e9676a | ||
|
|
676f538642 | ||
|
|
c81a486615 | ||
|
|
722769695d | ||
|
|
9511063f7e | ||
|
|
d755fbc507 | ||
|
|
f7aba759c2 | ||
|
|
79cfeb9a07 | ||
|
|
564d4f867f | ||
|
|
d66f2f4091 | ||
|
|
481dc9792c | ||
|
|
5c61d5b06c | ||
|
|
b068a339f5 | ||
|
|
7ac93be8dd | ||
|
|
7a6b9f8a33 | ||
|
|
ef5d00cb9a | ||
|
|
2a0a71107e | ||
|
|
6b1232b922 | ||
|
|
2b5ea17d79 | ||
|
|
3ec1ed6bf0 | ||
|
|
d2a2234eec | ||
|
|
a281b7c1aa | ||
|
|
eafcbb3ec0 | ||
|
|
820c123335 | ||
|
|
711ae69bb5 | ||
|
|
ba65896cef | ||
|
|
aa58a358ea |
4
.github/codeql/config.yml
vendored
4
.github/codeql/config.yml
vendored
@@ -1,4 +0,0 @@
|
||||
name: "OpenLayers CodeQL Config"
|
||||
|
||||
paths:
|
||||
- src
|
||||
29
.github/workflows/build-preview.yml
vendored
Normal file
29
.github/workflows/build-preview.yml
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
name: Build Preview
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
|
||||
jobs:
|
||||
build-preview:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npm ci
|
||||
- run: npm run build-site
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: site
|
||||
path: build/site
|
||||
- name: Store pull request number for later use
|
||||
run: |
|
||||
mkdir -p build/pr
|
||||
echo ${{github.event.number}} > build/pr/number
|
||||
- uses: actions/upload-artifact@v2
|
||||
with:
|
||||
name: pr
|
||||
path: build/pr
|
||||
102
.github/workflows/deploy-preview.yml
vendored
Normal file
102
.github/workflows/deploy-preview.yml
vendored
Normal file
@@ -0,0 +1,102 @@
|
||||
name: Deploy Preview
|
||||
|
||||
on:
|
||||
workflow_run:
|
||||
workflows: ["Build Preview"]
|
||||
types:
|
||||
- completed
|
||||
|
||||
jobs:
|
||||
deploy-preview:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{github.event.workflow_run.event == 'pull_request' && github.event.workflow_run.conclusion == 'success'}}
|
||||
steps:
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: '16'
|
||||
- run: npm install --global netlify-cli@6
|
||||
- run: npm install unzipper@0.10
|
||||
|
||||
- name: Get pull request number
|
||||
uses: actions/github-script@v5
|
||||
id: pull-request-number
|
||||
with:
|
||||
result-encoding: string
|
||||
script: |
|
||||
const unzipper = require('unzipper');
|
||||
|
||||
const artifacts = await github.rest.actions.listWorkflowRunArtifacts({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
run_id: ${{github.event.workflow_run.id}}
|
||||
});
|
||||
|
||||
const artifact = artifacts.data.artifacts.filter(
|
||||
artifact => artifact.name === 'pr'
|
||||
)[0];
|
||||
|
||||
if (!artifact) {
|
||||
throw new Error('No pr artifact found');
|
||||
}
|
||||
|
||||
const download = await github.rest.actions.downloadArtifact({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
artifact_id: artifact.id,
|
||||
archive_format: 'zip'
|
||||
});
|
||||
|
||||
const directory = await unzipper.Open.buffer(Buffer.from(download.data));
|
||||
const file = directory.files.find(d => d.path === 'number');
|
||||
const content = await file.buffer();
|
||||
return content.toString();
|
||||
|
||||
- uses: dawidd6/action-download-artifact@v2
|
||||
with:
|
||||
github_token: ${{secrets.GITHUB_TOKEN}}
|
||||
workflow: build-preview.yml
|
||||
pr: ${{steps.pull-request-number.outputs.result}}
|
||||
name: site
|
||||
path: build/site
|
||||
|
||||
- name: Deploy to Netlify
|
||||
env:
|
||||
NETLIFY_AUTH_TOKEN: ${{secrets.NETLIFY_AUTH_TOKEN}}
|
||||
NETLIFY_SITE_ID: ${{secrets.NETLIFY_SITE_ID}}
|
||||
run: netlify deploy --dir=build/site --alias=deploy-preview-${{steps.pull-request-number.outputs.result}}
|
||||
|
||||
- name: Add comment to pull request
|
||||
uses: actions/github-script@v5
|
||||
with:
|
||||
script: |
|
||||
const pullRequestNumber = parseInt(${{steps.pull-request-number.outputs.result}}, 10);
|
||||
|
||||
const start = ':package:';
|
||||
const author = 'github-actions[bot]';
|
||||
|
||||
const comments = await github.rest.issues.listComments({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pullRequestNumber
|
||||
});
|
||||
|
||||
const commentExists = comments.data.some(
|
||||
comment => comment.user.login === author && comment.body.startsWith(start)
|
||||
);
|
||||
|
||||
if (!commentExists) {
|
||||
const body = [
|
||||
`${start} Preview the [examples](https://deploy-preview-${pullRequestNumber}--ol-site.netlify.app/examples/) and`,
|
||||
`[docs](https://deploy-preview-${pullRequestNumber}--ol-site.netlify.app/apidoc/) from this branch`,
|
||||
`here: https://deploy-preview-${pullRequestNumber}--ol-site.netlify.app/.`
|
||||
].join(' ');
|
||||
|
||||
await github.rest.issues.createComment({
|
||||
owner: context.repo.owner,
|
||||
repo: context.repo.repo,
|
||||
issue_number: pullRequestNumber,
|
||||
body: body
|
||||
});
|
||||
} else {
|
||||
console.log(`Preview URL comment already added to PR #${pullRequestNumber}`);
|
||||
}
|
||||
10
.github/workflows/publish.yml
vendored
10
.github/workflows/publish.yml
vendored
@@ -9,11 +9,11 @@ jobs:
|
||||
publish-npm:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- uses: actions/setup-node@v1
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: https://registry.npmjs.org/
|
||||
node-version: '16'
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
- name: Publish
|
||||
@@ -24,4 +24,4 @@ jobs:
|
||||
cd build/ol
|
||||
npm publish --tag dev
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{secrets.npm_token}}
|
||||
NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN}}
|
||||
|
||||
11
.github/workflows/security.yml
vendored
11
.github/workflows/security.yml
vendored
@@ -15,20 +15,13 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
with:
|
||||
# Must fetch at least the immediate parents so that if this is
|
||||
# a pull request then we can checkout the head of the pull request.
|
||||
# Only include this option if you are running this workflow on pull requests.
|
||||
fetch-depth: 2
|
||||
- uses: actions/checkout@v2
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
with:
|
||||
languages: javascript
|
||||
config-file: ./.github/codeql/config.yml
|
||||
source-root: src
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
|
||||
85
.github/workflows/test.yml
vendored
85
.github/workflows/test.yml
vendored
@@ -24,22 +24,9 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Node.js Version
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Determine Cache Directory
|
||||
id: npm-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(npm config get cache)"
|
||||
|
||||
- name: Configure Job Cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.npm-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
node-version: '16'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
@@ -59,22 +46,9 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Node.js Version
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Determine Cache Directory
|
||||
id: npm-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(npm config get cache)"
|
||||
|
||||
- name: Configure Job Cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.npm-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
node-version: '16'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
@@ -94,22 +68,9 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Node.js Version
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Determine Cache Directory
|
||||
id: npm-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(npm config get cache)"
|
||||
|
||||
- name: Configure Job Cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.npm-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
node-version: '16'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
@@ -129,22 +90,9 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Node.js Version
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Determine Cache Directory
|
||||
id: npm-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(npm config get cache)"
|
||||
|
||||
- name: Configure Job Cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.npm-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
node-version: '16'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
@@ -167,22 +115,9 @@ jobs:
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Set Node.js Version
|
||||
uses: actions/setup-node@v1
|
||||
uses: actions/setup-node@v2
|
||||
with:
|
||||
node-version: 16
|
||||
|
||||
- name: Determine Cache Directory
|
||||
id: npm-cache
|
||||
run: |
|
||||
echo "::set-output name=dir::$(npm config get cache)"
|
||||
|
||||
- name: Configure Job Cache
|
||||
uses: actions/cache@v1
|
||||
with:
|
||||
path: ${{ steps.npm-cache.outputs.dir }}
|
||||
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
|
||||
restore-keys: |
|
||||
${{ runner.os }}-node-
|
||||
node-version: '16'
|
||||
|
||||
- name: Install Dependencies
|
||||
run: npm ci
|
||||
|
||||
@@ -36,10 +36,10 @@ new Map({
|
||||
|
||||
See the following examples for more detail on bundling OpenLayers with your application:
|
||||
|
||||
* Using [Vite](https://github.com/openlayers/ol-vite)
|
||||
* Using [Rollup](https://github.com/openlayers/ol-rollup)
|
||||
* Using [Webpack](https://github.com/openlayers/ol-webpack)
|
||||
* Using [webpack](https://github.com/openlayers/ol-webpack)
|
||||
* Using [Parcel](https://github.com/openlayers/ol-parcel)
|
||||
* Using [Browserify](https://github.com/openlayers/ol-browserify)
|
||||
|
||||
## Sponsors
|
||||
|
||||
@@ -97,9 +97,10 @@ For older browsers and platforms (Internet Explorer, Android 4.x, iOS v12 and ol
|
||||
* [`fetch`](https://caniuse.com/fetch): Available from [polyfill.io](https://polyfill.io/).
|
||||
* [`requestAnimationFrame`](https://caniuse.com/requestanimationframe): Available from [polyfill.io](https://polyfill.io/).
|
||||
* [`element.prototype.classList` (`add`/`remove`)](https://caniuse.com/classlist): Available from [polyfill.io](https://polyfill.io/).
|
||||
* [`URL` API](https://caniuse.com/url): Available from [polyfill.io](https://polyfill.io/).
|
||||
* [`URL` API](https://caniuse.com/url): Available from [polyfill.io](https://polyfill.io/) or [core-js](https://cdnjs.com/libraries/core-js/).
|
||||
* [`TextDecoder`](https://caniuse.com/textencoder): Available from [polyfill.io](https://polyfill.io/).
|
||||
* [`Number.isInteger`](https://caniuse.com/isInteger): Available from [polyfill.io](https://polyfill.io/).
|
||||
* [`Number.isInteger`](https://caniuse.com/isInteger): Available from [polyfill.io](https://polyfill.io/) or [core-js](https://cdnjs.com/libraries/core-js/).
|
||||
* [`Reflect`](https://caniuse.com/mdn-javascript_builtins_reflect): Available from [core-js](https://cdnjs.com/libraries/core-js/).
|
||||
* [Pointer events](https://caniuse.com/pointer): Use [elm-pep](https://npmjs.com/package/elm-pep) (lightweight) or [pepjs](https://npmjs.com/package/pepjs) (for really, really old browsers).
|
||||
|
||||
[`ol/source/GeoTIFF`](https://openlayers.org/en/latest/apidoc/module-ol_source_GeoTIFF-GeoTIFFSource.html) requires a browser that supports [ECMAScript 6](https://262.ecma-international.org/6.0/). Additionally a polyfill for [`Promise.allSettled`](https://caniuse.com/mdn-javascript_builtins_promise_allsettled) may be needed.
|
||||
|
||||
@@ -1,5 +1,33 @@
|
||||
## Upgrade notes
|
||||
|
||||
### v6.10.0
|
||||
|
||||
#### New `interpolate` option for sources
|
||||
|
||||
Sources now have an `interpolate` option. This option controls whether data from the source is interpolated when resampling.
|
||||
|
||||
For `ol/source/DataTile` sources, the default is `interpolate: false`. This means that when a data tile source is used with a WebGL tile layer renderer, your style expression will have access to pixel values in the data tiles without interpolation. If this option is set to true, linear interpolation will be used when over- or under-sampling the data.
|
||||
|
||||
#### Deprecation of the `imageSmoothing` option for sources
|
||||
|
||||
The `imageSmoothing` option for sources has been deprecated and will be removed in the next major release. Use the `interpolate` option instead.
|
||||
|
||||
```js
|
||||
// if you were using `imageSmoothing`
|
||||
const before = new TileSource({
|
||||
imageSmoothing: false
|
||||
});
|
||||
|
||||
// use the `interpolate` option instead
|
||||
const after = new TileSource({
|
||||
interpolate: false
|
||||
});
|
||||
```
|
||||
|
||||
### v6.9.0
|
||||
|
||||
There should be nothing special required when upgrading from v6.8 to v6.9.
|
||||
|
||||
### v6.8.0
|
||||
|
||||
There should be nothing special required when upgrading from v6.7 to v6.8.
|
||||
|
||||
200
changelog/v6.10.0.md
Normal file
200
changelog/v6.10.0.md
Normal file
@@ -0,0 +1,200 @@
|
||||
# 6.10.0
|
||||
|
||||
Just in time for the new year, the 6.10 release brings another great batch of features and fixes for your OpenLayers applications.
|
||||
|
||||
#### WebGL rendering
|
||||
|
||||
You can now update the style for your WebGL tile layers with `layer.setStyle()`. Keep in mind that it is more efficient to use style variables if you want to adjust styling on every render frame. However, in cases where you want to completely reconfigure the style, you can use the new `layer.setStyle()` method.
|
||||
|
||||
Additional WebGL tile layer rendering enhancements:
|
||||
* A new `palette` operator was added that allows styling raster data based on a colormap.
|
||||
* The `band` operator accepts expressions for the band number (in addition to numeric literals) – allowing for bands to be set by user provided style variables, for example.
|
||||
* Tile layers now dispatch `prerender`, `postrender`, `precompose` and `postcompose` events with access to the WebGL rendering context.
|
||||
* Layers that are adjacent to one another now share a single canvas element and rendering context – allowing for more layers in your maps before exhausting the browser's context limit.
|
||||
|
||||
#### Vector tiles
|
||||
|
||||
The Mapbox vector layer now works more easily with other vector tile providers. In addition, vector tile layers can now be configured with a background color.
|
||||
|
||||
#### New `interpolate` option for sources
|
||||
|
||||
Sources now have an `interpolate` option. This option controls whether data from the source is interpolated when resampling.
|
||||
|
||||
For `ol/source/DataTile` sources, the default is `interpolate: false`. This means that when a data tile source is used with a WebGL tile layer renderer, your style expression will have access to pixel values in the data tiles without interpolation. If this option is set to true, linear interpolation will be used when over- or under-sampling the data.
|
||||
|
||||
#### Deprecation of the `imageSmoothing` option for sources
|
||||
|
||||
The `imageSmoothing` option for sources has been deprecated and will be removed in the next major release. Use the `interpolate` option instead.
|
||||
|
||||
```js
|
||||
// if you were using `imageSmoothing`
|
||||
const before = new TileSource({
|
||||
imageSmoothing: false
|
||||
});
|
||||
|
||||
// use the `interpolate` option instead
|
||||
const after = new TileSource({
|
||||
interpolate: false
|
||||
});
|
||||
```
|
||||
|
||||
#### List of all changes
|
||||
|
||||
See below for more features and fixes.
|
||||
|
||||
* [#13155](https://github.com/openlayers/openlayers/pull/13155) - Allow interpolation to be configured for data tile sources ([@tschaub](https://github.com/tschaub))
|
||||
* [#13165](https://github.com/openlayers/openlayers/pull/13165) - Do not exceed maximum call stack when parsing TopoJSON ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13158](https://github.com/openlayers/openlayers/pull/13158) - Add example for dynamic clusters ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13156](https://github.com/openlayers/openlayers/pull/13156) - Ensure that tile range covers all pixels ([@tschaub](https://github.com/tschaub))
|
||||
* [#13154](https://github.com/openlayers/openlayers/pull/13154) - Update Export Map example to handle WebGL ([@mike-000](https://github.com/mike-000))
|
||||
* [#13147](https://github.com/openlayers/openlayers/pull/13147) - Support rendering with a palette in WebGL ([@tschaub](https://github.com/tschaub))
|
||||
* [#13142](https://github.com/openlayers/openlayers/pull/13142) - Include transpacific flights in Flight Animation example ([@mike-000](https://github.com/mike-000))
|
||||
* [#13150](https://github.com/openlayers/openlayers/pull/13150) - Include layer opacity in Heatmap shader ([@mike-000](https://github.com/mike-000))
|
||||
* [#13149](https://github.com/openlayers/openlayers/pull/13149) - Add layer also for programmatically selected features ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13151](https://github.com/openlayers/openlayers/pull/13151) - Avoid error accessing attributes when context is lost ([@mike-000](https://github.com/mike-000))
|
||||
* [#13144](https://github.com/openlayers/openlayers/pull/13144) - Replace deprecated syntax in example ([@mike-000](https://github.com/mike-000))
|
||||
* [#13131](https://github.com/openlayers/openlayers/pull/13131) - Unset canvas css in stylesheet ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13130](https://github.com/openlayers/openlayers/pull/13130) - Allow WebGL tile layers to be constructed without a source ([@tschaub](https://github.com/tschaub))
|
||||
* [#13126](https://github.com/openlayers/openlayers/pull/13126) - Preserve the drawing buffer by default for WebGL layers ([@tschaub](https://github.com/tschaub))
|
||||
* [#13127](https://github.com/openlayers/openlayers/pull/13127) - Fix for range slider on IE ([@mike-000](https://github.com/mike-000))
|
||||
* [#13095](https://github.com/openlayers/openlayers/pull/13095) - Render is only complete when no tiles are queued ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13120](https://github.com/openlayers/openlayers/pull/13120) - Populate view's object properties ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13102](https://github.com/openlayers/openlayers/pull/13102) - update line-arrows example ([@jipexu](https://github.com/jipexu))
|
||||
* [#13119](https://github.com/openlayers/openlayers/pull/13119) - Dispatch precompose and postcompose events for WebGL layers ([@tschaub](https://github.com/tschaub))
|
||||
* [#13118](https://github.com/openlayers/openlayers/pull/13118) - Add a layer opacity example ([@tschaub](https://github.com/tschaub))
|
||||
* [#13115](https://github.com/openlayers/openlayers/pull/13115) - Lazily create resources for worker ([@tschaub](https://github.com/tschaub))
|
||||
* [#13103](https://github.com/openlayers/openlayers/pull/13103) - Assume limited precision when rounding ([@tschaub](https://github.com/tschaub))
|
||||
* [#13097](https://github.com/openlayers/openlayers/pull/13097) - Use correct terrain-rgb tile size and update max zoom ([@mike-000](https://github.com/mike-000))
|
||||
* [#13101](https://github.com/openlayers/openlayers/pull/13101) - Fix View set center to undefined ([@M393](https://github.com/M393))
|
||||
* [#13085](https://github.com/openlayers/openlayers/pull/13085) - Add layer background ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13083](https://github.com/openlayers/openlayers/pull/13083) - Support expressions for band arguments ([@tschaub](https://github.com/tschaub))
|
||||
* [#13084](https://github.com/openlayers/openlayers/pull/13084) - Normalize relative sprite and glyph urls for style url ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13020](https://github.com/openlayers/openlayers/pull/13020) - Allow WebGL tile layer style to be updated ([@tschaub](https://github.com/tschaub))
|
||||
* [#13073](https://github.com/openlayers/openlayers/pull/13073) - Fall back to standard load handling when decode fails ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13077](https://github.com/openlayers/openlayers/pull/13077) - update draw and modify features example ([@jipexu](https://github.com/jipexu))
|
||||
* [#13069](https://github.com/openlayers/openlayers/pull/13069) - Normalize based on GDAL stats metadata ([@tschaub](https://github.com/tschaub))
|
||||
* [#13070](https://github.com/openlayers/openlayers/pull/13070) - Use source minzoom if not configured otherwise ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13065](https://github.com/openlayers/openlayers/pull/13065) - Fix typo in example ([@jipexu](https://github.com/jipexu))
|
||||
* [#13060](https://github.com/openlayers/openlayers/pull/13060) - Avoid fetching data outside the grid extent ([@tschaub](https://github.com/tschaub))
|
||||
* [#13054](https://github.com/openlayers/openlayers/pull/13054) - Updates for newer version of the OGC API spec draft ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13045](https://github.com/openlayers/openlayers/pull/13045) - Fix tiles and background handling ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13030](https://github.com/openlayers/openlayers/pull/13030) - Correctly set popover position in geographic example ([@MoonE](https://github.com/MoonE))
|
||||
* [#13031](https://github.com/openlayers/openlayers/pull/13031) - Allow data tile source loader to return a value or a promise ([@tschaub](https://github.com/tschaub))
|
||||
* [#13026](https://github.com/openlayers/openlayers/pull/13026) - Fix strokeStyle documentation ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13027](https://github.com/openlayers/openlayers/pull/13027) - Restore the security scan workflow ([@openlayers](https://github.com/openlayers))
|
||||
* [#13025](https://github.com/openlayers/openlayers/pull/13025) - Add background to MapboxVector layer ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#13013](https://github.com/openlayers/openlayers/pull/13013) - Use appropriate UNPACK_ALIGNMENT for data textures ([@mike-000](https://github.com/mike-000))
|
||||
* [#13021](https://github.com/openlayers/openlayers/pull/13021) - Add the renderer type to generic layer template variables ([@tschaub](https://github.com/tschaub))
|
||||
* [#13022](https://github.com/openlayers/openlayers/pull/13022) - Update the security scan task ([@tschaub](https://github.com/tschaub))
|
||||
* [#13015](https://github.com/openlayers/openlayers/pull/13015) - Additional types for WebGL renderer, sources, and tiles ([@tschaub](https://github.com/tschaub))
|
||||
* [#13012](https://github.com/openlayers/openlayers/pull/13012) - Remove unused dependencies ([@tschaub](https://github.com/tschaub))
|
||||
* [#12976](https://github.com/openlayers/openlayers/pull/12976) - Handle ReprojTile in ol/layer/WebGLTile ([@mike-000](https://github.com/mike-000))
|
||||
* [#13011](https://github.com/openlayers/openlayers/pull/13011) - Use registry URL when publishing ([@tschaub](https://github.com/tschaub))
|
||||
* [#13009](https://github.com/openlayers/openlayers/pull/13009) - Use workflow_run event to deploy pull request previews ([@tschaub](https://github.com/tschaub))
|
||||
* [#12965](https://github.com/openlayers/openlayers/pull/12965) - Allow canvas reuse for WebGL layers ([@tschaub](https://github.com/tschaub))
|
||||
* [#12999](https://github.com/openlayers/openlayers/pull/12999) - Fix style related apidoc issues ([@MoonE](https://github.com/MoonE))
|
||||
* [#12978](https://github.com/openlayers/openlayers/pull/12978) - Add null to style jsdoc of VectorImage ([@EvertEt](https://github.com/EvertEt))
|
||||
* [#12997](https://github.com/openlayers/openlayers/pull/12997) - Lazily create the WebGL helper ([@tschaub](https://github.com/tschaub))
|
||||
* [#12996](https://github.com/openlayers/openlayers/pull/12996) - Align labels with the Select elements in the Raster Reprojection example ([@mike-000](https://github.com/mike-000))
|
||||
* [#12994](https://github.com/openlayers/openlayers/pull/12994) - Add a map property to layers ([@tschaub](https://github.com/tschaub))
|
||||
* [#12987](https://github.com/openlayers/openlayers/pull/12987) - Browser test config update ([@tschaub](https://github.com/tschaub))
|
||||
* [#12939](https://github.com/openlayers/openlayers/pull/12939) - Example that demonstrates a color expression using variables ([@tschaub](https://github.com/tschaub))
|
||||
* [#12962](https://github.com/openlayers/openlayers/pull/12962) - No context sharing when layer opacity is set ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#12964](https://github.com/openlayers/openlayers/pull/12964) - Updated Bing Maps key ([@tschaub](https://github.com/tschaub))
|
||||
* [#12958](https://github.com/openlayers/openlayers/pull/12958) - Reuse temporary canvas in getDataAtPixel() ([@mike-000](https://github.com/mike-000))
|
||||
* [#12893](https://github.com/openlayers/openlayers/pull/12893) - Allow map target to be an external window ([@andrewcoder002](https://github.com/andrewcoder002))
|
||||
* [#12955](https://github.com/openlayers/openlayers/pull/12955) - Make MapboxVector layer work in more access key scenarios ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#12935](https://github.com/openlayers/openlayers/pull/12935) - fix bug #12913 ([@mrpan](https://github.com/mrpan))
|
||||
* [#12933](https://github.com/openlayers/openlayers/pull/12933) - Include WebGL context in render events for WebGL layers ([@tschaub](https://github.com/tschaub))
|
||||
* [#12917](https://github.com/openlayers/openlayers/pull/12917) - Make removeFeature consistent with other remove methods ([@mike-000](https://github.com/mike-000))
|
||||
* [#12918](https://github.com/openlayers/openlayers/pull/12918) - Add setDisplacement method to ol/style/Image and subclasses ([@mike-000](https://github.com/mike-000))
|
||||
* [#12930](https://github.com/openlayers/openlayers/pull/12930) - Fix flaky view animation test ([@MoonE](https://github.com/MoonE))
|
||||
* [#12915](https://github.com/openlayers/openlayers/pull/12915) - Test the new pull request deploy previews ([@tschaub](https://github.com/tschaub))
|
||||
* [#12916](https://github.com/openlayers/openlayers/pull/12916) - Updates to deploy-preview job ([@openlayers](https://github.com/openlayers))
|
||||
* [#12914](https://github.com/openlayers/openlayers/pull/12914) - Build site preview as a GitHub action ([@tschaub](https://github.com/tschaub))
|
||||
* [#12891](https://github.com/openlayers/openlayers/pull/12891) - Restore browser compatibility where possible ([@mike-000](https://github.com/mike-000))
|
||||
* [#12899](https://github.com/openlayers/openlayers/pull/12899) - Update docs to mention Vite ([@tschaub](https://github.com/tschaub))
|
||||
* [#12890](https://github.com/openlayers/openlayers/pull/12890) - Release 6.9.0 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Dependency Updates</summary>
|
||||
|
||||
* [#13162](https://github.com/openlayers/openlayers/pull/13162) - Bump yargs from 17.3.0 to 17.3.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13163](https://github.com/openlayers/openlayers/pull/13163) - Bump rollup from 2.61.1 to 2.62.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13161](https://github.com/openlayers/openlayers/pull/13161) - Bump webpack-dev-server from 4.6.0 to 4.7.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13160](https://github.com/openlayers/openlayers/pull/13160) - Bump puppeteer from 13.0.0 to 13.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13140](https://github.com/openlayers/openlayers/pull/13140) - Bump @rollup/plugin-node-resolve from 13.0.6 to 13.1.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13132](https://github.com/openlayers/openlayers/pull/13132) - Bump copy-webpack-plugin from 10.1.0 to 10.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13141](https://github.com/openlayers/openlayers/pull/13141) - Bump webpack-dev-middleware from 5.2.2 to 5.3.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13133](https://github.com/openlayers/openlayers/pull/13133) - Bump eslint from 8.4.1 to 8.5.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13139](https://github.com/openlayers/openlayers/pull/13139) - Bump @babel/core from 7.16.0 to 7.16.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13136](https://github.com/openlayers/openlayers/pull/13136) - Bump @babel/preset-env from 7.16.4 to 7.16.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13137](https://github.com/openlayers/openlayers/pull/13137) - Bump express from 4.17.1 to 4.17.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13138](https://github.com/openlayers/openlayers/pull/13138) - Bump ol-mapbox-style from 6.7.0 to 6.8.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13134](https://github.com/openlayers/openlayers/pull/13134) - Bump marked from 4.0.7 to 4.0.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13106](https://github.com/openlayers/openlayers/pull/13106) - Bump webpack from 5.64.4 to 5.65.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13108](https://github.com/openlayers/openlayers/pull/13108) - Bump rollup from 2.60.2 to 2.61.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13107](https://github.com/openlayers/openlayers/pull/13107) - Bump copy-webpack-plugin from 10.0.0 to 10.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13105](https://github.com/openlayers/openlayers/pull/13105) - Bump eslint from 8.4.0 to 8.4.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13109](https://github.com/openlayers/openlayers/pull/13109) - Bump marked from 4.0.6 to 4.0.7 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13110](https://github.com/openlayers/openlayers/pull/13110) - Bump puppeteer from 12.0.1 to 13.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13111](https://github.com/openlayers/openlayers/pull/13111) - Bump clean-css-cli from 5.4.2 to 5.5.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13091](https://github.com/openlayers/openlayers/pull/13091) - Bump rollup from 2.60.1 to 2.60.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13089](https://github.com/openlayers/openlayers/pull/13089) - Bump eslint from 8.3.0 to 8.4.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13090](https://github.com/openlayers/openlayers/pull/13090) - Bump marked from 4.0.5 to 4.0.6 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13093](https://github.com/openlayers/openlayers/pull/13093) - Bump yargs from 17.2.1 to 17.3.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13092](https://github.com/openlayers/openlayers/pull/13092) - Bump puppeteer from 12.0.0 to 12.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13088](https://github.com/openlayers/openlayers/pull/13088) - Bump geotiff from 1.0.8 to 1.0.9 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13057](https://github.com/openlayers/openlayers/pull/13057) - Bump puppeteer from 11.0.0 to 12.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13055](https://github.com/openlayers/openlayers/pull/13055) - Bump webpack from 5.64.2 to 5.64.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13056](https://github.com/openlayers/openlayers/pull/13056) - Bump webpack-dev-server from 4.5.0 to 4.6.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13058](https://github.com/openlayers/openlayers/pull/13058) - Bump marked from 4.0.4 to 4.0.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13032](https://github.com/openlayers/openlayers/pull/13032) - Bump webpack from 5.64.0 to 5.64.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13033](https://github.com/openlayers/openlayers/pull/13033) - Bump webpack-sources from 3.2.1 to 3.2.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13034](https://github.com/openlayers/openlayers/pull/13034) - Bump rollup from 2.60.0 to 2.60.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13035](https://github.com/openlayers/openlayers/pull/13035) - Bump copy-webpack-plugin from 9.1.0 to 10.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13036](https://github.com/openlayers/openlayers/pull/13036) - Bump webpack-dev-middleware from 5.2.1 to 5.2.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13037](https://github.com/openlayers/openlayers/pull/13037) - Bump @babel/preset-env from 7.16.0 to 7.16.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13038](https://github.com/openlayers/openlayers/pull/13038) - Bump marked from 4.0.3 to 4.0.4 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13039](https://github.com/openlayers/openlayers/pull/13039) - Bump eslint from 8.2.0 to 8.3.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13040](https://github.com/openlayers/openlayers/pull/13040) - Bump ol-mapbox-style from 6.5.2 to 6.5.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13041](https://github.com/openlayers/openlayers/pull/13041) - Bump karma from 6.3.8 to 6.3.9 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13001](https://github.com/openlayers/openlayers/pull/13001) - Bump webpack from 5.62.1 to 5.64.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13002](https://github.com/openlayers/openlayers/pull/13002) - Bump terser-webpack-plugin from 5.2.4 to 5.2.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13003](https://github.com/openlayers/openlayers/pull/13003) - Bump copy-webpack-plugin from 9.0.1 to 9.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13004](https://github.com/openlayers/openlayers/pull/13004) - Bump rollup from 2.59.0 to 2.60.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13005](https://github.com/openlayers/openlayers/pull/13005) - Bump webpack-dev-server from 4.4.0 to 4.5.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13006](https://github.com/openlayers/openlayers/pull/13006) - Bump ol-mapbox-style from 6.5.1 to 6.5.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13007](https://github.com/openlayers/openlayers/pull/13007) - Bump marked from 4.0.0 to 4.0.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#13008](https://github.com/openlayers/openlayers/pull/13008) - Bump glob from 7.1.7 to 7.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12968](https://github.com/openlayers/openlayers/pull/12968) - Bump sinon from 11.1.2 to 12.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12969](https://github.com/openlayers/openlayers/pull/12969) - Bump marked from 3.0.8 to 4.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12973](https://github.com/openlayers/openlayers/pull/12973) - Bump eslint from 8.1.0 to 8.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12972](https://github.com/openlayers/openlayers/pull/12972) - Bump karma-firefox-launcher from 2.1.1 to 2.1.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12971](https://github.com/openlayers/openlayers/pull/12971) - Bump puppeteer from 10.4.0 to 11.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12970](https://github.com/openlayers/openlayers/pull/12970) - Bump karma from 6.3.6 to 6.3.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12967](https://github.com/openlayers/openlayers/pull/12967) - Bump webpack from 5.61.0 to 5.62.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12948](https://github.com/openlayers/openlayers/pull/12948) - Bump webpack from 5.59.1 to 5.61.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12945](https://github.com/openlayers/openlayers/pull/12945) - Bump rollup from 2.58.3 to 2.59.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12946](https://github.com/openlayers/openlayers/pull/12946) - Bump @babel/preset-env from 7.15.8 to 7.16.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12947](https://github.com/openlayers/openlayers/pull/12947) - Bump @babel/core from 7.15.8 to 7.16.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12949](https://github.com/openlayers/openlayers/pull/12949) - Bump karma from 6.3.5 to 6.3.6 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12944](https://github.com/openlayers/openlayers/pull/12944) - Bump webpack-dev-server from 4.3.1 to 4.4.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12923](https://github.com/openlayers/openlayers/pull/12923) - Bump @rollup/plugin-commonjs from 21.0.0 to 21.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12922](https://github.com/openlayers/openlayers/pull/12922) - Bump webpack-cli from 4.9.0 to 4.9.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12929](https://github.com/openlayers/openlayers/pull/12929) - Bump rollup from 2.58.0 to 2.58.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12920](https://github.com/openlayers/openlayers/pull/12920) - Bump marked from 3.0.7 to 3.0.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12924](https://github.com/openlayers/openlayers/pull/12924) - Bump clean-css-cli from 5.4.1 to 5.4.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12926](https://github.com/openlayers/openlayers/pull/12926) - Bump @rollup/plugin-node-resolve from 13.0.5 to 13.0.6 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12928](https://github.com/openlayers/openlayers/pull/12928) - Bump babel-loader from 8.2.2 to 8.2.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12921](https://github.com/openlayers/openlayers/pull/12921) - Bump webpack from 5.58.2 to 5.59.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12927](https://github.com/openlayers/openlayers/pull/12927) - Bump eslint from 8.0.1 to 8.1.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12919](https://github.com/openlayers/openlayers/pull/12919) - Bump karma from 6.3.4 to 6.3.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12902](https://github.com/openlayers/openlayers/pull/12902) - Bump eslint from 7.32.0 to 8.0.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12904](https://github.com/openlayers/openlayers/pull/12904) - Bump mocha from 9.1.2 to 9.1.3 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12905](https://github.com/openlayers/openlayers/pull/12905) - Bump glob from 7.1.7 to 7.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12903](https://github.com/openlayers/openlayers/pull/12903) - Bump webpack from 5.58.1 to 5.58.2 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
</details>
|
||||
5
changelog/v6.8.1.md
Normal file
5
changelog/v6.8.1.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# 6.8.1
|
||||
|
||||
This is a patch release which updates `ol.css` to restore a legible control button size in applications that do not have a css `font-size` set for `button` elements.
|
||||
|
||||
* [#12811](https://github.com/openlayers/openlayers/pull/12811) - Controls inherit font size from parent ([@tschaub](https://github.com/tschaub))
|
||||
51
changelog/v6.9.0.md
Normal file
51
changelog/v6.9.0.md
Normal file
@@ -0,0 +1,51 @@
|
||||
# 6.9.0
|
||||
|
||||
The 6.9 release brings a few new features and a number of fixes. GeoTIFF sources now have a `normalize` option. Set `normalize: false` if you want your style expressions to work with raw floating point values instead of normalized values from 0 to 1. The GeoTIFF source also now uses nodata values from the source imagery – so in most cases you don't need to specify this yourself. For people configuring vector layers with styles that use custom rendering, you can now get hit detection on the rendered result. See details on these features and other included fixes below.
|
||||
|
||||
* [#12813](https://github.com/openlayers/openlayers/pull/12813) - Do not replace icon color if image not loaded ([@mike-000](https://github.com/mike-000))
|
||||
* [#12870](https://github.com/openlayers/openlayers/pull/12870) - Fix publicPath problem in legacy build ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#12889](https://github.com/openlayers/openlayers/pull/12889) - Simplified ESLint config ([@tschaub](https://github.com/tschaub))
|
||||
* [#12875](https://github.com/openlayers/openlayers/pull/12875) - Only trigger change event if animating a tile transition ([@tschaub](https://github.com/tschaub))
|
||||
* [#12885](https://github.com/openlayers/openlayers/pull/12885) - Fix typeDefs for several Control modules ([@MatthijsBon](https://github.com/MatthijsBon))
|
||||
* [#12861](https://github.com/openlayers/openlayers/pull/12861) - Update geotiff to 1.0.8; allow version range ([@ahocevar](https://github.com/ahocevar))
|
||||
* [#12865](https://github.com/openlayers/openlayers/pull/12865) - Add a note about installing git before using create-ol-app ([@tschaub](https://github.com/tschaub))
|
||||
* [#12847](https://github.com/openlayers/openlayers/pull/12847) - Add more definitions for GeoTIFF types ([@tschaub](https://github.com/tschaub))
|
||||
* [#12850](https://github.com/openlayers/openlayers/pull/12850) - Fix issues with animate on View without center or resolution ([@MoonE](https://github.com/MoonE))
|
||||
* [#12846](https://github.com/openlayers/openlayers/pull/12846) - Use nodata values in the GeoTIFF headers for fill value ([@tschaub](https://github.com/tschaub))
|
||||
* [#12837](https://github.com/openlayers/openlayers/pull/12837) - forEachLayerAtPixel return null for unsupported layer types ([@mike-000](https://github.com/mike-000))
|
||||
* [#12836](https://github.com/openlayers/openlayers/pull/12836) - Support a normalize option on the GeoTIFF source ([@tschaub](https://github.com/tschaub))
|
||||
* [#12646](https://github.com/openlayers/openlayers/pull/12646) - Support for hit detection in styles with custom rendering ([@ashchurova](https://github.com/ashchurova))
|
||||
* [#12831](https://github.com/openlayers/openlayers/pull/12831) - Fix rendering VectorImage with no features in view extent ([@MoonE](https://github.com/MoonE))
|
||||
* [#12830](https://github.com/openlayers/openlayers/pull/12830) - bugfix: Fix type of `layers` option in `OverviewMap` ([@ejn](https://github.com/ejn))
|
||||
* [#12815](https://github.com/openlayers/openlayers/pull/12815) - Spelling correction ([@tschaub](https://github.com/tschaub))
|
||||
* [#12812](https://github.com/openlayers/openlayers/pull/12812) - Release v6.8.1 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
<details>
|
||||
<summary>Dependency Updates</summary>
|
||||
|
||||
* [#12881](https://github.com/openlayers/openlayers/pull/12881) - Bump webpack from 5.56.1 to 5.58.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12882](https://github.com/openlayers/openlayers/pull/12882) - Bump marked from 3.0.4 to 3.0.7 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12878](https://github.com/openlayers/openlayers/pull/12878) - Bump webpack-dev-server from 4.3.0 to 4.3.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12879](https://github.com/openlayers/openlayers/pull/12879) - Bump @babel/preset-env from 7.15.6 to 7.15.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12880](https://github.com/openlayers/openlayers/pull/12880) - Bump @babel/eslint-parser from 7.15.7 to 7.15.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12884](https://github.com/openlayers/openlayers/pull/12884) - Bump @babel/core from 7.15.5 to 7.15.8 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12877](https://github.com/openlayers/openlayers/pull/12877) - Bump webpack-cli from 4.8.0 to 4.9.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12854](https://github.com/openlayers/openlayers/pull/12854) - Bump webpack from 5.54.0 to 5.56.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12857](https://github.com/openlayers/openlayers/pull/12857) - Bump webpack-dev-server from 4.2.1 to 4.3.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12856](https://github.com/openlayers/openlayers/pull/12856) - Bump @rollup/plugin-commonjs from 20.0.0 to 21.0.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12855](https://github.com/openlayers/openlayers/pull/12855) - Bump rollup from 2.57.0 to 2.58.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12853](https://github.com/openlayers/openlayers/pull/12853) - Bump clean-css-cli from 5.3.3 to 5.4.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12822](https://github.com/openlayers/openlayers/pull/12822) - Bump glob from 7.1.7 to 7.2.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12824](https://github.com/openlayers/openlayers/pull/12824) - Bump rollup from 2.56.3 to 2.57.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12818](https://github.com/openlayers/openlayers/pull/12818) - Bump threads from 1.6.5 to 1.7.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12821](https://github.com/openlayers/openlayers/pull/12821) - Bump @rollup/plugin-node-resolve from 13.0.4 to 13.0.5 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12823](https://github.com/openlayers/openlayers/pull/12823) - Bump walk from 2.3.14 to 2.3.15 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12819](https://github.com/openlayers/openlayers/pull/12819) - Bump webpack-dev-middleware from 5.1.0 to 5.2.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12820](https://github.com/openlayers/openlayers/pull/12820) - Bump mocha from 9.1.1 to 9.1.2 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12817](https://github.com/openlayers/openlayers/pull/12817) - Bump yargs from 17.1.1 to 17.2.1 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12825](https://github.com/openlayers/openlayers/pull/12825) - Bump webpack from 5.53.0 to 5.54.0 ([@openlayers](https://github.com/openlayers))
|
||||
* [#12826](https://github.com/openlayers/openlayers/pull/12826) - Bump puppeteer from 10.2.0 to 10.4.0 ([@openlayers](https://github.com/openlayers))
|
||||
|
||||
|
||||
</details>
|
||||
@@ -9,7 +9,7 @@
|
||||
* works around an issue with `~` characters in module paths by escaping them.
|
||||
*/
|
||||
|
||||
const marked = require('marked');
|
||||
const {marked} = require('marked');
|
||||
const format = require('util').format;
|
||||
|
||||
const tags = [
|
||||
|
||||
@@ -51,8 +51,8 @@
|
||||
// "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */
|
||||
// "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */
|
||||
// "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */
|
||||
"inlineSources": false /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
|
||||
"inlineSources": false, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */
|
||||
"skipLibCheck": true
|
||||
/* Experimental Options */
|
||||
// "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */
|
||||
// "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */
|
||||
|
||||
@@ -48,6 +48,7 @@ export default {
|
||||
},
|
||||
output: {
|
||||
path: path.resolve('./build/legacy'),
|
||||
publicPath: '',
|
||||
filename: 'ol.js',
|
||||
library: 'ol',
|
||||
libraryTarget: 'umd',
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
---
|
||||
title: Basic project setup using NPM and Parcel
|
||||
title: Basic project setup using NPM and Vite
|
||||
layout: doc.hbs
|
||||
---
|
||||
|
||||
@@ -7,7 +7,7 @@ layout: doc.hbs
|
||||
|
||||
Modern JavaScript works best when using and authoring modules. The recommended way of using OpenLayers is installing the [`ol`](https://npmjs.com/package/ol) package. This tutorial walks you through setting up a simple dev environment, which requires [node](https://nodejs.org) for everything to work.
|
||||
|
||||
In this tutorial, we will be using [Parcel](https://parceljs.org) to bundle our application. There are several other options, some of which are linked from the [README](https://npmjs.com/package/ol).
|
||||
In this tutorial, we will be using [Vite](https://vitejs.dev/) as a development tool and to bundle our application for production. There are several other options, some of which are linked from the [README](https://npmjs.com/package/ol).
|
||||
|
||||
## Application setup
|
||||
|
||||
@@ -15,13 +15,15 @@ Create a new empty directory for your project and navigate to it by running `mkd
|
||||
|
||||
npx create-ol-app
|
||||
|
||||
This will install the `ol` package, set up a development environment with additional dependencies, and give you an `index.html` and `main.js` starting point for your application. By default, [Parcel](https://parceljs.org) will be used as a module loader and bundler. See the [`create-ol-app`](https://github.com/openlayers/create-ol-app) documentation for details on using another bundler.
|
||||
*You will need to have `git` installed for the above command to work. If you receive an error, make sure that [Git is installed](https://github.com/git-guides/install-git) on your system.*
|
||||
|
||||
This will install the `ol` package, set up a development environment with additional dependencies, and give you an `index.html` and `main.js` starting point for your application. By default, [Vite](https://vitejs.dev/) will be used as a module loader and bundler. See the [`create-ol-app`](https://github.com/openlayers/create-ol-app) documentation for details on using another bundler.
|
||||
|
||||
To start the development server
|
||||
|
||||
npm start
|
||||
|
||||
You can now visit http://localhost:1234/ to view your application. Begin making changes to the `index.html` and `main.js` files to add additional functionality.
|
||||
You can now visit http://localhost:3000/ to view your application. Begin making changes to the `index.html` and `main.js` files to add additional functionality.
|
||||
|
||||
To create a production bundle of your application, simply type
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"$": false,
|
||||
"arc": false,
|
||||
"common": false,
|
||||
"chroma": false,
|
||||
"createMapboxStreetsV6Style": false,
|
||||
"d3": false,
|
||||
"html2canvas": false,
|
||||
@@ -13,6 +14,7 @@
|
||||
"jsts": false,
|
||||
"JSZip": false,
|
||||
"mapboxgl": false,
|
||||
"monotoneChainConvexHull": false,
|
||||
"NumpyLoader": false,
|
||||
"saveAs": false,
|
||||
"toastr": false,
|
||||
|
||||
@@ -6,7 +6,7 @@ docs: >
|
||||
<p>When the Bing Maps tile service doesn't have tiles for a given resolution and region it returns "placeholder" tiles indicating that. Zoom the map beyond level 19 to see the "placeholder" tiles. If you want OpenLayers to display stretched tiles in place of "placeholder" tiles beyond zoom level 19 then set <code>maxZoom</code> to <code>19</code> in the options passed to <code>ol/source/BingMaps</code>.</p>
|
||||
tags: "bing, bing-maps"
|
||||
cloak:
|
||||
- key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp
|
||||
- key: AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN
|
||||
value: Your Bing Maps Key from https://www.bingmapsportal.com/ here
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
|
||||
@@ -18,7 +18,7 @@ for (i = 0, ii = styles.length; i < ii; ++i) {
|
||||
visible: false,
|
||||
preload: Infinity,
|
||||
source: new BingMaps({
|
||||
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp',
|
||||
key: 'AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN',
|
||||
imagerySet: styles[i],
|
||||
// use maxZoom 19 to see stretched tiles instead of the BingMaps
|
||||
// "no photos at this zoom level" tiles
|
||||
|
||||
16
examples/clusters-dynamic.html
Normal file
16
examples/clusters-dynamic.html
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Dynamic clusters
|
||||
shortdesc: Clusters with zoom-to-cluster, hull view, and uncluttering of overlapping features.
|
||||
docs: >
|
||||
<p>This example shows open data of subsidized photovoltaic installations in Vienna. Different style functions
|
||||
are used for cluster display, single feature display, convex hull of a cluster, and an expanded view of
|
||||
overlapping features. Hovering over a cluster shows its convex hull. Clicking on a cluster zooms to the
|
||||
extent of the contained features. Clicking on a cluster consisting of features that are very close to each other reveals an expanded view
|
||||
of the features, along a circle around the cluster.</p>
|
||||
<p>Features are styled differently depending on the power of the photovoltaic installation.</p>
|
||||
tags: "marker, cluster, vector, style, convex hull"
|
||||
resources:
|
||||
- https://unpkg.com/monotone-chain-convex-hull@1.0.0/lib/index.js
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
278
examples/clusters-dynamic.js
Normal file
278
examples/clusters-dynamic.js
Normal file
@@ -0,0 +1,278 @@
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {
|
||||
Circle as CircleStyle,
|
||||
Fill,
|
||||
Icon,
|
||||
Stroke,
|
||||
Style,
|
||||
Text,
|
||||
} from '../src/ol/style.js';
|
||||
import {Cluster, Vector as VectorSource, XYZ} from '../src/ol/source.js';
|
||||
import {LineString, Point, Polygon} from '../src/ol/geom.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {createEmpty, extend, getWidth} from '../src/ol/extent.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
|
||||
const circleDistanceMultiplier = 1;
|
||||
const circleFootSeparation = 28;
|
||||
const circleStartAngle = Math.PI / 2;
|
||||
|
||||
const convexHullFill = new Fill({
|
||||
color: 'rgba(255, 153, 0, 0.4)',
|
||||
});
|
||||
const convexHullStroke = new Stroke({
|
||||
color: 'rgba(204, 85, 0, 1)',
|
||||
width: 1.5,
|
||||
});
|
||||
const outerCircleFill = new Fill({
|
||||
color: 'rgba(255, 153, 102, 0.3)',
|
||||
});
|
||||
const innerCircleFill = new Fill({
|
||||
color: 'rgba(255, 165, 0, 0.7)',
|
||||
});
|
||||
const textFill = new Fill({
|
||||
color: '#fff',
|
||||
});
|
||||
const textStroke = new Stroke({
|
||||
color: 'rgba(0, 0, 0, 0.6)',
|
||||
width: 3,
|
||||
});
|
||||
const innerCircle = new CircleStyle({
|
||||
radius: 14,
|
||||
fill: innerCircleFill,
|
||||
});
|
||||
const outerCircle = new CircleStyle({
|
||||
radius: 20,
|
||||
fill: outerCircleFill,
|
||||
});
|
||||
const darkIcon = new Icon({
|
||||
src: 'data/icons/emoticon-cool.svg',
|
||||
});
|
||||
const lightIcon = new Icon({
|
||||
src: 'data/icons/emoticon-cool-outline.svg',
|
||||
});
|
||||
|
||||
/**
|
||||
* Single feature style, users for clusters with 1 feature and cluster circles.
|
||||
* @param {Feature} clusterMember A feature from a cluster.
|
||||
* @return {Style} An icon style for the cluster member's location.
|
||||
*/
|
||||
function clusterMemberStyle(clusterMember) {
|
||||
return new Style({
|
||||
geometry: clusterMember.getGeometry(),
|
||||
image: clusterMember.get('LEISTUNG') > 5 ? darkIcon : lightIcon,
|
||||
});
|
||||
}
|
||||
|
||||
let clickFeature, clickResolution;
|
||||
/**
|
||||
* Style for clusters with features that are too close to each other, activated on click.
|
||||
* @param {Feature} cluster A cluster with overlapping members.
|
||||
* @param {number} resolution The current view resolution.
|
||||
* @return {Style} A style to render an expanded view of the cluster members.
|
||||
*/
|
||||
function clusterCircleStyle(cluster, resolution) {
|
||||
if (cluster !== clickFeature || resolution !== clickResolution) {
|
||||
return;
|
||||
}
|
||||
const clusterMembers = cluster.get('features');
|
||||
const centerCoordinates = cluster.getGeometry().getCoordinates();
|
||||
return generatePointsCircle(
|
||||
clusterMembers.length,
|
||||
cluster.getGeometry().getCoordinates(),
|
||||
resolution
|
||||
).reduce((styles, coordinates, i) => {
|
||||
const point = new Point(coordinates);
|
||||
const line = new LineString([centerCoordinates, coordinates]);
|
||||
styles.unshift(
|
||||
new Style({
|
||||
geometry: line,
|
||||
stroke: convexHullStroke,
|
||||
})
|
||||
);
|
||||
styles.push(
|
||||
clusterMemberStyle(
|
||||
new Feature({
|
||||
...clusterMembers[i].getProperties(),
|
||||
geometry: point,
|
||||
})
|
||||
)
|
||||
);
|
||||
return styles;
|
||||
}, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* From
|
||||
* https://github.com/Leaflet/Leaflet.markercluster/blob/31360f2/src/MarkerCluster.Spiderfier.js#L55-L72
|
||||
* Arranges points in a circle around the cluster center, with a line pointing from the center to
|
||||
* each point.
|
||||
* @param {number} count Number of cluster members.
|
||||
* @param {Array<number>} clusterCenter Center coordinate of the cluster.
|
||||
* @param {number} resolution Current view resolution.
|
||||
* @return {Array<Array<number>>} An array of coordinates representing the cluster members.
|
||||
*/
|
||||
function generatePointsCircle(count, clusterCenter, resolution) {
|
||||
const circumference =
|
||||
circleDistanceMultiplier * circleFootSeparation * (2 + count);
|
||||
let legLength = circumference / (Math.PI * 2); //radius from circumference
|
||||
const angleStep = (Math.PI * 2) / count;
|
||||
const res = [];
|
||||
let angle;
|
||||
|
||||
legLength = Math.max(legLength, 35) * resolution; // Minimum distance to get outside the cluster icon.
|
||||
|
||||
for (let i = 0; i < count; ++i) {
|
||||
// Clockwise, like spiral.
|
||||
angle = circleStartAngle + i * angleStep;
|
||||
res.push([
|
||||
clusterCenter[0] + legLength * Math.cos(angle),
|
||||
clusterCenter[1] + legLength * Math.sin(angle),
|
||||
]);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
let hoverFeature;
|
||||
/**
|
||||
* Style for convex hulls of clusters, activated on hover.
|
||||
* @param {Feature} cluster The cluster feature.
|
||||
* @return {Style} Polygon style for the convex hull of the cluster.
|
||||
*/
|
||||
function clusterHullStyle(cluster) {
|
||||
if (cluster !== hoverFeature) {
|
||||
return;
|
||||
}
|
||||
const originalFeatures = cluster.get('features');
|
||||
const points = originalFeatures.map((feature) =>
|
||||
feature.getGeometry().getCoordinates()
|
||||
);
|
||||
return new Style({
|
||||
geometry: new Polygon([monotoneChainConvexHull(points)]),
|
||||
fill: convexHullFill,
|
||||
stroke: convexHullStroke,
|
||||
});
|
||||
}
|
||||
|
||||
function clusterStyle(feature) {
|
||||
const size = feature.get('features').length;
|
||||
if (size > 1) {
|
||||
return [
|
||||
new Style({
|
||||
image: outerCircle,
|
||||
}),
|
||||
new Style({
|
||||
image: innerCircle,
|
||||
text: new Text({
|
||||
text: size.toString(),
|
||||
fill: textFill,
|
||||
stroke: textStroke,
|
||||
}),
|
||||
}),
|
||||
];
|
||||
} else {
|
||||
const originalFeature = feature.get('features')[0];
|
||||
return clusterMemberStyle(originalFeature);
|
||||
}
|
||||
}
|
||||
|
||||
const vectorSource = new VectorSource({
|
||||
format: new GeoJSON(),
|
||||
url: 'data/geojson/photovoltaic.json',
|
||||
});
|
||||
|
||||
const clusterSource = new Cluster({
|
||||
attributions:
|
||||
'Data: <a href="https://www.data.gv.at/auftritte/?organisation=stadt-wien">Stadt Wien</a>',
|
||||
distance: 35,
|
||||
source: vectorSource,
|
||||
});
|
||||
|
||||
// Layer displaying the convex hull of the hovered cluster.
|
||||
const clusterHulls = new VectorLayer({
|
||||
source: clusterSource,
|
||||
style: clusterHullStyle,
|
||||
});
|
||||
|
||||
// Layer displaying the clusters and individual features.
|
||||
const clusters = new VectorLayer({
|
||||
source: clusterSource,
|
||||
style: clusterStyle,
|
||||
});
|
||||
|
||||
// Layer displaying the expanded view of overlapping cluster members.
|
||||
const clusterCircles = new VectorLayer({
|
||||
source: clusterSource,
|
||||
style: clusterCircleStyle,
|
||||
});
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new XYZ({
|
||||
attributions:
|
||||
'Base map: <a target="_blank" href="https://basemap.at/">basemap.at</a>',
|
||||
url: 'https://maps{1-4}.wien.gv.at/basemap/bmapgrau/normal/google3857/{z}/{y}/{x}.png',
|
||||
}),
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [raster, clusterHulls, clusters, clusterCircles],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
maxZoom: 19,
|
||||
extent: [
|
||||
...fromLonLat([16.1793, 48.1124]),
|
||||
...fromLonLat([16.5559, 48.313]),
|
||||
],
|
||||
showFullExtent: true,
|
||||
}),
|
||||
});
|
||||
|
||||
map.on('pointermove', (event) => {
|
||||
clusters.getFeatures(event.pixel).then((features) => {
|
||||
if (features[0] !== hoverFeature) {
|
||||
// Display the convex hull on hover.
|
||||
hoverFeature = features[0];
|
||||
clusterHulls.setStyle(clusterHullStyle);
|
||||
// Change the cursor style to indicate that the cluster is clickable.
|
||||
map.getTargetElement().style.cursor =
|
||||
hoverFeature && hoverFeature.get('features').length > 1
|
||||
? 'pointer'
|
||||
: '';
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
map.on('click', (event) => {
|
||||
clusters.getFeatures(event.pixel).then((features) => {
|
||||
if (features.length > 0) {
|
||||
const clusterMembers = features[0].get('features');
|
||||
if (clusterMembers.length > 1) {
|
||||
// Calculate the extent of the cluster members.
|
||||
const extent = createEmpty();
|
||||
clusterMembers.forEach((feature) =>
|
||||
extend(extent, feature.getGeometry().getExtent())
|
||||
);
|
||||
const view = map.getView();
|
||||
const resolution = map.getView().getResolution();
|
||||
if (
|
||||
view.getZoom() === view.getMaxZoom() ||
|
||||
(getWidth(extent) < resolution && getWidth(extent) < resolution)
|
||||
) {
|
||||
// Show an expanded view of the cluster members.
|
||||
clickFeature = features[0];
|
||||
clickResolution = resolution;
|
||||
clusterCircles.setStyle(clusterCircleStyle);
|
||||
} else {
|
||||
// Zoom to the extent of the cluster members.
|
||||
view.fit(extent, {duration: 500, padding: [50, 50, 50, 50]});
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
10
examples/cog-colors.css
Normal file
10
examples/cog-colors.css
Normal file
@@ -0,0 +1,10 @@
|
||||
.data {
|
||||
text-align: right;
|
||||
font-family: monospace;
|
||||
}
|
||||
td {
|
||||
padding-right: 10px;
|
||||
}
|
||||
input[type="range"] {
|
||||
vertical-align: text-bottom;
|
||||
}
|
||||
32
examples/cog-colors.html
Normal file
32
examples/cog-colors.html
Normal file
@@ -0,0 +1,32 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: NDVI with a Dynamic Color Ramp
|
||||
shortdesc: NDVI from a COG with a dynamic color ramp
|
||||
docs: >
|
||||
The GeoTIFF layer in this example draws from two Sentinel 2 sources: a red band and a near infrared band.
|
||||
The layer style includes a `color` expression that calculates the Normalized Difference Vegetation Index (NDVI)
|
||||
from values in the two bands. The `interpolate` expression is used to map NDVI values to colors. The "stop" values
|
||||
for the color ramp are derived from application provided style variables. Using the inputs above, the min and max
|
||||
colors and values can be adjusted. The `layer.updateStyleVariables()` method is called to update the
|
||||
variables used in the interpolated color expression.
|
||||
tags: "cog, ndvi"
|
||||
resources:
|
||||
- https://cdnjs.cloudflare.com/ajax/libs/chroma-js/2.1.2/chroma.min.js
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Min NDVI</td>
|
||||
<td><input type="range" id="min-value-input" min="-1.0" max="-0.1" step="0.01"></td>
|
||||
<td class="data" id="min-value-output"></td>
|
||||
<td><input type="color" id="min-color"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Max NDVI</td>
|
||||
<td><input type="range" id="max-value-input" min="0.1" max="1.0" step="0.01"></td>
|
||||
<td class="data" id="max-value-output"></td>
|
||||
<td><input type="color" id="max-color"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
106
examples/cog-colors.js
Normal file
106
examples/cog-colors.js
Normal file
@@ -0,0 +1,106 @@
|
||||
import GeoTIFF from '../src/ol/source/GeoTIFF.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import TileLayer from '../src/ol/layer/WebGLTile.js';
|
||||
|
||||
const segments = 10;
|
||||
|
||||
const defaultMinColor = '#0300AD';
|
||||
const defaultMaxColor = '#00ff00';
|
||||
|
||||
const defaultMinValue = -0.5;
|
||||
const defaultMaxValue = 0.7;
|
||||
|
||||
const minColorInput = document.getElementById('min-color');
|
||||
minColorInput.value = defaultMinColor;
|
||||
|
||||
const maxColorInput = document.getElementById('max-color');
|
||||
maxColorInput.value = defaultMaxColor;
|
||||
|
||||
const minValueOutput = document.getElementById('min-value-output');
|
||||
const minValueInput = document.getElementById('min-value-input');
|
||||
minValueInput.value = defaultMinValue.toString();
|
||||
|
||||
const maxValueOutput = document.getElementById('max-value-output');
|
||||
const maxValueInput = document.getElementById('max-value-input');
|
||||
maxValueInput.value = defaultMaxValue.toString();
|
||||
|
||||
function getVariables() {
|
||||
const variables = {};
|
||||
|
||||
const minColor = minColorInput.value;
|
||||
const maxColor = maxColorInput.value;
|
||||
const scale = chroma.scale([minColor, maxColor]).mode('lab');
|
||||
|
||||
const minValue = parseFloat(minValueInput.value);
|
||||
const maxValue = parseFloat(maxValueInput.value);
|
||||
const delta = (maxValue - minValue) / segments;
|
||||
|
||||
for (let i = 0; i <= segments; ++i) {
|
||||
const color = scale(i / segments).rgb();
|
||||
const value = minValue + i * delta;
|
||||
variables[`value${i}`] = value;
|
||||
variables[`red${i}`] = color[0];
|
||||
variables[`green${i}`] = color[1];
|
||||
variables[`blue${i}`] = color[2];
|
||||
}
|
||||
return variables;
|
||||
}
|
||||
|
||||
function colors() {
|
||||
const stops = [];
|
||||
for (let i = 0; i <= segments; ++i) {
|
||||
stops[i * 2] = ['var', `value${i}`];
|
||||
const red = ['var', `red${i}`];
|
||||
const green = ['var', `green${i}`];
|
||||
const blue = ['var', `blue${i}`];
|
||||
stops[i * 2 + 1] = ['color', red, green, blue];
|
||||
}
|
||||
return stops;
|
||||
}
|
||||
|
||||
const ndvi = [
|
||||
'/',
|
||||
['-', ['band', 2], ['band', 1]],
|
||||
['+', ['band', 2], ['band', 1]],
|
||||
];
|
||||
|
||||
const source = new GeoTIFF({
|
||||
sources: [
|
||||
{
|
||||
// visible red, band 1 in the style expression above
|
||||
url: 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/2020/S2A_36QWD_20200701_0_L2A/B04.tif',
|
||||
max: 10000,
|
||||
},
|
||||
{
|
||||
// near infrared, band 2 in the style expression above
|
||||
url: 'https://sentinel-cogs.s3.us-west-2.amazonaws.com/sentinel-s2-l2a-cogs/2020/S2A_36QWD_20200701_0_L2A/B08.tif',
|
||||
max: 10000,
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const layer = new TileLayer({
|
||||
style: {
|
||||
variables: getVariables(),
|
||||
color: ['interpolate', ['linear'], ndvi, ...colors()],
|
||||
},
|
||||
source: source,
|
||||
});
|
||||
|
||||
function update() {
|
||||
layer.updateStyleVariables(getVariables());
|
||||
minValueOutput.innerText = parseFloat(minValueInput.value).toFixed(1);
|
||||
maxValueOutput.innerText = parseFloat(maxValueInput.value).toFixed(1);
|
||||
}
|
||||
|
||||
minColorInput.addEventListener('input', update);
|
||||
maxColorInput.addEventListener('input', update);
|
||||
minValueInput.addEventListener('input', update);
|
||||
maxValueInput.addEventListener('input', update);
|
||||
update();
|
||||
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
layers: [layer],
|
||||
view: source.getView(),
|
||||
});
|
||||
6
examples/cog-stretch.css
Normal file
6
examples/cog-stretch.css
Normal file
@@ -0,0 +1,6 @@
|
||||
.controls {
|
||||
display: grid;
|
||||
grid-template-columns: auto auto 1fr;
|
||||
align-items: baseline;
|
||||
gap: 0 1em;
|
||||
}
|
||||
44
examples/cog-stretch.html
Normal file
44
examples/cog-stretch.html
Normal file
@@ -0,0 +1,44 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Band Constrast Stretch
|
||||
shortdesc: Choosing bands and applying constrast stretch
|
||||
docs: >
|
||||
This example uses the `layer.updateStyleVariables()` method to update the rendering
|
||||
of a GeoTIFF based on user selected bands and contrast stretch parameters.
|
||||
tags: "cog, webgl, style"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div class="controls">
|
||||
<label for="red">Red channel</label>
|
||||
<select id="red">
|
||||
<option value="1" selected>visible red</option>
|
||||
<option value="2">visible green</option>
|
||||
<option value="3">visible blue</option>
|
||||
<option value="4">near infrared</option>
|
||||
</select>
|
||||
<label>max
|
||||
<input type="range" id="redMax" value="3000" min="2000" max="5000">
|
||||
</label>
|
||||
|
||||
<label for="green">Green channel</label>
|
||||
<select id="green">
|
||||
<option value="1">visible red</option>
|
||||
<option value="2" selected>visible green</option>
|
||||
<option value="3">visible blue</option>
|
||||
<option value="4">near infrared</option>
|
||||
</select>
|
||||
<label>max
|
||||
<input type="range" id="greenMax" value="3000" min="2000" max="5000">
|
||||
</label>
|
||||
|
||||
<label for="blue">Blue channel</label>
|
||||
<select id="blue">
|
||||
<option value="1">visible red</option>
|
||||
<option value="2">visible green</option>
|
||||
<option value="3" selected>visible blue</option>
|
||||
<option value="4">near infrared</option>
|
||||
</select>
|
||||
<label>max
|
||||
<input type="range" id="blueMax" value="3000" min="2000" max="5000">
|
||||
</label>
|
||||
</div>
|
||||
62
examples/cog-stretch.js
Normal file
62
examples/cog-stretch.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import GeoTIFF from '../src/ol/source/GeoTIFF.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import TileLayer from '../src/ol/layer/WebGLTile.js';
|
||||
import View from '../src/ol/View.js';
|
||||
|
||||
const channels = ['red', 'green', 'blue'];
|
||||
for (const channel of channels) {
|
||||
const selector = document.getElementById(channel);
|
||||
selector.addEventListener('change', update);
|
||||
|
||||
const input = document.getElementById(`${channel}Max`);
|
||||
input.addEventListener('input', update);
|
||||
}
|
||||
|
||||
function getVariables() {
|
||||
const variables = {};
|
||||
for (const channel of channels) {
|
||||
const selector = document.getElementById(channel);
|
||||
variables[channel] = parseInt(selector.value, 10);
|
||||
|
||||
const inputId = `${channel}Max`;
|
||||
const input = document.getElementById(inputId);
|
||||
variables[inputId] = parseInt(input.value, 10);
|
||||
}
|
||||
return variables;
|
||||
}
|
||||
|
||||
const layer = new TileLayer({
|
||||
style: {
|
||||
variables: getVariables(),
|
||||
color: [
|
||||
'array',
|
||||
['/', ['band', ['var', 'red']], ['var', 'redMax']],
|
||||
['/', ['band', ['var', 'green']], ['var', 'greenMax']],
|
||||
['/', ['band', ['var', 'blue']], ['var', 'blueMax']],
|
||||
1,
|
||||
],
|
||||
},
|
||||
source: new GeoTIFF({
|
||||
normalize: false,
|
||||
sources: [
|
||||
{
|
||||
url: 'https://s2downloads.eox.at/demo/EOxCloudless/2020/rgbnir/s2cloudless2020-16bits_sinlge-file_z0-4.tif',
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
function update() {
|
||||
layer.updateStyleVariables(getVariables());
|
||||
}
|
||||
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
layers: [layer],
|
||||
view: new View({
|
||||
projection: 'EPSG:4326',
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
maxZoom: 6,
|
||||
}),
|
||||
});
|
||||
20
examples/cog-style.html
Normal file
20
examples/cog-style.html
Normal file
@@ -0,0 +1,20 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Change Tile Layer Style
|
||||
shortdesc: Updating the style of a WebGL tile layer
|
||||
docs: >
|
||||
When you want to change the style of a WebGL tile layer based on some change in your
|
||||
application state, you should use the `layer.updateStyleVariables()` method. A layer can
|
||||
be efficiently rendered even if style variables are changed on every render frame.
|
||||
In cases where you need to completely replace the style of a layer, you can call the
|
||||
`layer.setStyle()` method. This method should not be called in response to frequent
|
||||
user events (e.g. mouse movement, dragging a slider, etc.).
|
||||
tags: "cog, webgl, style"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
Set the layer style
|
||||
<select id="style">
|
||||
<option value="trueColor">True Color</option>
|
||||
<option value="falseColor">False Color</option>
|
||||
<option value="ndvi">NDVI</option>
|
||||
</select>
|
||||
105
examples/cog-style.js
Normal file
105
examples/cog-style.js
Normal file
@@ -0,0 +1,105 @@
|
||||
import GeoTIFF from '../src/ol/source/GeoTIFF.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import TileLayer from '../src/ol/layer/WebGLTile.js';
|
||||
import View from '../src/ol/View.js';
|
||||
|
||||
const max = 3000;
|
||||
function normalize(value) {
|
||||
return ['/', value, max];
|
||||
}
|
||||
|
||||
const red = normalize(['band', 1]);
|
||||
const green = normalize(['band', 2]);
|
||||
const blue = normalize(['band', 3]);
|
||||
const nir = normalize(['band', 4]);
|
||||
|
||||
const trueColor = {
|
||||
color: ['array', red, green, blue, 1],
|
||||
gamma: 1.1,
|
||||
};
|
||||
|
||||
const falseColor = {
|
||||
color: ['array', nir, red, green, 1],
|
||||
gamma: 1.1,
|
||||
};
|
||||
|
||||
const ndvi = {
|
||||
color: [
|
||||
'interpolate',
|
||||
['linear'],
|
||||
['/', ['-', nir, red], ['+', nir, red]],
|
||||
// color ramp for NDVI values, ranging from -1 to 1
|
||||
-0.2,
|
||||
[191, 191, 191],
|
||||
-0.1,
|
||||
[219, 219, 219],
|
||||
0,
|
||||
[255, 255, 224],
|
||||
0.025,
|
||||
[255, 250, 204],
|
||||
0.05,
|
||||
[237, 232, 181],
|
||||
0.075,
|
||||
[222, 217, 156],
|
||||
0.1,
|
||||
[204, 199, 130],
|
||||
0.125,
|
||||
[189, 184, 107],
|
||||
0.15,
|
||||
[176, 194, 97],
|
||||
0.175,
|
||||
[163, 204, 89],
|
||||
0.2,
|
||||
[145, 191, 82],
|
||||
0.25,
|
||||
[128, 179, 71],
|
||||
0.3,
|
||||
[112, 163, 64],
|
||||
0.35,
|
||||
[97, 150, 54],
|
||||
0.4,
|
||||
[79, 138, 46],
|
||||
0.45,
|
||||
[64, 125, 36],
|
||||
0.5,
|
||||
[48, 110, 28],
|
||||
0.55,
|
||||
[33, 97, 18],
|
||||
0.6,
|
||||
[15, 84, 10],
|
||||
0.65,
|
||||
[0, 69, 0],
|
||||
],
|
||||
};
|
||||
|
||||
const layer = new TileLayer({
|
||||
style: trueColor,
|
||||
source: new GeoTIFF({
|
||||
normalize: false,
|
||||
sources: [
|
||||
{
|
||||
url: 'https://s2downloads.eox.at/demo/EOxCloudless/2020/rgbnir/s2cloudless2020-16bits_sinlge-file_z0-4.tif',
|
||||
},
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
target: 'map',
|
||||
layers: [layer],
|
||||
view: new View({
|
||||
projection: 'EPSG:4326',
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
maxZoom: 6,
|
||||
}),
|
||||
});
|
||||
|
||||
const styles = {trueColor, falseColor, ndvi};
|
||||
const styleSelector = document.getElementById('style');
|
||||
|
||||
function update() {
|
||||
const style = styles[styleSelector.value];
|
||||
layer.setStyle(style);
|
||||
}
|
||||
styleSelector.addEventListener('change', update);
|
||||
12
examples/custom-hit-detection-renderer.html
Normal file
12
examples/custom-hit-detection-renderer.html
Normal file
@@ -0,0 +1,12 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Custom Hit Detection Render
|
||||
shortdesc: Example of a custom hit detection renderer.
|
||||
docs: >
|
||||
This example demonstrates the use of 'ol/style/Style' hitDetectionRender option function in
|
||||
detecting if pointer is over a particular feature.
|
||||
Move pointer over the label for Columbus Circle feature and see that only label is used in
|
||||
hit detection.
|
||||
tags: "circle, feature, vector, render, custom, hitDetectionRenderer"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
103
examples/custom-hit-detection-renderer.js
Normal file
103
examples/custom-hit-detection-renderer.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {Circle} from '../src/ol/geom.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {Style} from '../src/ol/style.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
|
||||
const columbusCircleCoords = fromLonLat([-73.98189, 40.76805]);
|
||||
const labelTextStroke = 'rgba(120, 120, 120, 1)';
|
||||
const labelText = 'Columbus Circle';
|
||||
|
||||
let pointerOverFeature = null;
|
||||
|
||||
const renderLabelText = (ctx, x, y, stroke) => {
|
||||
ctx.fillStyle = 'rgba(255,0,0,1)';
|
||||
ctx.strokeStyle = stroke;
|
||||
ctx.lineWidth = 1;
|
||||
ctx.textAlign = 'center';
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.font = `bold 30px verdana`;
|
||||
ctx.filter = 'drop-shadow(7px 7px 2px #e81)';
|
||||
ctx.fillText(labelText, x, y);
|
||||
ctx.strokeText(labelText, x, y);
|
||||
};
|
||||
|
||||
const circleFeature = new Feature({
|
||||
geometry: new Circle(columbusCircleCoords, 50),
|
||||
});
|
||||
|
||||
circleFeature.set('label-color', labelTextStroke);
|
||||
|
||||
circleFeature.setStyle(
|
||||
new Style({
|
||||
renderer(coordinates, state) {
|
||||
const [[x, y], [x1, y1]] = coordinates;
|
||||
const ctx = state.context;
|
||||
const dx = x1 - x;
|
||||
const dy = y1 - y;
|
||||
const radius = Math.sqrt(dx * dx + dy * dy);
|
||||
|
||||
const innerRadius = 0;
|
||||
const outerRadius = radius * 1.4;
|
||||
|
||||
const gradient = ctx.createRadialGradient(
|
||||
x,
|
||||
y,
|
||||
innerRadius,
|
||||
x,
|
||||
y,
|
||||
outerRadius
|
||||
);
|
||||
gradient.addColorStop(0, 'rgba(255,0,0,0)');
|
||||
gradient.addColorStop(0.6, 'rgba(255,0,0,0.2)');
|
||||
gradient.addColorStop(1, 'rgba(255,0,0,0.8)');
|
||||
ctx.beginPath();
|
||||
ctx.arc(x, y, radius, 0, 2 * Math.PI, true);
|
||||
ctx.fillStyle = gradient;
|
||||
ctx.fill();
|
||||
ctx.strokeStyle = 'rgba(255,0,0,1)';
|
||||
ctx.stroke();
|
||||
|
||||
renderLabelText(ctx, x, y, circleFeature.get('label-color'));
|
||||
},
|
||||
hitDetectionRenderer(coordinates, state) {
|
||||
const [x, y] = coordinates[0];
|
||||
const ctx = state.context;
|
||||
renderLabelText(ctx, x, y, circleFeature.get('label-color'));
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM(),
|
||||
visible: true,
|
||||
}),
|
||||
new VectorLayer({
|
||||
source: new VectorSource({
|
||||
features: [circleFeature],
|
||||
}),
|
||||
}),
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: columbusCircleCoords,
|
||||
zoom: 19,
|
||||
}),
|
||||
});
|
||||
|
||||
map.on('pointermove', (evt) => {
|
||||
const featureOver = map.forEachFeatureAtPixel(evt.pixel, (feature) => {
|
||||
feature.set('label-color', 'rgba(255,255,255,1)');
|
||||
return feature;
|
||||
});
|
||||
|
||||
if (pointerOverFeature && pointerOverFeature != featureOver) {
|
||||
pointerOverFeature.set('label-color', labelTextStroke);
|
||||
}
|
||||
pointerOverFeature = featureOver;
|
||||
});
|
||||
@@ -32,7 +32,7 @@ const map = new Map({
|
||||
context.strokeRect(0, 0, size, size);
|
||||
const data = context.getImageData(0, 0, size, size).data;
|
||||
// converting to Uint8Array for increased browser compatibility
|
||||
return Promise.resolve(new Uint8Array(data.buffer));
|
||||
return new Uint8Array(data.buffer);
|
||||
},
|
||||
// disable opacity transition to avoid overlapping labels during tile loading
|
||||
transition: 0,
|
||||
|
||||
1
examples/data/geojson/photovoltaic.json
Normal file
1
examples/data/geojson/photovoltaic.json
Normal file
File diff suppressed because one or more lines are too long
1
examples/data/icons/emoticon-cool-outline.svg
Normal file
1
examples/data/icons/emoticon-cool-outline.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M19,10C19,11.38 16.88,12.5 15.5,12.5C14.12,12.5 12.75,11.38 12.75,10H11.25C11.25,11.38 9.88,12.5 8.5,12.5C7.12,12.5 5,11.38 5,10H4.25C4.09,10.64 4,11.31 4,12A8,8 0 0,0 12,20A8,8 0 0,0 20,12C20,11.31 19.91,10.64 19.75,10H19M12,4C9.04,4 6.45,5.61 5.07,8H18.93C17.55,5.61 14.96,4 12,4M22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12A10,10 0 0,1 12,2A10,10 0 0,1 22,12M12,17.23C10.25,17.23 8.71,16.5 7.81,15.42L9.23,14C9.68,14.72 10.75,15.23 12,15.23C13.25,15.23 14.32,14.72 14.77,14L16.19,15.42C15.29,16.5 13.75,17.23 12,17.23Z" /></svg>
|
||||
|
After Width: | Height: | Size: 812 B |
1
examples/data/icons/emoticon-cool.svg
Normal file
1
examples/data/icons/emoticon-cool.svg
Normal file
@@ -0,0 +1 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24" height="24" viewBox="0 0 24 24"><path d="M3.22,7.22C4.91,4.11 8.21,2 12,2C15.79,2 19.09,4.11 20.78,7.22L20,8H4L3.22,7.22M21.4,8.6C21.78,9.67 22,10.81 22,12A10,10 0 0,1 12,22A10,10 0 0,1 2,12C2,10.81 2.22,9.67 2.6,8.6L4,10H5C5,11.38 7.12,12.5 8.5,12.5C9.88,12.5 11.25,11.38 11.25,10H12.75C12.75,11.38 14.12,12.5 15.5,12.5C16.88,12.5 19,11.38 19,10H20L21.4,8.6M16.19,15.42L14.77,14C14.32,14.72 13.25,15.23 12,15.23C10.75,15.23 9.68,14.72 9.23,14L7.81,15.42C8.71,16.5 10.25,17.23 12,17.23C13.75,17.23 15.29,16.5 16.19,15.42Z" /></svg>
|
||||
|
After Width: | Height: | Size: 775 B |
1
examples/data/openweather/weather.json
Normal file
1
examples/data/openweather/weather.json
Normal file
File diff suppressed because one or more lines are too long
@@ -4,6 +4,7 @@ import {Circle as CircleStyle, Fill, Stroke, Style} from '../src/ol/style.js';
|
||||
import {Draw, Modify, Snap} from '../src/ol/interaction.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {get} from '../src/ol/proj.js';
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new OSM(),
|
||||
@@ -29,12 +30,18 @@ const vector = new VectorLayer({
|
||||
}),
|
||||
});
|
||||
|
||||
// Limit multi-world panning to one world east and west of the real world.
|
||||
// Geometry coordinates have to be within that range.
|
||||
const extent = get('EPSG:3857').getExtent().slice();
|
||||
extent[0] += extent[0];
|
||||
extent[2] += extent[2];
|
||||
const map = new Map({
|
||||
layers: [raster, vector],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [-11000000, 4600000],
|
||||
zoom: 4,
|
||||
extent,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
import GeoJSON from '../src/ol/format/GeoJSON.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {
|
||||
Heatmap as HeatmapLayer,
|
||||
Tile as TileLayer,
|
||||
Vector as VectorLayer,
|
||||
} from '../src/ol/layer.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
@@ -16,6 +20,18 @@ const map = new Map({
|
||||
}),
|
||||
opacity: 0.5,
|
||||
}),
|
||||
new HeatmapLayer({
|
||||
source: new VectorSource({
|
||||
url: 'data/geojson/world-cities.geojson',
|
||||
format: new GeoJSON(),
|
||||
}),
|
||||
weight: function (feature) {
|
||||
return feature.get('population') / 1e7;
|
||||
},
|
||||
radius: 15,
|
||||
blur: 15,
|
||||
opacity: 0.5,
|
||||
}),
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
@@ -32,17 +48,30 @@ document.getElementById('export-png').addEventListener('click', function () {
|
||||
mapCanvas.height = size[1];
|
||||
const mapContext = mapCanvas.getContext('2d');
|
||||
Array.prototype.forEach.call(
|
||||
document.querySelectorAll('.ol-layer canvas'),
|
||||
map.getViewport().querySelectorAll('.ol-layer canvas, canvas.ol-layer'),
|
||||
function (canvas) {
|
||||
if (canvas.width > 0) {
|
||||
const opacity = canvas.parentNode.style.opacity;
|
||||
const opacity =
|
||||
canvas.parentNode.style.opacity || canvas.style.opacity;
|
||||
mapContext.globalAlpha = opacity === '' ? 1 : Number(opacity);
|
||||
let matrix;
|
||||
const transform = canvas.style.transform;
|
||||
// Get the transform parameters from the style's transform matrix
|
||||
const matrix = transform
|
||||
.match(/^matrix\(([^\(]*)\)$/)[1]
|
||||
.split(',')
|
||||
.map(Number);
|
||||
if (transform) {
|
||||
// Get the transform parameters from the style's transform matrix
|
||||
matrix = transform
|
||||
.match(/^matrix\(([^\(]*)\)$/)[1]
|
||||
.split(',')
|
||||
.map(Number);
|
||||
} else {
|
||||
matrix = [
|
||||
parseFloat(canvas.style.width) / canvas.width,
|
||||
0,
|
||||
0,
|
||||
parseFloat(canvas.style.height) / canvas.height,
|
||||
0,
|
||||
0,
|
||||
];
|
||||
}
|
||||
// Apply the transform to the export map context
|
||||
CanvasRenderingContext2D.prototype.setTransform.apply(
|
||||
mapContext,
|
||||
|
||||
13
examples/external-map.html
Normal file
13
examples/external-map.html
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: External map
|
||||
shortdesc: Move a map to a seperate window.
|
||||
docs: >
|
||||
Move a map to a seperate window.
|
||||
tags: "external, window"
|
||||
sources:
|
||||
- path: resources/external-map-map.html
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<input id="external-map-button" type="button" value="Open external map"></input>
|
||||
<span id="blocker-notice" hidden>Could not open map in external window. If you are using a popup or ad blocker you may need to disable it for this example.</span>
|
||||
112
examples/external-map.js
Normal file
112
examples/external-map.js
Normal file
@@ -0,0 +1,112 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {
|
||||
Control,
|
||||
FullScreen,
|
||||
defaults as defaultControls,
|
||||
} from '../src/ol/control.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
|
||||
class UnusableMask extends Control {
|
||||
constructor() {
|
||||
super({
|
||||
element: document.createElement('div'),
|
||||
});
|
||||
this.element.setAttribute('hidden', 'hidden');
|
||||
this.element.className = 'ol-mask';
|
||||
this.element.innerHTML = '<div>Map not usable</div>';
|
||||
}
|
||||
}
|
||||
|
||||
const localMapTarget = document.getElementById('map');
|
||||
|
||||
const map = new Map({
|
||||
target: localMapTarget,
|
||||
controls: defaultControls().extend([new FullScreen(), new UnusableMask()]),
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM(),
|
||||
}),
|
||||
],
|
||||
view: new View({
|
||||
center: fromLonLat([37.41, 8.82]),
|
||||
zoom: 4,
|
||||
}),
|
||||
});
|
||||
|
||||
let mapWindow;
|
||||
function closeMapWindow() {
|
||||
if (mapWindow) {
|
||||
mapWindow.close();
|
||||
mapWindow = undefined;
|
||||
}
|
||||
}
|
||||
// Close external window in case the main page is closed or reloaded
|
||||
window.addEventListener('pagehide', closeMapWindow);
|
||||
|
||||
const button = document.getElementById('external-map-button');
|
||||
|
||||
function resetMapTarget() {
|
||||
localMapTarget.style.height = '';
|
||||
map.setTarget(localMapTarget);
|
||||
button.disabled = false;
|
||||
}
|
||||
|
||||
function updateOverlay() {
|
||||
if (!mapWindow) {
|
||||
return;
|
||||
}
|
||||
const externalMapTarget = mapWindow.document.getElementById('map');
|
||||
if (!externalMapTarget) {
|
||||
return;
|
||||
}
|
||||
if (document.visibilityState === 'visible') {
|
||||
// Show controls and enable keyboard input
|
||||
externalMapTarget.classList.remove('unusable');
|
||||
externalMapTarget.setAttribute('tabindex', '0');
|
||||
externalMapTarget.focus();
|
||||
} else {
|
||||
// Hide all controls and disable keyboard input
|
||||
externalMapTarget.removeAttribute('tabindex');
|
||||
externalMapTarget.classList.add('unusable');
|
||||
}
|
||||
}
|
||||
window.addEventListener('visibilitychange', updateOverlay);
|
||||
|
||||
button.addEventListener('click', function () {
|
||||
const blockerNotice = document.getElementById('blocker-notice');
|
||||
blockerNotice.setAttribute('hidden', 'hidden');
|
||||
button.disabled = true;
|
||||
|
||||
// Reset button and map target in case window did not load or open
|
||||
let timeoutKey = setTimeout(function () {
|
||||
closeMapWindow();
|
||||
resetMapTarget();
|
||||
blockerNotice.removeAttribute('hidden');
|
||||
timeoutKey = undefined;
|
||||
}, 3000);
|
||||
|
||||
mapWindow = window.open(
|
||||
'resources/external-map-map.html',
|
||||
'MapWindow',
|
||||
'toolbar=0,location=0,menubar=0,width=800,height=600'
|
||||
);
|
||||
mapWindow.addEventListener('DOMContentLoaded', function () {
|
||||
const externalMapTarget = mapWindow.document.getElementById('map');
|
||||
localMapTarget.style.height = '0px';
|
||||
map.setTarget(externalMapTarget);
|
||||
|
||||
if (timeoutKey) {
|
||||
timeoutKey = clearTimeout(timeoutKey);
|
||||
}
|
||||
mapWindow.addEventListener('pagehide', function () {
|
||||
resetMapTarget();
|
||||
// Close window in case user does a page reload
|
||||
closeMapWindow();
|
||||
});
|
||||
|
||||
updateOverlay();
|
||||
});
|
||||
});
|
||||
@@ -7,6 +7,7 @@ import View from '../src/ol/View.js';
|
||||
import {Stroke, Style} from '../src/ol/style.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {getVectorContext} from '../src/ol/render.js';
|
||||
import {getWidth} from '../src/ol/extent.js';
|
||||
|
||||
const tileLayer = new TileLayer({
|
||||
source: new Stamen({
|
||||
@@ -18,7 +19,7 @@ const map = new Map({
|
||||
layers: [tileLayer],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
center: [-11000000, 4600000],
|
||||
zoom: 2,
|
||||
}),
|
||||
});
|
||||
@@ -31,7 +32,6 @@ const style = new Style({
|
||||
});
|
||||
|
||||
const flightsSource = new VectorSource({
|
||||
wrapX: false,
|
||||
attributions:
|
||||
'Flight data by ' +
|
||||
'<a href="https://openflights.org/data.html">OpenFlights</a>,',
|
||||
@@ -55,18 +55,23 @@ const flightsSource = new VectorSource({
|
||||
);
|
||||
|
||||
const arcLine = arcGenerator.Arc(100, {offset: 10});
|
||||
if (arcLine.geometries.length === 1) {
|
||||
const line = new LineString(arcLine.geometries[0].coords);
|
||||
// paths which cross the -180°/+180° meridian are split
|
||||
// into two sections which will be animated sequentially
|
||||
const features = [];
|
||||
arcLine.geometries.forEach(function (geometry) {
|
||||
const line = new LineString(geometry.coords);
|
||||
line.transform('EPSG:4326', 'EPSG:3857');
|
||||
|
||||
const feature = new Feature({
|
||||
geometry: line,
|
||||
finished: false,
|
||||
});
|
||||
// add the feature with a delay so that the animation
|
||||
// for all features does not start at the same time
|
||||
addLater(feature, i * 50);
|
||||
}
|
||||
features.push(
|
||||
new Feature({
|
||||
geometry: line,
|
||||
finished: false,
|
||||
})
|
||||
);
|
||||
});
|
||||
// add the features with a delay so that the animation
|
||||
// for all features does not start at the same time
|
||||
addLater(features, i * 50);
|
||||
}
|
||||
tileLayer.on('postrender', animateFlights);
|
||||
});
|
||||
@@ -88,7 +93,7 @@ const flightsLayer = new VectorLayer({
|
||||
|
||||
map.addLayer(flightsLayer);
|
||||
|
||||
const pointsPerMs = 0.1;
|
||||
const pointsPerMs = 0.02;
|
||||
function animateFlights(event) {
|
||||
const vectorContext = getVectorContext(event);
|
||||
const frameState = event.frameState;
|
||||
@@ -101,26 +106,41 @@ function animateFlights(event) {
|
||||
// only draw the lines for which the animation has not finished yet
|
||||
const coords = feature.getGeometry().getCoordinates();
|
||||
const elapsedTime = frameState.time - feature.get('start');
|
||||
const elapsedPoints = elapsedTime * pointsPerMs;
|
||||
if (elapsedTime >= 0) {
|
||||
const elapsedPoints = elapsedTime * pointsPerMs;
|
||||
|
||||
if (elapsedPoints >= coords.length) {
|
||||
feature.set('finished', true);
|
||||
if (elapsedPoints >= coords.length) {
|
||||
feature.set('finished', true);
|
||||
}
|
||||
|
||||
const maxIndex = Math.min(elapsedPoints, coords.length);
|
||||
const currentLine = new LineString(coords.slice(0, maxIndex));
|
||||
|
||||
// animation is needed in the current and nearest adjacent wrapped world
|
||||
const worldWidth = getWidth(map.getView().getProjection().getExtent());
|
||||
const offset = Math.floor(map.getView().getCenter()[0] / worldWidth);
|
||||
|
||||
// directly draw the lines with the vector context
|
||||
currentLine.translate(offset * worldWidth, 0);
|
||||
vectorContext.drawGeometry(currentLine);
|
||||
currentLine.translate(worldWidth, 0);
|
||||
vectorContext.drawGeometry(currentLine);
|
||||
}
|
||||
|
||||
const maxIndex = Math.min(elapsedPoints, coords.length);
|
||||
const currentLine = new LineString(coords.slice(0, maxIndex));
|
||||
|
||||
// directly draw the line with the vector context
|
||||
vectorContext.drawGeometry(currentLine);
|
||||
}
|
||||
}
|
||||
// tell OpenLayers to continue the animation
|
||||
map.render();
|
||||
}
|
||||
|
||||
function addLater(feature, timeout) {
|
||||
function addLater(features, timeout) {
|
||||
window.setTimeout(function () {
|
||||
feature.set('start', Date.now());
|
||||
flightsSource.addFeature(feature);
|
||||
let start = Date.now();
|
||||
features.forEach(function (feature) {
|
||||
feature.set('start', start);
|
||||
flightsSource.addFeature(feature);
|
||||
const duration =
|
||||
(feature.getGeometry().getCoordinates().length - 1) / pointsPerMs;
|
||||
start += duration;
|
||||
});
|
||||
}, timeout);
|
||||
}
|
||||
|
||||
@@ -63,10 +63,15 @@ map.on('moveend', function () {
|
||||
});
|
||||
|
||||
map.on('click', function (event) {
|
||||
$(element).popover('dispose');
|
||||
|
||||
const feature = map.getFeaturesAtPixel(event.pixel)[0];
|
||||
if (feature) {
|
||||
const coordinate = feature.getGeometry().getCoordinates();
|
||||
popup.setPosition(coordinate);
|
||||
popup.setPosition([
|
||||
coordinate[0] + Math.round(event.coordinate[0] / 360) * 360,
|
||||
coordinate[1],
|
||||
]);
|
||||
$(element).popover({
|
||||
container: element.parentElement,
|
||||
html: true,
|
||||
@@ -75,8 +80,6 @@ map.on('click', function (event) {
|
||||
placement: 'top',
|
||||
});
|
||||
$(element).popover('show');
|
||||
} else {
|
||||
$(element).popover('dispose');
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Disable Image Smoothing
|
||||
shortdesc: Example of disabling image smoothing
|
||||
title: Interpolation
|
||||
shortdesc: Example of data interpolation
|
||||
docs: >
|
||||
Example of disabling image smoothing when using raster DEM (digital elevation model) data.
|
||||
The <code>imageSmoothing: false</code> setting is used to disable canvas image smoothing during
|
||||
Example of data resampling when using raster DEM (digital elevation model) data.
|
||||
The <code>interpolate: false</code> setting is used to disable interpolation of data values during
|
||||
reprojection and rendering. Elevation data is
|
||||
calculated from the pixel value returned by <b>forEachLayerAtPixel</b>. For comparison a second map
|
||||
with smoothing enabled returns inaccuate elevations which are very noticeable close to 3107 meters
|
||||
with interpolation enabled returns inaccuate elevations which are very noticeable close to 3107 meters
|
||||
due to how elevation is calculated from the pixel value.
|
||||
tags: "disable image smoothing, xyz, maptiler, reprojection"
|
||||
tags: "disable image interpolation, xyz, maptiler, reprojection"
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div class="wrapper">
|
||||
<div class="half">
|
||||
<h4>Smoothing Disabled</h4>
|
||||
<h4>Not Interpolated</h4>
|
||||
<div id="map1" class="map"></div>
|
||||
<div>
|
||||
<label>
|
||||
@@ -24,16 +24,9 @@ cloak:
|
||||
<span id="info1">0.0</span> meters
|
||||
</label>
|
||||
</div>
|
||||
<div>
|
||||
<label>
|
||||
Imagery opacity
|
||||
<input id="opacity" type="range" min="0" max="100" value="80" />
|
||||
<span id="output"></span> %
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
<div class="half">
|
||||
<h4>Uncorrected Comparison</h4>
|
||||
<h4>Interpolated</h4>
|
||||
<div id="map2" class="map"></div>
|
||||
<div>
|
||||
<label>
|
||||
@@ -8,63 +8,31 @@ const attributions =
|
||||
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>';
|
||||
|
||||
const disabledLayer = new TileLayer({
|
||||
const notInterpolated = new TileLayer({
|
||||
// specify className so forEachLayerAtPixel can distinguish layers
|
||||
className: 'ol-layer-dem',
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url:
|
||||
'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' + key,
|
||||
maxZoom: 10,
|
||||
tileSize: 512,
|
||||
maxZoom: 12,
|
||||
crossOrigin: '',
|
||||
imageSmoothing: false,
|
||||
interpolate: false,
|
||||
}),
|
||||
});
|
||||
|
||||
const imagery = new TileLayer({
|
||||
className: 'ol-layer-imagery',
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: '',
|
||||
}),
|
||||
});
|
||||
|
||||
const enabledLayer = new TileLayer({
|
||||
const interpolated = new TileLayer({
|
||||
source: new XYZ({
|
||||
attributions: attributions,
|
||||
url:
|
||||
'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' + key,
|
||||
maxZoom: 10,
|
||||
tileSize: 512,
|
||||
maxZoom: 12,
|
||||
crossOrigin: '',
|
||||
}),
|
||||
});
|
||||
|
||||
imagery.on('prerender', function (evt) {
|
||||
// use opaque background to conceal DEM while fully opaque imagery renders
|
||||
if (imagery.getOpacity() === 1) {
|
||||
evt.context.fillStyle = 'white';
|
||||
evt.context.fillRect(
|
||||
0,
|
||||
0,
|
||||
evt.context.canvas.width,
|
||||
evt.context.canvas.height
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
const control = document.getElementById('opacity');
|
||||
const output = document.getElementById('output');
|
||||
const listener = function () {
|
||||
output.innerText = control.value;
|
||||
imagery.setOpacity(control.value / 100);
|
||||
};
|
||||
control.addEventListener('input', listener);
|
||||
control.addEventListener('change', listener);
|
||||
output.innerText = control.value;
|
||||
imagery.setOpacity(control.value / 100);
|
||||
|
||||
const view = new View({
|
||||
center: [6.893, 45.8295],
|
||||
zoom: 16,
|
||||
@@ -73,13 +41,13 @@ const view = new View({
|
||||
|
||||
const map1 = new Map({
|
||||
target: 'map1',
|
||||
layers: [disabledLayer, imagery],
|
||||
layers: [notInterpolated],
|
||||
view: view,
|
||||
});
|
||||
|
||||
const map2 = new Map({
|
||||
target: 'map2',
|
||||
layers: [enabledLayer],
|
||||
layers: [interpolated],
|
||||
view: view,
|
||||
});
|
||||
|
||||
@@ -99,7 +67,7 @@ const showElevations = function (evt) {
|
||||
},
|
||||
{
|
||||
layerFilter: function (layer) {
|
||||
return layer === disabledLayer;
|
||||
return layer === notInterpolated;
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -112,7 +80,7 @@ const showElevations = function (evt) {
|
||||
},
|
||||
{
|
||||
layerFilter: function (layer) {
|
||||
return layer === enabledLayer;
|
||||
return layer === interpolated;
|
||||
},
|
||||
}
|
||||
);
|
||||
@@ -18,7 +18,7 @@ cloak:
|
||||
<li><span>OSM layer</span>
|
||||
<fieldset id="layer0">
|
||||
<label class="checkbox" for="visible0">
|
||||
visibile <input id="visible0" class="visible" type="checkbox"/>
|
||||
visible <input id="visible0" class="visible" type="checkbox"/>
|
||||
</label>
|
||||
<label>
|
||||
opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
|
||||
@@ -29,7 +29,7 @@ cloak:
|
||||
<span>Layer group</span>
|
||||
<fieldset id="layer1">
|
||||
<label class="checkbox" for="visible1">
|
||||
visibile <input id="visible1" class="visible" type="checkbox"/>
|
||||
visible <input id="visible1" class="visible" type="checkbox"/>
|
||||
</label>
|
||||
<label>
|
||||
opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
|
||||
@@ -40,7 +40,7 @@ cloak:
|
||||
<span>Food insecurity layer</span>
|
||||
<fieldset id="layer10">
|
||||
<label class="checkbox" for="visible10">
|
||||
visibile <input id="visible10" class="visible" type="checkbox"/>
|
||||
visible <input id="visible10" class="visible" type="checkbox"/>
|
||||
</label>
|
||||
<label>
|
||||
opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
|
||||
@@ -51,7 +51,7 @@ cloak:
|
||||
<span>World borders layer</span>
|
||||
<fieldset id="layer11">
|
||||
<label class="checkbox" for="visible11">
|
||||
visibile <input id="visible11" class="visible" type="checkbox"/>
|
||||
visible <input id="visible11" class="visible" type="checkbox"/>
|
||||
</label>
|
||||
<label>
|
||||
opacity <input class="opacity" type="range" min="0" max="1" step="0.01"/>
|
||||
|
||||
17
examples/layer-opacity.html
Normal file
17
examples/layer-opacity.html
Normal file
@@ -0,0 +1,17 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Layer Opacity
|
||||
shortdesc: Adjust layer opacity based on user input
|
||||
docs: >
|
||||
The `layer.setOpacity()` method can be called to adjust the opacity of a layer.
|
||||
tags: "opacity"
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<label>
|
||||
Layer opacity
|
||||
<input id="opacity-input" type="range" min="0" max="1" step="0.01" value="1" />
|
||||
<span id="opacity-output"></span>
|
||||
</label>
|
||||
42
examples/layer-opacity.js
Normal file
42
examples/layer-opacity.js
Normal file
@@ -0,0 +1,42 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import TileLayer from '../src/ol/layer/WebGLTile.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
|
||||
const imagery = new TileLayer({
|
||||
className: 'ol-layer-imagery',
|
||||
source: new XYZ({
|
||||
attributions:
|
||||
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ',
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
maxZoom: 20,
|
||||
crossOrigin: '',
|
||||
}),
|
||||
});
|
||||
|
||||
const osm = new TileLayer({
|
||||
source: new OSM(),
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [imagery, osm],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
}),
|
||||
});
|
||||
|
||||
const opacityInput = document.getElementById('opacity-input');
|
||||
const opacityOutput = document.getElementById('opacity-output');
|
||||
function update() {
|
||||
const opacity = parseFloat(opacityInput.value);
|
||||
osm.setOpacity(opacity);
|
||||
opacityOutput.innerText = opacity.toFixed(2);
|
||||
}
|
||||
opacityInput.addEventListener('input', update);
|
||||
opacityInput.addEventListener('change', update);
|
||||
update();
|
||||
@@ -5,6 +5,7 @@ import View from '../src/ol/View.js';
|
||||
import {Icon, Stroke, Style} from '../src/ol/style.js';
|
||||
import {OSM, Vector as VectorSource} from '../src/ol/source.js';
|
||||
import {Tile as TileLayer, Vector as VectorLayer} from '../src/ol/layer.js';
|
||||
import {get} from '../src/ol/proj.js';
|
||||
|
||||
const raster = new TileLayer({
|
||||
source: new OSM(),
|
||||
@@ -49,12 +50,19 @@ const vector = new VectorLayer({
|
||||
style: styleFunction,
|
||||
});
|
||||
|
||||
// Limit multi-world panning to one world east and west of the real world.
|
||||
// Geometry coordinates have to be within that range.
|
||||
const extent = get('EPSG:3857').getExtent().slice();
|
||||
extent[0] += extent[0];
|
||||
extent[2] += extent[2];
|
||||
|
||||
const map = new Map({
|
||||
layers: [raster, vector],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [-11000000, 4600000],
|
||||
zoom: 4,
|
||||
extent,
|
||||
}),
|
||||
});
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
.map {
|
||||
background: #f8f4f0;
|
||||
}
|
||||
@@ -4,7 +4,7 @@ title: Full-Screen Mobile
|
||||
shortdesc: Example of a full screen map.
|
||||
tags: "fullscreen, geolocation, mobile"
|
||||
cloak:
|
||||
- key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp
|
||||
- key: AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN
|
||||
value: Your Bing Maps Key from https://www.bingmapsportal.com/ here
|
||||
---
|
||||
<!doctype html>
|
||||
|
||||
@@ -13,7 +13,7 @@ const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new BingMaps({
|
||||
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp ',
|
||||
key: 'AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN',
|
||||
imagerySet: 'RoadOnDemand',
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -6,10 +6,12 @@ docs: >
|
||||
The map in this example is rendered in a web worker, using `OffscreenCanvas`. **Note:** This is currently only supported in Chrome and Edge.
|
||||
tags: "worker, offscreencanvas, vector-tiles"
|
||||
experimental: true
|
||||
sources:
|
||||
- path: offscreen-canvas.worker.js
|
||||
as: worker.js
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
|
||||
---
|
||||
<div id="map" class="map">
|
||||
<pre id="info" class="info"/>
|
||||
|
||||
@@ -18,9 +18,10 @@ const closer = document.getElementById('popup-closer');
|
||||
*/
|
||||
const overlay = new Overlay({
|
||||
element: container,
|
||||
autoPan: true,
|
||||
autoPanAnimation: {
|
||||
duration: 250,
|
||||
autoPan: {
|
||||
animation: {
|
||||
duration: 250,
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -6,7 +6,7 @@ docs: >
|
||||
<p>The map on the top preloads low resolution tiles. The map on the bottom does not use any preloading. Try zooming out and panning to see the difference.</p>
|
||||
tags: "preload, bing"
|
||||
cloak:
|
||||
- key: ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp
|
||||
- key: AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN
|
||||
value: Your Bing Maps Key from https://www.bingmapsportal.com/ here
|
||||
---
|
||||
<div id="map1" class="map"></div>
|
||||
|
||||
@@ -13,7 +13,7 @@ const map1 = new Map({
|
||||
new TileLayer({
|
||||
preload: Infinity,
|
||||
source: new BingMaps({
|
||||
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp',
|
||||
key: 'AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN',
|
||||
imagerySet: 'Aerial',
|
||||
}),
|
||||
}),
|
||||
@@ -27,7 +27,7 @@ const map2 = new Map({
|
||||
new TileLayer({
|
||||
preload: 0, // default value
|
||||
source: new BingMaps({
|
||||
key: 'ApTJzdkyN1DdFKkRAE6QIDtzihNaf6IWJsT-nQ_2eMoO4PN__0Tzhl2-WgJtXFSp',
|
||||
key: 'AlEoTLTlzFB6Uf4Sy-ugXcRO21skQO7K8eObA5_L-8d20rjqZJLs2nkO1RMjGSPN',
|
||||
imagerySet: 'AerialWithLabelsOnDemand',
|
||||
}),
|
||||
}),
|
||||
|
||||
@@ -8,6 +8,6 @@ tags: "reprojection, projection, proj4js, image, imagestatic"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<div>
|
||||
<input type="checkbox" id="imageSmoothing" checked />
|
||||
<label for="imageSmoothing">Image smoothing</label>
|
||||
<input type="checkbox" id="interpolate" checked />
|
||||
<label for="interpolate">Interpolate</label>
|
||||
</div>
|
||||
|
||||
@@ -34,7 +34,7 @@ const map = new Map({
|
||||
}),
|
||||
});
|
||||
|
||||
const imageSmoothing = document.getElementById('imageSmoothing');
|
||||
const interpolate = document.getElementById('interpolate');
|
||||
|
||||
function setSource() {
|
||||
const source = new Static({
|
||||
@@ -44,10 +44,10 @@ function setSource() {
|
||||
crossOrigin: '',
|
||||
projection: 'EPSG:27700',
|
||||
imageExtent: imageExtent,
|
||||
imageSmoothing: imageSmoothing.checked,
|
||||
interpolate: interpolate.checked,
|
||||
});
|
||||
imageLayer.setSource(source);
|
||||
}
|
||||
setSource();
|
||||
|
||||
imageSmoothing.addEventListener('change', setSource);
|
||||
interpolate.addEventListener('change', setSource);
|
||||
|
||||
3
examples/reprojection.css
Normal file
3
examples/reprojection.css
Normal file
@@ -0,0 +1,3 @@
|
||||
.form-inline label {
|
||||
justify-content: left;
|
||||
}
|
||||
@@ -37,8 +37,12 @@ tags: "reprojection, projection, proj4js, osm, wms, wmts, hidpi, grid"
|
||||
<option value="EPSG:5479">RSRGD2000 / MSLC2000 (EPSG:5479)</option>
|
||||
</select>
|
||||
</div>
|
||||
<label>
|
||||
Render reprojection edges
|
||||
<input type="checkbox" id="render-edges">
|
||||
</label>
|
||||
</form>
|
||||
<form class="form-inline">
|
||||
<div class="col-md-auto">
|
||||
<label>
|
||||
Render reprojection edges:
|
||||
<input type="checkbox" id="render-edges" />
|
||||
</label>
|
||||
</div>
|
||||
</form>
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
if (typeof Promise !== 'undefined' && !Promise.allSettled && Array.from) {
|
||||
Promise.allSettled =
|
||||
function (promises) {
|
||||
return Promise.all(
|
||||
Array.from(
|
||||
promises,
|
||||
function (p) {
|
||||
return p.then (
|
||||
function (value) {
|
||||
return {status: 'fulfilled', value: value};
|
||||
}
|
||||
).catch(
|
||||
function (reason) {
|
||||
return {status: 'rejected', reason: reason};
|
||||
}
|
||||
);
|
||||
}
|
||||
)
|
||||
)
|
||||
};
|
||||
}
|
||||
30
examples/resources/external-map-map.html
Normal file
30
examples/resources/external-map-map.html
Normal file
@@ -0,0 +1,30 @@
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<link rel="stylesheet" href="../css/ol.css" type="text/css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
}
|
||||
.map {
|
||||
height: 100%;
|
||||
}
|
||||
.map.unusable .ol-mask {
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
user-select: none;
|
||||
background-color: rgba(0, 0, 0, .7);
|
||||
color: white;
|
||||
font: bold 3rem 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
||||
}
|
||||
.map.unusable .ol-control {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="map" class="map"></div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -30,7 +30,8 @@ const elevation = new TileLayer({
|
||||
source: new XYZ({
|
||||
url:
|
||||
'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' + key,
|
||||
maxZoom: 10,
|
||||
tileSize: 512,
|
||||
maxZoom: 12,
|
||||
crossOrigin: '',
|
||||
}),
|
||||
});
|
||||
@@ -52,6 +53,7 @@ const map = new Map({
|
||||
attributions: attributions,
|
||||
url: 'https://api.maptiler.com/maps/streets/{z}/{x}/{y}.png?key=' + key,
|
||||
tileSize: 512,
|
||||
maxZoom: 22,
|
||||
}),
|
||||
}),
|
||||
new ImageLayer({
|
||||
|
||||
@@ -68,8 +68,8 @@
|
||||
<link rel="stylesheet" href="./css/ol.css" type="text/css">
|
||||
<link rel="stylesheet" href="./resources/layout.css" type="text/css">
|
||||
<script src="https://unpkg.com/elm-pep"></script>
|
||||
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder,Number.isInteger"></script>
|
||||
<script src="./resources/Promise.allSettled.js"></script>
|
||||
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,TextDecoder"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.3/minified.js"></script>
|
||||
{{{ extraHead.local }}}
|
||||
{{{ css.tag }}}
|
||||
<title>{{ title }}</title>
|
||||
@@ -194,8 +194,9 @@
|
||||
<title>{{ title }}</title>
|
||||
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
|
||||
<script src="https://unpkg.com/elm-pep"></script>
|
||||
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
|
||||
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder,Number.isInteger"></script>{{#if extraHead.remote}}
|
||||
<!-- The lines below are only needed for old environments like Internet Explorer and Android 4.x -->
|
||||
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,TextDecoder"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.3/minified.js"></script>{{#if extraHead.remote}}
|
||||
{{ indent extraHead.remote spaces=4 }}{{/if}}
|
||||
<style>
|
||||
.map {
|
||||
@@ -210,13 +211,12 @@
|
||||
</html></code></pre>
|
||||
</div>
|
||||
|
||||
{{#if worker.source}}
|
||||
<div class="row-fluid">
|
||||
<h5 class="source-heading">worker.js</h5>
|
||||
<pre><code id="example-worker-source" class="language-js">{{ worker.source }}</code></pre>
|
||||
{{#each extraSources}}
|
||||
<div class="row-fluid extra-source">
|
||||
<h5 class="source-heading">{{./name}}</h5>
|
||||
<pre><code class="language-{{./type}}">{{ ./source }}</code></pre>
|
||||
</div>
|
||||
{{/if}}
|
||||
|
||||
{{/each}}
|
||||
<div class="row-fluid">
|
||||
<h5 class="source-heading">package.json</h5>
|
||||
<pre><code id="example-pkg-source" class="language-json">{{ pkgJson }}</code></pre>
|
||||
|
||||
16
examples/webgl-layer-swipe.html
Normal file
16
examples/webgl-layer-swipe.html
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Layer Swipe (WebGL)
|
||||
shortdesc: Cropping a WebGL tile layer
|
||||
docs: >
|
||||
The <code>prerender</code> and <code>postrender</code> events on a WebGL tile layer can be
|
||||
used to manipulate the WebGL context before and after rendering. In this case, the
|
||||
<a href="https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/scissor"><code>gl.scissor()</code></a>
|
||||
method is called to clip the top layer based on the position of a slider.
|
||||
tags: "swipe, webgl"
|
||||
cloak:
|
||||
- key: get_your_own_D6rA4zTHduk6KOKTXzGB
|
||||
value: Get your own API key at https://www.maptiler.com/cloud/
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
<input id="swipe" type="range" style="width: 100%">
|
||||
61
examples/webgl-layer-swipe.js
Normal file
61
examples/webgl-layer-swipe.js
Normal file
@@ -0,0 +1,61 @@
|
||||
import Map from '../src/ol/Map.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import TileLayer from '../src/ol/layer/WebGLTile.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import XYZ from '../src/ol/source/XYZ.js';
|
||||
import {getRenderPixel} from '../src/ol/render.js';
|
||||
|
||||
const osm = new TileLayer({
|
||||
source: new OSM({wrapX: true}),
|
||||
});
|
||||
|
||||
const key = 'get_your_own_D6rA4zTHduk6KOKTXzGB';
|
||||
|
||||
const imagery = new TileLayer({
|
||||
source: new XYZ({
|
||||
url: 'https://api.maptiler.com/tiles/satellite/{z}/{x}/{y}.jpg?key=' + key,
|
||||
attributions:
|
||||
'<a href="https://www.maptiler.com/copyright/" target="_blank">© MapTiler</a> ' +
|
||||
'<a href="https://www.openstreetmap.org/copyright" target="_blank">© OpenStreetMap contributors</a>',
|
||||
crossOrigin: '',
|
||||
maxZoom: 20,
|
||||
}),
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [osm, imagery],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
}),
|
||||
});
|
||||
|
||||
const swipe = document.getElementById('swipe');
|
||||
|
||||
imagery.on('prerender', function (event) {
|
||||
const gl = event.context;
|
||||
gl.enable(gl.SCISSOR_TEST);
|
||||
|
||||
const mapSize = map.getSize(); // [width, height] in CSS pixels
|
||||
|
||||
// get render coordinates and dimensions given CSS coordinates
|
||||
const bottomLeft = getRenderPixel(event, [0, mapSize[1]]);
|
||||
const topRight = getRenderPixel(event, [mapSize[0], 0]);
|
||||
|
||||
const width = Math.round((topRight[0] - bottomLeft[0]) * (swipe.value / 100));
|
||||
const height = topRight[1] - bottomLeft[1];
|
||||
|
||||
gl.scissor(bottomLeft[0], bottomLeft[1], width, height);
|
||||
});
|
||||
|
||||
imagery.on('postrender', function (event) {
|
||||
const gl = event.context;
|
||||
gl.disable(gl.SCISSOR_TEST);
|
||||
});
|
||||
|
||||
const listener = function () {
|
||||
map.render();
|
||||
};
|
||||
swipe.addEventListener('input', listener);
|
||||
swipe.addEventListener('change', listener);
|
||||
@@ -31,8 +31,8 @@ const layer = new TileLayer({
|
||||
source: new XYZ({
|
||||
url:
|
||||
'https://api.maptiler.com/tiles/terrain-rgb/{z}/{x}/{y}.png?key=' + key,
|
||||
maxZoom: 10,
|
||||
tileSize: 512,
|
||||
maxZoom: 12,
|
||||
crossOrigin: 'anonymous',
|
||||
}),
|
||||
style: {
|
||||
@@ -58,6 +58,7 @@ const map = new Map({
|
||||
attributions: attributions,
|
||||
crossOrigin: 'anonymous',
|
||||
tileSize: 512,
|
||||
maxZoom: 22,
|
||||
}),
|
||||
}),
|
||||
layer,
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"node": true,
|
||||
"es6": true
|
||||
},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2017
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,7 @@ export default {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /^((?!es2015-)[\s\S])*\.js$/,
|
||||
test: /^((?!es2015-)[\s\S])*\.m?js$/,
|
||||
use: {
|
||||
loader: 'babel-loader',
|
||||
options: {
|
||||
|
||||
@@ -3,17 +3,17 @@ import frontMatter from 'front-matter';
|
||||
import fs from 'fs';
|
||||
import fse from 'fs-extra';
|
||||
import handlebars from 'handlebars';
|
||||
import marked from 'marked';
|
||||
import path, {dirname} from 'path';
|
||||
import sources from 'webpack-sources';
|
||||
import {fileURLToPath} from 'url';
|
||||
import {marked} from 'marked';
|
||||
|
||||
const RawSource = sources.RawSource;
|
||||
const baseDir = dirname(fileURLToPath(import.meta.url));
|
||||
|
||||
const isCssRegEx = /\.css(\?.*)?$/;
|
||||
const isJsRegEx = /\.js(\?.*)?$/;
|
||||
const importRegEx = /^import .* from '(.*)';$/;
|
||||
const importRegEx = /(?:^|\n)import .* from '(.*)';(?:\n|$)/g;
|
||||
const isTemplateJs =
|
||||
/\/(jquery(-\d+\.\d+\.\d+)?|(bootstrap(\.bundle)?))(\.min)?\.js(\?.*)?$/;
|
||||
const isTemplateCss = /\/bootstrap(\.min)?\.css(\?.*)?$/;
|
||||
@@ -134,26 +134,18 @@ function createWordIndex(exampleData) {
|
||||
* @return {Object<string, string>} dependencies
|
||||
*/
|
||||
function getDependencies(jsSource, pkg) {
|
||||
const lines = jsSource.split('\n');
|
||||
const dependencies = {
|
||||
ol: pkg.version,
|
||||
};
|
||||
for (let i = 0, ii = lines.length; i < ii; ++i) {
|
||||
const line = lines[i];
|
||||
const importMatch = line.match(importRegEx);
|
||||
if (importMatch) {
|
||||
const imp = importMatch[1];
|
||||
if (!imp.startsWith('ol/') && imp != 'ol') {
|
||||
const parts = imp.split('/');
|
||||
let dep;
|
||||
if (imp.startsWith('@')) {
|
||||
dep = parts.slice(0, 2).join('/');
|
||||
} else {
|
||||
dep = parts[0];
|
||||
}
|
||||
if (dep in pkg.devDependencies) {
|
||||
dependencies[dep] = pkg.devDependencies[dep];
|
||||
}
|
||||
|
||||
let importMatch;
|
||||
while ((importMatch = importRegEx.exec(jsSource))) {
|
||||
const imp = importMatch[1];
|
||||
if (!imp.startsWith('ol/') && imp != 'ol') {
|
||||
const parts = imp.split('/');
|
||||
const dep = imp.startsWith('@') ? parts.slice(0, 2).join('/') : parts[0];
|
||||
if (dep in pkg.devDependencies) {
|
||||
dependencies[dep] = pkg.devDependencies[dep];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -279,80 +271,79 @@ export default class ExampleBuilder {
|
||||
data.jsSource = jsSource;
|
||||
|
||||
// process tags
|
||||
if (data.tags) {
|
||||
data.tags = data.tags.replace(/[\s"]+/g, '').split(',');
|
||||
} else {
|
||||
data.tags = [];
|
||||
}
|
||||
data.tags = data.tags ? data.tags.replace(/[\s"]+/g, '').split(',') : [];
|
||||
return data;
|
||||
}
|
||||
|
||||
transformJsSource(source) {
|
||||
return (
|
||||
source
|
||||
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
|
||||
.replace(/'\.\.\/src\//g, "'")
|
||||
.replace(/\.js';/g, "';")
|
||||
// Remove worker loader import and modify `new Worker()` to add source
|
||||
.replace(/import Worker from 'worker-loader![^\n]*\n/g, '')
|
||||
.replace('new Worker()', "new Worker('./worker.js', {type: 'module'})")
|
||||
);
|
||||
}
|
||||
|
||||
cloakSource(source, cloak) {
|
||||
if (cloak) {
|
||||
for (const entry of cloak) {
|
||||
source = source.replace(new RegExp(entry.key, 'g'), entry.value);
|
||||
}
|
||||
}
|
||||
return source;
|
||||
}
|
||||
|
||||
async render(data) {
|
||||
const assets = {};
|
||||
const readOptions = {encoding: 'utf8'};
|
||||
|
||||
// add in script tag
|
||||
const jsName = `${data.name}.js`;
|
||||
|
||||
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
|
||||
let jsSource = data.jsSource.replace(/'\.\.\/src\//g, "'");
|
||||
jsSource = jsSource.replace(/\.js';/g, "';");
|
||||
if (data.cloak) {
|
||||
for (const entry of data.cloak) {
|
||||
jsSource = jsSource.replace(new RegExp(entry.key, 'g'), entry.value);
|
||||
}
|
||||
}
|
||||
// Remove worker loader import and modify `new Worker()` to add source
|
||||
jsSource = jsSource.replace(
|
||||
/import Worker from 'worker-loader![^\n]*\n/g,
|
||||
''
|
||||
const jsSource = this.transformJsSource(
|
||||
this.cloakSource(data.jsSource, data.cloak)
|
||||
);
|
||||
jsSource = jsSource.replace('new Worker()', "new Worker('./worker.js')");
|
||||
|
||||
data.js = {
|
||||
tag: `<script src="${this.common}.js"></script>
|
||||
<script src="${jsName}"></script>`,
|
||||
source: jsSource,
|
||||
};
|
||||
|
||||
// check for worker js
|
||||
const workerName = `${data.name}.worker.js`;
|
||||
const workerPath = path.join(data.dir, workerName);
|
||||
let workerSource;
|
||||
try {
|
||||
workerSource = await fse.readFile(workerPath, readOptions);
|
||||
} catch (err) {
|
||||
// pass
|
||||
}
|
||||
if (workerSource) {
|
||||
// remove "../src/" prefix and ".js" to have the same import syntax as the documentation
|
||||
workerSource = workerSource.replace(/'\.\.\/src\//g, "'");
|
||||
workerSource = workerSource.replace(/\.js';/g, "';");
|
||||
if (data.cloak) {
|
||||
for (const entry of data.cloak) {
|
||||
workerSource = workerSource.replace(
|
||||
new RegExp(entry.key, 'g'),
|
||||
entry.value
|
||||
);
|
||||
}
|
||||
}
|
||||
data.worker = {
|
||||
source: workerSource,
|
||||
};
|
||||
assets[workerName] = workerSource;
|
||||
let jsSources = jsSource;
|
||||
if (data.sources) {
|
||||
data.extraSources = await Promise.all(
|
||||
data.sources.map(async (sourceConfig) => {
|
||||
const fileName = sourceConfig.path;
|
||||
const extraSourcePath = path.join(data.dir, fileName);
|
||||
let source = await fse.readFile(extraSourcePath, readOptions);
|
||||
let ext = fileName.match(/\.(\w+)$/)[1];
|
||||
if (ext === 'mjs') {
|
||||
ext = 'js';
|
||||
}
|
||||
if (ext === 'js') {
|
||||
source = this.transformJsSource(source);
|
||||
jsSources += '\n' + source;
|
||||
}
|
||||
source = this.cloakSource(source, data.cloak);
|
||||
assets[fileName] = source;
|
||||
return {
|
||||
name: sourceConfig.as ?? fileName,
|
||||
source: source,
|
||||
type: ext,
|
||||
};
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
const pkg = await getPackageInfo();
|
||||
|
||||
data.pkgJson = JSON.stringify(
|
||||
{
|
||||
name: data.name,
|
||||
dependencies: getDependencies(
|
||||
jsSource + (workerSource ? `\n${workerSource}` : ''),
|
||||
pkg
|
||||
),
|
||||
dependencies: getDependencies(jsSources, pkg),
|
||||
devDependencies: {
|
||||
parcel: '^2.0.0-beta.1',
|
||||
parcel: '^2.0.0',
|
||||
},
|
||||
scripts: {
|
||||
start: 'parcel index.html',
|
||||
|
||||
13
examples/wind-arrows.html
Normal file
13
examples/wind-arrows.html
Normal file
@@ -0,0 +1,13 @@
|
||||
---
|
||||
layout: example.html
|
||||
title: Wind Arrows
|
||||
shortdesc: Example of Wind Arrows styled using Regular Shapes.
|
||||
docs: >
|
||||
This example shows wind arrows styled using regular shapes for the
|
||||
arrow shaft and head. The shaft is scaled based on the wind speed
|
||||
and a corresponding displacement is used to position the unscaled
|
||||
arrow head at the end of the scaled shaft.
|
||||
The weather data is provided by <a href="https://openweathermap.org/current">OpenWeather</a>.
|
||||
tags: "vector, symbol, regularshape, style, arrow"
|
||||
---
|
||||
<div id="map" class="map"></div>
|
||||
83
examples/wind-arrows.js
Normal file
83
examples/wind-arrows.js
Normal file
@@ -0,0 +1,83 @@
|
||||
import Feature from '../src/ol/Feature.js';
|
||||
import Map from '../src/ol/Map.js';
|
||||
import OSM from '../src/ol/source/OSM.js';
|
||||
import Point from '../src/ol/geom/Point.js';
|
||||
import TileLayer from '../src/ol/layer/Tile.js';
|
||||
import VectorLayer from '../src/ol/layer/Vector.js';
|
||||
import VectorSource from '../src/ol/source/Vector.js';
|
||||
import View from '../src/ol/View.js';
|
||||
import {Fill, RegularShape, Stroke, Style} from '../src/ol/style.js';
|
||||
import {fromLonLat} from '../src/ol/proj.js';
|
||||
|
||||
const shaft = new RegularShape({
|
||||
points: 2,
|
||||
radius: 5,
|
||||
stroke: new Stroke({
|
||||
width: 2,
|
||||
color: 'black',
|
||||
}),
|
||||
rotateWithView: true,
|
||||
});
|
||||
|
||||
const head = new RegularShape({
|
||||
points: 3,
|
||||
radius: 5,
|
||||
fill: new Fill({
|
||||
color: 'black',
|
||||
}),
|
||||
rotateWithView: true,
|
||||
});
|
||||
|
||||
const styles = [new Style({image: shaft}), new Style({image: head})];
|
||||
|
||||
const source = new VectorSource({
|
||||
attributions:
|
||||
'Weather data by <a href="https://openweathermap.org/current">OpenWeather</a>',
|
||||
});
|
||||
|
||||
const map = new Map({
|
||||
layers: [
|
||||
new TileLayer({
|
||||
source: new OSM(),
|
||||
}),
|
||||
new VectorLayer({
|
||||
source: source,
|
||||
style: function (feature) {
|
||||
const wind = feature.get('wind');
|
||||
// rotate arrow away from wind origin
|
||||
const angle = ((wind.deg - 180) * Math.PI) / 180;
|
||||
const scale = wind.speed / 10;
|
||||
shaft.setScale([1, scale]);
|
||||
shaft.setRotation(angle);
|
||||
head.setDisplacement([
|
||||
0,
|
||||
head.getRadius() / 2 + shaft.getRadius() * scale,
|
||||
]);
|
||||
head.setRotation(angle);
|
||||
return styles;
|
||||
},
|
||||
}),
|
||||
],
|
||||
target: 'map',
|
||||
view: new View({
|
||||
center: [0, 0],
|
||||
zoom: 2,
|
||||
}),
|
||||
});
|
||||
|
||||
fetch('data/openweather/weather.json')
|
||||
.then(function (response) {
|
||||
return response.json();
|
||||
})
|
||||
.then(function (data) {
|
||||
const features = [];
|
||||
data.list.forEach(function (report) {
|
||||
const feature = new Feature(
|
||||
new Point(fromLonLat([report.coord.lon, report.coord.lat]))
|
||||
);
|
||||
feature.setProperties(report);
|
||||
features.push(feature);
|
||||
});
|
||||
source.addFeatures(features);
|
||||
map.getView().fit(source.getExtent());
|
||||
});
|
||||
8282
package-lock.json
generated
8282
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
44
package.json
44
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ol",
|
||||
"version": "6.8.0",
|
||||
"version": "6.10.0",
|
||||
"description": "OpenLayers mapping library",
|
||||
"keywords": [
|
||||
"map",
|
||||
@@ -45,18 +45,17 @@
|
||||
"url": "https://opencollective.com/openlayers"
|
||||
},
|
||||
"dependencies": {
|
||||
"geotiff": "1.0.6",
|
||||
"ol-mapbox-style": "^6.5.1",
|
||||
"geotiff": "^1.0.8",
|
||||
"ol-mapbox-style": "^6.7.0",
|
||||
"pbf": "3.2.1",
|
||||
"rbush": "^3.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.6.4",
|
||||
"@babel/eslint-parser": "^7.13.14",
|
||||
"@babel/preset-env": "^7.4.4",
|
||||
"@openlayers/eslint-plugin": "^4.0.0",
|
||||
"@rollup/plugin-babel": "^5.3.0",
|
||||
"@rollup/plugin-commonjs": "^20.0.0",
|
||||
"@rollup/plugin-commonjs": "^21.0.0",
|
||||
"@rollup/plugin-node-resolve": "^13.0.0",
|
||||
"@types/arcgis-rest-api": "^10.4.4",
|
||||
"@types/geojson": "^7946.0.7",
|
||||
@@ -64,48 +63,41 @@
|
||||
"@types/topojson-specification": "^1.0.1",
|
||||
"babel-loader": "^8.2.2",
|
||||
"chaikin-smooth": "^1.0.4",
|
||||
"clean-css-cli": "5.3.3",
|
||||
"copy-webpack-plugin": "^9.0.0",
|
||||
"coverage-istanbul-loader": "^3.0.5",
|
||||
"coveralls": "3.1.1",
|
||||
"clean-css-cli": "5.5.0",
|
||||
"copy-webpack-plugin": "^10.0.0",
|
||||
"es-main": "^1.0.2",
|
||||
"eslint": "^7.2.0",
|
||||
"eslint-config-openlayers": "^15.0.0",
|
||||
"eslint": "^8.0.1",
|
||||
"eslint-config-openlayers": "^16.0.1",
|
||||
"expect.js": "0.3.1",
|
||||
"express": "^4.17.1",
|
||||
"front-matter": "^4.0.0",
|
||||
"fs-extra": "^10.0.0",
|
||||
"glob": "^7.1.5",
|
||||
"globby": "^12.0.0",
|
||||
"handlebars": "4.7.7",
|
||||
"istanbul": "0.4.5",
|
||||
"jquery": "3.6.0",
|
||||
"jsdoc": "3.6.7",
|
||||
"jsdoc-plugin-typescript": "^2.0.5",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"karma": "^6.3.2",
|
||||
"karma-chrome-launcher": "3.1.0",
|
||||
"karma-coverage-istanbul-reporter": "^3.0.0",
|
||||
"karma-firefox-launcher": "^2.0.0",
|
||||
"karma": "^6.3.8",
|
||||
"karma-chrome-launcher": "^3.1.0",
|
||||
"karma-firefox-launcher": "^2.1.2",
|
||||
"karma-mocha": "2.0.1",
|
||||
"karma-sourcemap-loader": "^0.3.8",
|
||||
"karma-source-map-support": "^1.4.0",
|
||||
"karma-webpack": "^5.0.0",
|
||||
"loglevelnext": "^5.0.5",
|
||||
"marked": "3.0.4",
|
||||
"mocha": "9.1.1",
|
||||
"marked": "4.0.8",
|
||||
"mocha": "9.1.3",
|
||||
"pixelmatch": "^5.1.0",
|
||||
"pngjs": "^6.0.0",
|
||||
"proj4": "^2.7.5",
|
||||
"puppeteer": "10.2.0",
|
||||
"puppeteer": "13.0.1",
|
||||
"regenerator-runtime": "^0.13.9",
|
||||
"rollup": "^2.42.3",
|
||||
"rollup-plugin-terser": "^7.0.2",
|
||||
"serve-static": "^1.14.0",
|
||||
"shx": "^0.3.2",
|
||||
"sinon": "^11.1.1",
|
||||
"terser-webpack-plugin": "^5.1.1",
|
||||
"sinon": "^12.0.1",
|
||||
"threads": "^1.6.5",
|
||||
"url-polyfill": "^1.1.5",
|
||||
"walk": "^2.3.9",
|
||||
"webpack": "^5.27.2",
|
||||
"webpack-cli": "^4.5.0",
|
||||
@@ -117,10 +109,6 @@
|
||||
},
|
||||
"eslintConfig": {
|
||||
"extends": "openlayers",
|
||||
"parser": "@babel/eslint-parser",
|
||||
"parserOptions": {
|
||||
"requireConfigFile": false
|
||||
},
|
||||
"plugins": [
|
||||
"@openlayers"
|
||||
],
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>OpenLayers</title>
|
||||
<link href='https://fonts.googleapis.com/css?family=Quattrocento+Sans:400,400italic,700' rel='stylesheet' type='text/css'>
|
||||
<link href='https://openlayers.org/assets/theme/site.css' rel='stylesheet' type='text/css'>
|
||||
<link href="./legacy/ol.css" rel='stylesheet' type='text/css'>
|
||||
<!-- Pointer events polyfill for old browsers, see https://caniuse.com/#feat=pointer -->
|
||||
<script src="https://unpkg.com/elm-pep"></script>
|
||||
<!-- The line below is only needed for old environments like Internet Explorer and Android 4.x -->
|
||||
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,URL,TextDecoder,Number.isInteger"></script>
|
||||
<!-- The lines below are only needed for old environments like Internet Explorer and Android 4.x -->
|
||||
<script src="https://cdn.polyfill.io/v3/polyfill.min.js?features=fetch,requestAnimationFrame,Element.prototype.classList,TextDecoder"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/3.18.3/minified.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<ul>
|
||||
@@ -32,4 +34,4 @@
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -13,9 +13,11 @@ import TileState from './TileState.js';
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {import("./tilecoord.js").TileCoord} tileCoord Tile coordinate.
|
||||
* @property {function() : Promise<Data>} loader Data loader.
|
||||
* @property {function(): Promise<Data>} loader Data loader.
|
||||
* @property {number} [transition=250] A duration for tile opacity
|
||||
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
||||
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||
* the nearest neighbor is used when resampling.
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -26,10 +28,27 @@ class DataTile extends Tile {
|
||||
constructor(options) {
|
||||
const state = TileState.IDLE;
|
||||
|
||||
super(options.tileCoord, state, {transition: options.transition});
|
||||
super(options.tileCoord, state, {
|
||||
transition: options.transition,
|
||||
interpolate: options.interpolate,
|
||||
});
|
||||
|
||||
/**
|
||||
* @type {function(): Promise<Data>}
|
||||
* @private
|
||||
*/
|
||||
this.loader_ = options.loader;
|
||||
|
||||
/**
|
||||
* @type {Data}
|
||||
* @private
|
||||
*/
|
||||
this.data_ = null;
|
||||
|
||||
/**
|
||||
* @type {Error}
|
||||
* @private
|
||||
*/
|
||||
this.error_ = null;
|
||||
}
|
||||
|
||||
|
||||
@@ -160,14 +160,23 @@ class ImageWrapper extends ImageBase {
|
||||
*/
|
||||
export function listenImage(image, loadHandler, errorHandler) {
|
||||
const img = /** @type {HTMLImageElement} */ (image);
|
||||
let listening = true;
|
||||
let decoding = false;
|
||||
let loaded = false;
|
||||
|
||||
const listenerKeys = [
|
||||
listenOnce(img, EventType.LOAD, function () {
|
||||
loaded = true;
|
||||
if (!decoding) {
|
||||
loadHandler();
|
||||
}
|
||||
}),
|
||||
];
|
||||
|
||||
if (img.src && IMAGE_DECODE) {
|
||||
const promise = img.decode();
|
||||
let listening = true;
|
||||
const unlisten = function () {
|
||||
listening = false;
|
||||
};
|
||||
promise
|
||||
decoding = true;
|
||||
img
|
||||
.decode()
|
||||
.then(function () {
|
||||
if (listening) {
|
||||
loadHandler();
|
||||
@@ -175,26 +184,19 @@ export function listenImage(image, loadHandler, errorHandler) {
|
||||
})
|
||||
.catch(function (error) {
|
||||
if (listening) {
|
||||
// FIXME: Unconditionally call errorHandler() when this bug is fixed upstream:
|
||||
// https://bugs.webkit.org/show_bug.cgi?id=198527
|
||||
if (
|
||||
error.name === 'EncodingError' &&
|
||||
error.message === 'Invalid image type.'
|
||||
) {
|
||||
if (loaded) {
|
||||
loadHandler();
|
||||
} else {
|
||||
errorHandler();
|
||||
}
|
||||
}
|
||||
});
|
||||
return unlisten;
|
||||
} else {
|
||||
listenerKeys.push(listenOnce(img, EventType.ERROR, errorHandler));
|
||||
}
|
||||
|
||||
const listenerKeys = [
|
||||
listenOnce(img, EventType.LOAD, loadHandler),
|
||||
listenOnce(img, EventType.ERROR, errorHandler),
|
||||
];
|
||||
return function unlisten() {
|
||||
listening = false;
|
||||
listenerKeys.forEach(unlistenByKey);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@ import BaseObject from './Object.js';
|
||||
import Collection from './Collection.js';
|
||||
import CollectionEventType from './CollectionEventType.js';
|
||||
import EventType from './events/EventType.js';
|
||||
import LayerGroup from './layer/Group.js';
|
||||
import Layer from './layer/Layer.js';
|
||||
import LayerGroup, {GroupEvent} from './layer/Group.js';
|
||||
import MapBrowserEvent from './MapBrowserEvent.js';
|
||||
import MapBrowserEventHandler from './MapBrowserEventHandler.js';
|
||||
import MapBrowserEventType from './MapBrowserEventType.js';
|
||||
@@ -33,6 +34,7 @@ import {
|
||||
isEmpty,
|
||||
} from './extent.js';
|
||||
import {fromUserCoordinate, toUserCoordinate} from './proj.js';
|
||||
import {getUid} from './util.js';
|
||||
import {hasArea} from './size.js';
|
||||
import {listen, unlistenByKey} from './events.js';
|
||||
import {removeNode} from './dom.js';
|
||||
@@ -59,6 +61,8 @@ import {removeNode} from './dom.js';
|
||||
* @property {!Object<string, Object<string, boolean>>} usedTiles UsedTiles.
|
||||
* @property {Array<number>} viewHints ViewHints.
|
||||
* @property {!Object<string, Object<string, boolean>>} wantedTiles WantedTiles.
|
||||
* @property {string} mapId The id of the map.
|
||||
* @property {Object<string, boolean>} renderTargets Identifiers of previously rendered elements.
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -143,6 +147,36 @@ import {removeNode} from './dom.js';
|
||||
* {@link module:ol/Map~Map#setView}.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import("./layer/Base.js").default} layer Layer.
|
||||
*/
|
||||
function removeLayerMapProperty(layer) {
|
||||
if (layer instanceof Layer) {
|
||||
layer.setMapInternal(null);
|
||||
return;
|
||||
}
|
||||
if (layer instanceof LayerGroup) {
|
||||
layer.getLayers().forEach(removeLayerMapProperty);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./layer/Base.js").default} layer Layer.
|
||||
* @param {PluggableMap} map Map.
|
||||
*/
|
||||
function setLayerMapProperty(layer, map) {
|
||||
if (layer instanceof Layer) {
|
||||
layer.setMapInternal(map);
|
||||
return;
|
||||
}
|
||||
if (layer instanceof LayerGroup) {
|
||||
const layers = layer.getLayers().getArray();
|
||||
for (let i = 0, ii = layers.length; i < ii; ++i) {
|
||||
setLayerMapProperty(layers[i], map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @fires import("./MapBrowserEvent.js").MapBrowserEvent
|
||||
* @fires import("./MapEvent.js").MapEvent
|
||||
@@ -175,6 +209,12 @@ class PluggableMap extends BaseObject {
|
||||
|
||||
const optionsInternal = createOptionsInternal(options);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.renderComplete_;
|
||||
|
||||
/** @private */
|
||||
this.boundHandleBrowserEvent_ = this.handleBrowserEvent.bind(this);
|
||||
|
||||
@@ -323,7 +363,7 @@ class PluggableMap extends BaseObject {
|
||||
* @private
|
||||
* @type {?Array<import("./events.js").EventsKey>}
|
||||
*/
|
||||
this.keyHandlerKeys_ = null;
|
||||
this.targetChangeHandlerKeys_ = null;
|
||||
|
||||
/**
|
||||
* @type {Collection<import("./control/Control.js").default>}
|
||||
@@ -356,12 +396,6 @@ class PluggableMap extends BaseObject {
|
||||
*/
|
||||
this.renderer_ = null;
|
||||
|
||||
/**
|
||||
* @type {undefined|function(Event): void}
|
||||
* @private
|
||||
*/
|
||||
this.handleResize_;
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {!Array<PostRenderFunction>}
|
||||
@@ -530,6 +564,14 @@ class PluggableMap extends BaseObject {
|
||||
layers.push(layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./layer/Group.js").GroupEvent} event The layer add event.
|
||||
* @private
|
||||
*/
|
||||
handleLayerAdd_(event) {
|
||||
setLayerMapProperty(event.layer, this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given overlay to the map.
|
||||
* @param {import("./Overlay.js").default} overlay Overlay.
|
||||
@@ -622,6 +664,25 @@ class PluggableMap extends BaseObject {
|
||||
return features;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all layers from all layer groups.
|
||||
* @return {Array<import("./layer/Layer.js").default>} Layers.
|
||||
*/
|
||||
getAllLayers() {
|
||||
const layers = [];
|
||||
function addLayersFrom(layerGroup) {
|
||||
layerGroup.forEach(function (layer) {
|
||||
if (layer instanceof LayerGroup) {
|
||||
addLayersFrom(layer.getLayers());
|
||||
} else {
|
||||
layers.push(layer);
|
||||
}
|
||||
});
|
||||
}
|
||||
addLayersFrom(this.getLayers());
|
||||
return layers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect layers that have a color value at a pixel on the viewport, and
|
||||
* execute a callback with each matching layer. Layers included in the
|
||||
@@ -1115,8 +1176,7 @@ class PluggableMap extends BaseObject {
|
||||
frameState &&
|
||||
this.hasListener(RenderEventType.RENDERCOMPLETE) &&
|
||||
!frameState.animate &&
|
||||
!this.tileQueue_.getTilesLoading() &&
|
||||
!this.getLoading()
|
||||
this.renderComplete_
|
||||
) {
|
||||
this.renderer_.dispatchRenderEvent(
|
||||
RenderEventType.RENDERCOMPLETE,
|
||||
@@ -1146,21 +1206,11 @@ class PluggableMap extends BaseObject {
|
||||
* @private
|
||||
*/
|
||||
handleTargetChanged_() {
|
||||
// target may be undefined, null, a string or an Element.
|
||||
// If it's a string we convert it to an Element before proceeding.
|
||||
// If it's not now an Element we remove the viewport from the DOM.
|
||||
// If it's an Element we append the viewport element to it.
|
||||
|
||||
let targetElement;
|
||||
if (this.getTarget()) {
|
||||
targetElement = this.getTargetElement();
|
||||
}
|
||||
|
||||
if (this.mapBrowserEventHandler_) {
|
||||
for (let i = 0, ii = this.keyHandlerKeys_.length; i < ii; ++i) {
|
||||
unlistenByKey(this.keyHandlerKeys_[i]);
|
||||
for (let i = 0, ii = this.targetChangeHandlerKeys_.length; i < ii; ++i) {
|
||||
unlistenByKey(this.targetChangeHandlerKeys_[i]);
|
||||
}
|
||||
this.keyHandlerKeys_ = null;
|
||||
this.targetChangeHandlerKeys_ = null;
|
||||
this.viewport_.removeEventListener(
|
||||
EventType.CONTEXTMENU,
|
||||
this.boundHandleBrowserEvent_
|
||||
@@ -1169,15 +1219,17 @@ class PluggableMap extends BaseObject {
|
||||
EventType.WHEEL,
|
||||
this.boundHandleBrowserEvent_
|
||||
);
|
||||
if (this.handleResize_ !== undefined) {
|
||||
removeEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||
this.handleResize_ = undefined;
|
||||
}
|
||||
this.mapBrowserEventHandler_.dispose();
|
||||
this.mapBrowserEventHandler_ = null;
|
||||
removeNode(this.viewport_);
|
||||
}
|
||||
|
||||
// target may be undefined, null, a string or an Element.
|
||||
// If it's a string we convert it to an Element before proceeding.
|
||||
// If it's not now an Element we remove the viewport from the DOM.
|
||||
// If it's an Element we append the viewport element to it.
|
||||
|
||||
const targetElement = this.getTargetElement();
|
||||
if (!targetElement) {
|
||||
if (this.renderer_) {
|
||||
clearTimeout(this.postRenderTimeoutHandle_);
|
||||
@@ -1217,10 +1269,11 @@ class PluggableMap extends BaseObject {
|
||||
PASSIVE_EVENT_LISTENERS ? {passive: false} : false
|
||||
);
|
||||
|
||||
const defaultView = this.getOwnerDocument().defaultView;
|
||||
const keyboardEventTarget = !this.keyboardEventTarget_
|
||||
? targetElement
|
||||
: this.keyboardEventTarget_;
|
||||
this.keyHandlerKeys_ = [
|
||||
this.targetChangeHandlerKeys_ = [
|
||||
listen(
|
||||
keyboardEventTarget,
|
||||
EventType.KEYDOWN,
|
||||
@@ -1233,12 +1286,8 @@ class PluggableMap extends BaseObject {
|
||||
this.handleBrowserEvent,
|
||||
this
|
||||
),
|
||||
listen(defaultView, EventType.RESIZE, this.updateSize, this),
|
||||
];
|
||||
|
||||
if (!this.handleResize_) {
|
||||
this.handleResize_ = this.updateSize.bind(this);
|
||||
window.addEventListener(EventType.RESIZE, this.handleResize_, false);
|
||||
}
|
||||
}
|
||||
|
||||
this.updateSize();
|
||||
@@ -1304,9 +1353,12 @@ class PluggableMap extends BaseObject {
|
||||
}
|
||||
const layerGroup = this.getLayerGroup();
|
||||
if (layerGroup) {
|
||||
this.handleLayerAdd_(new GroupEvent('addlayer', layerGroup));
|
||||
this.layerGroupPropertyListenerKeys_ = [
|
||||
listen(layerGroup, ObjectEventType.PROPERTYCHANGE, this.render, this),
|
||||
listen(layerGroup, EventType.CHANGE, this.render, this),
|
||||
listen(layerGroup, 'addlayer', this.handleLayerAdd_, this),
|
||||
listen(layerGroup, 'removelayer', this.handleLayerRemove_, this),
|
||||
];
|
||||
}
|
||||
this.render();
|
||||
@@ -1387,6 +1439,14 @@ class PluggableMap extends BaseObject {
|
||||
return layers.remove(layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import("./layer/Group.js").GroupEvent} event The layer remove event.
|
||||
* @private
|
||||
*/
|
||||
handleLayerRemove_(event) {
|
||||
removeLayerMapProperty(event.layer);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the given overlay from the map.
|
||||
* @param {import("./Overlay.js").default} overlay Overlay.
|
||||
@@ -1436,6 +1496,8 @@ class PluggableMap extends BaseObject {
|
||||
viewState: viewState,
|
||||
viewHints: viewHints,
|
||||
wantedTiles: {},
|
||||
mapId: getUid(this),
|
||||
renderTargets: {},
|
||||
};
|
||||
if (viewState.nextCenter && viewState.nextResolution) {
|
||||
const rotation = isNaN(viewState.nextRotation)
|
||||
@@ -1492,6 +1554,11 @@ class PluggableMap extends BaseObject {
|
||||
|
||||
this.dispatchEvent(new MapEvent(MapEventType.POSTRENDER, this, frameState));
|
||||
|
||||
this.renderComplete_ =
|
||||
!this.tileQueue_.getTilesLoading() &&
|
||||
!this.tileQueue_.getCount() &&
|
||||
!this.getLoading();
|
||||
|
||||
if (!this.postRenderTimeoutHandle_) {
|
||||
this.postRenderTimeoutHandle_ = setTimeout(() => {
|
||||
this.postRenderTimeoutHandle_ = undefined;
|
||||
@@ -1507,6 +1574,10 @@ class PluggableMap extends BaseObject {
|
||||
* @api
|
||||
*/
|
||||
setLayerGroup(layerGroup) {
|
||||
const oldLayerGroup = this.getLayerGroup();
|
||||
if (oldLayerGroup) {
|
||||
this.handleLayerRemove_(new GroupEvent('removelayer', oldLayerGroup));
|
||||
}
|
||||
this.set(MapProperty.LAYERGROUP, layerGroup);
|
||||
}
|
||||
|
||||
|
||||
@@ -63,6 +63,8 @@ import {easeIn} from './easing.js';
|
||||
* @typedef {Object} Options
|
||||
* @property {number} [transition=250] A duration for tile opacity
|
||||
* transitions in milliseconds. A duration of 0 disables the opacity transition.
|
||||
* @property {boolean} [interpolate=false] Use interpolated values when resampling. By default,
|
||||
* the nearest neighbor is used when resampling.
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -123,6 +125,11 @@ class Tile extends EventTarget {
|
||||
* @type {Object<string, number>}
|
||||
*/
|
||||
this.transitionStarts_ = {};
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
*/
|
||||
this.interpolate = !!options.interpolate;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -185,7 +192,11 @@ class Tile extends EventTarget {
|
||||
}
|
||||
|
||||
let tile = this.interimTile;
|
||||
let prev = /** @type {Tile} */ (this);
|
||||
|
||||
/**
|
||||
* @type {Tile}
|
||||
*/
|
||||
let prev = this;
|
||||
|
||||
do {
|
||||
if (tile.getState() == TileState.LOADED) {
|
||||
|
||||
@@ -416,10 +416,11 @@ class View extends BaseObject {
|
||||
* @param {ViewOptions} options View options.
|
||||
*/
|
||||
applyOptions_(options) {
|
||||
/**
|
||||
* @type {Object<string, *>}
|
||||
*/
|
||||
const properties = {};
|
||||
const properties = assign({}, options);
|
||||
for (const key in ViewProperty) {
|
||||
delete properties[key];
|
||||
}
|
||||
this.setProperties(properties, true);
|
||||
|
||||
const resolutionConstraintInfo = createResolutionConstraint(options);
|
||||
|
||||
@@ -482,14 +483,6 @@ class View extends BaseObject {
|
||||
} else if (options.zoom !== undefined) {
|
||||
this.setZoom(options.zoom);
|
||||
}
|
||||
|
||||
this.setProperties(properties);
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {ViewOptions}
|
||||
*/
|
||||
this.options_ = options;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -531,7 +524,7 @@ class View extends BaseObject {
|
||||
* @return {ViewOptions} New options updated with the current view state.
|
||||
*/
|
||||
getUpdatedOptions_(newOptions) {
|
||||
const options = assign({}, this.options_);
|
||||
const options = this.getProperties();
|
||||
|
||||
// preserve resolution (or zoom)
|
||||
if (options.resolution !== undefined) {
|
||||
@@ -621,29 +614,36 @@ class View extends BaseObject {
|
||||
callback = arguments[animationCount - 1];
|
||||
--animationCount;
|
||||
}
|
||||
if (!this.isDef()) {
|
||||
|
||||
let i = 0;
|
||||
for (; i < animationCount && !this.isDef(); ++i) {
|
||||
// if view properties are not yet set, shortcut to the final state
|
||||
const state = arguments[animationCount - 1];
|
||||
const state = arguments[i];
|
||||
if (state.center) {
|
||||
this.setCenterInternal(state.center);
|
||||
}
|
||||
if (state.zoom !== undefined) {
|
||||
this.setZoom(state.zoom);
|
||||
} else if (state.resolution) {
|
||||
this.setResolution(state.resolution);
|
||||
}
|
||||
if (state.rotation !== undefined) {
|
||||
this.setRotation(state.rotation);
|
||||
}
|
||||
}
|
||||
if (i === animationCount) {
|
||||
if (callback) {
|
||||
animationCallback(callback, true);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
let start = Date.now();
|
||||
let center = this.targetCenter_.slice();
|
||||
let resolution = this.targetResolution_;
|
||||
let rotation = this.targetRotation_;
|
||||
const series = [];
|
||||
for (let i = 0; i < animationCount; ++i) {
|
||||
for (; i < animationCount; ++i) {
|
||||
const options = /** @type {AnimationOptions} */ (arguments[i]);
|
||||
|
||||
const animation = {
|
||||
@@ -966,7 +966,7 @@ class View extends BaseObject {
|
||||
* @return {boolean} Resolution constraint is set
|
||||
*/
|
||||
getConstrainResolution() {
|
||||
return this.options_.constrainResolution;
|
||||
return this.get('constrainResolution');
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1729,8 +1729,10 @@ class View extends BaseObject {
|
||||
}
|
||||
if (this.get(ViewProperty.RESOLUTION) !== newResolution) {
|
||||
this.set(ViewProperty.RESOLUTION, newResolution);
|
||||
this.set('zoom', this.getZoom(), true);
|
||||
}
|
||||
if (
|
||||
!newCenter ||
|
||||
!this.get(ViewProperty.CENTER) ||
|
||||
!equals(this.get(ViewProperty.CENTER), newCenter)
|
||||
) {
|
||||
|
||||
@@ -213,7 +213,7 @@ export function toString(color) {
|
||||
if (b != (b | 0)) {
|
||||
b = (b + 0.5) | 0;
|
||||
}
|
||||
const a = color[3] === undefined ? 1 : color[3];
|
||||
const a = color[3] === undefined ? 1 : Math.round(color[3] * 100) / 100;
|
||||
return 'rgba(' + r + ',' + g + ',' + b + ',' + a + ')';
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ import {removeChildren, replaceNode} from '../dom.js';
|
||||
* @property {boolean} [collapsed=true] Specify if attributions should
|
||||
* be collapsed at startup.
|
||||
* @property {string} [tipLabel='Attributions'] Text label to use for the button tip.
|
||||
* @property {string} [label='i'] Text label to use for the
|
||||
* @property {string|HTMLElement} [label='i'] Text label to use for the
|
||||
* collapsed attributions button.
|
||||
* Instead of text, also an element (e.g. a `span` element) can be used.
|
||||
* @property {string} [expandClassName=className + '-expand'] CSS class name for the
|
||||
|
||||
@@ -3,8 +3,9 @@
|
||||
*/
|
||||
import Control from './Control.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import MapProperty from '../MapProperty.js';
|
||||
import {CLASS_CONTROL, CLASS_UNSELECTABLE, CLASS_UNSUPPORTED} from '../css.js';
|
||||
import {listen} from '../events.js';
|
||||
import {listen, unlistenByKey} from '../events.js';
|
||||
import {replaceNode} from '../dom.js';
|
||||
|
||||
const events = [
|
||||
@@ -44,15 +45,15 @@ const FullScreenEventType = {
|
||||
/**
|
||||
* @typedef {Object} Options
|
||||
* @property {string} [className='ol-full-screen'] CSS class name.
|
||||
* @property {string|Text} [label='\u2922'] Text label to use for the button.
|
||||
* @property {string|Text|HTMLElement} [label='\u2922'] Text label to use for the button.
|
||||
* Instead of text, also an element (e.g. a `span` element) can be used.
|
||||
* @property {string|Text} [labelActive='\u00d7'] Text label to use for the
|
||||
* @property {string|Text|HTMLElement} [labelActive='\u00d7'] Text label to use for the
|
||||
* button when full-screen is active.
|
||||
* Instead of text, also an element (e.g. a `span` element) can be used.
|
||||
* @property {string} [activeClassName=className + '-true'] CSS class name for the button
|
||||
* when full-screen is active.
|
||||
* @property {string} [inactiveClassName=className + '-false'] CSS class name for the button
|
||||
* when full-screen is inactive.
|
||||
* Instead of text, also an element (e.g. a `span` element) can be used.
|
||||
* @property {string} [tipLabel='Toggle full-screen'] Text label to use for the button tip.
|
||||
* @property {boolean} [keys=false] Full keyboard access.
|
||||
* @property {HTMLElement|string} [target] Specify a target if you want the
|
||||
@@ -111,6 +112,12 @@ class FullScreen extends Control {
|
||||
this.cssClassName_ =
|
||||
options.className !== undefined ? options.className : 'ol-full-screen';
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<import("../events.js").EventsKey>}
|
||||
*/
|
||||
this.documentListeners_ = [];
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Array<string>}
|
||||
@@ -133,7 +140,7 @@ class FullScreen extends Control {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Text}
|
||||
* @type {Text|HTMLElement}
|
||||
*/
|
||||
this.labelNode_ =
|
||||
typeof label === 'string' ? document.createTextNode(label) : label;
|
||||
@@ -143,7 +150,7 @@ class FullScreen extends Control {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {Text}
|
||||
* @type {Text|HTMLElement}
|
||||
*/
|
||||
this.labelActiveNode_ =
|
||||
typeof labelActive === 'string'
|
||||
@@ -157,7 +164,6 @@ class FullScreen extends Control {
|
||||
this.button_ = document.createElement('button');
|
||||
|
||||
const tipLabel = options.tipLabel ? options.tipLabel : 'Toggle full-screen';
|
||||
this.setClassName_(this.button_, isFullScreen());
|
||||
this.button_.setAttribute('type', 'button');
|
||||
this.button_.title = tipLabel;
|
||||
this.button_.appendChild(this.labelNode_);
|
||||
@@ -168,17 +174,8 @@ class FullScreen extends Control {
|
||||
false
|
||||
);
|
||||
|
||||
const cssClasses =
|
||||
this.cssClassName_ +
|
||||
' ' +
|
||||
CLASS_UNSELECTABLE +
|
||||
' ' +
|
||||
CLASS_CONTROL +
|
||||
' ' +
|
||||
(!isFullScreenSupported() ? CLASS_UNSUPPORTED : '');
|
||||
const element = this.element;
|
||||
element.className = cssClasses;
|
||||
element.appendChild(this.button_);
|
||||
this.element.className = `${this.cssClassName_} ${CLASS_UNSELECTABLE} ${CLASS_CONTROL}`;
|
||||
this.element.appendChild(this.button_);
|
||||
|
||||
/**
|
||||
* @private
|
||||
@@ -191,6 +188,17 @@ class FullScreen extends Control {
|
||||
* @type {HTMLElement|string|undefined}
|
||||
*/
|
||||
this.source_ = options.source;
|
||||
|
||||
/**
|
||||
* @type {boolean}
|
||||
* @private
|
||||
*/
|
||||
this.isInFullscreen_ = false;
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
this.boundHandleMapTargetChange_ = this.handleMapTargetChange_.bind(this);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -206,21 +214,22 @@ class FullScreen extends Control {
|
||||
* @private
|
||||
*/
|
||||
handleFullScreen_() {
|
||||
if (!isFullScreenSupported()) {
|
||||
return;
|
||||
}
|
||||
const map = this.getMap();
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
if (isFullScreen()) {
|
||||
exitFullScreen();
|
||||
const doc = map.getOwnerDocument();
|
||||
if (!isFullScreenSupported(doc)) {
|
||||
return;
|
||||
}
|
||||
if (isFullScreen(doc)) {
|
||||
exitFullScreen(doc);
|
||||
} else {
|
||||
let element;
|
||||
if (this.source_) {
|
||||
element =
|
||||
typeof this.source_ === 'string'
|
||||
? document.getElementById(this.source_)
|
||||
? doc.getElementById(this.source_)
|
||||
: this.source_;
|
||||
} else {
|
||||
element = map.getTargetElement();
|
||||
@@ -238,16 +247,20 @@ class FullScreen extends Control {
|
||||
*/
|
||||
handleFullScreenChange_() {
|
||||
const map = this.getMap();
|
||||
if (isFullScreen()) {
|
||||
this.setClassName_(this.button_, true);
|
||||
replaceNode(this.labelActiveNode_, this.labelNode_);
|
||||
this.dispatchEvent(FullScreenEventType.ENTERFULLSCREEN);
|
||||
} else {
|
||||
this.setClassName_(this.button_, false);
|
||||
replaceNode(this.labelNode_, this.labelActiveNode_);
|
||||
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
|
||||
if (!map) {
|
||||
return;
|
||||
}
|
||||
if (map) {
|
||||
const wasInFullscreen = this.isInFullscreen_;
|
||||
this.isInFullscreen_ = isFullScreen(map.getOwnerDocument());
|
||||
if (wasInFullscreen !== this.isInFullscreen_) {
|
||||
this.setClassName_(this.button_, this.isInFullscreen_);
|
||||
if (this.isInFullscreen_) {
|
||||
replaceNode(this.labelActiveNode_, this.labelNode_);
|
||||
this.dispatchEvent(FullScreenEventType.ENTERFULLSCREEN);
|
||||
} else {
|
||||
replaceNode(this.labelNode_, this.labelActiveNode_);
|
||||
this.dispatchEvent(FullScreenEventType.LEAVEFULLSCREEN);
|
||||
}
|
||||
map.updateSize();
|
||||
}
|
||||
}
|
||||
@@ -274,37 +287,76 @@ class FullScreen extends Control {
|
||||
* @api
|
||||
*/
|
||||
setMap(map) {
|
||||
const oldMap = this.getMap();
|
||||
if (oldMap) {
|
||||
oldMap.removeChangeListener(
|
||||
MapProperty.TARGET,
|
||||
this.boundHandleMapTargetChange_
|
||||
);
|
||||
}
|
||||
|
||||
super.setMap(map);
|
||||
|
||||
this.handleMapTargetChange_();
|
||||
if (map) {
|
||||
map.addChangeListener(
|
||||
MapProperty.TARGET,
|
||||
this.boundHandleMapTargetChange_
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleMapTargetChange_() {
|
||||
const listeners = this.documentListeners_;
|
||||
for (let i = 0, ii = listeners.length; i < ii; ++i) {
|
||||
unlistenByKey(listeners[i]);
|
||||
}
|
||||
listeners.length = 0;
|
||||
|
||||
const map = this.getMap();
|
||||
if (map) {
|
||||
const doc = map.getOwnerDocument();
|
||||
if (isFullScreenSupported(doc)) {
|
||||
this.element.classList.remove(CLASS_UNSUPPORTED);
|
||||
} else {
|
||||
this.element.classList.add(CLASS_UNSUPPORTED);
|
||||
}
|
||||
|
||||
for (let i = 0, ii = events.length; i < ii; ++i) {
|
||||
this.listenerKeys.push(
|
||||
listen(document, events[i], this.handleFullScreenChange_, this)
|
||||
listeners.push(
|
||||
listen(doc, events[i], this.handleFullScreenChange_, this)
|
||||
);
|
||||
}
|
||||
this.handleFullScreenChange_();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc The root document to check.
|
||||
* @return {boolean} Fullscreen is supported by the current platform.
|
||||
*/
|
||||
function isFullScreenSupported() {
|
||||
const body = document.body;
|
||||
function isFullScreenSupported(doc) {
|
||||
const body = doc.body;
|
||||
return !!(
|
||||
body['webkitRequestFullscreen'] ||
|
||||
(body['msRequestFullscreen'] && document['msFullscreenEnabled']) ||
|
||||
(body.requestFullscreen && document.fullscreenEnabled)
|
||||
(body['msRequestFullscreen'] && doc['msFullscreenEnabled']) ||
|
||||
(body.requestFullscreen && doc.fullscreenEnabled)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {Document} doc The root document to check.
|
||||
* @return {boolean} Element is currently in fullscreen.
|
||||
*/
|
||||
function isFullScreen() {
|
||||
function isFullScreen(doc) {
|
||||
return !!(
|
||||
document['webkitIsFullScreen'] ||
|
||||
document['msFullscreenElement'] ||
|
||||
document.fullscreenElement
|
||||
doc['webkitIsFullScreen'] ||
|
||||
doc['msFullscreenElement'] ||
|
||||
doc.fullscreenElement
|
||||
);
|
||||
}
|
||||
|
||||
@@ -336,14 +388,15 @@ function requestFullScreenWithKeys(element) {
|
||||
|
||||
/**
|
||||
* Exit fullscreen.
|
||||
* @param {Document} doc The document to exit fullscren from
|
||||
*/
|
||||
function exitFullScreen() {
|
||||
if (document.exitFullscreen) {
|
||||
document.exitFullscreen();
|
||||
} else if (document['msExitFullscreen']) {
|
||||
document['msExitFullscreen']();
|
||||
} else if (document['webkitExitFullscreen']) {
|
||||
document['webkitExitFullscreen']();
|
||||
function exitFullScreen(doc) {
|
||||
if (doc.exitFullscreen) {
|
||||
doc.exitFullscreen();
|
||||
} else if (doc['msExitFullscreen']) {
|
||||
doc['msExitFullscreen']();
|
||||
} else if (doc['webkitExitFullscreen']) {
|
||||
doc['webkitExitFullscreen']();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ class ControlledMap extends PluggableMap {
|
||||
* @property {boolean} [collapsible=true] Whether the control can be collapsed or not.
|
||||
* @property {string|HTMLElement} [label='›'] Text label to use for the collapsed
|
||||
* overviewmap button. Instead of text, also an element (e.g. a `span` element) can be used.
|
||||
* @property {Array<import("../layer/Layer.js").default>|import("../Collection.js").default<import("../layer/Layer.js").default>} [layers]
|
||||
* @property {Array<import("../layer/Base.js").default>|import("../Collection.js").default<import("../layer/Base.js").default>} [layers]
|
||||
* Layers for the overview map.
|
||||
* @property {function(import("../MapEvent.js").default):void} [render] Function called when the control
|
||||
* should be re-rendered. This is called in a `requestAnimationFrame` callback.
|
||||
|
||||
@@ -27,7 +27,6 @@ export function createCanvasContext2D(
|
||||
canvas = new OffscreenCanvas(opt_width || 300, opt_height || 300);
|
||||
} else {
|
||||
canvas = document.createElement('canvas');
|
||||
canvas.style.all = 'unset';
|
||||
}
|
||||
if (opt_width) {
|
||||
canvas.width = opt_width;
|
||||
|
||||
@@ -83,7 +83,9 @@ export const altShiftKeysOnly = function (mapBrowserEvent) {
|
||||
* @api
|
||||
*/
|
||||
export const focus = function (event) {
|
||||
return event.target.getTargetElement().contains(document.activeElement);
|
||||
const targetElement = event.map.getTargetElement();
|
||||
const activeElement = event.map.getOwnerDocument().activeElement;
|
||||
return targetElement.contains(activeElement);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -186,7 +186,7 @@ const GEOMETRY_READERS = {
|
||||
function concatenateArcs(indices, arcs) {
|
||||
/** @type {Array<import("../coordinate.js").Coordinate>} */
|
||||
const coordinates = [];
|
||||
let index, arc;
|
||||
let index;
|
||||
for (let i = 0, ii = indices.length; i < ii; ++i) {
|
||||
index = indices[i];
|
||||
if (i > 0) {
|
||||
@@ -195,16 +195,17 @@ function concatenateArcs(indices, arcs) {
|
||||
}
|
||||
if (index >= 0) {
|
||||
// forward arc
|
||||
arc = arcs[index];
|
||||
const arc = arcs[index];
|
||||
for (let j = 0, jj = arc.length; j < jj; ++j) {
|
||||
coordinates.push(arc[j].slice(0));
|
||||
}
|
||||
} else {
|
||||
// reverse arc
|
||||
arc = arcs[~index].slice().reverse();
|
||||
const arc = arcs[~index];
|
||||
for (let j = arc.length - 1; j >= 0; --j) {
|
||||
coordinates.push(arc[j].slice(0));
|
||||
}
|
||||
}
|
||||
coordinates.push.apply(coordinates, arc);
|
||||
}
|
||||
// provide fresh copies of coordinate arrays
|
||||
for (let j = 0, jj = coordinates.length; j < jj; ++j) {
|
||||
coordinates[j] = coordinates[j].slice();
|
||||
}
|
||||
return coordinates;
|
||||
}
|
||||
|
||||
@@ -58,3 +58,24 @@ export function memoizeOne(fn) {
|
||||
return lastResult;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {function(): (T | Promise<T>)} getter A function that returns a value or a promise for a value.
|
||||
* @return {Promise<T>} A promise for the value.
|
||||
*/
|
||||
export function toPromise(getter) {
|
||||
function promiseGetter() {
|
||||
let value;
|
||||
try {
|
||||
value = getter();
|
||||
} catch (err) {
|
||||
return Promise.reject(err);
|
||||
}
|
||||
if (value instanceof Promise) {
|
||||
return value;
|
||||
}
|
||||
return Promise.resolve(value);
|
||||
}
|
||||
return promiseGetter();
|
||||
}
|
||||
|
||||
@@ -89,7 +89,7 @@ export class DragAndDropEvent extends Event {
|
||||
* Handles input of vector data by drag and drop.
|
||||
*
|
||||
* Note that the DragAndDrop interaction uses the TextDecoder() constructor if the supplied
|
||||
* combinnation of formats read both text string and ArrayBuffer sources. Older browsers such
|
||||
* combination of formats read both text string and ArrayBuffer sources. Older browsers such
|
||||
* as IE which do not support this will need a TextDecoder polyfill to be loaded before use.
|
||||
*
|
||||
* @api
|
||||
|
||||
@@ -30,13 +30,13 @@ import {toUserExtent} from '../proj.js';
|
||||
* @property {import("../extent.js").Extent} [extent] Initial extent. Defaults to no
|
||||
* initial extent.
|
||||
* @property {import("../style/Style.js").StyleLike} [boxStyle]
|
||||
* Style for the drawn extent box. Defaults to
|
||||
* {@link module:ol/style/Style~createEditing()['Polygon']}
|
||||
* Style for the drawn extent box. Defaults to the `Polygon` editing style
|
||||
* documented in {@link module:ol/style/Style~Style}
|
||||
* @property {number} [pixelTolerance=10] Pixel tolerance for considering the
|
||||
* pointer close enough to a segment or vertex for editing.
|
||||
* @property {import("../style/Style.js").StyleLike} [pointerStyle]
|
||||
* Style for the cursor used to draw the extent. Defaults to
|
||||
* {@link module:ol/style/Style~createEditing()['Point']}
|
||||
* Style for the cursor used to draw the extent. Defaults to the `Point` editing style
|
||||
* documented in {@link module:ol/style/Style~Style}
|
||||
* @property {boolean} [wrapX=false] Wrap the drawn extent across multiple maps
|
||||
* in the X direction? Only affects visuals, not functionality.
|
||||
*/
|
||||
|
||||
@@ -110,7 +110,7 @@ const ModifyEventType = {
|
||||
* @property {import("../style/Style.js").StyleLike} [style]
|
||||
* Style used for the modification point or vertex. For linestrings and polygons, this will
|
||||
* be the affected vertex, for circles a point along the circle, and for points the actual
|
||||
* point. If not configured, the default edit style is used (see {@link module:ol/style}).
|
||||
* point. If not configured, the default edit style is used (see {@link module:ol/style/Style~Style}).
|
||||
* When using a style function, the point feature passed to the function will have a `features`
|
||||
* property - an array whose entries are the features that are being modified, and a `geometries`
|
||||
* property - an array whose entries are the geometries that are being modified. Both arrays are
|
||||
|
||||
@@ -6,6 +6,7 @@ import CollectionEventType from '../CollectionEventType.js';
|
||||
import Event from '../events/Event.js';
|
||||
import GeometryType from '../geom/GeometryType.js';
|
||||
import Interaction from './Interaction.js';
|
||||
import VectorLayer from '../layer/Vector.js';
|
||||
import {TRUE} from '../functions.js';
|
||||
import {clear} from '../obj.js';
|
||||
import {createEditingStyle} from '../style/Style.js';
|
||||
@@ -57,7 +58,7 @@ const SelectEventType = {
|
||||
* selectable.
|
||||
* @property {import("../style/Style.js").StyleLike|null} [style]
|
||||
* Style for the selected features. By default the default edit style is used
|
||||
* (see {@link module:ol/style}). Set to `null` if this interaction should not apply
|
||||
* (see {@link module:ol/style/Style~Style}). Set to `null` if this interaction should not apply
|
||||
* any style changes for selected features.
|
||||
* If set to a falsey value, the selected feature's style will not change.
|
||||
* @property {import("../events/condition.js").Condition} [removeCondition] A function
|
||||
@@ -308,10 +309,8 @@ class Select extends Interaction {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the associated {@link module:ol/layer/Vector~Vector vectorlayer} of
|
||||
* the (last) selected feature. Note that this will not work with any
|
||||
* programmatic method like pushing features to
|
||||
* {@link module:ol/interaction/Select~Select#getFeatures collection}.
|
||||
* Returns the associated {@link module:ol/layer/Vector~Vector vector layer} of
|
||||
* a selected feature.
|
||||
* @param {import("../Feature.js").FeatureLike} feature Feature
|
||||
* @return {import('../layer/Vector.js').default} Layer.
|
||||
* @api
|
||||
@@ -378,6 +377,24 @@ class Select extends Interaction {
|
||||
if (this.style_) {
|
||||
this.applySelectedStyle_(feature);
|
||||
}
|
||||
if (!this.getLayer(feature)) {
|
||||
const layer = /** @type {VectorLayer} */ (
|
||||
this.getMap()
|
||||
.getAllLayers()
|
||||
.find(function (layer) {
|
||||
if (
|
||||
layer instanceof VectorLayer &&
|
||||
layer.getSource() &&
|
||||
layer.getSource().hasFeature(feature)
|
||||
) {
|
||||
return layer;
|
||||
}
|
||||
})
|
||||
);
|
||||
if (layer) {
|
||||
this.addFeatureLayerAssociation_(feature, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -475,8 +492,8 @@ class Select extends Interaction {
|
||||
*/
|
||||
function (feature, layer) {
|
||||
if (this.filter_(feature, layer)) {
|
||||
selected.push(feature);
|
||||
this.addFeatureLayerAssociation_(feature, layer);
|
||||
selected.push(feature);
|
||||
return !this.multi_;
|
||||
}
|
||||
}.bind(this),
|
||||
@@ -511,8 +528,8 @@ class Select extends Interaction {
|
||||
function (feature, layer) {
|
||||
if (this.filter_(feature, layer)) {
|
||||
if ((add || toggle) && !includes(features.getArray(), feature)) {
|
||||
selected.push(feature);
|
||||
this.addFeatureLayerAssociation_(feature, layer);
|
||||
selected.push(feature);
|
||||
} else if (
|
||||
(remove || toggle) &&
|
||||
includes(features.getArray(), feature)
|
||||
|
||||
@@ -8,6 +8,13 @@ import {assert} from '../asserts.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {clamp} from '../math.js';
|
||||
|
||||
/**
|
||||
* A css color, or a function called with a view resolution returning a css color.
|
||||
*
|
||||
* @typedef {string|function(number):string} BackgroundColor
|
||||
* @api
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {import("../ObjectEventType").Types|'change:extent'|'change:maxResolution'|'change:maxZoom'|
|
||||
* 'change:minResolution'|'change:minZoom'|'change:opacity'|'change:visible'|'change:zIndex'} BaseLayerObjectEventTypes
|
||||
@@ -39,6 +46,8 @@ import {clamp} from '../math.js';
|
||||
* visible.
|
||||
* @property {number} [maxZoom] The maximum view zoom level (inclusive) at which this layer will
|
||||
* be visible.
|
||||
* @property {BackgroundColor} [background] Background color for the layer. If not specified, no background
|
||||
* will be rendered.
|
||||
* @property {Object<string, *>} [properties] Arbitrary observable properties. Can be accessed with `#get()` and `#set()`.
|
||||
*/
|
||||
|
||||
@@ -74,6 +83,12 @@ class BaseLayer extends BaseObject {
|
||||
*/
|
||||
this.un;
|
||||
|
||||
/**
|
||||
* @type {BackgroundColor|false}
|
||||
* @private
|
||||
*/
|
||||
this.background_ = options.background;
|
||||
|
||||
/**
|
||||
* @type {Object<string, *>}
|
||||
*/
|
||||
@@ -116,6 +131,14 @@ class BaseLayer extends BaseObject {
|
||||
this.state_ = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the background for this layer.
|
||||
* @return {BackgroundColor|false} Layer background.
|
||||
*/
|
||||
getBackground() {
|
||||
return this.background_;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {string} CSS class name.
|
||||
*/
|
||||
@@ -265,6 +288,15 @@ class BaseLayer extends BaseObject {
|
||||
return /** @type {number} */ (this.get(LayerProperty.Z_INDEX));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the backgrlound color.
|
||||
* @param {BackgroundColor} [opt_background] Background color.
|
||||
*/
|
||||
setBackground(opt_background) {
|
||||
this.background_ = opt_background;
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the extent at which the layer is visible. If `undefined`, the layer
|
||||
* will be visible at all extents.
|
||||
|
||||
@@ -40,7 +40,8 @@ import Layer from './Layer.js';
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
*
|
||||
* @template {import("../source/Image.js").default} ImageSourceType
|
||||
* @extends {Layer<ImageSourceType>}
|
||||
* @template {import("../renderer/Layer.js").default} RendererType
|
||||
* @extends {Layer<ImageSourceType, RendererType>}
|
||||
* @api
|
||||
*/
|
||||
class BaseImageLayer extends Layer {
|
||||
|
||||
@@ -55,7 +55,8 @@ import {assign} from '../obj.js';
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
*
|
||||
* @template {import("../source/Tile.js").default} TileSourceType
|
||||
* @extends {Layer<TileSourceType>}
|
||||
* @template {import("../renderer/Layer.js").default} RendererType
|
||||
* @extends {Layer<TileSourceType, RendererType>}
|
||||
* @api
|
||||
*/
|
||||
class BaseTileLayer extends Layer {
|
||||
|
||||
@@ -46,8 +46,10 @@ import {
|
||||
* Higher z-index means higher priority. Within the same z-index, a feature rendered before another has
|
||||
* higher priority.
|
||||
* @property {import("../style/Style.js").StyleLike|null} [style] Layer style. When set to `null`, only
|
||||
* features that have their own style will be rendered. See {@link module:ol/style} for default style
|
||||
* features that have their own style will be rendered. See {@link module:ol/style/Style~Style} for the default style
|
||||
* which will be used if this is not set.
|
||||
* @property {import("./Base.js").BackgroundColor} [background] Background color for the layer. If not specified, no background
|
||||
* will be rendered.
|
||||
* @property {boolean} [updateWhileAnimating=false] When set to `true`, feature batches will
|
||||
* be recreated during animations. This means that no vectors will be shown clipped, but the
|
||||
* setting will have a performance impact for large amounts of vector data. When set to `false`,
|
||||
@@ -73,7 +75,8 @@ const Property = {
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
*
|
||||
* @template {import("../source/Vector.js").default|import("../source/VectorTile.js").default} VectorSourceType
|
||||
* @extends {Layer<VectorSourceType>}
|
||||
* @template {import("../renderer/Layer.js").default} RendererType
|
||||
* @extends {Layer<VectorSourceType, RendererType>}
|
||||
* @api
|
||||
*/
|
||||
class BaseVectorLayer extends Layer {
|
||||
@@ -242,7 +245,7 @@ class BaseVectorLayer extends Layer {
|
||||
* an array of styles. If set to `null`, the layer has no style (a `null` style),
|
||||
* so only features that have their own styles will be rendered in the layer. Call
|
||||
* `setStyle()` without arguments to reset to the default style. See
|
||||
* {@link module:ol/style} for information on the default style.
|
||||
* {@link module:ol/style/Style~Style} for information on the default style.
|
||||
* @param {import("../style/Style.js").StyleLike|null} [opt_style] Layer style.
|
||||
* @api
|
||||
*/
|
||||
|
||||
@@ -86,9 +86,13 @@ const INTERVALS = [
|
||||
* appropriate for conformal projections like Spherical Mercator. If you
|
||||
* increase the value, more lines will be drawn and the drawing performance will
|
||||
* decrease.
|
||||
* @property {Stroke} [strokeStyle='rgba(0,0,0,0.2)'] The
|
||||
* stroke style to use for drawing the graticule. If not provided, a not fully
|
||||
* opaque black will be used.
|
||||
* @property {Stroke} [strokeStyle] The
|
||||
* stroke style to use for drawing the graticule. If not provided, the following stroke will be used:
|
||||
* ```js
|
||||
* new Stroke({
|
||||
* color: 'rgba(0, 0, 0, 0.2)' // a not fully opaque black
|
||||
* });
|
||||
* ```
|
||||
* @property {number} [targetSize=100] The target size of the graticule cells,
|
||||
* in pixels.
|
||||
* @property {boolean} [showLabels=false] Render a label with the respective
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
import BaseLayer from './Base.js';
|
||||
import Collection from '../Collection.js';
|
||||
import CollectionEventType from '../CollectionEventType.js';
|
||||
import Event from '../events/Event.js';
|
||||
import EventType from '../events/EventType.js';
|
||||
import ObjectEventType from '../ObjectEventType.js';
|
||||
import SourceState from '../source/State.js';
|
||||
@@ -13,6 +14,33 @@ import {getIntersection} from '../extent.js';
|
||||
import {getUid} from '../util.js';
|
||||
import {listen, unlistenByKey} from '../events.js';
|
||||
|
||||
/**
|
||||
* @typedef {'addlayer'|'removelayer'} EventType
|
||||
*/
|
||||
|
||||
/**
|
||||
* @classdesc
|
||||
* A layer group triggers 'addlayer' and 'removelayer' events when layers are added to or removed from
|
||||
* the group or one of its child groups. When a layer group is added to or removed from another layer group,
|
||||
* a single event will be triggered (instead of one per layer in the group added or removed).
|
||||
*/
|
||||
export class GroupEvent extends Event {
|
||||
/**
|
||||
* @param {EventType} type The event type.
|
||||
* @param {BaseLayer} layer The layer.
|
||||
*/
|
||||
constructor(type, layer) {
|
||||
super(type);
|
||||
|
||||
/**
|
||||
* The added or removed layer.
|
||||
* @type {BaseLayer}
|
||||
* @api
|
||||
*/
|
||||
this.layer = layer;
|
||||
}
|
||||
}
|
||||
|
||||
/***
|
||||
* @template Return
|
||||
* @typedef {import("../Observable").OnSignature<import("../Observable").EventTypes, import("../events/Event.js").default, Return> &
|
||||
@@ -142,18 +170,48 @@ class LayerGroup extends BaseLayer {
|
||||
const layersArray = layers.getArray();
|
||||
for (let i = 0, ii = layersArray.length; i < ii; i++) {
|
||||
const layer = layersArray[i];
|
||||
this.listenerKeys_[getUid(layer)] = [
|
||||
listen(
|
||||
layer,
|
||||
ObjectEventType.PROPERTYCHANGE,
|
||||
this.handleLayerChange_,
|
||||
this
|
||||
),
|
||||
listen(layer, EventType.CHANGE, this.handleLayerChange_, this),
|
||||
];
|
||||
this.registerLayerListeners_(layer);
|
||||
this.dispatchEvent(new GroupEvent('addlayer', layer));
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {BaseLayer} layer The layer.
|
||||
*/
|
||||
registerLayerListeners_(layer) {
|
||||
const listenerKeys = [
|
||||
listen(
|
||||
layer,
|
||||
ObjectEventType.PROPERTYCHANGE,
|
||||
this.handleLayerChange_,
|
||||
this
|
||||
),
|
||||
listen(layer, EventType.CHANGE, this.handleLayerChange_, this),
|
||||
];
|
||||
|
||||
if (layer instanceof LayerGroup) {
|
||||
listenerKeys.push(
|
||||
listen(layer, 'addlayer', this.handleLayerGroupAdd_, this),
|
||||
listen(layer, 'removelayer', this.handleLayerGroupRemove_, this)
|
||||
);
|
||||
}
|
||||
|
||||
this.changed();
|
||||
this.listenerKeys_[getUid(layer)] = listenerKeys;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GroupEvent} event The layer group event.
|
||||
*/
|
||||
handleLayerGroupAdd_(event) {
|
||||
this.dispatchEvent(new GroupEvent('addlayer', event.layer));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {GroupEvent} event The layer group event.
|
||||
*/
|
||||
handleLayerGroupRemove_(event) {
|
||||
this.dispatchEvent(new GroupEvent('removelayer', event.layer));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -164,15 +222,8 @@ class LayerGroup extends BaseLayer {
|
||||
const layer = /** @type {import("./Base.js").default} */ (
|
||||
collectionEvent.element
|
||||
);
|
||||
this.listenerKeys_[getUid(layer)] = [
|
||||
listen(
|
||||
layer,
|
||||
ObjectEventType.PROPERTYCHANGE,
|
||||
this.handleLayerChange_,
|
||||
this
|
||||
),
|
||||
listen(layer, EventType.CHANGE, this.handleLayerChange_, this),
|
||||
];
|
||||
this.registerLayerListeners_(layer);
|
||||
this.dispatchEvent(new GroupEvent('addlayer', layer));
|
||||
this.changed();
|
||||
}
|
||||
|
||||
@@ -187,6 +238,7 @@ class LayerGroup extends BaseLayer {
|
||||
const key = getUid(layer);
|
||||
this.listenerKeys_[key].forEach(unlistenByKey);
|
||||
delete this.listenerKeys_[key];
|
||||
this.dispatchEvent(new GroupEvent('removelayer', layer));
|
||||
this.changed();
|
||||
}
|
||||
|
||||
@@ -213,6 +265,14 @@ class LayerGroup extends BaseLayer {
|
||||
* @api
|
||||
*/
|
||||
setLayers(layers) {
|
||||
const collection = this.getLayers();
|
||||
if (collection) {
|
||||
const currentLayers = collection.getArray();
|
||||
for (let i = 0, ii = currentLayers.length; i < ii; ++i) {
|
||||
this.dispatchEvent(new GroupEvent('removelayer', currentLayers[i]));
|
||||
}
|
||||
}
|
||||
|
||||
this.set(Property.LAYERS, layers);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* @module ol/layer/Heatmap
|
||||
*/
|
||||
import VectorLayer from './Vector.js';
|
||||
import BaseVector from './BaseVector.js';
|
||||
import WebGLPointsLayerRenderer from '../renderer/webgl/PointsLayer.js';
|
||||
import {assign} from '../obj.js';
|
||||
import {clamp} from '../math.js';
|
||||
@@ -61,10 +61,10 @@ const DEFAULT_GRADIENT = ['#00f', '#0ff', '#0f0', '#ff0', '#f00'];
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
*
|
||||
* @fires import("../render/Event.js").RenderEvent
|
||||
* @extends {VectorLayer<import("../source/Vector.js").default>}
|
||||
* @extends {BaseVector<import("../source/Vector.js").default, WebGLPointsLayerRenderer>}
|
||||
* @api
|
||||
*/
|
||||
class Heatmap extends VectorLayer {
|
||||
class Heatmap extends BaseVector {
|
||||
/**
|
||||
* @param {Options} [opt_options] Options.
|
||||
*/
|
||||
@@ -174,10 +174,6 @@ class Heatmap extends VectorLayer {
|
||||
this.set(Property.RADIUS, radius);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a renderer for this layer.
|
||||
* @return {WebGLPointsLayerRenderer} A layer renderer.
|
||||
*/
|
||||
createRenderer() {
|
||||
return new WebGLPointsLayerRenderer(this, {
|
||||
className: this.getClassName(),
|
||||
@@ -289,12 +285,13 @@ class Heatmap extends VectorLayer {
|
||||
|
||||
uniform sampler2D u_image;
|
||||
uniform sampler2D u_gradientTexture;
|
||||
uniform float u_opacity;
|
||||
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
vec4 color = texture2D(u_image, v_texCoord);
|
||||
gl_FragColor.a = color.a;
|
||||
gl_FragColor.a = color.a * u_opacity;
|
||||
gl_FragColor.rgb = texture2D(u_gradientTexture, vec2(0.5, color.a)).rgb;
|
||||
gl_FragColor.rgb *= gl_FragColor.a;
|
||||
}`,
|
||||
@@ -302,6 +299,9 @@ class Heatmap extends VectorLayer {
|
||||
u_gradientTexture: function () {
|
||||
return this.gradient_;
|
||||
}.bind(this),
|
||||
u_opacity: function () {
|
||||
return this.getOpacity();
|
||||
}.bind(this),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -13,7 +13,7 @@ import CanvasImageLayerRenderer from '../renderer/canvas/ImageLayer.js';
|
||||
* options means that `title` is observable, and has get/set accessors.
|
||||
*
|
||||
* @template {import("../source/Image.js").default} ImageSourceType
|
||||
* @extends {BaseImageLayer<ImageSourceType>}
|
||||
* @extends {BaseImageLayer<ImageSourceType, CanvasImageLayerRenderer>}
|
||||
* @api
|
||||
*/
|
||||
class ImageLayer extends BaseImageLayer {
|
||||
@@ -24,10 +24,6 @@ class ImageLayer extends BaseImageLayer {
|
||||
super(opt_options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a renderer for this layer.
|
||||
* @return {import("../renderer/Layer.js").default} A layer renderer.
|
||||
*/
|
||||
createRenderer() {
|
||||
return new CanvasImageLayerRenderer(this);
|
||||
}
|
||||
|
||||
@@ -94,6 +94,7 @@ import {listen, unlistenByKey} from '../events.js';
|
||||
* @fires import("../render/Event.js").RenderEvent#postrender
|
||||
*
|
||||
* @template {import("../source/Source.js").default} SourceType
|
||||
* @template {import("../renderer/Layer.js").default} RendererType
|
||||
* @api
|
||||
*/
|
||||
class Layer extends BaseLayer {
|
||||
@@ -141,7 +142,7 @@ class Layer extends BaseLayer {
|
||||
|
||||
/**
|
||||
* @private
|
||||
* @type {import("../renderer/Layer.js").default}
|
||||
* @type {RendererType}
|
||||
*/
|
||||
this.renderer_ = null;
|
||||
|
||||
@@ -258,6 +259,22 @@ class Layer extends BaseLayer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* For use inside the library only.
|
||||
* @param {import("../PluggableMap.js").default} map Map.
|
||||
*/
|
||||
setMapInternal(map) {
|
||||
this.set(LayerProperty.MAP, map);
|
||||
}
|
||||
|
||||
/**
|
||||
* For use inside the library only.
|
||||
* @return {import("../PluggableMap.js").default} Map.
|
||||
*/
|
||||
getMapInternal() {
|
||||
return this.get(LayerProperty.MAP);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the layer to be rendered on top of other layers on a map. The map will
|
||||
* not manage this layer in its layers collection, and the callback in
|
||||
@@ -319,7 +336,7 @@ class Layer extends BaseLayer {
|
||||
|
||||
/**
|
||||
* Get the renderer for this layer.
|
||||
* @return {import("../renderer/Layer.js").default} The layer renderer.
|
||||
* @return {RendererType} The layer renderer.
|
||||
*/
|
||||
getRenderer() {
|
||||
if (!this.renderer_) {
|
||||
@@ -337,7 +354,7 @@ class Layer extends BaseLayer {
|
||||
|
||||
/**
|
||||
* Create a renderer for this layer.
|
||||
* @return {import("../renderer/Layer.js").default} A layer renderer.
|
||||
* @return {RendererType} A layer renderer.
|
||||
* @protected
|
||||
*/
|
||||
createRenderer() {
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user