diff --git a/package-lock.json b/package-lock.json index 77c62c11..08d91465 100644 --- a/package-lock.json +++ b/package-lock.json @@ -48,6 +48,7 @@ "jsts": "2.1.0", "jszip": "^3.2.1", "mapbox-gl": "^1.6.1", + "maplibre-gl": "^4.7.1", "moment": "^2.29.4", "ng-lazyload-image": "^9.1.3", "ngeohash": "^0.6.0", @@ -3571,6 +3572,44 @@ "node": ">=6.0.0" } }, + "node_modules/@maplibre/maplibre-gl-style-spec": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", + "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", + "license": "ISC", + "dependencies": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" + }, + "bin": { + "gl-style-format": "dist/gl-style-format.mjs", + "gl-style-migrate": "dist/gl-style-migrate.mjs", + "gl-style-validate": "dist/gl-style-validate.mjs" + } + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@maplibre/maplibre-gl-style-spec/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, "node_modules/@material/animation": { "version": "15.0.0-canary.684e33d25.0", "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.684e33d25.0.tgz", @@ -5322,6 +5361,15 @@ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" }, + "node_modules/@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -5359,6 +5407,23 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "node_modules/@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==", + "license": "MIT" + }, + "node_modules/@types/mapbox__vector-tile": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", + "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, "node_modules/@types/mapbox-gl": { "version": "1.13.10", "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-1.13.10.tgz", @@ -5403,6 +5468,12 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "dev": true }, + "node_modules/@types/pbf": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==", + "license": "MIT" + }, "node_modules/@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -5484,6 +5555,15 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "node_modules/@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } + }, "node_modules/@types/tinycolor2": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz", @@ -10184,6 +10264,53 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "node_modules/global-prefix": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", + "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "license": "MIT", + "dependencies": { + "ini": "^4.1.3", + "kind-of": "^6.0.3", + "which": "^4.0.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/global-prefix/node_modules/ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==", + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/global-prefix/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, "node_modules/globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -11709,6 +11836,12 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "node_modules/json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==", + "license": "MIT" + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -12214,7 +12347,6 @@ "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -13025,6 +13157,104 @@ "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" }, + "node_modules/maplibre-gl": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", + "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", + "license": "BSD-3-Clause", + "dependencies": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^20.3.1", + "@types/geojson": "^7946.0.14", + "@types/geojson-vt": "3.2.5", + "@types/mapbox__point-geometry": "^0.1.4", + "@types/mapbox__vector-tile": "^1.3.4", + "@types/pbf": "^3.0.5", + "@types/supercluster": "^7.1.3", + "earcut": "^3.0.0", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.3", + "global-prefix": "^4.0.0", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^3.3.0", + "potpack": "^2.0.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0", + "vt-pbf": "^3.1.3" + }, + "engines": { + "node": ">=16.14.0", + "npm": ">=8.1.0" + }, + "funding": { + "url": "https://github.com/maplibre/maplibre-gl-js?sponsor=1" + } + }, + "node_modules/maplibre-gl/node_modules/@mapbox/tiny-sdf": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", + "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==", + "license": "BSD-2-Clause" + }, + "node_modules/maplibre-gl/node_modules/@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==", + "license": "BSD-2-Clause" + }, + "node_modules/maplibre-gl/node_modules/earcut": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", + "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/geojson-vt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/potpack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", + "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==", + "license": "ISC" + }, + "node_modules/maplibre-gl/node_modules/supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "license": "ISC", + "dependencies": { + "kdbush": "^4.0.2" + } + }, + "node_modules/maplibre-gl/node_modules/tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==", + "license": "ISC" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -14810,9 +15040,10 @@ } }, "node_modules/pbf": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", + "license": "BSD-3-Clause", "dependencies": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" @@ -21302,6 +21533,37 @@ "resolved": "https://registry.npmjs.org/@mapbox/whoots-js/-/whoots-js-3.1.0.tgz", "integrity": "sha512-Es6WcD0nO5l+2BOQS4uLfNPYQaNDfbot3X1XUoloz+x0mPDS3eeORZJl06HXjwBG1fOGwCRnzK88LMdxKRrd6Q==" }, + "@maplibre/maplibre-gl-style-spec": { + "version": "20.4.0", + "resolved": "https://registry.npmjs.org/@maplibre/maplibre-gl-style-spec/-/maplibre-gl-style-spec-20.4.0.tgz", + "integrity": "sha512-AzBy3095fTFPjDjmWpR2w6HVRAZJ6hQZUCwk5Plz6EyfnfuQW1odeW5i2Ai47Y6TBA2hQnC+azscjBSALpaWgw==", + "requires": { + "@mapbox/jsonlint-lines-primitives": "~2.0.2", + "@mapbox/unitbezier": "^0.0.1", + "json-stringify-pretty-compact": "^4.0.0", + "minimist": "^1.2.8", + "quickselect": "^2.0.0", + "rw": "^1.3.3", + "tinyqueue": "^3.0.0" + }, + "dependencies": { + "@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + }, + "rw": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz", + "integrity": "sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==" + }, + "tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" + } + } + }, "@material/animation": { "version": "15.0.0-canary.684e33d25.0", "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.684e33d25.0.tgz", @@ -22839,6 +23101,14 @@ "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.14.tgz", "integrity": "sha512-WCfD5Ht3ZesJUsONdhvm84dmzWOiOzOAqOncN0++w0lBw1o8OuDNJF2McvvCef/yBqb/HYRahp1BYtODFQ8bRg==" }, + "@types/geojson-vt": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/@types/geojson-vt/-/geojson-vt-3.2.5.tgz", + "integrity": "sha512-qDO7wqtprzlpe8FfQ//ClPV9xiuoh2nkIgiouIptON9w5jvD/fA4szvP9GBlDVdJ5dldAl0kX/sy3URbWwLx0g==", + "requires": { + "@types/geojson": "*" + } + }, "@types/glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", @@ -22876,6 +23146,21 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, + "@types/mapbox__point-geometry": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__point-geometry/-/mapbox__point-geometry-0.1.4.tgz", + "integrity": "sha512-mUWlSxAmYLfwnRBmgYV86tgYmMIICX4kza8YnE/eIlywGe2XoOxlpVnXWwir92xRLjwyarqwpu2EJKD2pk0IUA==" + }, + "@types/mapbox__vector-tile": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/@types/mapbox__vector-tile/-/mapbox__vector-tile-1.3.4.tgz", + "integrity": "sha512-bpd8dRn9pr6xKvuEBQup8pwQfD4VUyqO/2deGjfpe6AwC8YRlyEipvefyRJUSiCJTZuCb8Pl1ciVV5ekqJ96Bg==", + "requires": { + "@types/geojson": "*", + "@types/mapbox__point-geometry": "*", + "@types/pbf": "*" + } + }, "@types/mapbox-gl": { "version": "1.13.10", "resolved": "https://registry.npmjs.org/@types/mapbox-gl/-/mapbox-gl-1.13.10.tgz", @@ -22920,6 +23205,11 @@ "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", "dev": true }, + "@types/pbf": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/pbf/-/pbf-3.0.5.tgz", + "integrity": "sha512-j3pOPiEcWZ34R6a6mN07mUkM4o4Lwf6hPNt8eilOeZhTFbxFXmKhvXl9Y28jotFPaI1bpPDJsbCprUoNke6OrA==" + }, "@types/qs": { "version": "6.9.15", "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.15.tgz", @@ -23001,6 +23291,14 @@ "integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==", "dev": true }, + "@types/supercluster": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/supercluster/-/supercluster-7.1.3.tgz", + "integrity": "sha512-Z0pOY34GDFl3Q6hUFYf3HkTwKEE02e7QgtJppBt+beEAxnyOpJua+voGFvxINBHa06GwLFFym7gRPY2SiKIfIA==", + "requires": { + "@types/geojson": "*" + } + }, "@types/tinycolor2": { "version": "1.4.6", "resolved": "https://registry.npmjs.org/@types/tinycolor2/-/tinycolor2-1.4.6.tgz", @@ -26472,6 +26770,36 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, + "global-prefix": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-4.0.0.tgz", + "integrity": "sha512-w0Uf9Y9/nyHinEk5vMJKRie+wa4kR5hmDbEhGGds/kG1PwGLLHKRoNMeJOyCQjjBkANlnScqgzcFwGHgmgLkVA==", + "requires": { + "ini": "^4.1.3", + "kind-of": "^6.0.3", + "which": "^4.0.0" + }, + "dependencies": { + "ini": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.3.tgz", + "integrity": "sha512-X7rqawQBvfdjS10YU1y1YVreA3SsLrW9dX2CewP2EbBJM4ypVNLDkO5y04gejPwKIY9lR+7r9gn3rFPt/kmWFg==" + }, + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "requires": { + "isexe": "^3.1.1" + } + } + } + }, "globals": { "version": "11.12.0", "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", @@ -27571,6 +27899,11 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "dev": true }, + "json-stringify-pretty-compact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-stringify-pretty-compact/-/json-stringify-pretty-compact-4.0.0.tgz", + "integrity": "sha512-3CNZ2DnrpByG9Nqj6Xo8vqbjT4F6N+tb4Gb28ESAZjYZ5yqvmc56J+/kuIwkaAMOyblTQhUW7PxMkUb8Q36N3Q==" + }, "json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -27988,8 +28321,7 @@ "kind-of": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", - "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", - "dev": true + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, "klaw-sync": { "version": "6.0.0", @@ -28631,6 +28963,89 @@ } } }, + "maplibre-gl": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/maplibre-gl/-/maplibre-gl-4.7.1.tgz", + "integrity": "sha512-lgL7XpIwsgICiL82ITplfS7IGwrB1OJIw/pCvprDp2dhmSSEBgmPzYRvwYYYvJGJD7fxUv1Tvpih4nZ6VrLuaA==", + "requires": { + "@mapbox/geojson-rewind": "^0.5.2", + "@mapbox/jsonlint-lines-primitives": "^2.0.2", + "@mapbox/point-geometry": "^0.1.0", + "@mapbox/tiny-sdf": "^2.0.6", + "@mapbox/unitbezier": "^0.0.1", + "@mapbox/vector-tile": "^1.3.1", + "@mapbox/whoots-js": "^3.1.0", + "@maplibre/maplibre-gl-style-spec": "^20.3.1", + "@types/geojson": "^7946.0.14", + "@types/geojson-vt": "3.2.5", + "@types/mapbox__point-geometry": "^0.1.4", + "@types/mapbox__vector-tile": "^1.3.4", + "@types/pbf": "^3.0.5", + "@types/supercluster": "^7.1.3", + "earcut": "^3.0.0", + "geojson-vt": "^4.0.2", + "gl-matrix": "^3.4.3", + "global-prefix": "^4.0.0", + "kdbush": "^4.0.2", + "murmurhash-js": "^1.0.0", + "pbf": "^3.3.0", + "potpack": "^2.0.0", + "quickselect": "^3.0.0", + "supercluster": "^8.0.1", + "tinyqueue": "^3.0.0", + "vt-pbf": "^3.1.3" + }, + "dependencies": { + "@mapbox/tiny-sdf": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@mapbox/tiny-sdf/-/tiny-sdf-2.0.6.tgz", + "integrity": "sha512-qMqa27TLw+ZQz5Jk+RcwZGH7BQf5G/TrutJhspsca/3SHwmgKQ1iq+d3Jxz5oysPVYTGP6aXxCo5Lk9Er6YBAA==" + }, + "@mapbox/unitbezier": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@mapbox/unitbezier/-/unitbezier-0.0.1.tgz", + "integrity": "sha512-nMkuDXFv60aBr9soUG5q+GvZYL+2KZHVvsqFCzqnkGEf46U2fvmytHaEVc1/YZbiLn8X+eR3QzX1+dwDO1lxlw==" + }, + "earcut": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.0.tgz", + "integrity": "sha512-41Fs7Q/PLq1SDbqjsgcY7GA42T0jvaCNGXgGtsNdvg+Yv8eIu06bxv4/PoREkZ9nMDNwnUSG9OFB9+yv8eKhDg==" + }, + "geojson-vt": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/geojson-vt/-/geojson-vt-4.0.2.tgz", + "integrity": "sha512-AV9ROqlNqoZEIJGfm1ncNjEXfkz2hdFlZf0qkVfmkwdKa8vj7H16YUOT81rJw1rdFhyEDlN2Tds91p/glzbl5A==" + }, + "kdbush": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/kdbush/-/kdbush-4.0.2.tgz", + "integrity": "sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==" + }, + "potpack": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/potpack/-/potpack-2.0.0.tgz", + "integrity": "sha512-Q+/tYsFU9r7xoOJ+y/ZTtdVQwTWfzjbiXBDMM/JKUux3+QPP02iUuIoeBQ+Ot6oEDlC+/PGjB/5A3K7KKb7hcw==" + }, + "quickselect": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz", + "integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==" + }, + "supercluster": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/supercluster/-/supercluster-8.0.1.tgz", + "integrity": "sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==", + "requires": { + "kdbush": "^4.0.2" + } + }, + "tinyqueue": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tinyqueue/-/tinyqueue-3.0.0.tgz", + "integrity": "sha512-gRa9gwYU3ECmQYv3lslts5hxuIa90veaEcxDYuu3QGOIAEM2mOZkVHp48ANJuu1CURtRdHKUBY5Lm1tHV+sD4g==" + } + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -29972,9 +30387,9 @@ "dev": true }, "pbf": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.2.1.tgz", - "integrity": "sha512-ClrV7pNOn7rtmoQVF4TS1vyU0WhYRnP92fzbfF75jAIwpnzdJXf8iTd4CMEqO4yUenH6NDqLiwjqlh6QgZzgLQ==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/pbf/-/pbf-3.3.0.tgz", + "integrity": "sha512-XDF38WCH3z5OV/OVa8GKUNtLAyneuzbCisx7QUCF8Q6Nutx0WnJrQe5O+kOtBlLfRNUws98Y58Lblp+NJG5T4Q==", "requires": { "ieee754": "^1.1.12", "resolve-protobuf-schema": "^2.1.0" diff --git a/projects/arlas-components/package.json b/projects/arlas-components/package.json index e06d8990..6e103e1c 100644 --- a/projects/arlas-components/package.json +++ b/projects/arlas-components/package.json @@ -1,6 +1,6 @@ { "name": "arlas-web-components", - "version": "27.0.0-map.alpha.4", + "version": "27.0.0-map.beta.1", "peerDependencies": { "@angular/animations": "^15.2.10", "@angular/cdk": "^15.2.9", diff --git a/projects/arlas-components/src/lib/components/mapgl-legend/mapgl-legend.module.ts b/projects/arlas-components/src/lib/components/mapgl-legend/mapgl-legend.module.ts deleted file mode 100644 index 475c0ec8..00000000 --- a/projects/arlas-components/src/lib/components/mapgl-legend/mapgl-legend.module.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Licensed to Gisaïa under one or more contributor - * license agreements. See the NOTICE.txt file distributed with - * this work for additional information regarding copyright - * ownership. Gisaïa licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { CommonModule } from '@angular/common'; -import { NgModule } from '@angular/core'; -import { TranslateModule } from '@ngx-translate/core'; -import { MapglLegendComponent } from './mapgl-legend.component'; -import { MapglLayerIconModule } from '../mapgl-layer-icon/mapgl-layer-icon.module'; -import { MatButtonModule } from '@angular/material/button'; -import { MatIconModule } from '@angular/material/icon'; -import { MatTooltipModule } from '@angular/material/tooltip'; -import { FormatNumberModule } from '../../pipes/format-number/format-number.module'; -import { LayerIdToName } from './layer-name.pipe'; -import { MatMenuModule } from '@angular/material/menu'; -import { GetCollectionDisplayModule } from '../../pipes/get-collection-display-name/get-collection-display.module'; -import { FormatLegendModule } from '../../pipes/format-legend/format-legend.module'; -import { GetColorModule } from '../../pipes/get-color/get-color.module'; -import { MapglLegendItemComponent } from './mapgl-legend-item/mapgl-legend-item.component'; -import { GetFieldDisplayModule } from '../../pipes/get-field-display-name/get-field-display.module'; - - -@NgModule({ - imports: [ - CommonModule, - TranslateModule, - MapglLayerIconModule, - MatButtonModule, - MatIconModule, - MatMenuModule, - MatTooltipModule, - FormatNumberModule, - GetColorModule, - GetCollectionDisplayModule, - GetFieldDisplayModule, - FormatLegendModule - ], - declarations: [MapglLegendComponent, LayerIdToName, MapglLegendItemComponent], - exports: [MapglLegendComponent, LayerIdToName, MapglLegendItemComponent] -}) -export class MapglLegendModule { - -} diff --git a/projects/arlas-components/src/lib/components/mapgl/mapgl.component.util.ts b/projects/arlas-components/src/lib/components/mapgl/mapgl.component.util.ts deleted file mode 100644 index 73fce69c..00000000 --- a/projects/arlas-components/src/lib/components/mapgl/mapgl.component.util.ts +++ /dev/null @@ -1,120 +0,0 @@ -/* - * Licensed to Gisaïa under one or more contributor - * license agreements. See the NOTICE.txt file distributed with - * this work for additional information regarding copyright - * ownership. Gisaïa licenses this file to you under - * the Apache License, Version 2.0 (the "License"); you may - * not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -import { Pipe, PipeTransform } from '@angular/core'; -import { Point } from 'mapbox-gl'; - -export function paddedBounds(npad: number, spad: number, epad: number, - wpad: number, map: any, SW, NE) { - const topRight = map.project(NE); - const bottomLeft = map.project(SW); - const scale = 1; - const southWestToPoint = map.project(SW); - const southWestPoint = new Point(((southWestToPoint.x - bottomLeft.x) * scale) - wpad, ((southWestToPoint.y - topRight.y) * scale) + spad); - const southWestWorld = new Point(southWestPoint.x / scale + bottomLeft.x, southWestPoint.y / scale + topRight.y); - const swWorld = map.unproject(southWestWorld); - const northEastToPoint = map.project(NE); - const northEastPoint = new Point(((northEastToPoint.x - bottomLeft.x) * scale) + epad, ((northEastToPoint.y - topRight.y) * scale) - npad); - const northEastWorld = new Point(northEastPoint.x / scale + bottomLeft.x, northEastPoint.y / scale + topRight.y); - const neWorld = map.unproject(northEastWorld); - return [swWorld, neWorld]; -} - -export function project(lat: number, lng: number, zoom: number): { x: number; y: number; } { - - const R = 6378137; - const sphericalScale = 0.5 / (Math.PI * R); - const d = Math.PI / 180; - const max = 1 - 1E-15; - const sin = Math.max(Math.min(Math.sin(lat * d), max), -max); - const scale = 256 * Math.pow(2, zoom); - - const point = { - x: R * lng * d, - y: R * Math.log((1 + sin) / (1 - sin)) / 2 - }; - - point.x = tiled(scale * (sphericalScale * point.x + 0.5)); - point.y = tiled(scale * (-sphericalScale * point.y + 0.5)); - - return point; -} - -function tiled(num: number): number { - return Math.floor(num / 256); -} - -export interface MapExtend { - bounds: number[][]; - center: number[]; - zoom: number; -} - -/** - * @deprecated Use GetValuePipe instead which performs the same operation, but generically - */ -@Pipe({ name: 'getLayer' }) -export class GetLayerPipe implements PipeTransform { - public transform(value: string, layersMap?: Map): mapboxgl.Layer { - return !!layersMap ? layersMap.get(value) : undefined; - } -} - -@Pipe({ name: 'getCollection' }) -export class GetCollectionPipe implements PipeTransform { - public transform(value: string, layersMap?: Map): string { - let collection: string; - if (!!layersMap && !!layersMap.get(value).metadata) { - if (!!layersMap.get(value).metadata.collection) { - collection = layersMap.get(value).metadata.collection; - } - } - return collection; - } -} - -export interface LegendData { - minValue?: string; - maxValue?: string; - keysColorsMap?: Map; -} - -export interface Legend { - type?: PROPERTY_SELECTOR_SOURCE; - title?: string; - minValue?: string; - maxValue?: string; - fixValue?: string | number; - interpolatedValues?: Array; - manualValues?: Map; - visible?: boolean; -} - - -export enum PROPERTY_SELECTOR_SOURCE { - fix = 'Fix', - provided = 'Provided', - generated = 'Generated', - manual = 'Manual', - interpolated = 'Interpolated', - metric_on_field = 'Metric on field', - heatmap_density = 'Density' -} - -export type ArlasAnyLayer = mapboxgl.CircleLayer | mapboxgl.FillLayer | mapboxgl.HeatmapLayer | mapboxgl.LineLayer | mapboxgl.SymbolLayer; diff --git a/projects/arlas-map/package.json b/projects/arlas-map/package.json index f4f22643..2495b0c8 100644 --- a/projects/arlas-map/package.json +++ b/projects/arlas-map/package.json @@ -1,16 +1,16 @@ { "name": "arlas-map", - "version": "27.0.0-alpha.8", + "version": "27.0.0-map.beta.1", "peerDependencies": { - "@angular/animations": "^14.2.12", - "@angular/cdk": "^14.2.7", - "@angular/common": "^14.2.12", - "@angular/core": "^14.2.12", - "@angular/forms": "^14.2.12", - "@angular/material": "^14.2.7", - "@angular/platform-browser": "^14.2.12", - "@angular/platform-browser-dynamic": "^14.2.12", - "@angular/router": "^14.2.12", + "@angular/animations": "^15.2.10", + "@angular/cdk": "^15.2.9", + "@angular/common": "^15.2.10", + "@angular/core": "^15.2.10", + "@angular/forms": "^15.2.10", + "@angular/material": "^15.2.9", + "@angular/platform-browser": "^15.2.10", + "@angular/platform-browser-dynamic": "^15.2.10", + "@angular/router": "^15.2.10", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "rxjs": "~7.4.0", @@ -34,6 +34,6 @@ "@turf/rhumb-destination": "^6.5.0", "@turf/transform-rotate": "^6.5.0", "pmtiles": "^2.11.0", - "arlas-web-components": "27.0.0-map.alpha.4" + "arlas-web-components": "27.0.0-map.beta.1" } } \ No newline at end of file diff --git a/projects/arlas-map/src/lib/arlas-map.component.ts b/projects/arlas-map/src/lib/arlas-map.component.ts index 3f5d276a..26dec943 100644 --- a/projects/arlas-map/src/lib/arlas-map.component.ts +++ b/projects/arlas-map/src/lib/arlas-map.component.ts @@ -306,6 +306,8 @@ export class ArlasMapComponent implements OnInit { + protected ICONS_BASE_PATH = 'assets/icons/'; + /** ------------------------------------------------------- VISUAL SEPERATOR - INIT ----------------------------------------- */ @@ -455,6 +457,18 @@ export class ArlasMapComponent implements OnInit { } } + /** + * Adds the custom icons given in the component's input + */ + public addIcons() { + this.icons.forEach(icon => { + const iconName = icon.path.split('.')[0]; + const iconPath = this.ICONS_BASE_PATH + icon.path; + const iconErrorMessage = 'The icon "' + this.ICONS_BASE_PATH + icon.path + '" is not found'; + this.mapService.addImage(iconName, iconPath, this.map, iconErrorMessage, { 'sdf': icon.recolorable } ); + }); + } + public declareMap() { console.log('declaaaring') this.initTransformRequest(); @@ -534,6 +548,7 @@ export class ArlasMapComponent implements OnInit { console.log('declare'); this.map = this.mapService.createMap(config); console.log(this.map); + this.map.eventEmitter$.subscribe({ next: (e: MapLayerMouseEvent) => { if (e.type === 'click') { @@ -602,6 +617,8 @@ export class ArlasMapComponent implements OnInit { // TODO: should change the this.basemapService.declareProtomapProtocol(this.map); this.basemapService.addProtomapBasemap(this.map); + this.addIcons(); + }); this.map.on('load', () => { diff --git a/projects/arlas-map/src/lib/arlas-map.service.ts b/projects/arlas-map/src/lib/arlas-map.service.ts index 4f6348d9..2b64f028 100644 --- a/projects/arlas-map/src/lib/arlas-map.service.ts +++ b/projects/arlas-map/src/lib/arlas-map.service.ts @@ -3,6 +3,7 @@ import { AbstractArlasMapGL, MapConfig } from './map/AbstractArlasMapGL'; import { AbstractDraw } from './draw/AbstractDraw'; import { LngLat } from './map/model/map'; import { FeatureCollection } from '@turf/helpers'; +import { VectorStyle } from './map/model/vector-style'; @Injectable({ providedIn: 'root' @@ -87,9 +88,43 @@ export abstract class ArlasMapService { * @param source A Geojson source * @param data A feature collection object. */ - public abstract setDataToGeojsonSource(source: any, data: FeatureCollection ); + public abstract setDataToGeojsonSource(source: any, data: FeatureCollection); - + public abstract addImage(name: string, url: string, map: AbstractArlasMapGL, errorMessage: string, opt?: any); + /** + * Checks if the given layer is already added to the map instance + * @param map Map instance + * @param layer layer identifier + */ + public abstract hasLayer(map: AbstractArlasMapGL, layer: any); + /** */ + public abstract setSource(sourceId: string, source: any, options: any); + public abstract addLayer(map: AbstractArlasMapGL, layer: any); + public abstract removeLayer(map: AbstractArlasMapGL, layer: any); + public abstract removeSource(map: AbstractArlasMapGL, layer: any); + public abstract createPopup(lng: number, lat: number, message: string); + public abstract addPopup(map: AbstractArlasMapGL, popup: any); + public abstract removePopup(map: AbstractArlasMapGL, popup: any); + public abstract removeLayers(map: AbstractArlasMapGL, layers: any) + public abstract removeLayersFromPattern(map: AbstractArlasMapGL, layersIdPattern: string); + public abstract hasLayersFromPattern(map: AbstractArlasMapGL, layersIdPattern: string); + public abstract setMapCursor(map: AbstractArlasMapGL, cursor: string): void; + + public abstract addIconLayer(map: AbstractArlasMapGL, layerId: string, iconName: string, + iconSize: number, data: GeoJSON.Feature | GeoJSON.FeatureCollection); + public abstract addRasterLayer(map: AbstractArlasMapGL, layerId: string, url: string, bounds: number[], + maxZoom: number, minZoom: number, tileSize: number, beforeId?: string): void; + + public abstract addGeojsonLayer(map: AbstractArlasMapGL, layerId: string, style: VectorStyle, + data: GeoJSON.Feature | GeoJSON.FeatureCollection + ): void; + + public abstract createGeojsonSource(data: GeoJSON.GeoJSON): any; + public abstract createRasterSource(url: string, bounds: number[], + maxZoom: number, minZoom: number, tileSize: number): any; + + public abstract onLayerEvent(eventName: any, map: AbstractArlasMapGL, layer: any, fn: () => void); + public abstract onMapEvent(eventName: any, map: AbstractArlasMapGL, fn: (e) => void); } diff --git a/projects/arlas-map/src/lib/map/AbstractArlasMapGL.ts b/projects/arlas-map/src/lib/map/AbstractArlasMapGL.ts index e34f3e5b..7feaade0 100644 --- a/projects/arlas-map/src/lib/map/AbstractArlasMapGL.ts +++ b/projects/arlas-map/src/lib/map/AbstractArlasMapGL.ts @@ -229,16 +229,7 @@ export abstract class AbstractArlasMapGL implements MapInterface { public getSource(id: string): unknown { throw new Error('Method not implemented.'); } - public addImage(name: string, image: HTMLImageElement - | ArrayBufferView | ImageData | ImageBitmap | { - width: number; height: number; data: Uint8Array - | Uint8ClampedArray; - }, options?: { pixelRatio?: number; sdf?: boolean; }): this { - throw new Error('Method not implemented.'); - } - public loadImage(url: string, callback: (error: any, image: any) => void): this { - throw new Error('Method not implemented.'); - } + public addLayer(layer: unknown, before?: string): this { throw new Error('Method not implemented.'); } @@ -312,10 +303,6 @@ export abstract class AbstractArlasMapGL implements MapInterface { throw new Error('Method not implemented.'); } - public removeImage(id: string): void { - throw new Error('Method not implemented.'); - } - public easeTo(options: unknown, unknown?: unknown): this { throw new Error('Method not implemented.'); } @@ -340,7 +327,6 @@ export abstract class AbstractArlasMapGL implements MapInterface { try { this._initMapProvider(config); this._initControls(); - this._initImages(); this._initOnLoad(); this._initMapMoveEvents(); } catch (e) { @@ -355,7 +341,6 @@ export abstract class AbstractArlasMapGL implements MapInterface { this._updateBounds(); this._updateZoom(); this.firstDrawLayer = this.getColdOrHotLayers()[0]; - this._initLoadIcons(); this._initSources(); this._initMapLayers(this); this._bindCustomEvent(this); @@ -419,25 +404,6 @@ export abstract class AbstractArlasMapGL implements MapInterface { } } - protected _initImages() { - console.log('init image call'); - this._loadInternalImage('assets/rotate/01.png', 'rotate'); - this._loadInternalImage('assets/resize/01.png', 'resize'); - } - - protected _initLoadIcons() { - if (this._icons) { - this._icons.forEach(icon => { - this._loadInternalImage( - this.ICONS_BASE_PATH + icon.path, - icon.path.split('.')[0], - 'The icon "' + this.ICONS_BASE_PATH + icon.path + '" is not found', - { 'sdf': icon.recolorable } - ); - }); - } - } - protected _initSources(): void { console.log('ini _initSources', this._dataSources); if (this._dataSources) { @@ -555,20 +521,6 @@ export abstract class AbstractArlasMapGL implements MapInterface { } } - protected _loadInternalImage(filePath: string, name: string, errorMessage?: string, opt?: any) { - this.loadImage(filePath, (error, image) => { - if (error) { - console.warn(errorMessage); - } else { - if (opt) { - this.addImage(name, image, opt); - } else { - this.addImage(name, image); - } - } - }); - } - protected addVisualLayers(): void { for (let i = this.visualisationSetsConfig.length - 1; i >= 0; i--) { const visualisation: VisualisationSetConfig = this.visualisationSetsConfig[i]; diff --git a/projects/arlas-map/src/lib/map/interface/map.interface.ts b/projects/arlas-map/src/lib/map/interface/map.interface.ts index a66a2a69..2653fc0f 100644 --- a/projects/arlas-map/src/lib/map/interface/map.interface.ts +++ b/projects/arlas-map/src/lib/map/interface/map.interface.ts @@ -118,20 +118,7 @@ export interface MapInterface { removeSource(id: string): this; getSource(id: string): unknown; - - addImage( - name: string, - image: - | HTMLImageElement - | ArrayBufferView - | { width: number; height: number; data: Uint8Array | Uint8ClampedArray; } - | ImageData - | ImageBitmap, - options?: { pixelRatio?: number | undefined; sdf?: boolean | undefined; }, - ): this; - - loadImage(url: string, callback: Function): this; - + addLayer(layer: unknown, before?: string): this; @@ -187,10 +174,7 @@ export interface MapInterface { fitBounds(bounds: unknown, options?: unknown, unknown?: unknown): this; - hasImage(id: string): boolean; - removeImage(id: string): void; - - + easeTo(options: unknown, unknown?: unknown): this; flyTo(options: unknown, unknown?: unknown): this; diff --git a/projects/arlas-map/src/lib/map/model/vector-style.ts b/projects/arlas-map/src/lib/map/model/vector-style.ts new file mode 100644 index 00000000..7029a1bd --- /dev/null +++ b/projects/arlas-map/src/lib/map/model/vector-style.ts @@ -0,0 +1,66 @@ +/* + * Licensed to Gisaïa under one or more contributor + * license agreements. See the NOTICE.txt file distributed with + * this work for additional information regarding copyright + * ownership. Gisaïa licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + + +/** This file describes how to style a vector layer */ + +export enum VectorStyleEnum { + circle = 'circle', + fill = 'fill', + line = 'line' +} + +export interface ArlasCircle { + 'circle-color': any; + 'circle-radius': any; + 'circle-blur': any; + 'circle-opacity': any; + 'circle-stroke-width': any; + 'circle-stroke-color': any; + 'circle-stroke-opacity': any; +} + +export interface ArlasFill { + 'fill-color': any; + 'fill-opacity': any; + 'fill-outline-color': any; +} + +export abstract class VectorStyle { + public type: VectorStyleEnum; + public style: ArlasCircle | ArlasFill; + public constructor(type: VectorStyleEnum, style: ArlasCircle | ArlasFill ) { + this.type = type; + this.style = style; + } + + public applyStyle(layer: any) { + switch (this.type) { + case VectorStyleEnum.circle: + this.circle(layer); + break; + case VectorStyleEnum.fill: + this.fill(layer); + break; + } + } + + public abstract circle(layer: any); + public abstract fill(layer: any); +} \ No newline at end of file diff --git a/projects/arlas-map/src/public-api.ts b/projects/arlas-map/src/public-api.ts index 52fc5d15..a4ecb41b 100644 --- a/projects/arlas-map/src/public-api.ts +++ b/projects/arlas-map/src/public-api.ts @@ -30,38 +30,39 @@ export { BboxGeneratorComponent } from './lib/bbox-generator/bbox-generator.comp export { BboxGeneratorModule } from './lib/bbox-generator/bbox-generator.module'; export { BboxFormGroup } from './lib/bbox-generator/bbox-generator.utils'; export { Coordinate } from './lib/bbox-generator/coordinates.tools'; -export { AbstractDraw } from './lib/draw/AbstractDraw' -export { AoiDimensions as AoiEdition, BboxDrawCommand, Corner, EditionState } from './lib/draw/draw.models' -export { MapboxAoiDrawService } from './lib/draw/draw.service' -export { limitVertexDirectSelectMode } from './lib/draw/modes/LimitVertexDirectSelectMode' -export { validGeomDrawPolygonMode } from './lib/draw/modes/ValidGeomDrawPolygonMode' -export { directModeOverride } from './lib/draw/modes/directSelectOverride' -export { simpleSelectModeOverride } from './lib/draw/modes/simpleSelectOverride' -export { circleMode } from './lib/draw/modes/circles/circle.mode' -export { radiusCircleMode } from './lib/draw/modes/circles/radius.circle.mode' -export { createSupplementaryPointsForCircle, dragPan } from './lib/draw/modes/circles/utils' -export { stripDirectSelectMode } from './lib/draw/modes/strip/strip.direct.mode' -export { stripMode } from './lib/draw/modes/strip/strip.mode' +export { AbstractDraw } from './lib/draw/AbstractDraw'; +export { AoiDimensions as AoiEdition, BboxDrawCommand, Corner, EditionState } from './lib/draw/draw.models'; +export { MapboxAoiDrawService } from './lib/draw/draw.service'; +export { limitVertexDirectSelectMode } from './lib/draw/modes/LimitVertexDirectSelectMode'; +export { validGeomDrawPolygonMode } from './lib/draw/modes/ValidGeomDrawPolygonMode'; +export { directModeOverride } from './lib/draw/modes/directSelectOverride'; +export { simpleSelectModeOverride } from './lib/draw/modes/simpleSelectOverride'; +export { circleMode } from './lib/draw/modes/circles/circle.mode'; +export { radiusCircleMode } from './lib/draw/modes/circles/radius.circle.mode'; +export { createSupplementaryPointsForCircle, dragPan } from './lib/draw/modes/circles/utils'; +export { stripDirectSelectMode } from './lib/draw/modes/strip/strip.direct.mode'; +export { stripMode } from './lib/draw/modes/strip/strip.mode'; export { AbstractArlasMapGL, ArlasMapOffset, CROSS_LAYER_PREFIX, BindLayerToEvent, ElementIdentifier, GEOJSON_SOURCE_TYPE, LAYER_SWITCHER_TOOLTIP, MapConfig, MapEventBinds, RESET_BEARING, ZOOM_IN, ZOOM_OUT - } from './lib/map/AbstractArlasMapGL' -export { MapInterface } from './lib/map/interface/map.interface' + } from './lib/map/AbstractArlasMapGL'; +export { MapInterface } from './lib/map/interface/map.interface'; export { ConfigControls, ControlButton, ControlPosition, ControlsOption, DrawConfigControl, DrawControlsOption, IconConfig, PitchToggle, PitchToggleConfigControls -} from './lib/map/model/controls' -export { MapExtent } from './lib/map/model/extent' +} from './lib/map/model/controls'; +export { MapExtent } from './lib/map/model/extent'; export { ARLAS_ID, ARLAS_VSET, ExternalEvent, ExternalEventLayer, FILLSTROKE_LAYER_PREFIX, FillStroke, HOVER_LAYER_PREFIX, LayerEvents, LayerMetadata, MapLayers, MetadataHiddenProps, PaintColor, PaintValue, SCROLLABLE_ARLAS_ID, SELECT_LAYER_PREFIX, getLayerName -} from './lib/map/model/layers' -export { ArlasMapSource } from './lib/map/model/sources' -export { VisualisationSetConfig } from './lib/map/model/visualisationsets' -export { Legend, LegendData, PROPERTY_SELECTOR_SOURCE, CircleLegend, LineLegend, FillLegend, HeatmapLegend, LabelLegend } from './lib/legend/legend.config' -export { getMax, MAX_CIRLE_RADIUS, MAX_LINE_WIDTH } from './lib/legend/legend.tools' -export * as styles from './lib/draw/themes/default-theme' -export { ArlasMapComponent } from './lib/arlas-map.component' -export { ArlasMapService } from './lib/arlas-map.service' -export { LngLat, OnMoveResult} from './lib/map/model/map' +} from './lib/map/model/layers'; +export { ArlasMapSource } from './lib/map/model/sources'; +export { VisualisationSetConfig } from './lib/map/model/visualisationsets'; +export { Legend, LegendData, PROPERTY_SELECTOR_SOURCE, CircleLegend, LineLegend, FillLegend, HeatmapLegend, LabelLegend } from './lib/legend/legend.config'; +export { getMax, MAX_CIRLE_RADIUS, MAX_LINE_WIDTH } from './lib/legend/legend.tools'; +export * as styles from './lib/draw/themes/default-theme'; +export { ArlasMapComponent } from './lib/arlas-map.component'; +export { ArlasMapService } from './lib/arlas-map.service'; +export { LngLat, OnMoveResult} from './lib/map/model/map'; +export { VectorStyle, ArlasCircle, ArlasFill, VectorStyleEnum } from './lib/map/model/vector-style'; diff --git a/projects/arlas-mapbox/package.json b/projects/arlas-mapbox/package.json index ef308f16..c83557e7 100644 --- a/projects/arlas-mapbox/package.json +++ b/projects/arlas-mapbox/package.json @@ -1,21 +1,21 @@ { "name": "arlas-mapbox", - "version": "27.0.0-alpha.4", + "version": "27.0.0-map.beta.1", "peerDependencies": { - "@angular/common": "^14.2.0", - "@angular/core": "^14.2.0", - "@angular/animations": "^14.2.12", - "@angular/cdk": "^14.2.7", - "@angular/forms": "^14.2.12", - "@angular/material": "^14.2.7", - "@angular/platform-browser": "^14.2.12", - "@angular/platform-browser-dynamic": "^14.2.12", - "@angular/router": "^14.2.12", + "@angular/animations": "^15.2.10", + "@angular/cdk": "^15.2.9", + "@angular/common": "^15.2.10", + "@angular/core": "^15.2.10", + "@angular/forms": "^15.2.10", + "@angular/material": "^15.2.9", + "@angular/platform-browser": "^15.2.10", + "@angular/platform-browser-dynamic": "^15.2.10", + "@angular/router": "^15.2.10", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "rxjs": "~7.4.0", "zone.js": "^0.11.4", - "arlas-map": "27.0.0-alpha.8" + "arlas-map": "27.0.0-map.beta.1" }, "dependencies": { "tslib": "^2.3.0", diff --git a/projects/arlas-mapbox/src/lib/arlas-mapbox.service.ts b/projects/arlas-mapbox/src/lib/arlas-mapbox.service.ts index e379e20c..7df479f7 100644 --- a/projects/arlas-mapbox/src/lib/arlas-mapbox.service.ts +++ b/projects/arlas-mapbox/src/lib/arlas-mapbox.service.ts @@ -1,10 +1,11 @@ import { Injectable } from '@angular/core'; import { ArlasMapService, CROSS_LAYER_PREFIX, LngLat } from 'arlas-map'; -import { GeoJSONSource, LngLatBounds, Point } from 'mapbox-gl'; +import { AnyLayer, AnySourceData, GeoJSONSource, GeoJSONSourceOptions, GeoJSONSourceRaw, LngLatBounds, Point, Popup, RasterLayer, RasterSource, Source, SymbolLayer } from 'mapbox-gl'; import { ArlasMapboxConfig, ArlasMapboxGL } from './map/ArlasMapboxGL'; import { ArlasDraw } from './draw/ArlasDraw'; import { ArlasAnyLayer } from './map/model/layers'; import { FeatureCollection } from '@turf/helpers'; +import { MapboxVectorStyle } from './map/model/vector-style'; @Injectable() export class ArlasMapboxService extends ArlasMapService { @@ -72,4 +73,327 @@ export class ArlasMapboxService extends ArlasMapService { source.setData(data); }; + /** + * @override Add an Image to the map. + * @param name Name of the image. + * @param url URL to fetch the image. + * @param map Mapbox map instance. + * @param errorMessage Error message shown as a warning if the image is not loaded. + * @param opt Options of image visualisation. + */ + public addImage(name: string, url: string, map: ArlasMapboxGL, errorMessage: string, opt?: any) { + const mapboxMap = map.getMapProvider(); + mapboxMap.loadImage( + url, + (error, image) => { + if (error) { + console.warn(errorMessage); + } + console.log('adding the imahe') + if (!mapboxMap.hasImage(name)) { + console.log(image) + mapboxMap.addImage(name, image, opt); + } + }); + } + + /** + * @override Mapbox implementation. + * Checks if the given layer is already added to the map instance + * @param map Map instance + * @param layer layer identifier + */ + public hasLayer(map: ArlasMapboxGL, layer: string): boolean { + return !!map.getMapProvider().getLayer(layer); + }; + + /** + * Checks if the given source is already added to the map instance + * @param sourceId source identifier + * @param map Map instance + */ + private hasSource(sourceId: string, map: ArlasMapboxGL): boolean { + return !!map.getMapProvider().getSource(sourceId); + } + /** + * Creates and returns a Geojson source instance. + * @param data Geojson data to add to the source. + * @returns returns a Geojson source instance + */ + public createGeojsonSource(data: GeoJSON.Feature | GeoJSON.FeatureCollection): GeoJSONSourceRaw { + return { + type: 'geojson', + data + } + }; + + /** + * @override Mapbox implementation. + * Adds the given source to the map instance + * @param sourceId Source identifier + * @param source Source instance + * @param map Map + */ + public setSource(sourceId: string, source: AnySourceData, map: ArlasMapboxGL) { + if (!this.hasSource(sourceId, map)) { + map.getMapProvider().addSource(sourceId, source); + } else { + console.warn(`The source ${sourceId} is already added to the map`); + } + }; + + /** + * @override Mapbox implementation. + * Adds the given layer to the map instance, optionnaly before a layer. Otherwise it's added to the top. + * @param map Map + * @param layer Layer to add to the map + * @param before Identifier of an already added layer. The given Layer (second param) is added under this 'before' layer. + */ + public addLayer(map: ArlasMapboxGL, layer: AnyLayer, before?: string) { + if (!this.hasLayer(map, layer.id)) { + map.getMapProvider().addLayer(layer, before); + } else { + console.warn(`The layer ${layer.id} is already added to the map`); + } + } + + + /** + * Executes the 'fn' function on 'eventName' triggered from the given 'layer' of the 'map' instance. + * @param eventName + * @param map + * @param layer + * @param fn + */ + public onLayerEvent(eventName: 'click' | 'mousemove' | 'mouseleave', map: ArlasMapboxGL, layer: string, fn: () => void): void { + map.getMapProvider().on(eventName, layer, fn); + } + + /** + * @override Mapbox implementation. + * Executes the 'fn' function on 'eventName' triggered from the 'map' instance. + * @param eventName + * @param map + * @param fn + */ + public onMapEvent(eventName: 'load' | 'moveend' | 'zoomend', map: ArlasMapboxGL, fn: (e) => void) { + map.getMapProvider().on(eventName, fn); + } + + /** + * @override Mapbox implementation. + * Removes the given layer from the map. If the source of this layer is still on the map, it is also removed. + * @param map Map instance. + * @param layer layer to remove. + */ + public removeLayer(map: ArlasMapboxGL, layer: string): void { + if (this.hasLayer(map, layer)) { + const sourceId = this.getLayer(map, layer)?.source as string; + map.getMapProvider().removeLayer(layer); + this.removeSource(map, sourceId); + } + }; + + /** + * Returns the layer object of the given layer id. + * @param map Map instance. + * @param layer Layer identifier + * @returns the layer object. + */ + private getLayer(map: ArlasMapboxGL, layer: string): ArlasAnyLayer { + return map.getMapProvider().getLayer(layer) as ArlasAnyLayer; + } + + + /** + * @override Mapbox implementation. + * Removes the source from the map instance + * @param map + * @param source + */ + public removeSource(map: ArlasMapboxGL, source: string) { + if (!!source && this.hasSource(source, map)) { + map.getMapProvider().removeSource(source); + } + }; + + /** + * @override Mapbox implementation. + * Creates a popup at lng,lat with the given message. The popup is not yet added to the map. + * @param lng Longitude. + * @param lat Latitude. + * @param message The popup message. + * @returns The popup instance. + */ + public createPopup(lng: number, lat: number, message: string): Popup { + const popup = new Popup({ + closeButton: false, + closeOnClick: false + }); + return popup.setLngLat([lat, lng]) + .setHTML(message) + } + + /** + * @override Mapbox implementation. + * Adds the given popup to the map. + * @param map Map instance. + * @param popup Popup instance. + */ + public addPopup(map: ArlasMapboxGL, popup: Popup): void { + popup.addTo(map.getMapProvider()); + } + + /** + * @override Mapbox implementation. + * Removes the given popup from the map. + * @param map Map instance. + * @param popup Popup instance. + */ + public removePopup(map: ArlasMapboxGL, popup: Popup): void { + popup.remove(); + } + + /** + * @override Mapbox implementation. + * Removes all the given layers (and their sources) from the map. + * @param map Map instance. + * @param layers Identifiers of layers to remove. + */ + public removeLayers(map: ArlasMapboxGL, layers: string[]): void { + layers.forEach(l => this.removeLayer(map, l)); + } + + /** + * @override Mapbox implementation. + * Removes all layers which identifier includes the given id pattern. + * @param map Map instance. + * @param layersIdPattern Identifiers pattern to remove from the map. + */ + public removeLayersFromPattern(map: ArlasMapboxGL, layersIdPattern: string) { + map.getMapProvider().getStyle().layers.filter(l => l.id.includes(layersIdPattern)).forEach(l => this.removeLayer(map, l.id)); + } + + /** + * @override Mapbox implementation. + * Checks if there are any layers respecting the given id patters + * @param map Map instance. + * @param layersIdPattern Identifiers pattern. + * @returns + */ + public hasLayersFromPattern(map: ArlasMapboxGL, layersIdPattern: string) { + return map.getMapProvider().getStyle().layers.filter(l => l.id.includes(layersIdPattern)).length > 0; + } + + /** + * @override Mapbox implementation. + * Set the mouse cursor when it's over the map + * @param map Map instance. + * @param cursor cursor type (https://developer.mozilla.org/fr/docs/Web/CSS/cursor) + */ + public setMapCursor(map: ArlasMapboxGL, cursor: string): void { + map.getMapProvider().getCanvas().style.cursor = cursor; + } + + /** + * @override Mapbox implementation. + * Creates and returns a raster source instance. + * @param url Url to the raster source. + * @param bounds Bounds of the image [west, south, east, north]. + * @param maxZoom Maximal zoom to display the raster. + * @param minZoom Minimal zoom to display the raster. + * @param tileSize Size of the tiles fetched to display the raster (in pixels). Default to 256. + * @returns + */ + public createRasterSource(url: string, bounds: number[], + maxZoom: number, minZoom: number, tileSize: number = 256): RasterSource { + return { + type: 'raster', + tiles: [url], + bounds: bounds as [number, number, number, number], + maxzoom: maxZoom, + minzoom: minZoom, + tileSize: tileSize + } + } + + /** + * @override Mapbox implementation. + * Creates a new Raster layer and adds it to the map. + * @param map Map instance + * @param url Url to the raster source. + * @param bounds Bounds of the image [west, south, east, north]. + * @param maxZoom Maximal zoom to display the raster. + * @param minZoom Minimal zoom to display the raster. + * @param tileSize Size of the tiles fetched to display the raster (in pixels). Default to 256. + * @param beforeId Identifier of an already added layer. The raster Layer is added under this 'beforeId' layer. + */ + + public addRasterLayer(map: ArlasMapboxGL, layerId: string, url: string, bounds: number[], + maxZoom: number, minZoom: number, tileSize: number, beforeId?: string): void { + const rasterSource: RasterSource = this.createRasterSource(url, bounds, maxZoom, minZoom, tileSize); + const sourceId = layerId; + this.setSource(sourceId, rasterSource, map); + const iconLayer: RasterLayer = { + id: layerId, + source: sourceId, + type: 'raster', + layout: { + visibility: 'visible' + } + } + this.addLayer(map, iconLayer, beforeId); + } + + /** + * @override Mapbox implementation. + * Creates a new Icon layer and adds to the map + * @param map Map instance + * @param layerId The identifier of the new icon layer + * @param iconName The icon name + * @param iconSize The icon size + * @param data Geojson data which features will be represented with the given icon. + */ + public addIconLayer(map: ArlasMapboxGL, layerId: string, iconName: string, iconSize: number, data: GeoJSON.Feature | GeoJSON.FeatureCollection) { + const iconSource: GeoJSONSourceRaw = this.createGeojsonSource(data); + const sourceId = layerId; + this.setSource(sourceId, iconSource, map); + const iconLayer: SymbolLayer = { + id: layerId, + source: sourceId, + type: 'symbol', + layout: { + 'icon-image': iconName, + 'icon-size': iconSize, + 'visibility': 'visible' + } + } + this.addLayer(map, iconLayer); + }; + + /** + * @override Mapbox implementation. + * Creates a new geojsob layer and adds to the map + * @param map Map instance + * @param layerId The identifier of the new icon layer + * @param style Vector style to apply to the geojson + * @param data Geojson data which features will be styled with the given style. + */ + public addGeojsonLayer(map: ArlasMapboxGL, layerId: string, style: MapboxVectorStyle, + data: GeoJSON.Feature | GeoJSON.FeatureCollection): void { + const source: GeoJSONSourceRaw = this.createGeojsonSource(data); + const sourceId = layerId; + this.setSource(sourceId, source, map); + const geojsonLayer: ArlasAnyLayer = { + id: layerId, + source: sourceId, + type: style.type, + layout: { + 'visibility': 'visible' + }, + } + style.applyStyle(geojsonLayer); + this.addLayer(map, geojsonLayer); + } + } diff --git a/projects/arlas-mapbox/src/lib/map/ArlasMapboxGL.ts b/projects/arlas-mapbox/src/lib/map/ArlasMapboxGL.ts index 5e17c427..921e4bf7 100644 --- a/projects/arlas-mapbox/src/lib/map/ArlasMapboxGL.ts +++ b/projects/arlas-mapbox/src/lib/map/ArlasMapboxGL.ts @@ -504,19 +504,6 @@ export class ArlasMapboxGL extends AbstractArlasMapGL { return this.getMapProvider().hasImage(id); } - public removeImage(id: string): void { - this.getMapProvider().removeImage(id); - } - - public addImage(name: string, image: HTMLImageElement | ArrayBufferView | { - width: number; - height: number; - data: Uint8Array | Uint8ClampedArray; - } | ImageData | ImageBitmap, options?: { pixelRatio?: number | undefined; sdf?: boolean | undefined; }): this { - this._mapProvider.addImage(name, image); - return this; - } - public cameraForBounds(bounds: mapboxgl.LngLatBoundsLike, options?: mapboxgl.CameraForBoundsOptions): mapboxgl.CameraForBoundsResult | undefined { return this._mapProvider.cameraForBounds(bounds, options); @@ -641,10 +628,6 @@ export class ArlasMapboxGL extends AbstractArlasMapGL { return this; } - public loadImage(url: string, callback: Function): this { - this._mapProvider.loadImage(url, callback); - return this; - } public addSource(id: string, source: AnySourceData): this { this._mapProvider.addSource(id, source); diff --git a/projects/arlas-mapbox/src/lib/map/model/vector-style.ts b/projects/arlas-mapbox/src/lib/map/model/vector-style.ts new file mode 100644 index 00000000..cf968182 --- /dev/null +++ b/projects/arlas-mapbox/src/lib/map/model/vector-style.ts @@ -0,0 +1,43 @@ +/* + * Licensed to Gisaïa under one or more contributor + * license agreements. See the NOTICE.txt file distributed with + * this work for additional information regarding copyright + * ownership. Gisaïa licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { VectorStyleEnum } from 'arlas-map'; +import { ArlasFill } from 'arlas-map'; +import { ArlasCircle } from 'arlas-map'; +import { VectorStyle } from 'arlas-map'; +import { CircleLayer, FillLayer } from 'mapbox-gl'; + + +/** This file describes how to style a vector layer */ + +export class MapboxVectorStyle extends VectorStyle { + public constructor(type: VectorStyleEnum, style: ArlasCircle | ArlasFill) { + super(type, style); + } + + /** Any adjustment from ArlasCircle to the layer circle style should be implemented here. */ + public circle(layer: CircleLayer) { + layer.paint = this.style as any; + }; + + /** Any adjustment from ArlasFill to the layer fill style should be implemented here. */ + public fill(layer: FillLayer) { + layer.paint = this.style as any; + }; +} \ No newline at end of file diff --git a/projects/arlas-maplibre/package.json b/projects/arlas-maplibre/package.json index 426ce0b3..db6d6d8f 100644 --- a/projects/arlas-maplibre/package.json +++ b/projects/arlas-maplibre/package.json @@ -1,21 +1,21 @@ { "name": "arlas-maplibre", - "version": "27.0.0-alpha.4", + "version": "27.0.0-map.beta.1", "peerDependencies": { - "@angular/common": "^14.2.0", - "@angular/core": "^14.2.0", - "@angular/animations": "^14.2.12", - "@angular/cdk": "^14.2.7", - "@angular/forms": "^14.2.12", - "@angular/material": "^14.2.7", - "@angular/platform-browser": "^14.2.12", - "@angular/platform-browser-dynamic": "^14.2.12", - "@angular/router": "^14.2.12", + "@angular/animations": "^15.2.10", + "@angular/cdk": "^15.2.9", + "@angular/common": "^15.2.10", + "@angular/core": "^15.2.10", + "@angular/forms": "^15.2.10", + "@angular/material": "^15.2.9", + "@angular/platform-browser": "^15.2.10", + "@angular/platform-browser-dynamic": "^15.2.10", + "@angular/router": "^15.2.10", "@ngx-translate/core": "^14.0.0", "@ngx-translate/http-loader": "^7.0.0", "rxjs": "~7.4.0", "zone.js": "^0.11.4", - "arlas-map": "27.0.0.alpha.8" + "arlas-map": "27.0.0-map.beta.1" }, "dependencies": { "tslib": "^2.3.0", diff --git a/projects/arlas-maplibre/src/lib/arlas-maplibre.service.ts b/projects/arlas-maplibre/src/lib/arlas-maplibre.service.ts index e5220d0d..f4e11308 100644 --- a/projects/arlas-maplibre/src/lib/arlas-maplibre.service.ts +++ b/projects/arlas-maplibre/src/lib/arlas-maplibre.service.ts @@ -1,11 +1,13 @@ import { Injectable } from '@angular/core'; import { ArlasMapService, CROSS_LAYER_PREFIX } from 'arlas-map'; -import { GeoJSONSource, LngLatBounds, Point, ResourceType, TypedStyleLayer } from 'maplibre-gl'; +import { AddLayerObject, CanvasSourceSpecification, GeoJSONSource, GeoJSONSourceSpecification, LayerSpecification, LngLatBounds, Point, Popup, RasterLayerSpecification, RasterSourceSpecification, ResourceType, SourceSpecification, SymbolLayerSpecification, TypedStyleLayer } from 'maplibre-gl'; import { ArlasMaplibreConfig, ArlasMaplibreGL } from './map/ArlasMaplibreGL'; import { ArlasDraw } from './draw/ArlasDraw'; import { LngLat } from 'arlas-map'; import { LayerMetadata } from 'arlas-map'; import { FeatureCollection } from '@turf/helpers'; +import { from } from 'rxjs'; +import { MaplibreVectorStyle } from './map/model/vector-style'; @Injectable() export class ArlasMaplibreService extends ArlasMapService { @@ -73,4 +75,328 @@ export class ArlasMaplibreService extends ArlasMapService { source.setData(data); }; + /** + * @override Add an Image to the map. + * @param name Name of the image. + * @param url URL to fetch the image. + * @param map Maplibre map instance. + * @param errorMessage Error message shown as a warning if the image is not loaded. + * @param opt Options of image visualisation. + */ + public addImage(name: string, url: string, map: ArlasMaplibreGL, errorMessage: string, opt?: any) { + const maplibreMap = map.getMapProvider(); + from(maplibreMap.loadImage(url)).subscribe({ + next: (r) => { + if (!maplibreMap.hasImage(name)) { + maplibreMap.addImage(name, r.data, opt); + } + }, + error: (err) => { + console.warn(errorMessage) + } + }) + } + + + /** + * @override Maplibre implementation. + * Checks if the given layer is already added to the map instance + * @param map Map instance + * @param layer layer identifier + */ + public hasLayer(map: ArlasMaplibreGL, layer: string): boolean { + return !!map.getMapProvider().getLayer(layer); + }; + + /** + * Checks if the given source is already added to the map instance + * @param sourceId source identifier + * @param map Map instance + */ + private hasSource(sourceId: string, map: ArlasMaplibreGL): boolean { + return !!map.getMapProvider().getSource(sourceId); + } + /** + * Creates and returns a Geojson source instance. + * @param data Geojson data to add to the source. + * @returns returns a Geojson source instance + */ + public createGeojsonSource(data: GeoJSON.Feature | GeoJSON.FeatureCollection): GeoJSONSourceSpecification { + return { + type: 'geojson', + data + } + }; + + /** + * @override Maplibre implementation. + * Adds the given source to the map instance + * @param sourceId Source identifier + * @param source Source instance + * @param map Map + */ + public setSource(sourceId: string, source: SourceSpecification | CanvasSourceSpecification, map: ArlasMaplibreGL) { + if (!this.hasSource(sourceId, map)) { + map.getMapProvider().addSource(sourceId, source); + } else { + console.warn(`The source ${sourceId} is already added to the map`); + } + }; + + /** + * @override Maplibre implementation. + * Adds the given layer to the map instance, optionnaly before a layer. Otherwise it's added to the top. + * @param map Map + * @param layer Layer to add to the map + * @param before Identifier of an already added layer. The given Layer (second param) is added under this 'before' layer. + */ + public addLayer(map: ArlasMaplibreGL, layer: AddLayerObject, before?: string) { + if (!this.hasLayer(map, layer.id)) { + map.getMapProvider().addLayer(layer, before); + } else { + console.warn(`The layer ${layer.id} is already added to the map`); + } + } + + /** + * @override Maplibre implementation. + * Executes the 'fn' function on 'eventName' triggered from the given 'layer' of the 'map' instance. + * @param eventName + * @param map + * @param layer + * @param fn + */ + public onLayerEvent(eventName: 'click' | 'mousemove' | 'mouseleave' | 'mouseenter', map: ArlasMaplibreGL, layer: string, fn: () => void): void { + map.getMapProvider().on(eventName, layer, fn); + } + + /** + * @override Maplibre implementation. + * Executes the 'fn' function on 'eventName' triggered from the 'map' instance. + * @param eventName + * @param map + * @param fn + */ + public onMapEvent(eventName: 'load' | 'moveend' | 'zoomend', map: ArlasMaplibreGL, fn: (e) => void) { + map.getMapProvider().on(eventName, fn); + } + + + /** + * @override Maplibre implementation. + * Removes the given layer from the map. If the source of this layer is still on the map, it is also removed. + * @param map Map instance. + * @param layer layer to remove. + */ + public removeLayer(map: ArlasMaplibreGL, layer: string): void { + if (this.hasLayer(map, layer)) { + const sourceId = this.getLayer(map, layer).source; + map.getMapProvider().removeLayer(layer); + this.removeSource(map, sourceId); + } + }; + + /** + * Returns the layer object of the given layer id. + * @param map Map instance. + * @param layer Layer identifier + * @returns the layer object. + */ + private getLayer(map: ArlasMaplibreGL, layer: string) { + return map.getMapProvider().getLayer(layer); + } + + + /** + * @override Maplibre implementation. + * Removes the source from the map instance + * @param map + * @param source + */ + public removeSource(map: ArlasMaplibreGL, source: string) { + if (!!source && this.hasSource(source, map)) { + map.getMapProvider().removeSource(source); + } + }; + + /** + * @override Maplibre implementation. + * Creates a popup at lng,lat with the given message. The popup is not yet added to the map. + * @param lng Longitude. + * @param lat Latitude. + * @param message The popup message. + * @returns The popup instance. + */ + public createPopup(lng: number, lat: number, message: string): Popup { + const popup = new Popup({ + closeButton: false, + closeOnClick: false + }); + return popup.setLngLat([lat, lng]) + .setHTML(message) + } + + /** + * @override Maplibre implementation. + * Adds the given popup to the map. + * @param map Map instance. + * @param popup Popup instance. + */ + public addPopup(map: ArlasMaplibreGL, popup: Popup): void { + popup.addTo(map.getMapProvider()); + } + + /** + * @override Maplibre implementation. + * Removes the given popup from the map. + * @param map Map instance. + * @param popup Popup instance. + */ + public removePopup(map: ArlasMaplibreGL, popup: Popup): void { + popup.remove(); + } + + /** + * @override Maplibre implementation. + * Removes all the given layers (and their sources) from the map. + * @param map Map instance. + * @param layers Identifiers of layers to remove. + */ + public removeLayers(map: ArlasMaplibreGL, layers: string[]): void { + layers.forEach(l => this.removeLayer(map, l)); + } + + /** + * @override Maplibre implementation. + * Removes all layers which identifier includes the given id pattern. + * @param map Map instance. + * @param layersIdPattern Identifiers pattern to remove from the map. + */ + public removeLayersFromPattern(map: ArlasMaplibreGL, layersIdPattern: string) { + map.getMapProvider().getStyle().layers.filter(l => l.id.includes(layersIdPattern)).forEach(l => this.removeLayer(map, l.id)); + } + + /** + * @override Maplibre implementation. + * Checks if there are any layers respecting the given id patters + * @param map Map instance. + * @param layersIdPattern Identifiers pattern. + * @returns + */ + public hasLayersFromPattern(map: ArlasMaplibreGL, layersIdPattern: string) { + return map.getMapProvider().getStyle().layers.filter(l => l.id.includes(layersIdPattern)).length > 0; + } + + /** + * @override Maplibre implementation. + * Set the mouse cursor when it's over the map + * @param map Map instance. + * @param cursor cursor type (https://developer.mozilla.org/fr/docs/Web/CSS/cursor) + */ + public setMapCursor(map: ArlasMaplibreGL, cursor: string): void { + map.getMapProvider().getCanvas().style.cursor = cursor; + } + + /** + * @override Maplibre implementation. + * Creates and returns a raster source instance. + * @param url Url to the raster source. + * @param bounds Bounds of the image [west, south, east, north]. + * @param maxZoom Maximal zoom to display the raster. + * @param minZoom Minimal zoom to display the raster. + * @param tileSize Size of the tiles fetched to display the raster (in pixels). Default to 256. + * @returns + */ + public createRasterSource(url: string, bounds: number[], + maxZoom: number, minZoom: number, tileSize: number = 256): RasterSourceSpecification { + return { + type: 'raster', + tiles: [url], + bounds: bounds as [number, number, number, number], + maxzoom: maxZoom, + minzoom: minZoom, + tileSize: tileSize + } + } + + /** + * @override Maplibre implementation. + * Creates a new Raster layer and adds it to the map. + * @param map Map instance + * @param url Url to the raster source. + * @param bounds Bounds of the image [west, south, east, north]. + * @param maxZoom Maximal zoom to display the raster. + * @param minZoom Minimal zoom to display the raster. + * @param tileSize Size of the tiles fetched to display the raster (in pixels). Default to 256. + * @param beforeId Identifier of an already added layer. The raster Layer is added under this 'beforeId' layer. + */ + public addRasterLayer(map: ArlasMaplibreGL, layerId: string, url: string, bounds: number[], + maxZoom: number, minZoom: number, tileSize: number, beforeId?: string): void { + const rasterSource: RasterSourceSpecification = this.createRasterSource(url, bounds, maxZoom, minZoom, tileSize); + const sourceId = layerId; + this.setSource(sourceId, rasterSource, map); + const iconLayer: RasterLayerSpecification = { + id: layerId, + source: sourceId, + type: 'raster', + layout: { + visibility: 'visible' + } + } + this.addLayer(map, iconLayer, beforeId); + } + + /** + * @override Maplibre implementation. + * Creates a new geojsob layer and adds to the map + * @param map Map instance + * @param layerId The identifier of the new icon layer + * @param style Vector style to apply to the geojson + * @param data Geojson data which features will be styled with the given style. + */ + public addGeojsonLayer(map: ArlasMaplibreGL, layerId: string, style: MaplibreVectorStyle, + data: GeoJSON.Feature | GeoJSON.FeatureCollection): void { + const source: GeoJSONSourceSpecification = this.createGeojsonSource(data); + const sourceId = layerId; + this.setSource(sourceId, source, map); + const geojsonLayer: LayerSpecification = { + id: layerId, + source: sourceId, + type: style.type, + layout: { + 'visibility': 'visible' + }, + } + style.applyStyle(geojsonLayer); + this.addLayer(map, geojsonLayer); + } + + /** + * @override Maplibre implementation. + * Creates a new Icon layer and adds to the map + * @param map Map instance + * @param layerId The identifier of the new icon layer + * @param iconName The icon name + * @param iconSize The icon size + * @param data Geojson data which features will be represented with the given icon. + */ + public addIconLayer(map: ArlasMaplibreGL, layerId: string, iconName: string, iconSize: number, data: GeoJSON.Feature | GeoJSON.FeatureCollection) { + const iconSource: GeoJSONSourceSpecification = this.createGeojsonSource(data); + const sourceId = layerId; + this.setSource(sourceId, iconSource, map); + const iconLayer: SymbolLayerSpecification = { + id: layerId, + source: sourceId, + type: 'symbol', + layout: { + 'icon-image': iconName, + 'icon-size': iconSize, + 'visibility': 'visible' + } + } + this.addLayer(map, iconLayer); + }; + + + } diff --git a/projects/arlas-maplibre/src/lib/map/ArlasMaplibreGL.ts b/projects/arlas-maplibre/src/lib/map/ArlasMaplibreGL.ts index 683cb1e0..922e347e 100644 --- a/projects/arlas-maplibre/src/lib/map/ArlasMaplibreGL.ts +++ b/projects/arlas-maplibre/src/lib/map/ArlasMaplibreGL.ts @@ -346,9 +346,6 @@ export class ArlasMaplibreGL extends AbstractArlasMapGL { return this.getMapProvider().hasImage(id); } - public removeImage(id: string): void { - this.getMapProvider().removeImage(id); - } public initDrawControls(config: DrawControlsOption) { @@ -490,24 +487,7 @@ export class ArlasMaplibreGL extends AbstractArlasMapGL { public getSource(id: string): unknown { return this._mapProvider.getSource(id); } - public addImage(name: string, image: HTMLImageElement | ImageBitmap | ImageData | { - width: number; - height: number; - data: Uint8Array | Uint8ClampedArray; - } | StyleImageInterface, options?: { pixelRatio?: number; sdf?: boolean; }): this { - this._mapProvider.addImage(name, image); - return this; - } - public loadImage(url: string, callback: (error: any, image: any) => void): this { - this._mapProvider.loadImage(url) - .then(res => { - callback(null, res.data); - }) - .catch(err => { - callback(err, null); - }); - return this; - } + public addLayer(layer: AddLayerObject, before?: string): this { this.getMapProvider().addLayer(layer, before); return this; diff --git a/projects/arlas-maplibre/src/lib/map/model/vector-style.ts b/projects/arlas-maplibre/src/lib/map/model/vector-style.ts new file mode 100644 index 00000000..b2cfa999 --- /dev/null +++ b/projects/arlas-maplibre/src/lib/map/model/vector-style.ts @@ -0,0 +1,42 @@ +/* + * Licensed to Gisaïa under one or more contributor + * license agreements. See the NOTICE.txt file distributed with + * this work for additional information regarding copyright + * ownership. Gisaïa licenses this file to you under + * the Apache License, Version 2.0 (the "License"); you may + * not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import { ArlasFill, VectorStyleEnum } from 'arlas-map'; +import { ArlasCircle } from 'arlas-map'; +import { VectorStyle } from 'arlas-map'; +import { CircleLayerSpecification, FillLayerSpecification } from 'maplibre-gl'; + + +/** This file describes how to style a vector layer */ + +export class MaplibreVectorStyle extends VectorStyle { + public constructor(type: VectorStyleEnum, style: ArlasCircle | ArlasFill) { + super(type, style); + } + + /** Any adjustment from ArlasCircle to the layer circle style should be implemented here. */ + public circle(layer: CircleLayerSpecification) { + layer.paint = this.style as any; + }; + + /** Any adjustment from ArlasFill to the layer fill style should be implemented here. */ + public fill(layer: FillLayerSpecification) { + layer.paint = this.style as any; + }; +} \ No newline at end of file diff --git a/projects/arlas-maplibre/src/public-api.ts b/projects/arlas-maplibre/src/public-api.ts index 2ec1b111..1220150f 100644 --- a/projects/arlas-maplibre/src/public-api.ts +++ b/projects/arlas-maplibre/src/public-api.ts @@ -5,4 +5,5 @@ export * from './lib/arlas-maplibre.service'; export * from './lib/arlas-maplibre.module'; export { MaplibreLegendService } from './lib/legend/legend.service'; -export { MaplibreBasemapService } from './lib/basemaps/maplibre-basemap.service'; \ No newline at end of file +export { MaplibreBasemapService } from './lib/basemaps/maplibre-basemap.service'; +export { MaplibreVectorStyle } from './lib/map/model/vector-style'; \ No newline at end of file