diff --git a/.github/renovate.json5 b/.github/renovate.json5 index 6d321eb36dc2..07cc4682beea 100644 --- a/.github/renovate.json5 +++ b/.github/renovate.json5 @@ -98,11 +98,6 @@ groupName: 'CI dependencies', automerge: true, }, - /** Disable ol-cesium updates */ - { - enabled: false, - matchDepNames: ['ol-cesium'], - }, /** Packages published very recently are not pushed to stabilization branches for security reasons */ { matchBaseBranches: ['/^[0-9]+\\.[0-9]+$/'], diff --git a/DEVELOPING.md b/DEVELOPING.md index f791ce76b1b7..1e4bb376ed56 100644 --- a/DEVELOPING.md +++ b/DEVELOPING.md @@ -9,7 +9,7 @@ make serve-ngeo Use the _ONE_EXAMPLE_ environment variable to build (and rebuild on each change) only one example. ``` -ONE_EXAMPLE=offline make serve-ngeo +ONE_EXAMPLE=simple make serve-ngeo ``` The ngeo examples are now available on your https://localhost:3000/examples/. diff --git a/buildtools/extract-ngeo-dependencies b/buildtools/extract-ngeo-dependencies index e148d41fdce4..1aa5c356f6ad 100755 --- a/buildtools/extract-ngeo-dependencies +++ b/buildtools/extract-ngeo-dependencies @@ -51,7 +51,6 @@ all_required_js = {a for a in all_required_js if not a.startswith("./")} all_required_js = {a for a in all_required_js if not a.startswith("ngeo/")} all_required_js = {a for a in all_required_js if not a.startswith("gmf/")} all_required_js = {a for a in all_required_js if not a.startswith("gmfapi/")} -all_required_js = {a for a in all_required_js if not a.startswith("olcs/")} all_required_js = {a for a in all_required_js if not a.startswith("jsts/")} all_required_js = {a for a in all_required_js if not a.startswith("mapillary-js/")} all_required_js = { diff --git a/package-lock.json b/package-lock.json index 7801acde744e..554f7afc6797 100644 --- a/package-lock.json +++ b/package-lock.json @@ -155,9 +155,7 @@ }, "optionalDependencies": { "jsts": "2.11.3", - "localforage": "1.10.0", - "mapillary-js": "4.1.2", - "ol-cesium": "2.14.0" + "mapillary-js": "4.1.2" }, "peerDependencies": { "color-rgba": "3.0.0", @@ -1049,53 +1047,6 @@ "node": ">=6.9.0" } }, - "node_modules/@cesium/engine": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/@cesium/engine/-/engine-11.1.0.tgz", - "integrity": "sha512-vrEQAbYQuXt2cMYF9BpBu4Kxu+8uje1CrFHfyI5aNp7gCrUK1RYquldyqT7TDr3YKe7oZMHL+Xeb5Vm8ua6gZQ==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@tweenjs/tween.js": "^25.0.0", - "@zip.js/zip.js": "^2.7.34", - "autolinker": "^4.0.0", - "bitmap-sdf": "^1.0.3", - "dompurify": "^3.0.2", - "draco3d": "^1.5.1", - "earcut": "^3.0.0", - "grapheme-splitter": "^1.0.4", - "jsep": "^1.3.8", - "kdbush": "^4.0.1", - "ktx-parse": "^0.7.0", - "lerc": "^2.0.0", - "mersenne-twister": "^1.1.0", - "meshoptimizer": "^0.21.0", - "pako": "^2.0.4", - "protobufjs": "^7.1.0", - "rbush": "3.0.1", - "topojson-client": "^3.1.0", - "urijs": "^1.19.7" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@cesium/widgets": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/@cesium/widgets/-/widgets-8.1.0.tgz", - "integrity": "sha512-WD5eokNfSQmB3oqe97KmdmDefwzooHaMWBm9kE/Af9edyD2j3eQVTrbNhiJ06UIyEjd01U1af2iDOawI9adAgA==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "dependencies": { - "@cesium/engine": "^11.1.0", - "nosleep.js": "^0.12.0" - }, - "engines": { - "node": ">=14.0.0" - } - }, "node_modules/@chromatic-com/storybook": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/@chromatic-com/storybook/-/storybook-2.0.2.tgz", @@ -2199,90 +2150,6 @@ "url": "https://opencollective.com/popperjs" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" - } - }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true - }, "node_modules/@puppeteer/browsers": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-2.4.0.tgz", @@ -3906,14 +3773,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@tweenjs/tween.js": { - "version": "25.0.0", - "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-25.0.0.tgz", - "integrity": "sha512-XKLA6syeBUaPzx4j3qwMqzzq+V4uo72BnlbOjmuljLrRqdsd3qnzvZZoxvMHZ23ndsRS4aufU6JOZYpCbU6T1A==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/@types/angular": { "version": "1.8.9", "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.8.9.tgz", @@ -4590,7 +4449,7 @@ "version": "20.16.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.16.10.tgz", "integrity": "sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" @@ -5411,19 +5270,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/@zip.js/zip.js": { - "version": "2.7.52", - "resolved": "https://registry.npmjs.org/@zip.js/zip.js/-/zip.js-2.7.52.tgz", - "integrity": "sha512-+5g7FQswvrCHwYKNMd/KFxZSObctLSsQOgqBSi0LzwHo3li9Eh1w5cF5ndjQw9Zbr3ajVnd2+XyiX85gAetx1Q==", - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "engines": { - "bun": ">=0.7.0", - "deno": ">=1.0.0", - "node": ">=16.5.0" - } - }, "node_modules/abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -5935,17 +5781,6 @@ "node": ">= 4.0.0" } }, - "node_modules/autolinker": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/autolinker/-/autolinker-4.0.0.tgz", - "integrity": "sha512-fl5Kh6BmEEZx+IWBfEirnRUU5+cOiV0OK7PEt0RBKvJMJ8GaRseIOeDU3FKf4j3CE5HVefcjHmhYPOcaVt0bZw==", - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.3.0" - } - }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -6997,14 +6832,6 @@ "integrity": "sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==", "license": "CC0-1.0" }, - "node_modules/bitmap-sdf": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/bitmap-sdf/-/bitmap-sdf-1.0.4.tgz", - "integrity": "sha512-1G3U4n5JE6RAiALMxu0p1XmeZkTeCwGKykzsLTCqVzfSDaN6S7fKnkIkfejogz+iwqBWc0UYAIKnKHNN7pSfDg==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/bl": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz", @@ -7481,25 +7308,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/cesium": { - "version": "1.122.0", - "resolved": "https://registry.npmjs.org/cesium/-/cesium-1.122.0.tgz", - "integrity": "sha512-zHxF4QMVE9/ukhxvV/UULzytZp5uz0JVjegc+qxfhHtvN3crFbpL6/8frkVrcQ0GTjH6/LT1AcMERj/bNdVYng==", - "license": "Apache-2.0", - "optional": true, - "peer": true, - "workspaces": [ - "packages/engine", - "packages/widgets" - ], - "dependencies": { - "@cesium/engine": "^11.1.0", - "@cesium/widgets": "^8.1.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, "node_modules/chai": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", @@ -9619,14 +9427,6 @@ "domelementtype": "1" } }, - "node_modules/dompurify": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", - "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==", - "license": "(MPL-2.0 OR Apache-2.0)", - "optional": true, - "peer": true - }, "node_modules/domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", @@ -9647,14 +9447,6 @@ "tslib": "^2.0.3" } }, - "node_modules/draco3d": { - "version": "1.5.7", - "resolved": "https://registry.npmjs.org/draco3d/-/draco3d-1.5.7.tgz", - "integrity": "sha512-m6WCKt/erDXcw+70IJXnG7M3awwQPAsZvJGX5zY7beBqpELw6RDGkYVU0W43AFxye4pDZ5i2Lbyc/NNGqwjUVQ==", - "license": "Apache-2.0", - "optional": true, - "peer": true - }, "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", @@ -11938,14 +11730,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/grapheme-splitter": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", - "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", @@ -12875,13 +12659,6 @@ "node": ">= 4" } }, - "node_modules/immediate": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", - "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "license": "MIT", - "optional": true - }, "node_modules/immutable": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.7.tgz", @@ -13717,17 +13494,6 @@ "node": ">=12.0.0" } }, - "node_modules/jsep": { - "version": "1.3.9", - "resolved": "https://registry.npmjs.org/jsep/-/jsep-1.3.9.tgz", - "integrity": "sha512-i1rBX5N7VPl0eYb6+mHNp52sEuaS2Wi8CDYx1X5sn9naevL78+265XJqy1qENEk7mRKwS06NHpUqiBwR7qeodw==", - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 10.16.0" - } - }, "node_modules/jsesc": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz", @@ -14086,14 +13852,6 @@ "node": ">=0.10.0" } }, - "node_modules/kdbush": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", - "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", - "license": "ISC", - "optional": true, - "peer": true - }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -14114,14 +13872,6 @@ "node": ">=0.10.0" } }, - "node_modules/ktx-parse": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/ktx-parse/-/ktx-parse-0.7.1.tgz", - "integrity": "sha512-FeA3g56ksdFNwjXJJsc1CCc7co+AJYDp6ipIp878zZ2bU8kWROatLYf39TQEd4/XRSUvBXovQ8gaVKWPXsCLEQ==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/launch-editor": { "version": "2.9.1", "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.9.1.tgz", @@ -14152,14 +13902,6 @@ "node": ">=10.13.0" } }, - "node_modules/lerc": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/lerc/-/lerc-2.0.0.tgz", - "integrity": "sha512-7qo1Mq8ZNmaR4USHHm615nEW2lPeeWJ3bTyoqFbd35DLx0LUH7C6ptt5FDCTAlbIzs3+WKrk5SkJvw8AFDE2hg==", - "license": "Apache-2.0", - "optional": true, - "peer": true - }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -14174,16 +13916,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lie": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/lie/-/lie-3.1.1.tgz", - "integrity": "sha512-RiNhHysUjhrDQntfYSfY4MU24coXXdEOgw9WGcKHNeEwffDYbF//u87M1EWaMGzuFoSbqW0C9C6lEEhDOAswfw==", - "license": "MIT", - "optional": true, - "dependencies": { - "immediate": "~3.0.5" - } - }, "node_modules/lilconfig": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.2.tgz", @@ -14329,16 +14061,6 @@ "integrity": "sha512-JKwc6JOsmKxBZTKNA666x+7qiJpdR+XtHpKJhY7s5bR/Q/NJNDpLae/Dgx4EFC/j6YbelR3t0qEw2ZFhCdG/Cw==", "license": "MIT" }, - "node_modules/localforage": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/localforage/-/localforage-1.10.0.tgz", - "integrity": "sha512-14/H1aX7hzBBmmh7sGPd+AOMkkIrHM3Z1PAyGgZigA1H1p5O5ANnMyWzvpAETtG68/dC4pC0ncy3+PPGzXZHPg==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "lie": "3.1.1" - } - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -14546,14 +14268,6 @@ "node": ">=8.0" } }, - "node_modules/long": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", - "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==", - "license": "Apache-2.0", - "optional": true, - "peer": true - }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -14931,22 +14645,6 @@ "node": ">= 8" } }, - "node_modules/mersenne-twister": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/mersenne-twister/-/mersenne-twister-1.1.0.tgz", - "integrity": "sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA==", - "license": "MIT", - "optional": true, - "peer": true - }, - "node_modules/meshoptimizer": { - "version": "0.21.0", - "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.21.0.tgz", - "integrity": "sha512-WabtlpnK/GgD0GMwYd1fBTfYHf4MIcQPEg6dt7y4GuDcY51RzLSkSNE8ZogD7U3Vs2/fIf4z89TOLpA80EOnhg==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -15600,14 +15298,6 @@ "node": ">=0.10.0" } }, - "node_modules/nosleep.js": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/nosleep.js/-/nosleep.js-0.12.0.tgz", - "integrity": "sha512-9d1HbpKLh3sdWlhXMhU6MMH+wQzKkrgfRkYV0EBdvt99YJfj0ilCJrWRDYG2130Tm4GXbEoTCx5b34JSaP+HhA==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/now-and-later": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz", @@ -15703,17 +15393,6 @@ "url": "https://opencollective.com/openlayers" } }, - "node_modules/ol-cesium": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/ol-cesium/-/ol-cesium-2.14.0.tgz", - "integrity": "sha512-/4bAW2BMSSQUBfnhOEuIZzFamtco9OC4lvzN2lzrdoLhAaatfSW6+AJhHZcVesVWZg09uUbnlWDp3QuP3v9JGg==", - "license": "BSD-2-Clause", - "optional": true, - "peerDependencies": { - "cesium": ">= 1.62.0", - "ol": ">= 6.0.1 || 7" - } - }, "node_modules/ol-layerswitcher": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/ol-layerswitcher/-/ol-layerswitcher-4.1.2.tgz", @@ -16750,32 +16429,6 @@ "url": "https://github.com/sponsors/wooorm" } }, - "node_modules/protobufjs": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.4.0.tgz", - "integrity": "sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw==", - "hasInstallScript": true, - "license": "BSD-3-Clause", - "optional": true, - "peer": true, - "dependencies": { - "@protobufjs/aspromise": "^1.1.2", - "@protobufjs/base64": "^1.1.2", - "@protobufjs/codegen": "^2.0.4", - "@protobufjs/eventemitter": "^1.1.0", - "@protobufjs/fetch": "^1.1.0", - "@protobufjs/float": "^1.0.2", - "@protobufjs/inquire": "^1.1.0", - "@protobufjs/path": "^1.1.2", - "@protobufjs/pool": "^1.1.0", - "@protobufjs/utf8": "^1.1.0", - "@types/node": ">=13.7.0", - "long": "^5.0.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/protocol-buffers-schema": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz", @@ -19915,30 +19568,6 @@ "node": ">=0.6" } }, - "node_modules/topojson-client": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/topojson-client/-/topojson-client-3.1.0.tgz", - "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", - "license": "ISC", - "optional": true, - "peer": true, - "dependencies": { - "commander": "2" - }, - "bin": { - "topo2geo": "bin/topo2geo", - "topomerge": "bin/topomerge", - "topoquantize": "bin/topoquantize" - } - }, - "node_modules/topojson-client/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/tough-cookie": { "version": "4.1.4", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz", @@ -20406,7 +20035,7 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "devOptional": true, + "dev": true, "license": "MIT" }, "node_modules/unicorn-magic": { @@ -20573,14 +20202,6 @@ "node": ">=6" } }, - "node_modules/urijs": { - "version": "1.19.11", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.11.tgz", - "integrity": "sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==", - "license": "MIT", - "optional": true, - "peer": true - }, "node_modules/url": { "version": "0.11.4", "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", diff --git a/package.json b/package.json index 09a564e2f20d..a60e1c192f83 100644 --- a/package.json +++ b/package.json @@ -107,9 +107,7 @@ "_optionalDependenciesComment_": "Dep. for plugins", "optionalDependencies": { "jsts": "2.11.3", - "localforage": "1.10.0", - "mapillary-js": "4.1.2", - "ol-cesium": "2.14.0" + "mapillary-js": "4.1.2" }, "devDependencies": { "@chromatic-com/storybook": "2.0.2", diff --git a/src/offline/AbstractLocalforageWrapper.js b/src/offline/AbstractLocalforageWrapper.js deleted file mode 100644 index 6082cbd821e8..000000000000 --- a/src/offline/AbstractLocalforageWrapper.js +++ /dev/null @@ -1,147 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -/** - * @typedef {Object} Action - * @property {number} id - * @property {string} plugin - * @property {string} command - * @property {!*[]} args - * @property {?} context - * @property {string} [msg] - */ - -/** - * @abstract - */ -const exports = class AbstractLocalforageWrapper { - constructor() { - this.waitingPromises_ = new Map(); - this.currentId_ = 0; - } - - /** - * @param {...unknown} args Some arguments. - * @returns {Promise} - */ - setItem(...args) { - return this.createAction('setItem', ...args); - } - - /** - * @param {...unknown} args Some arguments. - * @returns {Promise} - */ - getItem(...args) { - return this.createAction('getItem', ...args); - } - - /** - * @returns {Promise} - */ - clear() { - return this.createAction('clear'); - } - - /** - * @param {...unknown} args Some arguments. - * @returns {Promise} - */ - config(...args) { - return this.createAction('config', ...args); - } - - /** - * @export - * @param {string} command . - * @param {...unknown} args . - * @returns {Promise} . - */ - createAction(command, ...args) { - const id = ++this.currentId_; - /** - * @type {Action} - */ - const action = { - plugin: 'localforage', - command: command, - args: args, - id: id, - context: null, - }; - const waitingPromise = { - /** - * @param {any} _any - */ - resolve(_any) {}, - /** - * @param {any} _any - */ - reject(_any) {}, - }; - const promise = new Promise((resolve, reject) => { - waitingPromise.resolve = resolve; - waitingPromise.reject = reject; - }); - this.waitingPromises_.set(id, waitingPromise); - this.postToBackend(action); - return promise; - } - - /** - * @export - * @param {*} event . - */ - receiveMessage(event) { - /** - * @type {Action} - */ - const action = event.data; - const id = action.id; - const command = action.command; - const args = action.args || []; - const context = action.context; - const msg = action.msg; - - const waitingPromise = this.waitingPromises_.get(id); - if (command === 'error') { - console.error(msg, args, context); - if (waitingPromise) { - waitingPromise.reject(args, context); - this.waitingPromises_.delete(id); - } - } else if (command === 'response') { - waitingPromise.resolve(...args); - this.waitingPromises_.delete(id); - } else { - console.error('Unhandled command', JSON.stringify(action, null, '\t')); - } - } - - /** - * @abstract - * @protected - * @param {Action} action . - */ - postToBackend(action) {} -}; - -export default exports; diff --git a/src/offline/Configuration.js b/src/offline/Configuration.js deleted file mode 100644 index f27709e45805..000000000000 --- a/src/offline/Configuration.js +++ /dev/null @@ -1,398 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import olObservable from 'ol/Observable'; -import olLayerLayer from 'ol/layer/Layer'; -import olLayerVector from 'ol/layer/Vector'; -import olLayerTile from 'ol/layer/WebGLTile'; -import olLayerImage from 'ol/layer/Image'; -import * as olProj from 'ol/proj'; -import {defaultImageLoadFunction} from 'ol/source/Image'; -import olSourceImageWMS from 'ol/source/ImageWMS'; -import olSourceTileWMS from 'ol/source/TileWMS'; -import {createForProjection as createTileGridForProjection} from 'ol/tilegrid'; -import SerializerDeserializer from 'ngeo/offline/SerializerDeserializer'; -import LocalforageCordovaWrapper from 'ngeo/offline/LocalforageCordovaWrapper'; -import LocalforageAndroidWrapper from 'ngeo/offline/LocalforageAndroidWrapper'; -import LocalforageIosWrapper from 'ngeo/offline/LocalforageIosWrapper'; -import ngeoCustomEvent from 'ngeo/CustomEvent'; -import {normalizeURL, traverseLayer} from 'ngeo/offline/utils'; -// @ts-ignore -import localforage from 'localforage/src/localforage'; - -/** - * implements {import('ngeo/offline/index').OfflineOnTileDownload} - */ -export default class _ngInjectAnonymousClass extends olObservable { - /** - * @param {!angular.IScope} $rootScope The rootScope provider. - * @param {!import('ngeo/map/BackgroundLayerMgr').MapBackgroundLayerManager} ngeoBackgroundLayerMgr - * Background layer manager. - * @param {number} ngeoOfflineGutter A gutter around the tiles to download (to avoid cut symbols) - */ - constructor($rootScope, ngeoBackgroundLayerMgr, ngeoOfflineGutter) { - super(); - this.localforage_ = this.createLocalforage(); - this.configureLocalforage(); - - /** - * @private - * @type {!angular.IScope} - */ - this.rootScope_ = $rootScope; - - /** - * @protected - * @type {boolean} - */ - this.hasData = false; - this.initializeHasOfflineData(); - - /** - * @private - * @type {!import('ngeo/map/BackgroundLayerMgr').MapBackgroundLayerManager} - */ - this.ngeoBackgroundLayerMgr_ = ngeoBackgroundLayerMgr; - - /** - * @private - * @type {SerializerDeserializer} - */ - // @ts-ignore - this.serDes_ = new SerializerDeserializer({ - gutter: ngeoOfflineGutter, - }); - - /** - * @private - * @type {number} - */ - this.gutter_ = ngeoOfflineGutter; - } - - /** - * @private - * @param {number} progress new progress. - */ - dispatchProgress_(progress) { - this.dispatchEvent( - new ngeoCustomEvent('progress', { - 'progress': progress, - }), - ); - } - - /** - * @protected - */ - initializeHasOfflineData() { - this.getItem('offline_content').then((value) => this.setHasOfflineData(!!value)); - } - - /** - * @export - * @returns {boolean} whether some offline data is available in the storage - */ - hasOfflineData() { - return this.hasData; - } - - /** - * @param {boolean} value whether there is offline data available in the storage. - */ - setHasOfflineData(value) { - const needDigest = value !== this.hasData; - this.hasData = value; - if (needDigest) { - this.rootScope_.$applyAsync(); // force update of the UI - } - } - - /** - * Hook to allow measuring get/set item performance. - * - * @param {string} msg A message - * @param {string} key The key to work on - * @param {Promise} promise A promise - * @returns {Promise} The promise we passed - */ - traceGetSetItem(msg, key, promise) { - return promise; - } - createLocalforage() { - if (location.search.includes('localforage=cordova')) { - console.log('Using cordova localforage'); - return new LocalforageCordovaWrapper(); - } else if (location.search.includes('localforage=android')) { - console.log('Using android localforage'); - return new LocalforageAndroidWrapper(); - } else if (location.search.includes('localforage=ios')) { - console.log('Using ios localforage'); - return new LocalforageIosWrapper(); - } - return localforage; - } - configureLocalforage() { - this.localforage_.config({ - 'name': 'ngeoOfflineStorage', - 'version': 1.0, - 'storeName': 'offlineStorage', - }); - } - - /** - * @param {string} key The key - * @returns {Promise} A promise - */ - getItem(key) { - const promise = this.localforage_['getItem'](key); - return this.traceGetSetItem('getItem', key, promise); - } - - /** - * @param {string} key . - * @returns {Promise} . - */ - removeItem(key) { - const promise = this.localforage_['removeItem'](key); - return this.traceGetSetItem('removeItem', key, promise); - } - - /** - * @param {string} key The key - * @param {*} value A value - * @returns {Promise} A promise - */ - setItem(key, value) { - const promise = this.localforage_['setItem'](key, value); - return this.traceGetSetItem('setItem', key, promise); - } - - /** - * @returns {Promise} A promise - */ - clear() { - this.setHasOfflineData(false); - const promise = this.localforage_.clear(); - return this.traceGetSetItem('clear', '', promise); - } - - /** - * @param {!import('ol/Map').default} map A map - * @returns {number} An "estimation" of the size of the data to download - */ - estimateLoadDataSize(map) { - return 50; - } - - /** - * @param {import('./index').OfflineLayerMetadata} layerItem The layer metadata - * @returns {string} A key identifying an offline layer and used during restore. - */ - getLayerKey(layerItem) { - return /** @type {string} */ layerItem.layer.get('label'); - } - - /** - * @param {number} progress The download progress - * @param {import('./index').OfflineTile} tile The tile - * @returns {Promise} A promise - */ - onTileDownloadSuccess(progress, tile) { - this.dispatchProgress_(progress); - if (tile.response) { - return this.setItem(normalizeURL(tile.url), tile.response); - } - return Promise.resolve(); - } - - /** - * @param {number} progress The progress - * @returns {Promise} A promise - */ - onTileDownloadError(progress) { - this.dispatchProgress_(progress); - return Promise.resolve(); - } - - /** - * @param {import('ol/Map').default} map A map - * @param {import('ol/layer/Layer').default} layer A layer - * @param {import('ol/layer/Group').default[]} ancestors The ancestors of that layer - * @param {import('ol/extent').Extent} userExtent The extent selected by the user. - * @returns {import('./index').OfflineExtentByZoom[]} The extent to download per zoom level - */ - getExtentByZoom(map, layer, ancestors, userExtent) { - const currentZoom = map.getView().getZoom(); - if (currentZoom === undefined) { - throw new Error('Missing currentZoom'); - } - /** - * @type {import('./index').OfflineExtentByZoom[]} - */ - const results = []; - [0, 1, 2, 3, 4].forEach((dz) => { - results.push({ - zoom: currentZoom + dz, - extent: userExtent, - }); - }); - return results; - } - - /** - * @protected - * @param {import('ol/source/Source').default} source An ImageWMS source - * @param {!import('ol/proj/Projection').default} projection The projection - * @returns {import('ol/source/Source').default} A tiled equivalent source - */ - sourceImageWMSToTileWMS(source, projection) { - if ( - source instanceof olSourceImageWMS && - source.getUrl() && - source.getImageLoadFunction() === defaultImageLoadFunction - ) { - const tileGrid = createTileGridForProjection(source.getProjection() || projection, 42, 256); - const attributions = source.getAttributions() || ''; - const url = source.getUrl(); - if (!url || !attributions) { - throw new Error('Invalid values'); - } - source = new olSourceTileWMS({ - gutter: this.gutter_, - url, - tileGrid, - attributions, - projection: source.getProjection(), - params: source.getParams(), - }); - } - return source; - } - - /** - * @param {import('ol/Map').default} map The map to work on. - * @param {import('ol/extent').Extent} userExtent The extent selected by the user. - * @returns {!import('./index').OfflineLayerMetadata[]} the downloadable layers and metadata. - */ - createLayerMetadatas(map, userExtent) { - /** - * @type {import('./index').OfflineLayerMetadata[]} - */ - const layersItems = []; - - /** - * @param {import('ol/layer/Base').default} layer . - * @param {import('ol/layer/Group').default[]} ancestors . - * @returns {boolean} whether to traverse this layer children. - */ - const visitLayer = (layer, ancestors) => { - if (layer instanceof olLayerLayer) { - const extentByZoom = this.getExtentByZoom(map, layer, ancestors, userExtent); - const projection = olProj.get(map.getView().getProjection()); - const source = this.sourceImageWMSToTileWMS(layer.getSource(), projection); - /** - * @type {string|undefined} - */ - let layerType; - /** - * @type {string|undefined} - */ - let layerSerialization; - if (layer instanceof olLayerTile || layer instanceof olLayerImage) { - layerType = 'tile'; - // @ts-ignore - layerSerialization = this.serDes_.serializeTileLayer(layer, source); - } else if (layer instanceof olLayerVector) { - layerType = 'vector'; - } - const backgroundLayer = this.ngeoBackgroundLayerMgr_.get(map) === layer; - layersItems.push({ - backgroundLayer, - map, - extentByZoom, - layerType, - layerSerialization, - layer, - source, - ancestors, - }); - } - return true; - }; - map.getLayers().forEach((root) => { - traverseLayer(root, [], visitLayer); - }); - return layersItems; - } - - /** - * @private - * @param {import('./index').OfflinePersistentLayer} offlineLayer The offline layer - * @returns {function(import('ol/ImageTile').default, string)} the tile function - */ - createTileLoadFunction_(offlineLayer) { - /** - * Load the tile from persistent storage. - * - * @param {import('ol/ImageTile').default} imageTile The image tile - * @param {string} src The tile URL - */ - const tileLoadFunction = (imageTile, src) => { - this.getItem(normalizeURL(src)).then((content) => { - if (!content) { - // use a transparent 1x1 image to make the map consistent - /* eslint-disable-next-line */ - content = - 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVR42mNkYAAAAAYAAjCB0C8AAAAASUVORK5CYII='; - } - /** @type {HTMLImageElement} */ - imageTile.getImage().src = content; - }); - }; - return tileLoadFunction; - } - - /** - * @param {import('./index').OfflinePersistentLayer} offlineLayer The layer to recreate - * @returns {?import('ol/layer/Layer').default} the layer. - */ - recreateOfflineLayer(offlineLayer) { - if (offlineLayer.layerType === 'tile') { - const serialization = offlineLayer.layerSerialization; - if (serialization) { - const tileLoadFunction = this.createTileLoadFunction_(offlineLayer); - // @ts-ignore - const layer = this.serDes_.deserializeTileLayer(serialization, tileLoadFunction); - return layer; - } - } - return null; - } - - /** - * @returns {number} The number - */ - getMaxNumberOfParallelDownloads() { - return 11; - } -} -_ngInjectAnonymousClass.$inject = ['$rootScope', 'ngeoBackgroundLayerMgr', 'ngeoOfflineGutter']; diff --git a/src/offline/Downloader.js b/src/offline/Downloader.js deleted file mode 100644 index c0d01bcbca65..000000000000 --- a/src/offline/Downloader.js +++ /dev/null @@ -1,196 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import {DEVICE_PIXEL_RATIO} from 'ol/has'; -import olSourceTileWMS from 'ol/source/TileWMS'; -import olSourceWMTS from 'ol/source/WMTS'; -import TilesDownloader from 'ngeo/offline/TilesDownloader'; -import angular from 'angular'; - -/** - * @param {import('ol/coordinate').Coordinate} a Some coordinates. - * @param {import('ol/coordinate').Coordinate} b Some other coordinates. - * @returns {number} The squared magnitude. - */ -function magnitude2(a, b) { - let magnitudeSquared = 0; - for (let i = 0; i < a.length; ++i) { - magnitudeSquared += Math.pow(a[i] - b[i], 2); - } - return magnitudeSquared; -} -const Downloader = class { - /** - * @param {import('ngeo/offline/Configuration').default} ngeoOfflineConfiguration - * A service for customizing offline behavior. - */ - constructor(ngeoOfflineConfiguration) { - /** - * @private - * @type {import('ngeo/offline/Configuration').default} - */ - this.configuration_ = ngeoOfflineConfiguration; - - /** - * @type {?TilesDownloader} - * @private - */ - this.tileDownloader_ = null; - } - cancel() { - if (this.tileDownloader_) { - this.tileDownloader_.cancel(); - } - } - - /** - * @param {import('./index').OfflineLayerMetadata} layerMetadata Layers metadata. - * @param {import('./index').OfflineTile[]} queue Queue of tiles to download. - */ - queueLayerTiles_(layerMetadata, queue) { - const source = /** @type {olSourceTileWMS|olSourceWMTS} */ layerMetadata.source; - const {map, extentByZoom} = layerMetadata; - if (!source) { - return; - } - console.assert(source instanceof olSourceTileWMS || source instanceof olSourceWMTS); - const projection = map.getView().getProjection(); - const tileGrid = source.getTileGrid(); - const tileUrlFunction = source.getTileUrlFunction(); - console.assert(extentByZoom); - for (const extentZoom of extentByZoom) { - const z = extentZoom.zoom; - const extent = extentZoom.extent; - /** - * @type {import('./index').OfflineTile[]} - */ - const queueByZ = []; - /** - * @type {number} - */ - let minX; - /** - * @type {number} - */ - let minY; - /** - * @type {number} - */ - let maxX; - /** - * @type {number} - */ - let maxY; - tileGrid.forEachTileCoord(extent, z, (coord) => { - maxX = coord[1]; - maxY = coord[2]; - if (minX === undefined || minY === undefined) { - minX = coord[1]; - minY = coord[2]; - } - const url = tileUrlFunction(coord, DEVICE_PIXEL_RATIO, projection); - console.assert(url); - if (url) { - /** - * @type {import('./index').OfflineTile} - */ - const tile = { - coord, - url, - response: null, - }; - queueByZ.push(tile); - } - }); - const centerTileCoord = [z, (minX + maxX) / 2, (minY + maxY) / 2]; - queueByZ.sort((a, b) => magnitude2(a.coord, centerTileCoord) - magnitude2(b.coord, centerTileCoord)); - queue.push(...queueByZ); - } - } - - /** - * @param {import('ol/extent').Extent} extent The extent to download. - * @param {import('ol/Map').default} map The map to work on. - * @returns {Promise<*>} A promise resolving when save is finished. - */ - save(extent, map) { - /** - * @type {!import('./index').OfflineLayerMetadata[]} - */ - const layersMetadatas = this.configuration_.createLayerMetadatas(map, extent); - - /** - * @type {!import('./index').OfflinePersistentLayer[]} - */ - const persistentLayers = []; - /** - * @type {import('./index').OfflineTile[]} - */ - const queue = []; - /** - * @type {number[]} - */ - const zooms = []; - for (const layerItem of layersMetadatas) { - if (layerItem.layerType === 'tile') { - /** - * @type {import('./index').OfflineTile[]} - */ - const tiles = []; - this.queueLayerTiles_(layerItem, tiles); - queue.push(...tiles); - } - persistentLayers.push({ - backgroundLayer: layerItem.backgroundLayer, - layerType: layerItem.layerType, - layerSerialization: layerItem.layerSerialization, - key: this.configuration_.getLayerKey(layerItem), - }); - layerItem.extentByZoom.forEach((obj) => { - const zoom = obj.zoom; - if (!zooms.includes(zoom)) { - zooms.push(zoom); - } - }); - } - - /** - * @type {import('./index').OfflinePersistentContent} - */ - const persistentObject = { - extent: extent, - layers: persistentLayers, - zooms: zooms.sort((a, b) => (a < b ? -1 : 1)), - }; - const setOfflineContentPromise = this.configuration_.setItem('offline_content', persistentObject); - const maxDownloads = this.configuration_.getMaxNumberOfParallelDownloads(); - this.tileDownloader_ = new TilesDownloader(queue, this.configuration_, maxDownloads); - const tileDownloadPromise = this.tileDownloader_.download(); - const allPromise = Promise.all([setOfflineContentPromise, tileDownloadPromise]); - const setHasOfflineData = () => this.configuration_.setHasOfflineData(true); - allPromise.then(setHasOfflineData, setHasOfflineData); - return allPromise; - } -}; -const name = 'offlineDownloader'; -Downloader.module = angular.module(name, []).service(name, Downloader); -const exports = Downloader; -export default exports; diff --git a/src/offline/LocalforageAndroidWrapper.js b/src/offline/LocalforageAndroidWrapper.js deleted file mode 100644 index 626480c9c95b..000000000000 --- a/src/offline/LocalforageAndroidWrapper.js +++ /dev/null @@ -1,53 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import AbstractWrapper from 'ngeo/offline/AbstractLocalforageWrapper'; - -const exports = class AndroidWrapper extends AbstractWrapper { - constructor() { - super(); - // @ts-ignore - window.androidWrapper = this; - } - - /** - * @param {unknown} action - * @override - */ - postToBackend(action) { - const stringified = JSON.stringify(action); - // @ts-ignore - window.ngeoHost.postMessageToAndroid(stringified); - } - - /** - * @export - * @param {string} actionString . - */ - receiveFromAndroid(actionString) { - const action = JSON.parse(actionString); - this.receiveMessage({ - 'data': action, - }); - } -}; - -export default exports; diff --git a/src/offline/LocalforageCordovaWrapper.js b/src/offline/LocalforageCordovaWrapper.js deleted file mode 100644 index a4ac026877c2..000000000000 --- a/src/offline/LocalforageCordovaWrapper.js +++ /dev/null @@ -1,39 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import AbstractWrapper from 'ngeo/offline/AbstractLocalforageWrapper'; - -const exports = class CordovaWrapper extends AbstractWrapper { - constructor() { - super(); - window.addEventListener('message', this.receiveMessage.bind(this), false); - } - - /** - * @param {unknown} action - * @override - */ - postToBackend(action) { - window.parent.postMessage(action, '*'); - } -}; - -export default exports; diff --git a/src/offline/LocalforageIosWrapper.js b/src/offline/LocalforageIosWrapper.js deleted file mode 100644 index 83838bb15a7a..000000000000 --- a/src/offline/LocalforageIosWrapper.js +++ /dev/null @@ -1,66 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import AbstractWrapper from 'ngeo/offline/AbstractLocalforageWrapper'; - -/** - * @typedef {Object} Action - * @property {string} command - * @property {string[]} args - */ -const exports = class IosWrapper extends AbstractWrapper { - constructor() { - super(); - // @ts-ignore - window.iosWrapper = this; - } - - /** - * @param {Action} action - * @override - */ - postToBackend(action) { - if (action.command === 'setItem') { - action.args[1] = JSON.stringify(action.args[1]); - } - const stringified = JSON.stringify(action); - // @ts-ignore - window.webkit.messageHandlers.ios.postMessage(stringified); - } - - /** - * @export - * @param {string} actionString . - */ - receiveFromIos(actionString) { - const action = JSON.parse(actionString); - /** - * @type {string[]} - */ - const args = action['args'] || []; - action['args'] = args.map((item) => JSON.parse(item)); - this.receiveMessage({ - 'data': action, - }); - } -}; - -export default exports; diff --git a/src/offline/Mask.js b/src/offline/Mask.js deleted file mode 100644 index 4d891dec5fbd..000000000000 --- a/src/offline/Mask.js +++ /dev/null @@ -1,109 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import Layer from 'ol/layer/Layer'; -import {createCanvasContext2D} from 'ol/dom'; -import {DEVICE_PIXEL_RATIO} from 'ol/has'; - -/** - * @typedef {Object} Options - * @property {number} [margin] - * @property {number} [extentInMeters] - */ - -/** - * @augments {Layer} - */ -export default class Mask extends Layer { - /** - * @param {import('ol/layer/Layer').Options} layerOptions - * @param {Options} maskOptions - */ - constructor(layerOptions = {}, maskOptions = {}) { - super(layerOptions); - - /** - * @private - */ - this.context_ = createCanvasContext2D(); - - this.context_.canvas.style.opacity = '0.5'; - this.context_.canvas.style.position = 'absolute'; - - this.margin_ = maskOptions.margin || 100; - this.extentInMeters_ = maskOptions.extentInMeters || 0; - } - - /** - * @param {import('ol/coordinate').Coordinate} center center, a xy point. - * @param {number} halfLength a half length of a square's side. - * @returns {import('ol/extent').Extent} an extent. - */ - createExtent(center, halfLength) { - const minx = center[0] - halfLength; - const miny = center[1] - halfLength; - const maxx = center[0] + halfLength; - const maxy = center[1] + halfLength; - return [minx, miny, maxx, maxy]; - } - - /** - * @param {import("ol/Map").FrameState} frameState - * @returns {HTMLElement} - */ - render(frameState) { - const context = this.context_; - const cwidth = frameState.size[0]; - context.canvas.width = cwidth; - const cheight = frameState.size[1]; - context.canvas.height = cheight; - - // background (clockwise) - context.beginPath(); - context.moveTo(0, 0); - context.lineTo(cwidth, 0); - context.lineTo(cwidth, cheight); - context.lineTo(0, cheight); - context.lineTo(0, 0); - context.closePath(); - - let extentLength = Math.min(cwidth, cheight) - this.margin_ * 2; - if (this.extentInMeters_) { - extentLength = (DEVICE_PIXEL_RATIO * this.extentInMeters_) / frameState.viewState.resolution; - } - - // Draw the get data zone - const extent = this.createExtent([cwidth / 2, cheight / 2], Math.ceil(extentLength / 2)); - - context.moveTo(extent[0], extent[1]); - context.lineTo(extent[0], extent[3]); - context.lineTo(extent[2], extent[3]); - context.lineTo(extent[2], extent[1]); - context.lineTo(extent[0], extent[1]); - context.closePath(); - - // Fill the mask - context.fillStyle = 'rgba(0, 5, 25, 0.5)'; - context.fill(); - - return context.canvas; - } -} diff --git a/src/offline/Mode.js b/src/offline/Mode.js deleted file mode 100644 index 29f46e5b0229..000000000000 --- a/src/offline/Mode.js +++ /dev/null @@ -1,107 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import angular from 'angular'; -class Mode { - /** - * @param {import('ngeo/offline/Configuration').default} ngeoOfflineConfiguration - * ngeo offline configuration service. - * @ngdoc service - * @ngname ngeoOfflineState - */ - constructor(ngeoOfflineConfiguration) { - /** - * Offline mode is enabled or not. - * - * @type {boolean} - * @private - */ - this.enabled_ = false; - - /** - * Offline component. - * - * @type {?import('ngeo/offline/component').Controller} - * @private - */ - this.component_ = null; - - /** - * @private - * @type {import('ngeo/offline/Configuration').default} - */ - this.ngeoOfflineConfiguration_ = ngeoOfflineConfiguration; - } - - /** - * Return if we are in offline mode. - * - * @returns {boolean} whether offline mode is enabled - * @export - */ - isEnabled() { - return this.enabled_; - } - - /** - * Enable offline mode. ATM we cannot escape from the offline mode. - * - * @export - */ - enable() { - this.enabled_ = true; - } - - /** - * - * @param {import('ngeo/offline/component').Controller} component Offline component. - * @export - */ - registerComponent(component) { - this.component_ = component; - } - - /** - * @export - */ - activateOfflineMode() { - if (!this.component_) { - throw new Error('The component is not registered'); - } - this.component_.activateOfflineMode(); - } - - /** - * @returns {boolean} True if data are accessible offline. - * @export - */ - hasData() { - return this.ngeoOfflineConfiguration_.hasOfflineData(); - } -} -Mode.$inject = ['ngeoOfflineConfiguration']; -/** - * @type {!angular.IModule} - */ -const myModule = angular.module('ngeoOfflineMode', []); -myModule.service('ngeoOfflineMode', Mode); -Mode.module = myModule; -export default Mode; diff --git a/src/offline/NetworkStatus.js b/src/offline/NetworkStatus.js deleted file mode 100644 index 2610409b0eac..000000000000 --- a/src/offline/NetworkStatus.js +++ /dev/null @@ -1,224 +0,0 @@ -configFunction_.$inject = ['$httpProvider']; -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import ngeoMiscDebounce from 'ngeo/misc/debounce'; -import angular from 'angular'; -const Service = class { - /** - * This service watches the status of network connection. - * - * Currently it watches every $http and $.ajax requests errors, if an error - * occurs we wait 2 sec then we make an http request on the checker file. - * If the checker responds that means we are online, otherwise we make a - * 2nd request 2 sec later, if the 2nd requests failed that means we - * are offline. - * - * A timeout of 1 sec is set for the checker file, so if we have a bad - * connection, we consider we are offline. - * - * During offline mode we test every 2 sec if we are back online. - * - * @param {!jQuery} $document Angular document service. - * @param {angular.IWindowService} $window Angular window service. - * @param {angular.ITimeoutService} $timeout Angular timeout service. - * @param {angular.IScope} $rootScope The root scope. - * @param {import('ngeo/options').ngeoOfflineTestUrl} ngeoOfflineTestUrl URL of the test page. - */ - constructor($document, $window, $timeout, $rootScope, ngeoOfflineTestUrl) { - /** - * @private - * @type {!jQuery} - */ - this.$document_ = $document; - - /** - * @private - * @type {!Window} - */ - this.$window_ = $window; - - /** - * @private - * @type {!angular.ITimeoutService} - */ - this.$timeout_ = $timeout; - - /** - * @private - * @type {angular.IScope} - */ - this.$rootScope_ = $rootScope; - - /** - * @private - * @type {import('ngeo/options').ngeoOfflineTestUrl} - */ - this.ngeoOfflineTestUrl_ = ngeoOfflineTestUrl; - - /** - * @private - * @type {!number} - */ - this.count_ = 0; - - /** - * @type {!boolean|undefined} - * @private - */ - this.offline_; - - /** - * @private - * @type {angular.IPromise|undefined} - */ - this.promise_; - this.initialize_(); - } - initialize_() { - this.offline_ = !this.$window_.navigator.onLine; - - // airplane mode, works offline(firefox) - this.$window_.addEventListener('offline', () => { - this.triggerChangeStatusEvent_(true); - }); - - // online event doesn't means we have a internet connection, that means we - // have possibly one (connected to a router ...) - this.$window_.addEventListener('online', () => { - this.check(undefined); - }); - - // We catch every $.ajax request errors or (canceled request). - // @ts-ignore - if (this.$document_.ajaxError) { - /** - * @param {unknown} evt - * @param {unknown} jqxhr - * @param {unknown} settings - * @param {string} thrownError - */ - const onAjaxError = (evt, jqxhr, settings, thrownError) => { - // Filter out canceled requests - if (!/^(canceled|abort)$/.test(thrownError)) { - this.check(2000); - } - }; - // @ts-ignore - this.$document_.ajaxError(onAjaxError); - } - } - - /** - * Check fir network status - * - * @param {number} [timeout] Delay for timeout. - */ - check(timeout) { - if (this.promise_) { - this.$timeout_.cancel(this.promise_); - this.promise_ = undefined; - } - if (timeout !== undefined) { - this.count_++; - this.promise_ = this.$timeout_(() => this.check(), timeout); - return; - } - $.ajax({ - method: 'GET', - url: this.ngeoOfflineTestUrl_, - timeout: 1000, - success: () => { - this.count_ = 0; - if (this.offline_) { - this.triggerChangeStatusEvent_(false); - } - }, - error: () => { - this.count_++; - // We consider we are offline after 3 requests failed - if (this.count_ > 2 && !this.offline_) { - this.triggerChangeStatusEvent_(true); - } - }, - }); - } - - /** - * @param {boolean} offline whether it's offline or not. - * @private - */ - triggerChangeStatusEvent_(offline) { - this.offline_ = offline; - // this.$rootScope_.$broadcast('ngeoNetworkStatusChange', net.offline); - this.$rootScope_.$digest(); - } - - /** - * @returns {boolean} True if we are disconnected. - * @export - */ - isDisconnected() { - return !!this.offline_; - } -}; -const name = 'ngeoNetworkStatus'; -Service.module = angular.module(name, [ngeoMiscDebounce.name]); -Service.module.service(name, Service); - -/** - * @param {angular.IQService} $q The Angular $q service. - * @param {import('ngeo/misc/debounce').miscDebounce} ngeoDebounce ngeo debounce service. - * @param {Service} ngeoNetworkStatus ngeo network status service. - * @returns {angular.IHttpInterceptor} the interceptor - */ -const httpInterceptor = function ($q, ngeoDebounce, ngeoNetworkStatus) { - const debouncedCheck = ngeoDebounce(() => ngeoNetworkStatus.check(undefined), 2000, false); - return { - request(config) { - return config; - }, - requestError(rejection) { - return $q.reject(rejection); - }, - response(response) { - return response; - }, - responseError(rejection) { - debouncedCheck(); - return $q.reject(rejection); - }, - }; -}; -httpInterceptor.$inject = ['$q', 'ngeoDebounce', 'ngeoNetworkStatus']; -httpInterceptor.$inject = ['$q', 'ngeoDebounce', 'ngeoNetworkStatus']; -Service.module.factory('httpInterceptor', httpInterceptor); - -/** - * @private - * @param {angular.IHttpProvider} $httpProvider . - */ -function configFunction_($httpProvider) { - $httpProvider.interceptors.push('httpInterceptor'); -} -Service.module.config(configFunction_); -const exports = Service; -export default exports; diff --git a/src/offline/Restorer.js b/src/offline/Restorer.js deleted file mode 100644 index e93aa2124b18..000000000000 --- a/src/offline/Restorer.js +++ /dev/null @@ -1,79 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import ngeoMapBackgroundLayerMgr from 'ngeo/map/BackgroundLayerMgr'; -import angular from 'angular'; -class Restorer { - /** - * @param {import('ngeo/offline/Configuration').default} ngeoOfflineConfiguration - * A service for customizing offline behavior. - * @param {import('ngeo/map/BackgroundLayerMgr').MapBackgroundLayerManager} ngeoBackgroundLayerMgr - * The background layer manager. - */ - constructor(ngeoOfflineConfiguration, ngeoBackgroundLayerMgr) { - /** - * @private - * @type {import('ngeo/offline/Configuration').default} - */ - this.configuration_ = ngeoOfflineConfiguration; - - /** - * @private - * @type {import('ngeo/map/BackgroundLayerMgr').MapBackgroundLayerManager} - */ - this.ngeoBackgroundLayerMgr_ = ngeoBackgroundLayerMgr; - } - - /** - * @param {import('ol/Map').default} map The map to work on. - * @returns {Promise} A promise to the extent of the restored area. - */ - restore(map) { - return this.configuration_ - .getItem('offline_content') - .then((offlineContent) => this.doRestore(map, offlineContent)); - } - - /** - * @protected - * @param {import('ol/Map').default} map A map - * @param {import('./index').OfflinePersistentContent} offlineContent The offline content - * @returns {import('ol/extent').Extent} The extent of the restored area - */ - doRestore(map, offlineContent) { - map.getLayerGroup().getLayers().clear(); - for (const offlineLayer of offlineContent.layers) { - const layer = this.configuration_.recreateOfflineLayer(offlineLayer); - if (layer) { - map.addLayer(layer); - if (offlineLayer.backgroundLayer) { - this.ngeoBackgroundLayerMgr_.set(map, layer); - } - } - } - return offlineContent.extent; - } -} -Restorer.$inject = ['ngeoOfflineConfiguration', 'ngeoBackgroundLayerMgr']; -const name = 'ngeoOfflineRestorer'; -Restorer.module = angular.module(name, [ngeoMapBackgroundLayerMgr.name]).service(name, Restorer); -const exports = Restorer; -export default exports; diff --git a/src/offline/SerializerDeserializer.js b/src/offline/SerializerDeserializer.js deleted file mode 100644 index 0ef2927c3525..000000000000 --- a/src/offline/SerializerDeserializer.js +++ /dev/null @@ -1,271 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import OlTilegridTileGrid from 'ol/tilegrid/TileGrid'; -import OlTilegridWMTS from 'ol/tilegrid/WMTS'; -import * as olProj from 'ol/proj'; -import OlSourceTileWMS from 'ol/source/TileWMS'; -import OlSourceWMTS from 'ol/source/WMTS'; -import OlLayerTile from 'ol/layer/WebGLTile'; - -const SerDes = class { - /** - * @param {unknown} options The options - */ - // @ts-ignore - constructor({gutter}) { - /** - * @private - */ - this.gutter_ = gutter; - } - - /** - * @private - * @param {import('ol/Object').default} olObject An OL object - * @returns {Object} The serializable properties of the object - */ - createBaseObject_(olObject) { - const properties = olObject.getProperties(); - /** - * @type {Object} - */ - const obj = {}; - for (const key in properties) { - const value = properties[key]; - const typeOf = typeof value; - if (typeOf === 'string' || typeOf === 'number') { - obj[key] = value; - } - } - return obj; - } - - /** - * @param {OlTilegridTileGrid} tilegrid . - * @returns {string} . - */ - serializeTilegrid(tilegrid) { - /** - * @type {Object} - */ - const obj = {}; - obj.extent = tilegrid.getExtent(); - obj.minZoom = tilegrid.getMinZoom(); - obj.origin = tilegrid.getOrigin(0); // hack - obj.resolutions = tilegrid.getResolutions(); - obj.tileSize = tilegrid.getTileSize(tilegrid.getMinZoom()); - return JSON.stringify(obj); - } - - /** - * @param {string} serialization . - * @returns {OlTilegridTileGrid} tilegrid - */ - deserializeTilegrid(serialization) { - /** - * @type {import ("ol/tilegrid/WMTS").Options} - */ - const options = JSON.parse(serialization); - return new OlTilegridTileGrid(options); - } - - /** - * @param {OlTilegridWMTS} tilegrid . - * @returns {string|undefined} . - */ - serializeTilegridWMTS(tilegrid) { - if (!tilegrid) { - return undefined; - } - /** - * @type {{ - * 'extent': import('ol/extent').Extent, - * 'minZoom': number, - * 'matrixIds': string[], - * 'resolutions': number[], - * 'origins': import('ol/coordinate').Coordinate[], - * }} - */ - const obj = {}; - const resolutions = tilegrid.getResolutions(); - obj.extent = tilegrid.getExtent(); - obj.minZoom = tilegrid.getMinZoom(); - obj.matrixIds = tilegrid.getMatrixIds(); - obj.resolutions = resolutions; - - obj.origins = []; - for (let z = 0; z < resolutions.length; ++z) { - obj.origins.push(tilegrid.getOrigin(z)); - } - return JSON.stringify(obj); - } - - /** - * @param {string} serialization . - * @returns {OlTilegridWMTS} tilegrid . - */ - deserializeTilegridWMTS(serialization) { - /** - * @type {import ("ol/tilegrid/WMTS").Options} - */ - const options = JSON.parse(serialization); - return new OlTilegridWMTS(options); - } - - /** - * @param {OlSourceTileWMS} source . - * @returns {string} . - */ - serializeSourceTileWMS(source) { - const obj = this.createBaseObject_(source); - obj.params = source.getParams(); - obj.urls = source.getUrls(); - obj.tileGrid = this.serializeTilegrid(source.getTileGrid()); - const projection = source.getProjection(); - if (projection) { - obj.projection = olProj.get(source.getProjection()).getCode(); - } - - return JSON.stringify(obj); - } - - /** - * @param {string} serialization . - * @param {function(import('ol/ImageTile').default, string): void} [tileLoadFunction] . - * @returns {OlSourceTileWMS} source . - */ - deserializeSourceTileWMS(serialization, tileLoadFunction) { - /** - * @type {import ("ol/source/TileWMS").Options} - */ - const options = JSON.parse(serialization); - // @ts-ignore - options.tileLoadFunction = tileLoadFunction; - if (options.tileGrid) { - options.tileGrid = this.deserializeTilegrid(/** @type {any} */ (options).tileGrid); - } - options.gutter = this.gutter_; - return new OlSourceTileWMS(options); - } - - /** - * @param {OlSourceWMTS} source . - * @returns {string} . - */ - serializeSourceWMTS(source) { - const obj = this.createBaseObject_(source); - obj.dimensions = source.getDimensions(); - obj.format = source.getFormat(); - obj.urls = source.getUrls(); - obj.version = source.getVersion(); - obj.layer = source.getLayer(); - obj.style = source.getStyle(); - obj.matrixSet = source.getMatrixSet(); - // The OL getTileGrid method is expected to return a WMTS tilegrid so it is OK to cast here. - const tileGridWMTS = /** @type {OlTilegridWMTS} */ (source.getTileGrid()); - obj.tileGrid = this.serializeTilegridWMTS(tileGridWMTS); - obj.requestEncoding = source.getRequestEncoding(); - const projection = source.getProjection(); - if (projection) { - obj.projection = olProj.get(source.getProjection()).getCode(); - } - - return JSON.stringify(obj); - } - - /** - * @param {string} serialization . - * @param {function(import('ol/ImageTile').default, string): void} [tileLoadFunction] . - * @returns {OlSourceWMTS} . - */ - deserializeSourceWMTS(serialization, tileLoadFunction) { - /** - * @type {import("ol/source/WMTS").Options} - */ - const options = JSON.parse(serialization); - // @ts-ignore - options.tileLoadFunction = tileLoadFunction; - if (options.tileGrid) { - options.tileGrid = this.deserializeTilegridWMTS(/** @type {any} */ (options).tileGrid); - } - return new OlSourceWMTS(options); - } - - /** - * @private - * @param {number} number Some number which may be Infinity - * @returns {number} The same number or an arbitrary big number instead of Infinity - */ - makeInfinitySerializable_(number) { - if (number === Infinity) { - return 1000; - } - return number; - } - - /** - * @param {!import('ol/layer/WebGLTile').default|import('ol/layer/Image').default} layer . - * @param {import('ol/source/Source').default} [source] . - * @returns {string} . - */ - serializeTileLayer(layer, source) { - const obj = this.createBaseObject_(layer); - obj.opacity = layer.getOpacity(); - obj.visible = layer.getVisible(); - obj.minResolution = layer.getMinResolution(); - obj.maxResolution = this.makeInfinitySerializable_(layer.getMaxResolution()); - obj.zIndex = layer.getZIndex(); - source = source || layer.getSource(); - if (source instanceof OlSourceTileWMS) { - obj.source = this.serializeSourceTileWMS(source); - obj.sourceType = 'tileWMS'; - } else if (source instanceof OlSourceWMTS) { - obj.source = this.serializeSourceWMTS(source); - obj.sourceType = 'WMTS'; - } - return JSON.stringify(obj); - } - - /** - * @param {string} serialization . - * @param {function(import('ol/ImageTile').default, string): void} [tileLoadFunction] . - * @returns {!import('ol/layer/WebGLTile').default} . - */ - deserializeTileLayer(serialization, tileLoadFunction) { - /** - * @type {import('ol/layer/BaseTile').Options} - */ - const options = JSON.parse(serialization); - // @ts-ignore - const sourceType = options.sourceType; - if (sourceType === 'tileWMS') { - options.source = this.deserializeSourceTileWMS(/** @type {any} */ (options).source, tileLoadFunction); - } else if (sourceType === 'WMTS') { - options.source = this.deserializeSourceWMTS(/** @type {any} */ (options).source, tileLoadFunction); - } - return new OlLayerTile(options); - } -}; - -const exports = SerDes; - -export default exports; diff --git a/src/offline/ServiceManager.js b/src/offline/ServiceManager.js deleted file mode 100644 index c21d45d6b05a..000000000000 --- a/src/offline/ServiceManager.js +++ /dev/null @@ -1,134 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import angular from 'angular'; -class ServiceManager { - /** - * @param {angular.auto.IInjectorService} $injector Main injector. - * @struct - * @ngdoc service - * @ngname ngeoOfflineServiceManager - */ - constructor($injector) { - /** - * @type {angular.auto.IInjectorService} - * @private - */ - this.$injector_ = $injector; - - /** - * @type {*} - * @private - */ - this.saveService_ = null; - - /** - * @type {*} - * @private - */ - this.restoreService_ = null; - } - - /** - * @param {string|unknown} serviceLike A service like. - * @param {string} method A method. - * @returns {unknown} A returned object. - */ - getOfflineService_(serviceLike, method) { - if (typeof serviceLike === 'string') { - if (!this.$injector_.has(serviceLike)) { - console.error(`The offline ${method} service could not be found`); - return; - } - const service = this.$injector_.get(serviceLike); - if (!service[method]) { - console.error(`The offline service ${serviceLike} does not have a ${method} method`); - return; - } - return service; - } - // @ts-ignore - if (!serviceLike[method]) { - console.error(`The provided offline service does not have a ${method} method`); - return; - } - return serviceLike; - } - - /** - * Set the service to call on 'save'. - * - * @param {string|{save: Function}} saveLikeService - * A service name that can be injected or an object that have a 'save' method. - */ - setSaveService(saveLikeService) { - this.saveService_ = this.getOfflineService_(saveLikeService, 'save'); - } - - /** - * Set the service to call on 'restore' - * - * @param {string|{restore: Function}} restoreLikeService - * A service name that can be injected or an object that have a 'restore' method. - */ - setRestoreService(restoreLikeService) { - this.restoreService_ = this.getOfflineService_(restoreLikeService, 'restore'); - } - cancel() { - if (!this.saveService_) { - console.warn('You must register a saveService first'); - return; - } - this.saveService_.cancel(); - } - - /** - * Ask the provided service to save the data to an offline purpose - * - * @param {import('ol/extent').Extent} extent The extent to download. - * @param {import("ol/Map").default} map The map to work on. - */ - save(extent, map) { - if (!this.saveService_) { - console.warn('You must register a saveService first'); - return; - } - this.saveService_.save(extent, map); - } - - /** - * Ask the provided service to restore the saved data on the map - * - * @param {import('ol/Map').default} map The map to work on. - * @returns {Promise} A promise to the extent of the downloaded area - */ - restore(map) { - if (!this.restoreService_) { - console.warn('You must register a restoreService first'); - return Promise.reject(); - } - return this.restoreService_.restore(map); - } -} -ServiceManager.$inject = ['$injector']; -ServiceManager.module = angular.module('ngeoOfflineServiceManager', []); -ServiceManager.module.service('ngeoOfflineServiceManager', ServiceManager); -export default ServiceManager; diff --git a/src/offline/TilesDownloader.js b/src/offline/TilesDownloader.js deleted file mode 100644 index 850716a22adc..000000000000 --- a/src/offline/TilesDownloader.js +++ /dev/null @@ -1,223 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -/** - * @param {!Blob} blob A blob - * @returns {Promise} data URL - */ -function blobToDataUrl(blob) { - return new Promise((resolve, reject) => { - const reader = new FileReader(); - reader.onload = function () { - resolve(/** @type {string} */ (reader.result)); - }; - reader.onerror = reject; - reader.readAsDataURL(blob); - }); -} - -export default class TileDownloader { - /** - * @param {import('./index').OfflineTile[]} tiles An array of tiles to download. - * @param {import('./index').OfflineOnTileDownload} callbacks The callbacks. - * @param {number} workers The maximum number of workers. - */ - constructor(tiles, callbacks, workers) { - /** - * @private - * @type {number} - */ - this.maxNumberOfWorkers_ = workers; - - /** - * @private - */ - this.wasStarted_ = false; - - /** - * @type {import('./index').OfflineTile[]} - * @private - */ - this.tiles_ = tiles; - - /** - * @private - * @type {import('./index').OfflineOnTileDownload} - */ - this.callbacks_ = callbacks; - - /** - * @private - */ - this.allCount_ = 0; - - /** - * @private - */ - this.okCount_ = 0; - - /** - * @private - */ - this.koCount_ = 0; - - /** - * @private - */ - this.requestedCount_ = 0; - - /** - * @private - * @type {?function(): unknown} - */ - this.resolvePromise_ = null; - - /** - * @private - * @type {?Promise} - */ - this.promise_ = null; - - /** - * @type {number} - * @private - */ - this.tileIndex_ = 0; - - /** - * @type {boolean} - * @private - */ - this.cancel_ = false; - } - - cancel() { - this.cancel_ = true; - } - - /** - * @returns {Promise} A promise that resolves when the downloads are complete (failing or not) - */ - download() { - if (this.promise_) { - return this.promise_; - } - - this.promise_ = new Promise((resolve, reject) => { - this.resolvePromise_ = resolve; - }); - - console.assert(this.tiles_); - if (this.tiles_.length === 0) { - this.callbacks_.onTileDownloadError(1); // forcing progress update - if (this.resolvePromise_) { - this.resolvePromise_(); - } - } else { - for (let i = 0; i < this.maxNumberOfWorkers_; ++i) { - this.downloadTile_(); - } - } - - return this.promise_; - } - - /** - * @private - */ - downloadTile_() { - if (this.cancel_ || this.tileIndex_ >= this.tiles_.length) { - return; - } - const tile = this.tiles_[this.tileIndex_++]; - const tileUrl = tile.url; - const xhr = new XMLHttpRequest(); - xhr.open('GET', tileUrl, true); - xhr.responseType = 'blob'; - const onTileDownloaded = () => { - if (this.allCount_ === this.tiles_.length && this.resolvePromise_) { - this.resolvePromise_(); - } - this.downloadTile_(); - }; - - /** - * @param {unknown} _ Unused. - */ - const errorCallback = (_) => { - if (this.cancel_) { - return; - } - ++this.allCount_; - ++this.koCount_; - const progress = this.allCount_ / this.tiles_.length; - this.callbacks_.onTileDownloadError(progress).then(onTileDownloaded, onTileDownloaded); - }; - - /** - * - * @param {!ProgressEvent} e The load event. - */ - const onloadCallback = (e) => { - /** - * @type {?Blob} - */ - const response = xhr.response; - if (response && response.size !== 0) { - // non-empty tile - blobToDataUrl(response).then( - (dataUrl) => { - if (this.cancel_) { - return; - } - ++this.allCount_; - ++this.okCount_; - tile.response = dataUrl; - const progress = this.allCount_ / this.tiles_.length; - this.callbacks_.onTileDownloadSuccess(progress, tile).then(onTileDownloaded, onTileDownloaded); - }, - () => { - if (this.cancel_) { - return; - } - errorCallback(e); - }, - ); - } else { - if (this.cancel_) { - return; - } - ++this.allCount_; - ++this.okCount_; - this.callbacks_ - .onTileDownloadSuccess(this.allCount_ / this.tiles_.length, tile) - .then(onTileDownloaded, onTileDownloaded); - } - }; - - xhr.onload = onloadCallback; - xhr.onerror = errorCallback; - xhr.onabort = errorCallback; - xhr.ontimeout = errorCallback; - xhr.send(); - ++this.requestedCount_; - } -} diff --git a/src/offline/component.html.js b/src/offline/component.html.js deleted file mode 100644 index 6ef1f175da22..000000000000 --- a/src/offline/component.html.js +++ /dev/null @@ -1,182 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -export default `
- -
-
- -
-
-
- -
-
- Save map -
-
Abort
-
- -
-
{{$ctrl.progressPercents}}%
-
- - - - - - - - - - - - - - - - - - - - - - - - -`; diff --git a/src/offline/component.js b/src/offline/component.js deleted file mode 100644 index 3828567d7769..000000000000 --- a/src/offline/component.js +++ /dev/null @@ -1,578 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import ngeoMapFeatureOverlayMgr from 'ngeo/map/FeatureOverlayMgr'; -import ngeoMessageModalComponent from 'ngeo/message/modalComponent'; -import {extentToRectangle} from 'ngeo/utils'; -import olCollection from 'ol/Collection'; -import Feature from 'ol/Feature'; -import Polygon from 'ol/geom/Polygon'; -import {DEVICE_PIXEL_RATIO} from 'ol/has'; -import angular from 'angular'; -import MaskLayer from './Mask'; -import htmlTemplate from './component.html'; - -/** - * @type {!angular.IModule} - */ -const myModule = angular.module('ngeoOffline', [ngeoMessageModalComponent.name]); -myModule.value( - 'ngeoOfflineTemplateUrl', - /** - * @param {JQuery} element Element. - * @param {angular.IAttributes} attrs Attributes. - * @returns {string} Template URL. - */ - (element, attrs) => { - const templateUrl = attrs['ngeoOfflineTemplateurl']; - return templateUrl !== undefined ? templateUrl : 'ngeo/offline/component.html'; - }, -); -myModule.run( - /** - * @param {angular.ITemplateCacheService} $templateCache - */ - [ - '$templateCache', - ($templateCache) => { - // @ts-ignore: webpack - $templateCache.put('ngeo/offline/component.html', htmlTemplate); - }, - ], -); - -/** - * @param {!JQuery} $element Element. - * @param {!angular.IAttributes} $attrs Attributes. - * @param {!function(!JQuery, !angular.IAttributes): string} ngeoOfflineTemplateUrl Template function. - * @returns {string} Template URL. - */ -ngeoOfflineTemplateUrl.$inject = ['$element', '$attrs', 'ngeoOfflineTemplateUrl']; -function ngeoOfflineTemplateUrl($element, $attrs, ngeoOfflineTemplateUrl) { - return ngeoOfflineTemplateUrl($element, $attrs); -} - -/** - * Provides the "offline" component. - * - * Example: - * - * - * ngeo-offline-mask-margin="::100" - * ngeo-offline-min_zoom="::11" - * ngeo-offline-max_zoom="::15" - * - * - * See our live example: [../examples/offline.html](../examples/offline.html) - * - * @htmlAttribute {import('ol/Map').default} ngeo-offline-map The map. - * @htmlAttribute {number} ngeo-offline-extentsize The size, in map units, of a side of the extent. - * @private - * @ngdoc component - * @ngname ngeoOffline - */ -const component = { - bindings: { - 'map': '>} - * @private - */ - this.overlayCollection_ = new olCollection(); - this.featuresOverlay_.setFeatures(this.overlayCollection_); - - /** - * @type {?Polygon} - * @private - */ - this.dataPolygon_ = null; - - /** - * Whether the current view is the extent selection. - * - * @type {boolean} - * @export - */ - this.selectingExtent = false; - - /** - * Whether the current view is downloading one. - * - * @type {boolean} - * @export - */ - this.downloading = false; - - /** - * The progression of the data loading (0-100%). - * - * @type {number} - * @export - */ - this.progressPercents = 0; - - /** - * Whether the menu is currently displayed. - * - * @type {boolean} - * @export - */ - this.menuDisplayed = false; - - /** - * Whether the cancel download modal is displayed. - * - * @type {boolean} - * @export - */ - this.displayAlertAbortDownload = false; - - /** - * Whether the load data modal is displayed. - * - * @type {boolean} - * @export - */ - this.displayAlertLoadData = false; - - /** - * Whether the "no layer" modal is displayed. - * - * @type {boolean} - * @export - */ - this.displayAlertNoLayer = false; - - /** - * Offline mask minimum margin in pixels. - * - * @type {number} - * @export - */ - this.maskMargin = 0; - - /** - * Minimum zoom where offline is enable. - * - * @type {number} - * @export - */ - this.minZoom; - - /** - * Maximum zoom where offline is enable. - * - * @type {number} - * @export - */ - this.maxZoom; - - /** - * Map view max zoom constraint. - * - * @type {number} - * @export - */ - this.originalMinZoom; - - /** - * Map view min zoom constraint. - * - * @type {number} - * @export - */ - this.originalMaxZoom; - - /** - * @type {number} - * @export - */ - this.estimatedLoadDataSize = 0; - - /** - * @type {boolean} - */ - this.rotateMask = false; - - /** - * @private - * @param {import("ngeo/CustomEvent").default<{'progress': number}>} event the progress event. - */ - this.progressCallback_ = (event) => { - const progress = event.detail.progress; - this.progressPercents = Math.floor(progress * 100); - if (progress === 1) { - this.finishDownload_(); - } - this.$timeout_(() => {}, 0); // FIXME: force redraw - }; - } - $onInit() { - this.offlineMode.registerComponent(this); - this.ngeoOfflineConfiguration_.on( - /** @type {import('ol/Observable').EventTypes} */ 'progress', - /** @type {function(?): ?} */ this.progressCallback_, - ); - this.maskMargin = this.maskMargin || 100; - this.minZoom = this.minZoom || 10; - this.maxZoom = this.maxZoom || 15; - // @ts-ignore: extentInMeters does not exists... - this.maskLayer_ = new MaskLayer( - { - extentInMeters: this.extentSize, - }, - { - margin: this.maskMargin, - }, - ); - } - $onDestroy() { - this.ngeoOfflineConfiguration_.un( - /** @type {import('ol/Observable').EventTypes} */ 'progress', - /** @type {function(?): ?} */ this.progressCallback_, - ); - } - - /** - * @returns {boolean} True if data are accessible offline. - * @export - */ - hasData() { - return this.ngeoOfflineConfiguration_.hasOfflineData(); - } - - /** - * @export - */ - computeSizeAndDisplayAlertLoadData() { - this.estimatedLoadDataSize = this.ngeoOfflineConfiguration_.estimateLoadDataSize(this.map); - if (this.estimatedLoadDataSize > 0) { - this.displayAlertLoadData = true; - } else { - this.displayAlertNoLayer = true; - } - } - /** - * Toggle the selecting extent view. - * - * @param {boolean} [finished] If just finished downloading. - * @export - */ - toggleViewExtentSelection(finished) { - this.menuDisplayed = false; - this.selectingExtent = !this.selectingExtent; - this.map.removeLayer(this.maskLayer_); - this.removeZoomConstraints_(); - if (this.selectingExtent && !this.map.getLayers().getArray().includes(this.maskLayer_)) { - this.addZoomConstraints_(); - this.map.addLayer(this.maskLayer_); - } - this.map.render(); - } - - /** - * Validate the current extent and download data. - * - * @export - */ - validateExtent() { - this.progressPercents = 0; - const extent = this.getDowloadExtent_(); - this.downloading = true; - this.ngeoOfflineServiceManager_.save(extent, this.map); - } - - /** - * @private - */ - finishDownload_() { - this.downloading = false; - this.toggleViewExtentSelection(true); - } - - /** - * Ask to abort the download of data. - * - * @export - */ - askAbortDownload() { - this.displayAlertAbortDownload = true; - } - - /** - * Abort the download of data. - * - * @export - */ - abortDownload() { - this.downloading = false; - this.ngeoOfflineServiceManager_.cancel(); - this.deleteData(); - } - - /** - * Show the main menu. - * - * @export - */ - showMenu() { - this.menuDisplayed = true; - } - - /** - * Activate offline mode. - * Zoom to the extent of that data and restore the data. - * - * @export - */ - activateOfflineMode() { - this.ngeoOfflineServiceManager_.restore(this.map).then((extent) => { - this.dataPolygon_ = this.createPolygonFromExtent_(extent); - const size = this.map.getSize(); - if (size === undefined) { - throw new Error('Missing size'); - } - this.map.getView().fit(extent, { - size, - }); - this.menuDisplayed = false; - this.displayExtent_(); - this.offlineMode.enable(); - }); - } - - /** - * - * Deactivate offline mode. - * Reload the page. - * - * @export - */ - deactivateOfflineMode() { - window.location.reload(); - } - - /** - * Toggle the visibility of the data's extent. - * - * @export - */ - toggleExtentVisibility() { - if (this.isExtentVisible()) { - this.overlayCollection_.clear(); - } else { - this.displayExtent_(); - } - } - - /** - * @returns {boolean} True if the extent is currently visible. False otherwise. - * @export - */ - isExtentVisible() { - return this.overlayCollection_.getLength() > 0; - } - - /** - * Delete the saved data. - * - * @export - */ - deleteData() { - this.overlayCollection_.clear(); - this.dataPolygon_ = null; - if (this.networkStatus.isDisconnected()) { - this.menuDisplayed = false; - } - const reloadIfInOfflineMode = () => { - if (this.offlineMode.isEnabled()) { - this.deactivateOfflineMode(); - } - }; - this.ngeoOfflineConfiguration_.clear().then(reloadIfInOfflineMode); - } - - /** - * @private - */ - displayExtent_() { - if (!this.isExtentVisible() && this.dataPolygon_) { - const feature = new Feature(this.dataPolygon_); - this.overlayCollection_.push(feature); - } - } - - /** - * When enabling mask extent, zoom the view to the defined zoom range and - * add constraints to the view to not allow user to move out of this range. - * - * @private - */ - addZoomConstraints_() { - const view = this.map.getView(); - const zoom = view.getZoom() || 0; - this.originalMinZoom = view.getMinZoom(); - this.originalMaxZoom = view.getMaxZoom(); - if (zoom < this.minZoom) { - view.setZoom(this.minZoom); - } else if (zoom > this.maxZoom) { - view.setZoom(this.maxZoom); - } - view.setMaxZoom(this.maxZoom); - view.setMinZoom(this.minZoom); - } - - /** - * @private - */ - removeZoomConstraints_() { - const view = this.map.getView(); - if (this.originalMaxZoom !== undefined && this.originalMinZoom !== undefined) { - view.setMaxZoom(this.originalMaxZoom); - view.setMinZoom(this.originalMinZoom); - } - } - - /** - * A polygon on the whole extent of the projection, with a hole for the offline extent. - * - * @param {import('ol/extent').Extent} extent An extent - * @returns {Polygon} Polygon to save, based on the projection extent, the center of the map and - * the extentSize property. - * @private - */ - createPolygonFromExtent_(extent) { - const projExtent = this.map.getView().getProjection().getExtent(); - return new Polygon([extentToRectangle(projExtent), extentToRectangle(extent)], 'XY'); - } - - /** - * @returns {import('ol/extent').Extent} the download extent. - * @private - */ - getDowloadExtent_() { - const center = this.map.getView().getCenter(); - const halfLength = Math.ceil(this.extentSize || this.getExtentSize_()) / 2; - return this.maskLayer_.createExtent(center, halfLength); - } - getExtentSize_() { - const mapSize = this.map.getSize() || [150, 150]; - const maskSizePixel = DEVICE_PIXEL_RATIO * Math.min(mapSize[0], mapSize[1]) - this.maskMargin * 2; - const maskSizeMeter = (maskSizePixel * (this.map.getView().getResolution() || 1)) / DEVICE_PIXEL_RATIO; - return maskSizeMeter; - } -} -Controller.$inject = [ - '$timeout', - 'ngeoOfflineServiceManager', - 'ngeoOfflineConfiguration', - 'ngeoOfflineMode', - 'ngeoNetworkStatus', -]; -myModule.controller('ngeoOfflineController', Controller); -export default myModule; diff --git a/src/offline/index.js b/src/offline/index.js deleted file mode 100644 index 91b6b54e4098..000000000000 --- a/src/offline/index.js +++ /dev/null @@ -1,81 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2019-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -/** - * @typedef {Object} OfflineExtentByZoom - * @property {number} zoom - * @property {import('ol/extent').Extent} extent - */ - -/** - * @typedef {Object} OfflineLayerMetadata - * @property {import('ol/Map').default} map - * @property {OfflineExtentByZoom[]} extentByZoom - * @property {import('ol/layer/Layer').default} layer - * @property {import('ol/source/Source').default} source - * @property {string|undefined} layerType - * @property {string|undefined} layerSerialization - * @property {boolean} backgroundLayer - * @property {import('ol/layer/Group').default[]} ancestors - */ - -/** - * @typedef {Object} OfflinePersistentLayer - * @property {string|undefined} layerType - * @property {string|undefined} layerSerialization - * @property {boolean} backgroundLayer - * @property {string} key - */ - -/** - * @typedef {Object} OfflinePersistentContent - * @property {import('ol/extent').Extent} extent - * @property {!OfflinePersistentLayer[]} layers - * @property {!number[]} zooms - */ - -/** - * @typedef {Object} OfflineTile - * @property {import('ol/coordinate').Coordinate} coord - * @property {string} url - * @property {?string} response - */ - -/** - * @callback onTileDownloadSuccess - * @param {number} progress - * @param {OfflineTile} tile - * @returns {Promise} - */ - -/** - * @callback onTileDownloadError - * @param {number} progress - * @returns {Promise} - */ - -/** - * @typedef {Object} OfflineOnTileDownload - * @property {onTileDownloadSuccess} onTileDownloadSuccess - * @property {onTileDownloadError} onTileDownloadError - */ - -export default {}; diff --git a/src/offline/module.js b/src/offline/module.js deleted file mode 100644 index f14a4e6d14cd..000000000000 --- a/src/offline/module.js +++ /dev/null @@ -1,44 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import ngeoOfflineComponent from 'ngeo/offline/component'; -import ngeoOfflineNetworkStatus from 'ngeo/offline/NetworkStatus'; -import ngeoOfflineServiceManager from 'ngeo/offline/ServiceManager'; -import downloader from 'ngeo/offline/Downloader'; -import restorer from 'ngeo/offline/Restorer'; -import mode from 'ngeo/offline/Mode'; -import angular from 'angular'; - -/** - * @type {!angular.IModule} - */ -const exports = angular.module('ngeoOfflineModule', [ - ngeoOfflineComponent.name, - ngeoOfflineNetworkStatus.module.name, - ngeoOfflineServiceManager.module.name, - downloader.module.name, - restorer.module.name, - mode.module.name, -]); - -exports.value('ngeoOfflineGutter', 96); - -export default exports; diff --git a/src/offline/utils.js b/src/offline/utils.js deleted file mode 100644 index 8a16b732b986..000000000000 --- a/src/offline/utils.js +++ /dev/null @@ -1,53 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import olLayerGroup from 'ol/layer/Group'; - -/** - * @param {import('ol/layer/Base').default} layer A layer tree. - * @param {!import('ol/layer/Group').default[]} ancestors The groups to which the layer belongs to. - * @param {function(import('ol/layer/Base').default, import('ol/layer/Group').default[]): boolean} visitor - * A function which will return false if descend must stop. - */ -export function traverseLayer(layer, ancestors, visitor) { - const descend = visitor(layer, ancestors); - if (descend && layer instanceof olLayerGroup) { - layer.getLayers().forEach((childLayer) => { - traverseLayer(childLayer, [...ancestors, layer], visitor); - }); - } -} - -const extractor = new RegExp('[^/]*//[^/]+/(.*)'); - -/** - * Extract the part after the URL authority. - * - * @param {string} url A URL to normalize - * @returns {string} The normalized string. - */ -export function normalizeURL(url) { - const matches = extractor.exec(url); - if (!matches) { - throw new Error('Could not normalize url ' + url); - } - return matches[1]; -} diff --git a/src/olcs/Manager.js b/src/olcs/Manager.js deleted file mode 100644 index fb6ff110300b..000000000000 --- a/src/olcs/Manager.js +++ /dev/null @@ -1,57 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import olcsContribManager from 'olcs/contrib/Manager'; - -/** - * @hidden - */ -class Manager extends olcsContribManager { - /** - * @param {string} url . - * @param {angular.IScope} $rootScope . - * @param {import('olcs/contrib/Manager').ManagerOptions} options . - */ - constructor(url, $rootScope, options) { - super(url, options); - /** - * @type {angular.IScope} - * @private - */ - this.rootScope_ = $rootScope; - } - - /** - * @override - */ - toggle3d() { - // The transition is asynchronous and at the end of it the state of OLCesium is changed. - // In order to have all code dependent on OLCesium state updated, we kick an Angular digest cycle. - const promise = super.toggle3d(); - return /** @type {Promise} */ ( - promise.then(() => { - this.rootScope_.$apply(); - }) - ); - } -} - -export default Manager; diff --git a/src/olcs/Service.js b/src/olcs/Service.js deleted file mode 100644 index 2d766dfa6aa3..000000000000 --- a/src/olcs/Service.js +++ /dev/null @@ -1,164 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -import angular from 'angular'; -import ngeoMiscDebounce from 'ngeo/misc/debounce'; -import ngeoStatemanagerLocation from 'ngeo/statemanager/Location'; -import {Permalink3dParam} from 'ngeo/olcs/constants'; -import ngeoStatemanagerService from 'ngeo/statemanager/Service'; -import {toDegrees} from 'ol/math'; - -/** - * @hidden - */ -export class OlcsService { - /** - * @param {import('ngeo/misc/debounce').miscDebounce} ngeoDebounce ngeo debounce - * service. - * @param {import('ngeo/statemanager/Location').StatemanagerLocation} ngeoLocation ngeo location - * service. - * @param {import('ngeo/statemanager/Service').StatemanagerService} ngeoStateManager The ngeo - * StateManager service. - */ - constructor(ngeoDebounce, ngeoLocation, ngeoStateManager) { - /** - * @private - * @type {?import('olcs/contrib/Manager').default} - */ - this.manager_ = null; - - /** - * @private - * @type {import('ngeo/misc/debounce').miscDebounce} - */ - this.ngeoDebounce_ = ngeoDebounce; - - /** - * @private - * @type {import('ngeo/statemanager/Location').StatemanagerLocation} - */ - this.ngeoLocation_ = ngeoLocation; - - /** - * @private - * @type {import('ngeo/statemanager/Service').StatemanagerService} - */ - this.ngeoStateManager_ = ngeoStateManager; - } - - /** - * @param {import('olcs/contrib/Manager').default} manager Manager. - */ - initialize(manager) { - this.manager_ = manager; - this.manager_.on('load', () => { - this.cameraToState_(); - }); - if (this.ngeoStateManager_.getInitialBooleanValue('3d_enabled')) { - this.initialStateToCamera_(); - } - } - - /** - * @returns {?import('olcs/contrib/Manager').default} the manager. - */ - getManager() { - return this.manager_; - } - - /** - * @private - * @returns {Promise} A promise after load & enabled. - */ - initialStateToCamera_() { - if (!this.manager_) { - throw new Error('Missing manager'); - } - const stateManager = this.ngeoStateManager_; - const lon = stateManager.getInitialNumberValue(Permalink3dParam.LON); - const lat = stateManager.getInitialNumberValue(Permalink3dParam.LAT); - const elevation = stateManager.getInitialNumberValue(Permalink3dParam.ELEVATION); - const heading = stateManager.getInitialNumberValue(Permalink3dParam.HEADING) || 0; - const pitch = stateManager.getInitialNumberValue(Permalink3dParam.PITCH) || 0; - if (!lon) { - throw new Error('Missing lon'); - } - if (!lat) { - throw new Error('Missing lat'); - } - if (!elevation) { - throw new Error('Missing elevation'); - } - return this.manager_.set3dWithView(lon, lat, elevation, heading, pitch); - } - - /** - * @private - */ - cameraToState_() { - if (!this.manager_) { - throw new Error('Missing manager'); - } - const manager = this.manager_; - const scene = manager.getOl3d().getCesiumScene(); - const camera = scene.camera; - camera.moveEnd.addEventListener( - this.ngeoDebounce_( - () => { - const position = camera.positionCartographic; - this.ngeoStateManager_.updateState({ - [Permalink3dParam.ENABLED]: true, - [Permalink3dParam.LON]: toDegrees(position.longitude).toFixed(5), - [Permalink3dParam.LAT]: toDegrees(position.latitude).toFixed(5), - [Permalink3dParam.ELEVATION]: position.height.toFixed(0), - [Permalink3dParam.HEADING]: toDegrees(camera.heading).toFixed(3), - [Permalink3dParam.PITCH]: toDegrees(camera.pitch).toFixed(3), - }); - }, - 1000, - true, - ), - ); - this.manager_.on('toggle', (event) => { - if (!event.target.is3dEnabled()) { - this.remove3dState_(); - } - }); - } - - /** - * @private - */ - remove3dState_() { - this.ngeoLocation_.getParamKeysWithPrefix(Permalink3dParam.PREFIX).forEach((key) => { - this.ngeoStateManager_.deleteParam(key); - }); - } -} -OlcsService.$inject = ['ngeoDebounce', 'ngeoLocation', 'ngeoStateManager']; -/** - * @type {angular.IModule} - * @hidden - */ -const myModule = angular - .module(name, [ngeoMiscDebounce.name, ngeoStatemanagerLocation.name, ngeoStatemanagerService.name]) - .service('ngeoOlcsService', OlcsService); -export default myModule; diff --git a/src/olcs/constants.js b/src/olcs/constants.js deleted file mode 100644 index 3f899f3600b9..000000000000 --- a/src/olcs/constants.js +++ /dev/null @@ -1,55 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2018-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -/** - * @enum {string} - * @hidden - */ -export const Permalink3dParam = { - /** - * @type {string} - */ - ENABLED: '3d_enabled', - /** - * @type {string} - */ - LON: '3d_lon', - /** - * @type {string} - */ - LAT: '3d_lat', - /** - * @type {string} - */ - ELEVATION: '3d_elevation', - /** - * @type {string} - */ - HEADING: '3d_heading', - /** - * @type {string} - */ - PITCH: '3d_pitch', - /** - * @type {string} - */ - PREFIX: '3d_', -}; diff --git a/src/olcs/controls3d.html.js b/src/olcs/controls3d.html.js deleted file mode 100644 index 76d92ed9e13f..000000000000 --- a/src/olcs/controls3d.html.js +++ /dev/null @@ -1,35 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -export default `
-
- - -
-
- - -
-
-
- - -
`; diff --git a/src/olcs/controls3d.js b/src/olcs/controls3d.js deleted file mode 100644 index b2222e7cb9a2..000000000000 --- a/src/olcs/controls3d.js +++ /dev/null @@ -1,315 +0,0 @@ -ngeoOlcsControls3dTemplateUrlInjectable.$inject = ['$attrs', 'ngeoOlcsControls3dTemplateUrl']; -// The MIT License (MIT) -// -// Copyright (c) 2017-2024 Camptocamp SA -// -// Permission is hereby granted, free of charge, to any person obtaining a copy of -// this software and associated documentation files (the "Software"), to deal in -// the Software without restriction, including without limitation the rights to -// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of -// the Software, and to permit persons to whom the Software is furnished to do so, -// subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS -// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR -// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER -// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN -// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - -/* global Cesium */ - -import angular from 'angular'; -import * as olEasing from 'ol/easing'; -import {toRadians} from 'ol/math'; -import olcsCore from 'olcs/core'; -import htmlTemplate from './controls3d.html'; - -/** - * @type {angular.IModule} - * @hidden - */ -const myModule = angular.module('ngeoOlcsControls3d', []); - -/** - * @private - * @hidden - * @param {number} older Older - * @param {number} newer Newer - * @returns {boolean} ? - */ -function shouldUpdate(older, newer) { - return Number.isFinite(newer) && (!Number.isFinite(older) || Math.abs(newer - older) > 0.05); -} - -/** - * @hidden - */ -export class Controller { - /** - * @param {JQuery} $element The element - * @param {import('ngeo/olcs/Service').OlcsService} ngeoOlcsService The ol-cesium service. - */ - constructor($element, ngeoOlcsService) { - /** - * @type {JQuery} - * @private - */ - this.element_ = $element; - - /** - * @type {?import('olcs/contrib/Manager').default} - */ - this.ol3dm = null; - - /** - * @type {number} - */ - this.minTilt = -1; - - /** - * @type {number} - * @private - */ - this.maxTilt = -1; - - /** - * @type {?JQuery} - * @private - */ - this.tiltRightEl_ = null; - - /** - * @type {?JQuery} - * @private - */ - this.tiltLeftEl_ = null; - - /** - * @type {?JQuery} - * @private - */ - this.rotation3dEl_ = null; - - /** - * @type {?JQuery} - * @private - */ - this.angle3dEl_ = null; - - /** - * @type {number} - * @private - */ - this.previousRotation_ = -1; - - /** - * @type {?Cesium.Matrix4} - * @private - */ - this.previousViewMatrix_ = null; - - /** - * @type {number} - * @private - */ - this.animationFrameRequestId_ = -1; - - /** - * @type {import('ngeo/olcs/Service').OlcsService} - * @private - */ - this.olcsService_ = ngeoOlcsService; - } - updateWidget_() { - if (!this.ol3dm) { - throw new Error('Missing ol3dm'); - } - if (!this.rotation3dEl_) { - throw new Error('Missing rotation3dEl_'); - } - if (!this.angle3dEl_) { - throw new Error('Missing angle3dEl_'); - } - if (!this.tiltRightEl_) { - throw new Error('Missing tiltRightEl_'); - } - if (!this.tiltLeftEl_) { - throw new Error('Missing tiltLeftEl_'); - } - const newRotation = this.ol3dm.getOl3d().getOlView().getRotation(); - if (shouldUpdate(this.previousRotation_, newRotation)) { - this.rotateElement_(this.rotation3dEl_, newRotation); - this.previousRotation_ = newRotation; - } - const newViewMatrix = this.ol3dm.getCesiumViewMatrix(); - if (!Cesium.Matrix4.equalsEpsilon(this.previousViewMatrix_, newViewMatrix, 1e-5)) { - const newTilt = this.ol3dm.getTiltOnGlobe(); // this is expensive!! - if (newTilt != undefined && Number.isFinite(newTilt || 0)) { - this.rotateElement_(this.angle3dEl_, newTilt); - this.previousViewMatrix_ = Cesium.Matrix4.clone(newViewMatrix); - - // if min or max tilt is reached, disable the tilting buttons - const buffer = 0.01; // rad - if (newTilt - this.minTilt < buffer) { - this.tiltRightEl_.addClass('ngeo-right-inactive'); - } else if (this.tiltRightEl_.hasClass('ngeo-right-inactive')) { - this.tiltRightEl_.removeClass('ngeo-right-inactive'); - } - if (this.maxTilt - newTilt < buffer) { - this.tiltLeftEl_.addClass('ngeo-left-inactive'); - } else if (this.tiltLeftEl_.hasClass('ngeo-left-inactive')) { - this.tiltLeftEl_.removeClass('ngeo-left-inactive'); - } - } - } - this.animationFrameRequestId_ = requestAnimationFrame(() => this.updateWidget_()); - } - $onDestroy() { - if (this.animationFrameRequestId_) { - cancelAnimationFrame(this.animationFrameRequestId_); - } - } - $onInit() { - if (this.minTilt === undefined) { - this.minTilt = 0; - } - if (this.maxTilt === undefined) { - this.maxTilt = (7 * Math.PI) / 16; - } - if (!this.ol3dm) { - this.ol3dm = this.olcsService_.getManager() || null; - } - this.tiltRightEl_ = this.element_.find('.ngeo-tilt-right'); - this.tiltLeftEl_ = this.element_.find('.ngeo-tilt-left'); - this.rotation3dEl_ = this.element_.find('.ngeo-rotation3d'); - this.angle3dEl_ = this.element_.find('.ngeo-angle3d'); - this.updateWidget_(); - } - - /** - * @param {JQuery} element Element to rotate. - * @param {(number|undefined)} angle Angle in radians - * @private - */ - rotateElement_(element, angle) { - const r = `rotate(${angle}rad)`; - element.css({ - '-moz-transform': r, - '-webkit-transform': r, - '-o-transform': r, - '-ms-transform': r, - 'transform': r, - }); - } - - /** - * @param {number} angle Angle in degrees. - */ - rotate(angle) { - if (!this.ol3dm) { - throw new Error('Missing ol3dm'); - } - this.ol3dm.setHeading(toRadians(angle)); - } - - /** - * @param {number} angle Angle in degrees. - */ - tilt(angle) { - if (!this.ol3dm) { - throw new Error('Missing ol3dm'); - } - angle = toRadians(angle); - const tiltOnGlobe = Number(this.ol3dm.getTiltOnGlobe()); - if (tiltOnGlobe + angle < this.minTilt) { - angle = this.minTilt - tiltOnGlobe; - } else if (tiltOnGlobe + angle > this.maxTilt) { - angle = this.maxTilt - tiltOnGlobe; - } - const scene = this.ol3dm.getCesiumScene(); - olcsCore.rotateAroundBottomCenter(scene, angle); - } - - /** - * @param {number} delta 1 to zoom out and 1 to zoom in. - */ - zoom(delta) { - if (!this.ol3dm) { - throw new Error('Missing ol3dm'); - } - const view = this.ol3dm.getOlView(); - const cur = view.getResolution(); - const newResolution = view.constrainResolution(cur, delta); - if (view.getAnimating()) { - view.cancelAnimations(); - } - view.animate({ - resolution: newResolution, - duration: 250, - easing: olEasing.easeOut, - }); - } -} -Controller.$inject = ['$element', 'ngeoOlcsService']; -/** - * @param {angular.IAttributes} $attrs Attributes. - * @param {string} ngeoOlcsControls3dTemplateUrl Template function. - * @returns {string} Template URL. - * @private - * @hidden - */ -function ngeoOlcsControls3dTemplateUrlInjectable($attrs, ngeoOlcsControls3dTemplateUrl) { - if (ngeoOlcsControls3dTemplateUrl) { - return ngeoOlcsControls3dTemplateUrl; - } - const templateUrl = $attrs['ngeoOlcsControls3dTemplateUrl']; - return templateUrl ? templateUrl : 'ngeo/olsc/controls3d'; -} -myModule.run( - /** - * @param {angular.ITemplateCacheService} $templateCache - */ - [ - '$templateCache', - ($templateCache) => { - // @ts-ignore: webpack - $templateCache.put('ngeo/olsc/controls3d', htmlTemplate); - }, - ], -); - -/** - * Provides the "ngeoOlcsControls3d" component, a widget for - * controlling the 3D camera. - * - * Example: - * - * - * - * - * By default the directive uses "controls3d.html" as its templateUrl. This - * can be changed by redefining the "ngeoOlcsControls3dTemplateUrl" value. - * - * See our live example: [../examples/simple3d.html](../examples/simple3d.html) - * - * @htmlAttribute {olcs.contrib.Manager} ngeo-olcs-manager The OL-Cesium manager. - * @type {angular.IComponentOptions} - * @ngdoc component - * @ngname ngeoOlcsControls3d - */ -const olscControls3dComponent = { - bindings: { - 'minTilt': ' { }, }); - configuration.setConfig({ngeoOfflineTestUrl: 'test'} as Configuration); - expect(config.ngeoOfflineTestUrl).to.equal('test'); - configuration.setConfig({ngeoOfflineTestUrl: 'test2'} as Configuration); - expect(config.ngeoOfflineTestUrl).to.equal('test2'); + configuration.setConfig({authenticationBaseUrl: 'test'} as Configuration); + expect(config.authenticationBaseUrl).to.equal('test'); + configuration.setConfig({authenticationBaseUrl: 'test2'} as Configuration); + expect(config.authenticationBaseUrl).to.equal('test2'); }); }); diff --git a/srcapi/store/config.ts b/srcapi/store/config.ts index 285cd0e02571..3e0b462cfb87 100644 --- a/srcapi/store/config.ts +++ b/srcapi/store/config.ts @@ -250,11 +250,6 @@ export function buildStyle(styleDescriptor: StyleLike): OlStyleStyleStyleLike { } } -/** - * URL of the test page to detect online/offline. - */ -export type ngeoOfflineTestUrl = string; - /** * URL to the WFS server. */ @@ -1405,7 +1400,6 @@ export type gmfDatasourceOptions = { */ export type Configuration = { authenticationBaseUrl: authenticationBaseUrl; - ngeoOfflineTestUrl: ngeoOfflineTestUrl; ngeoPermalinkOgcserverUrl: ngeoPermalinkOgcserverUrl; ngeoNominatimSearchDefaultParams: ngeoNominatimSearchDefaultParams; ngeoQueryOptions: ngeoQueryOptions;