From cab9de1e90787deb0b71607e6b8782bbbdf7dbae Mon Sep 17 00:00:00 2001 From: troispoils Date: Tue, 7 May 2024 18:01:11 +0200 Subject: [PATCH] Fist Push --- .gitignore | 2 + Dockerfile | 15 + public old/favicon.ico | Bin 0 -> 22559 bytes public old/icons/blue_circle_full.png | Bin 0 -> 650 bytes public old/icons/blue_circle_void.png | Bin 0 -> 658 bytes public old/icons/blue_cross_full.png | Bin 0 -> 580 bytes public old/icons/green_circle_full.png | Bin 0 -> 849 bytes public old/icons/green_star.png | Bin 0 -> 565 bytes public old/icons/green_star_big.png | Bin 0 -> 720 bytes public old/icons/grey_square.png | Bin 0 -> 562 bytes public old/icons/orange_star.png | Bin 0 -> 568 bytes public old/icons/red_cross_full.png | Bin 0 -> 582 bytes public old/icons/red_cross_void.png | Bin 0 -> 568 bytes public old/icons/red_star.png | Bin 0 -> 563 bytes public old/icons/yellow_crown.png | Bin 0 -> 598 bytes public old/icons/yellow_square_full.png | Bin 0 -> 559 bytes public old/icons/yellow_square_void.png | Bin 0 -> 581 bytes public old/icons/yellow_star.png | Bin 0 -> 554 bytes public old/icons/yellow_star_big.png | Bin 0 -> 675 bytes public old/index.html | 17 + public old/scripts/._leafletBase.js | Bin 0 -> 4096 bytes public old/scripts/coordOverlay.js | 16 + .../scripts/dist/MarkerCluster.Default.css | 60 + public old/scripts/dist/MarkerCluster.css | 14 + .../dist/WhereAreTheJavascriptFiles.txt | 5 + public old/scripts/dist/images/layers-2x.png | Bin 0 -> 1259 bytes public old/scripts/dist/images/layers.png | Bin 0 -> 696 bytes .../scripts/dist/images/marker-icon-2x.png | Bin 0 -> 2464 bytes .../scripts/dist/images/marker-icon.png | Bin 0 -> 1466 bytes .../scripts/dist/images/marker-shadow.png | Bin 0 -> 618 bytes public old/scripts/dist/leaflet-src.esm.js | 14419 +++++ .../scripts/dist/leaflet-src.esm.js.map | 1 + public old/scripts/dist/leaflet-src.js | 14512 +++++ public old/scripts/dist/leaflet-src.js.map | 1 + public old/scripts/dist/leaflet.css | 661 + public old/scripts/dist/leaflet.js | 6 + public old/scripts/dist/leaflet.js.map | 1 + .../scripts/dist/leaflet.markercluster-src.js | 2718 + .../dist/leaflet.markercluster-src.js.map | 1 + .../scripts/dist/leaflet.markercluster.js | 2 + .../scripts/dist/leaflet.markercluster.js.map | 1 + public old/scripts/dist/three.cjs | 53446 ++++++++++++++++ public old/scripts/dist/three.module.js | 53032 +++++++++++++++ public old/scripts/dist/three.module.min.js | 6 + public old/scripts/fetching.js | 45 + public old/scripts/iconsMap.js | 54 + public old/scripts/leafletBase.js | 166 + public old/scripts/poi/testGroups.js | 41573 ++++++++++++ public old/style/style.css | 24 + public/favicon.ico | Bin 0 -> 22559 bytes public/icons/blue_circle_full.png | Bin 0 -> 650 bytes public/icons/blue_circle_void.png | Bin 0 -> 658 bytes public/icons/blue_cross_full.png | Bin 0 -> 580 bytes public/icons/green_circle_full.png | Bin 0 -> 849 bytes public/icons/green_star.png | Bin 0 -> 565 bytes public/icons/green_star_big.png | Bin 0 -> 720 bytes public/icons/grey_square.png | Bin 0 -> 562 bytes public/icons/orange_star.png | Bin 0 -> 568 bytes public/icons/red_cross_full.png | Bin 0 -> 582 bytes public/icons/red_cross_void.png | Bin 0 -> 568 bytes public/icons/red_star.png | Bin 0 -> 563 bytes public/icons/yellow_crown.png | Bin 0 -> 598 bytes public/icons/yellow_square_full.png | Bin 0 -> 559 bytes public/icons/yellow_square_void.png | Bin 0 -> 581 bytes public/icons/yellow_star.png | Bin 0 -> 554 bytes public/icons/yellow_star_big.png | Bin 0 -> 675 bytes public/index.html | 17 + public/scripts/dist/MarkerCluster.Default.css | 60 + public/scripts/dist/MarkerCluster.css | 14 + .../dist/WhereAreTheJavascriptFiles.txt | 5 + public/scripts/dist/images/layers-2x.png | Bin 0 -> 1259 bytes public/scripts/dist/images/layers.png | Bin 0 -> 696 bytes public/scripts/dist/images/marker-icon-2x.png | Bin 0 -> 2464 bytes public/scripts/dist/images/marker-icon.png | Bin 0 -> 1466 bytes public/scripts/dist/images/marker-shadow.png | Bin 0 -> 618 bytes public/scripts/dist/leaflet-src.esm.js | 14419 +++++ public/scripts/dist/leaflet-src.esm.js.map | 1 + public/scripts/dist/leaflet-src.js | 14512 +++++ public/scripts/dist/leaflet-src.js.map | 1 + public/scripts/dist/leaflet.css | 661 + public/scripts/dist/leaflet.js | 6 + public/scripts/dist/leaflet.js.map | 1 + .../scripts/dist/leaflet.markercluster-src.js | 2718 + .../dist/leaflet.markercluster-src.js.map | 1 + public/scripts/dist/leaflet.markercluster.js | 2 + .../scripts/dist/leaflet.markercluster.js.map | 1 + public/scripts/dist/three.cjs | 53446 ++++++++++++++++ public/scripts/dist/three.module.js | 53032 +++++++++++++++ public/scripts/dist/three.module.min.js | 6 + public/scripts/main.js | 18 + public/scripts/map.js | 33 + public/scripts/modules/iconsMap.js | 59 + public/scripts/modules/math.js | 35 + public/scripts/overlays/overlaysCoord.js | 26 + public/scripts/overlays/overlaysNpc.js | 21 + public/scripts/overlays/overlaysPlayer.js | 46 + public/scripts/overlays/overlaysPoi.js | 54 + public/scripts/poi/testGroups.js | 41573 ++++++++++++ public/style/style.css | 24 + server/.gitignore | 169 + server/app.js | 59 + server/data/city.json | 27 + server/data/dungeon.json | 192 + server/data/faction.json | 97 + server/data/gateways.json | 182 + server/data/outpost.json | 297 + server/data/poi.json | 502 + server/data/ringways.json | 422 + server/data/town.json | 112 + server/data/vault.json | 107 + server/db.js | 101 + server/jsconfig.json | 10 + server/modules/poi.js | 10 + server/package-lock.json | 802 + server/package.json | 17 + server/process.env | 4 + server/utils/utilsMath.js | 24 + tiles/.gitignore | 2 + 118 files changed, 364726 insertions(+) create mode 100644 .gitignore create mode 100644 Dockerfile create mode 100644 public old/favicon.ico create mode 100644 public old/icons/blue_circle_full.png create mode 100644 public old/icons/blue_circle_void.png create mode 100644 public old/icons/blue_cross_full.png create mode 100644 public old/icons/green_circle_full.png create mode 100644 public old/icons/green_star.png create mode 100644 public old/icons/green_star_big.png create mode 100644 public old/icons/grey_square.png create mode 100644 public old/icons/orange_star.png create mode 100644 public old/icons/red_cross_full.png create mode 100644 public old/icons/red_cross_void.png create mode 100644 public old/icons/red_star.png create mode 100644 public old/icons/yellow_crown.png create mode 100644 public old/icons/yellow_square_full.png create mode 100644 public old/icons/yellow_square_void.png create mode 100644 public old/icons/yellow_star.png create mode 100644 public old/icons/yellow_star_big.png create mode 100644 public old/index.html create mode 100644 public old/scripts/._leafletBase.js create mode 100644 public old/scripts/coordOverlay.js create mode 100644 public old/scripts/dist/MarkerCluster.Default.css create mode 100644 public old/scripts/dist/MarkerCluster.css create mode 100644 public old/scripts/dist/WhereAreTheJavascriptFiles.txt create mode 100644 public old/scripts/dist/images/layers-2x.png create mode 100644 public old/scripts/dist/images/layers.png create mode 100644 public old/scripts/dist/images/marker-icon-2x.png create mode 100644 public old/scripts/dist/images/marker-icon.png create mode 100644 public old/scripts/dist/images/marker-shadow.png create mode 100644 public old/scripts/dist/leaflet-src.esm.js create mode 100644 public old/scripts/dist/leaflet-src.esm.js.map create mode 100644 public old/scripts/dist/leaflet-src.js create mode 100644 public old/scripts/dist/leaflet-src.js.map create mode 100644 public old/scripts/dist/leaflet.css create mode 100644 public old/scripts/dist/leaflet.js create mode 100644 public old/scripts/dist/leaflet.js.map create mode 100644 public old/scripts/dist/leaflet.markercluster-src.js create mode 100644 public old/scripts/dist/leaflet.markercluster-src.js.map create mode 100644 public old/scripts/dist/leaflet.markercluster.js create mode 100644 public old/scripts/dist/leaflet.markercluster.js.map create mode 100644 public old/scripts/dist/three.cjs create mode 100644 public old/scripts/dist/three.module.js create mode 100644 public old/scripts/dist/three.module.min.js create mode 100644 public old/scripts/fetching.js create mode 100644 public old/scripts/iconsMap.js create mode 100644 public old/scripts/leafletBase.js create mode 100644 public old/scripts/poi/testGroups.js create mode 100644 public old/style/style.css create mode 100644 public/favicon.ico create mode 100644 public/icons/blue_circle_full.png create mode 100644 public/icons/blue_circle_void.png create mode 100644 public/icons/blue_cross_full.png create mode 100644 public/icons/green_circle_full.png create mode 100644 public/icons/green_star.png create mode 100644 public/icons/green_star_big.png create mode 100644 public/icons/grey_square.png create mode 100644 public/icons/orange_star.png create mode 100644 public/icons/red_cross_full.png create mode 100644 public/icons/red_cross_void.png create mode 100644 public/icons/red_star.png create mode 100644 public/icons/yellow_crown.png create mode 100644 public/icons/yellow_square_full.png create mode 100644 public/icons/yellow_square_void.png create mode 100644 public/icons/yellow_star.png create mode 100644 public/icons/yellow_star_big.png create mode 100644 public/index.html create mode 100644 public/scripts/dist/MarkerCluster.Default.css create mode 100644 public/scripts/dist/MarkerCluster.css create mode 100644 public/scripts/dist/WhereAreTheJavascriptFiles.txt create mode 100644 public/scripts/dist/images/layers-2x.png create mode 100644 public/scripts/dist/images/layers.png create mode 100644 public/scripts/dist/images/marker-icon-2x.png create mode 100644 public/scripts/dist/images/marker-icon.png create mode 100644 public/scripts/dist/images/marker-shadow.png create mode 100644 public/scripts/dist/leaflet-src.esm.js create mode 100644 public/scripts/dist/leaflet-src.esm.js.map create mode 100644 public/scripts/dist/leaflet-src.js create mode 100644 public/scripts/dist/leaflet-src.js.map create mode 100644 public/scripts/dist/leaflet.css create mode 100644 public/scripts/dist/leaflet.js create mode 100644 public/scripts/dist/leaflet.js.map create mode 100644 public/scripts/dist/leaflet.markercluster-src.js create mode 100644 public/scripts/dist/leaflet.markercluster-src.js.map create mode 100644 public/scripts/dist/leaflet.markercluster.js create mode 100644 public/scripts/dist/leaflet.markercluster.js.map create mode 100644 public/scripts/dist/three.cjs create mode 100644 public/scripts/dist/three.module.js create mode 100644 public/scripts/dist/three.module.min.js create mode 100644 public/scripts/main.js create mode 100644 public/scripts/map.js create mode 100644 public/scripts/modules/iconsMap.js create mode 100644 public/scripts/modules/math.js create mode 100644 public/scripts/overlays/overlaysCoord.js create mode 100644 public/scripts/overlays/overlaysNpc.js create mode 100644 public/scripts/overlays/overlaysPlayer.js create mode 100644 public/scripts/overlays/overlaysPoi.js create mode 100644 public/scripts/poi/testGroups.js create mode 100644 public/style/style.css create mode 100644 server/.gitignore create mode 100644 server/app.js create mode 100644 server/data/city.json create mode 100644 server/data/dungeon.json create mode 100644 server/data/faction.json create mode 100644 server/data/gateways.json create mode 100644 server/data/outpost.json create mode 100644 server/data/poi.json create mode 100644 server/data/ringways.json create mode 100644 server/data/town.json create mode 100644 server/data/vault.json create mode 100644 server/db.js create mode 100644 server/jsconfig.json create mode 100644 server/modules/poi.js create mode 100644 server/package-lock.json create mode 100644 server/package.json create mode 100644 server/process.env create mode 100644 server/utils/utilsMath.js create mode 100644 tiles/.gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..03a576d --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +*.zip diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..ad5e742 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,15 @@ +FROM node:latest + +WORKDIR /app + +COPY ./server/package*.json ./ + +RUN npm install + +COPY . . + +EXPOSE 3000 + +WORKDIR /app/server + +CMD ["npm", "start"] \ No newline at end of file diff --git a/public old/favicon.ico b/public old/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d703c26cf20a614e2836922ad154fd6c5df609a8 GIT binary patch literal 22559 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

#Gu2 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

pEFe*F)OP!jW?!tI;43cJ?n`! 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 literal 0 HcmV?d00001 diff --git a/public old/icons/blue_circle_void.png b/public old/icons/blue_circle_void.png new file mode 100644 index 0000000000000000000000000000000000000000..e70cc2f839ed958b862c539ef4159695f6bd3dbd GIT binary patch literal 658 zcmV;D0&V??P)EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9DiEX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9Dif5+jOZ|D(C-KQ2#@?{EfU!U+HnL>}wf S_~pR>0000EX>4Tx04R}tkv&MmP!xqvQ;Q-M5j%)DWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRR6lU)@%UlD?UJ_Il-Gs~Ehq$GUn>z?|k?qWR4zwgiLQF9gp0wVD&GfbO!gLrz= zHaPDSM_5r-iO-40Ou8WPBi9v=-#8as7IZLMN=c5B95w>PWeK{ zW0mt3XRTai&3p0}hI9JLGS_JhA%R6KL4pVcRg_SMjTr4ZDHc+69{2GNx_*gV3b{&P zj3p8qu^L^|%jT0dF3|#3gf29u0e3D*k zY0)E~cN@64ZfVLMaJd5vJQ=bnyHb#rkk13}XY@^3p#K)=Ui0SGJjdw+kfvEBZ-9eC zV5C6V>pt)9YMy{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2j~R?5d2h~O2PmD2jHJ` zGiA296fIfVlFVN; za3Dr|siB>)*G|gO0??CeML8}%6}tE9LGmJz3m`1Ae7|j~Qh9`*uhnh-A$mqw+R|rC z7U@JTfanp&Gg}Vq9eDUeE&yY)NL$*{M+zy10}v8KmUpov0KmnP5JZ*-03pS2gwir~ z00X6IsB>cl0GJyqC{05JFi={iPHcqM-dMl0-mZ-C{%WYk@E6?|U2Rv!VExWI?WLxO zW!+Lyj?3FA=XG$OYOoP}0%+`r&U{gh%gJ+2w*5b4N)gV|mOdfHa7xS6X)iUcUG?-% bb(Z`C63~Nf-uAgq00000NkvXXu0mjfQ9^G& literal 0 HcmV?d00001 diff --git a/public old/icons/green_star.png b/public old/icons/green_star.png new file mode 100644 index 0000000000000000000000000000000000000000..690faa034fef53e57b2efbc9720f93b5d3bfe0b8 GIT binary patch literal 565 zcmV-50?Pe~P)EX>4Tx04R}tkv&MmKpe$iQ%glE3U&~2$WR5rf~bgYT7@E12(?114kp)6Xws0R zxHt-~1qVMCs}3&Cx;nTDg5U>;vxAeOiU6f~epZjxkXLBY4d?N8I(+!JwgLrDw z(mC%Fhgnh15}y-~8gxP8N3JU_zi}=&Ebz>*kxI@Jhl#~P8!K(hiiS!&NgTgAzdp00000NkvXXu0mjf DN*?Dk literal 0 HcmV?d00001 diff --git a/public old/icons/green_star_big.png b/public old/icons/green_star_big.png new file mode 100644 index 0000000000000000000000000000000000000000..d53a5b8caabf9e5f0412f457c0549d3df65fdb22 GIT binary patch literal 720 zcmV;>0x$iEP)EX>4Tx04R}tkv&MmP!xqvQ;Q-M5j%)DWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRR6lU)@%UlD?UJ_Il-Gs~Ehq$GUn>z?|k?qWR4zwgiLQF9gp0wVD&GfbO!gLrz= zHaPDSM_5r-iO-40Ou8WPBi9v=-#8as7IZLMN=c5B95w>PWeK{ zW0mt3XRTai&3p0}hI9JLGS_JhA%R6KL4pVcRg_SMjTr4ZDHc+69{2GNx_*gV3b{&P zj3p8qu^L^|%jT0dF3|#3gf29u0e3D*k zY0)E~cN@64ZfVLMaJd5vJQ=bnyHb#rkk13}XY@^3p#K)=Ui0SGJjdw+kfvEBZ-9eC zV5C6V>pt)9YMy{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2j~R?5d{c3V!?y}007KML_t&-(_>)31pm zCI$;$S%w$24-6Qj%vk?3GBMb|CMewI~o2n zJYis9U|`@^X8515R{8&g{}%rhojCqa_;2w)VXg9ier1H!|2saL{_pr~`d{6L>pv?G z!!%V-uKyjMAYyPgBAX^AFJAeQAox;Y+%;49q#BgQHTZYriUNSs6 z{>u{XCaB}>q|8|V*FG@#&%nU&pOJ~df&mY}2qypmZ&Qo}vxKq$0000EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9Div04M_`JzN0cZ2$lO07*qoM6N<$f)Rl5 A_W%F@ literal 0 HcmV?d00001 diff --git a/public old/icons/orange_star.png b/public old/icons/orange_star.png new file mode 100644 index 0000000000000000000000000000000000000000..e519025bffec41001d78f5733cb2bdd6050659fc GIT binary patch literal 568 zcmV-80>}M{P)EX>4Tx04R}tkv&MmP!xqvQ;Q-M5j%)DWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRR6lU)@%UlD?UJ_Il-Gs~Ehq$GUn>z?|k?qWR4zwgiLQF9gp0wVD&GfbO!gLrz= zHaPDSM_5r-iO-40Ou8WPBi9v=-#8as7IZLMN=c5B95w>PWeK{ zW0mt3XRTai&3p0}hI9JLGS_JhA%R6KL4pVcRg_SMjTr4ZDHc+69{2GNx_*gV3b{&P zj3p8qu^L^|%jT0dF3|#3gf29u0e3D*k zY0)E~cN@64ZfVLMaJd5vJQ=bnyHb#rkk13}XY@^3p#K)=Ui0SGJjdw+kfvEBZ-9eC zV5C6V>pt)9YMy{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2j~R?5dto!F4DdL001;eL_t&-(_>(u8F-bV@E=`_ z30;Axi~@#2CUgZ14hanC3K_AP^!mvI2C+F07)f#y^#B0DMi(ct_UVKG0000EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9DiV07FScK~xyiV_;xln8v`s@E=Me z0~GQ9|2;kbqbZz*CXONSABRSSLKsF?zywv4#ef}TAuF1OLlLG`_}oOi@9>2a06>mF UslEY?uK)l507*qoM6N<$g0!3b4*&oF literal 0 HcmV?d00001 diff --git a/public old/icons/red_cross_void.png b/public old/icons/red_cross_void.png new file mode 100644 index 0000000000000000000000000000000000000000..49901c706d506dbc622d335ea1106407906fd58c GIT binary patch literal 568 zcmV-80>}M{P)EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9DiEX>4Tx04R}tkv&MmP!xqvQ;Q-M5j%)DWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRR6lU)@%UlD?UJ_Il-Gs~Ehq$GUn>z?|k?qWR4zwgiLQF9gp0wVD&GfbO!gLrz= zHaPDSM_5r-iO-40Ou8WPBi9v=-#8as7IZLMN=c5B95w>PWeK{ zW0mt3XRTai&3p0}hI9JLGS_JhA%R6KL4pVcRg_SMjTr4ZDHc+69{2GNx_*gV3b{&P zj3p8qu^L^|%jT0dF3|#3gf29u0e3D*k zY0)E~cN@64ZfVLMaJd5vJQ=bnyHb#rkk13}XY@^3p#K)=Ui0SGJjdw+kfvEBZ-9eC zV5C6V>pt)9YMy{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2j~R?5d#POhkKI%001vZL_t&-(_>(u8Tik@@E=`_ z30=XzzCNr9;R^ot_5J^U>KKG3s1TO|d~Tv1008xt9^-f{u?heH002ovPDHLkV1mPE B<)8on literal 0 HcmV?d00001 diff --git a/public old/icons/yellow_crown.png b/public old/icons/yellow_crown.png new file mode 100644 index 0000000000000000000000000000000000000000..9ff2cfd1288b7bd6e209ab743b2f6955d7697476 GIT binary patch literal 598 zcmV-c0;&CpP)EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9DidsK~xyiV_+Z_{QqnFA0L|q zCa`X;)_-hl1_lNOMs(fifRXtyBNGDy1H<|aZ#Q650261#Wd#ER14B^oHAWOSF)%PN k1O^Brn*wJuF;EKt0D;gSx9o+a>;M1&07*qoM6N<$f}KA2(*OVf literal 0 HcmV?d00001 diff --git a/public old/icons/yellow_square_full.png b/public old/icons/yellow_square_full.png new file mode 100644 index 0000000000000000000000000000000000000000..d3080e9d369ab8176912c218bc206721ef060214 GIT binary patch literal 559 zcmV+~0?_@5P)EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9Dil|H@c;K)2AqIZn1O+bfe0{U6)_MKP5|%p6IUZrG3x*T002ovPDHLkV1k8Y@*DsF literal 0 HcmV?d00001 diff --git a/public old/icons/yellow_square_void.png b/public old/icons/yellow_square_void.png new file mode 100644 index 0000000000000000000000000000000000000000..aea92a19f02a0274fbd211d1dfce4c95603c95fa GIT binary patch literal 581 zcmV-L0=oT)P)EX>4Tx04R}tkv&MmKp2MKrj?3R9Lyl%kfAzR5EXIMDionYs1;guFuC*(ni!H4 z7e~Rh;NZ_<)xpJCR|i)?5c~mgc5qU3krKa43N2#1P_vh%<3N`~m67dW(Er)oWcxuxz zIqwsTtgL9n=ftBHU6A;Z>#EOhoJ$@HJX5r?nK@#SSSod}+QF=B>BN)7aZNWUUa zao*yrS8J?wPyWJK!B}46I;|n3uz*F#kf5T53aW6Bpxq$FMuyIl0scYHFOy3pR|Sk5 z^Von6#q)#z!SCMM#ffo0DV7AfUR?KM7>Moy&ARJ;AG>bz1PDI^S4P{v(Ez4DNw2rH z_z}>z4P0EeHFXcT+yMrjOvO?>DNIW!7J>IO`ldY4e+%@i`h9DiEX>4Tx04R}tkv&MmP!xqvQ;Q-M5j%)DWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRR6lU)@%UlD?UJ_Il-Gs~Ehq$GUn>z?|k?qWR4zwgiLQF9gp0wVD&GfbO!gLrz= zHaPDSM_5r-iO-40Ou8WPBi9v=-#8as7IZLMN=c5B95w>PWeK{ zW0mt3XRTai&3p0}hI9JLGS_JhA%R6KL4pVcRg_SMjTr4ZDHc+69{2GNx_*gV3b{&P zj3p8qu^L^|%jT0dF3|#3gf29u0e3D*k zY0)E~cN@64ZfVLMaJd5vJQ=bnyHb#rkk13}XY@^3p#K)=Ui0SGJjdw+kfvEBZ-9eC zV5C6V>pt)9YMy{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2j~R?5dt6f@X~|;001UQL_t&-(_>(u891>~>_0&T s|Nk@m$Egse;Q#+?#3>}oO4|7t0FqWDINHlf(*OVf07*qoM6N<$g2RL2z5oCK literal 0 HcmV?d00001 diff --git a/public old/icons/yellow_star_big.png b/public old/icons/yellow_star_big.png new file mode 100644 index 0000000000000000000000000000000000000000..621cb7593f46c4f1bfb4bbb77b7dfcf87f72abf0 GIT binary patch literal 675 zcmV;U0$lxxP)EX>4Tx04R}tkv&MmP!xqvQ;Q-M5j%)DWT-A$5EXIMDionYs1;guFnQ@8G-*gu zTpR`0f`dPcRR6lU)@%UlD?UJ_Il-Gs~Ehq$GUn>z?|k?qWR4zwgiLQF9gp0wVD&GfbO!gLrz= zHaPDSM_5r-iO-40Ou8WPBi9v=-#8as7IZLMN=c5B95w>PWeK{ zW0mt3XRTai&3p0}hI9JLGS_JhA%R6KL4pVcRg_SMjTr4ZDHc+69{2GNx_*gV3b{&P zj3p8qu^L^|%jT0dF3|#3gf29u0e3D*k zY0)E~cN@64ZfVLMaJd5vJQ=bnyHb#rkk13}XY@^3p#K)=Ui0SGJjdw+kfvEBZ-9eC zV5C6V>pt)9YMy{D4^000SaNLh0L z01FcU01FcV0GgZ_00007bV*G`2j~R?5d$)+G{3L_005s!L_t&-(}j>R3c@e|MSnLB z5od`M$>5q3cnH@NiVnp^=~fDkP6b`+9lV5t2XK}k&c#Hh?;sAfLErrNJU;M+5Q6x{ z%t*2^Eb=%k)|H~OnsiJ0t7cuPwwR^zE%=g~^@#K(oz=`zNdSn15WJkH0D$f8faB?b zvFag7CIBP!2m9{QVm|CFwVIwcP2N{@Hqi8;$YZiG{Ch)4cmc+-U+CVbje!6F002ov JPDHLkV1m{-A5H)O literal 0 HcmV?d00001 diff --git a/public old/index.html b/public old/index.html new file mode 100644 index 0000000..a9750b9 --- /dev/null +++ b/public old/index.html @@ -0,0 +1,17 @@ + + + + Map : Asheron's Call 2 + + + + + + + + + +

+ + + diff --git a/public old/scripts/._leafletBase.js b/public old/scripts/._leafletBase.js new file mode 100644 index 0000000000000000000000000000000000000000..1e4537ab1ede698f5b7adc6aabf00804d421ed5d GIT binary patch literal 4096 zcmZQz6=P>$Vqox1Ojhs@R)|o50+1L3ClDJkFz{^v(m+1nBL)UWIUt(=a103vVu" + + "0x" + coord.x.toString(16).toUpperCase().padStart(2, '0') + + "" + coord.y.toString(16).toUpperCase().padStart(2, '0') + + "FFFF" + + "
" + + cardinal; +}; diff --git a/public old/scripts/dist/MarkerCluster.Default.css b/public old/scripts/dist/MarkerCluster.Default.css new file mode 100644 index 0000000..bbc8c9f --- /dev/null +++ b/public old/scripts/dist/MarkerCluster.Default.css @@ -0,0 +1,60 @@ +.marker-cluster-small { + background-color: rgba(181, 226, 140, 0.6); + } +.marker-cluster-small div { + background-color: rgba(110, 204, 57, 0.6); + } + +.marker-cluster-medium { + background-color: rgba(241, 211, 87, 0.6); + } +.marker-cluster-medium div { + background-color: rgba(240, 194, 12, 0.6); + } + +.marker-cluster-large { + background-color: rgba(253, 156, 115, 0.6); + } +.marker-cluster-large div { + background-color: rgba(241, 128, 23, 0.6); + } + + /* IE 6-8 fallback colors */ +.leaflet-oldie .marker-cluster-small { + background-color: rgb(181, 226, 140); + } +.leaflet-oldie .marker-cluster-small div { + background-color: rgb(110, 204, 57); + } + +.leaflet-oldie .marker-cluster-medium { + background-color: rgb(241, 211, 87); + } +.leaflet-oldie .marker-cluster-medium div { + background-color: rgb(240, 194, 12); + } + +.leaflet-oldie .marker-cluster-large { + background-color: rgb(253, 156, 115); + } +.leaflet-oldie .marker-cluster-large div { + background-color: rgb(241, 128, 23); +} + +.marker-cluster { + background-clip: padding-box; + border-radius: 20px; + } +.marker-cluster div { + width: 30px; + height: 30px; + margin-left: 5px; + margin-top: 5px; + + text-align: center; + border-radius: 15px; + font: 12px "Helvetica Neue", Arial, Helvetica, sans-serif; + } +.marker-cluster span { + line-height: 30px; + } \ No newline at end of file diff --git a/public old/scripts/dist/MarkerCluster.css b/public old/scripts/dist/MarkerCluster.css new file mode 100644 index 0000000..c60d71b --- /dev/null +++ b/public old/scripts/dist/MarkerCluster.css @@ -0,0 +1,14 @@ +.leaflet-cluster-anim .leaflet-marker-icon, .leaflet-cluster-anim .leaflet-marker-shadow { + -webkit-transition: -webkit-transform 0.3s ease-out, opacity 0.3s ease-in; + -moz-transition: -moz-transform 0.3s ease-out, opacity 0.3s ease-in; + -o-transition: -o-transform 0.3s ease-out, opacity 0.3s ease-in; + transition: transform 0.3s ease-out, opacity 0.3s ease-in; +} + +.leaflet-cluster-spider-leg { + /* stroke-dashoffset (duration and function) should match with leaflet-marker-icon transform in order to track it exactly */ + -webkit-transition: -webkit-stroke-dashoffset 0.3s ease-out, -webkit-stroke-opacity 0.3s ease-in; + -moz-transition: -moz-stroke-dashoffset 0.3s ease-out, -moz-stroke-opacity 0.3s ease-in; + -o-transition: -o-stroke-dashoffset 0.3s ease-out, -o-stroke-opacity 0.3s ease-in; + transition: stroke-dashoffset 0.3s ease-out, stroke-opacity 0.3s ease-in; +} diff --git a/public old/scripts/dist/WhereAreTheJavascriptFiles.txt b/public old/scripts/dist/WhereAreTheJavascriptFiles.txt new file mode 100644 index 0000000..3a731a3 --- /dev/null +++ b/public old/scripts/dist/WhereAreTheJavascriptFiles.txt @@ -0,0 +1,5 @@ +We don't ship the .js files in the git master branch. +They are only present in version tags and in npm. + +See how to get the JS files here: https://github.com/Leaflet/Leaflet.markercluster#using-the-plugin +Or how to build them: https://github.com/Leaflet/Leaflet.markercluster#building-testing-and-linting-scripts diff --git a/public old/scripts/dist/images/layers-2x.png b/public old/scripts/dist/images/layers-2x.png new file mode 100644 index 0000000000000000000000000000000000000000..200c333dca9652ac4cba004d609e5af4eee168c1 GIT binary patch literal 1259 zcmVFhCYNy;#0irRPomHqW|G1C*;4?@4#E?jH>?v@U%cy?3dQAc-DchXVErpOh~ z-jbon+tNbnl6hoEb;)TVk+%hTDDi_G%i3*RZ&15!$Fjr^f;Ke&A@|?=`2&+{zr+3a z{D*=t(`AXyS%X7N z%a#RZw6vD^t_rnM`L4E>m=U&R!A-&}nZIi$BOPvkhrCuUe@BN~-lRD)f44;J%TwgE zcze8u!PQ_NR7?o(NylLXVTfDO zxs5=@|GsYEsNo4M#nT%N!UE(?dnS)t2+{ELYAFp*3=iF=|EQnTp`#vlSXuGVraYo? z+RCzXo6h3qA8{KG?S4nE(lM+;Eb4nT3XV;7gcAxUi5m)`k5tv}cPy()8ZR3TLW3I- zAS^}cq-IJvL7a4RgR!yk@~RT%$lA7{L5ES*hyx)M4(yxI$Ub(4f)K|^v1>zvwQY!_ zIrWw8q9GS^!Dp~}+?mbnB6jDF8mVlbQ!jFKDY;w=7;XO{9bq7>LXGK24WA`;rL)_Z z)&j}pbV(;6gY;VMhbxgvn`X;6x}VUEE-7 z%)7j-%t8S=ZL3yc)HbXDAqJZvBTPoiW_A-+a8m3_Z?v{DN7Tnr#O_VUMT0UBt$;p` zDh6JbGHN8JJ*JN%y2%msb97@_S>9!%Egwk;?PEkU9ntz&3uR}%Fj5d$JHQbQb3}a{ zSzFT^#n=VInPpcAS}CNxj?_ zVscANk5Cfz(51EI1pz};AWWb|kgbYNb4wCEGUn3+eMUMV?1-{=I4TlmLJMot@rd07 zZuo2hk1ccu{YmGkcYdWAVdk{Z4Nm?^cTD&}jGm+Q1SYIXMwmG*oO*83&#>l%nbR`G zhh=lZ%xIb7kU3#;TBbfECrnC9P=-XpL|TG2BoZdj61*XiFbW8?1Z_wp%#;>${SUIy V$8qr;L*)Pf002ovPDHLkV1hYLS~36t literal 0 HcmV?d00001 diff --git a/public old/scripts/dist/images/layers.png b/public old/scripts/dist/images/layers.png new file mode 100644 index 0000000000000000000000000000000000000000..1a72e5784b2b456eac5d7670738db80697af3377 GIT binary patch literal 696 zcmV;p0!RIcP)*@&l2<6p=!C&s@#ZL+%BQvF&b?w6S%wp=I>1QHj7AP5C)IWy#b znXXB;g;j=$a-tW89K%FbDceHVq&unY*Wx3L#=EGWH=rjqnp|4c_Ulec!ql3#G-5ZF zVlbBA@XP=)C8U&+Lrc)S4O5%1$&{(;7R^K(CSnvSr$v;+B$8q&7Bf|h$#PARo1^%M zf1H^nG-EiXVXr07OH(*8R)xa|FD;lXUlg_-%)~ZGsL2cX0NXaAzN2q%jqLRR6ruVk8`Jb7n#{`T;o@`F= z#3YcynIR^s83UNF3D!f5m#Mg)NJ24&Qfrqb&_z=yF;=B)#9Iq7u-@^O!(mW{D;qvr zPc)gVb%aowtS8m@ElL4A9G>w#ffQ~q{i&_i)*6f^)Sz|C?C>zb4Uo?H<-&Hz@a?J; z$ml@zGygWofb9$ZBj6aLjpLhsT2AzjOu=-*u_gSCUYnU^5s62$4H-fe}gSR(=wKRaTHh!@*b)YV6mo|a4Fn6Rgc&Rpk zvn_X|3VY?v=>nJ{slE^V1GaGWk}m@aIWGIpghbfPh8m@aIWEo_%AZI>==moIFVE^L=C zZJ91?mo03UEp3-BY?wBGur6$uD{Yr9Y?m%SHF8Fk1pc(Nva%QJ+{FLkalfypz3&M|||Fn`7|g3c~4(nXHKFmRnwn$J#_$xE8i z|Ns9!kC;(oC1qQk>LMp3_a2(odYyMT@>voX=UI)k>1cJdn;gjmJ-|6v4nb1Oryh)eQMwHP(i@!36%vGJyFK(JTj?Vb{{C=jx&)@1l zlFmnw%0`&bqruifkkHKC=vbiAM3&E`#Mv>2%tw;VK8?_|&E89cs{a1}$J*!f_xd-C z&F%B|oxRgPlh0F!txkxrQjNA`m9~?&&|jw4W0<`_iNHsX$VQXVK!B}Xkh4>av|f_8 zLY2?t?ejE=%(TnfV5iqOjm?d;&qI~ZGl|SzU77a)002XDQchC<95+*MjE@82?VLm= z3xf6%Vd@99z|q|-ua5l3kJxvZwan-8K1cPiwQAtlcNX~ZqLeoMB+a;7)WA|O#HOB% zg6SX;754xD1{Fy}K~#8Ntklac&zTpadXZ& zC*_=T&g7hfbI$R?v%9?sknIb97gJOJ=`-8YyS3ndqN+Jm+x33!p&Hc@@L$w))s2@N ztv~i}Emc?DykgwFWwma($8+~b>l?tqj$dh13R^nMZnva9 zn0Vflzv2Dvp`oVQw{Guby~i`JGbyBGTEC{y>yzCkg>K&CIeQ$u;lyQ+M{O~gEJ^)Z zrF3p)^>|uT;57}WY&IRwyOQ=dq%Az}_t=_hKowP!Z79q0;@Zu(SWEJJcHY+5T6I({ zw)wj*SNi4wrd+POUfZe4gF77vW?j zoFS}|r2n&$U9Y!S4VEOyN}OpZZi|?cr1VcE_tHsDQgp-ga(SwkBrkCm{|*-yb=}ZW zvcYvLvfA90TPn|!-TuYJV<6`}+RJeRgP3EA=qQcF9k0*#*{f&I_pjam%I6Dd#YE|G zqB!R}tW-K!wV1w+4JcFA_s6~=@9F&j8`u$-ifLN3vK;`lvaA-`jRn_}(8|)!3?-}I zvFi{H;@A$gEZYh?%|Qr_y#*UkOPjwiRCsJQ>mb6h5yGIk6C5_XA=8T?IBfm_?+P0; zhhUs)-(0R*H<&Kku(1>#cGtOpk&Z&kQcw&SJv-4VY<+;=8hYnoX zfNJMCa9)^5Z0;2dCUk;x-%#yS!I~Jr3pNuI!g_tHz!$hKwt1GL~sFvx)3u4TA zv>CLGdQtoZ7Du7ctJRfTqY;FPxs1G{ZJ?73D5J@OO{6BHcPbk{_mjg&p2QFeke%QI zlAJ-kvjuwy1<5D-6>su68A+i998aSZNnQX)+Q}6(GK-C%8G-!1bOJBONU{gT%IOOE z;Yk24YC@^lFW77>r6x7eS1Omc;8=GUp#&zLQ&L{ zv8$hGC`wp~$9pR>f%-_Ps3>YhzP(+vC(E*zr1CVO8ChN^MI-VGMX7+|(r!SGZ9gd5 zzO9sQd>sm|f1|X&oh=8lOzd6+ITvo zCXInR?>RZ#>Hb*PO=7dI!dZ(wY4O}ZGv zdfQFio7+0~PN*RFCZGM6@9-o~y*@?;k00NvOsw54t1^tt{*ATMs^2j}4Wp=4t3RH* z_+8b`F-{E=0sOgM<;VHTo!Ij3u zmmI`2?K7g(GOcGA)@h?$SW&pwHdtj1n57PLI8&6RHhx4R%Q7b z^JEqR)@06V!pbS*@D_ZyRMo_LlT}r{#sXOx4kM-V<_V{!5SSuM^SIVCA37|nY7LWQ zZA#B1h4l`6asz=Lvax_#GMRX|NF>=$=p{Qn0i@ExX1jGhy@B8a*_uR+ODEbVi8ObL zezG?azy>E~S~dl43&8<$(2H}P&*tuBdESUP83KQ?8B z?K(!uS>H1wlWQz;qOfB`T#TZ=EoSp~vZ5XtCvwm1h*Ex6mzTsn_y@_=xREIslV-%- zpdWkEzMjeNOGWrSM32gpBt27*O29NdhGzuDgYxcf`Jjjqw@B;Vmdb@fxdhCRi`Kg> zmUTr$=&@#i!%F4Q6mb&4QKfR^95KJ!<6~fqx-f^66AV!|ywG{6D^Vay-3b99>XOe# e-I|>x8~*?ZhF3snGbtJX0000cOl4 literal 0 HcmV?d00001 diff --git a/public old/scripts/dist/images/marker-icon.png b/public old/scripts/dist/images/marker-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..950edf24677ded147df13b26f91baa2b0fa70513 GIT binary patch literal 1466 zcmV;r1x5OaP)P001cn1^@s6z>|W`000GnNklGNuHDcIX17Zdjl&3`L?0sTjIws<{((Dh&g-s0<@jYQyl?D*X^?%13;ml^gy> ziMrY_^1WI=(g@LMizu=zCoA>C`6|QEq1eV92k*7m>G65*&@&6)aC&e}G zI)pf-Za|N`DT&Cn1J|o`19mumxW~hiKiKyc-P`S@q)rdTo84@QI@;0yXrG%9uhI>A zG5QHb6s4=<6xy{1 z@NMxEkryp{LS44%z$3lP^cX!9+2-;CTt3wM4(k*#C{aiIiLuB>jJj;KPhPzIC00bL zU3a#;aJld94lCW=`4&aAy8M7PY=HQ>O%$YEP4c4UY#CRxfgbE~(|uiI=YS8q;O9y6 zmIkXzR`}p7ti|PrM3a}WMnR=3NVnWdAAR>b9X@)DKL6=YsvmH%?I24wdq?Gh54_;# z$?_LvgjEdspdQlft#4CQ z`2Zyvy?*)N1Ftw|{_hakhG9WjS?Az@I@+IZ8JbWewR!XUK4&6346+d#~gsE0SY(LX8&JfY>Aj)RxGy96nwhs2rv zzW6pTnMpFkDSkT*a*6Dx|u@ds6ISVn0@^RmIsKZ5Y;bazbc;tTSq(kg(=481ODrPyNB6n z-$+U}(w$m6U6H$w17Bw+wDaFIe~GvNMYvnw31MpY0eQKT9l>SU``8k7w4)z!GZKMI z#_cEKq7k~i%nlK@6c-K?+R;B#5$?T#YpKD`t_4bAs^#E+@5QW$@OX3*`;(#{U^d-vY)&xEE>n5lYl&T?Amke9$Lam@{1K@O ze*LXqlKQHiv=gx+V^Cbb2?z@ISBQ*3amF;9UJ3SBg(N|710TLamQmYZ&Qjn2LuO<* zCZlB4n%@pc&7NNnY1}x+NWpHlq`OJEo|`aYN9<`RBUB+79g;>dgb6YlfN#kGL?lO_ z!6~M^7sOnbsUkKk<@Ysie&`G>ruxH&Mgy&8;i=A zB9OO!xR{AyODw>DS-q5YM{0ExFEAzt zm>RdS+ssW(-8|?xr0(?$vBVB*%(xDLtq3Hf0I5yFm<_g=W2`QWAax{1rWVH=I!VrP zs(rTFX@W#t$hXNvbgX`gK&^w_YD;CQ!B@e0QbLIWaKAXQe2-kkloo;{iF#6}z!4=W zi$giRj1{ zt;2w`VSCF#WE&*ev7jpsC=6175@(~nTE2;7M-L((0bH@yG}-TB$R~WXd?tA$s3|%y zA`9$sA(>F%J3ioz<-LJl*^o1|w84l>HBR`>3l9c8$5Xr@xCiIQ7{x$fMCzOk_-M=% z+{a_Q#;42`#KfUte@$NT77uaTz?b-fBe)1s5XE$yA79fm?KqM^VgLXD07*qoM6N<$ Ef<_J(9smFU literal 0 HcmV?d00001 diff --git a/public old/scripts/dist/leaflet-src.esm.js b/public old/scripts/dist/leaflet-src.esm.js new file mode 100644 index 0000000..8f91d5d --- /dev/null +++ b/public old/scripts/dist/leaflet-src.esm.js @@ -0,0 +1,14419 @@ +/* @preserve + * Leaflet 1.9.4, a JS library for interactive maps. https://leafletjs.com + * (c) 2010-2023 Vladimir Agafonkin, (c) 2010-2011 CloudMade + */ + +var version = "1.9.4"; + +/* + * @namespace Util + * + * Various utility functions, used by Leaflet internally. + */ + +// @function extend(dest: Object, src?: Object): Object +// Merges the properties of the `src` object (or multiple objects) into `dest` object and returns the latter. Has an `L.extend` shortcut. +function extend(dest) { + var i, j, len, src; + + for (j = 1, len = arguments.length; j < len; j++) { + src = arguments[j]; + for (i in src) { + dest[i] = src[i]; + } + } + return dest; +} + +// @function create(proto: Object, properties?: Object): Object +// Compatibility polyfill for [Object.create](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Object/create) +var create$2 = Object.create || (function () { + function F() {} + return function (proto) { + F.prototype = proto; + return new F(); + }; +})(); + +// @function bind(fn: Function, …): Function +// Returns a new function bound to the arguments passed, like [Function.prototype.bind](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Function/bind). +// Has a `L.bind()` shortcut. +function bind(fn, obj) { + var slice = Array.prototype.slice; + + if (fn.bind) { + return fn.bind.apply(fn, slice.call(arguments, 1)); + } + + var args = slice.call(arguments, 2); + + return function () { + return fn.apply(obj, args.length ? args.concat(slice.call(arguments)) : arguments); + }; +} + +// @property lastId: Number +// Last unique ID used by [`stamp()`](#util-stamp) +var lastId = 0; + +// @function stamp(obj: Object): Number +// Returns the unique ID of an object, assigning it one if it doesn't have it. +function stamp(obj) { + if (!('_leaflet_id' in obj)) { + obj['_leaflet_id'] = ++lastId; + } + return obj._leaflet_id; +} + +// @function throttle(fn: Function, time: Number, context: Object): Function +// Returns a function which executes function `fn` with the given scope `context` +// (so that the `this` keyword refers to `context` inside `fn`'s code). The function +// `fn` will be called no more than one time per given amount of `time`. The arguments +// received by the bound function will be any arguments passed when binding the +// function, followed by any arguments passed when invoking the bound function. +// Has an `L.throttle` shortcut. +function throttle(fn, time, context) { + var lock, args, wrapperFn, later; + + later = function () { + // reset lock and call if queued + lock = false; + if (args) { + wrapperFn.apply(context, args); + args = false; + } + }; + + wrapperFn = function () { + if (lock) { + // called too soon, queue to call later + args = arguments; + + } else { + // call and lock until later + fn.apply(context, arguments); + setTimeout(later, time); + lock = true; + } + }; + + return wrapperFn; +} + +// @function wrapNum(num: Number, range: Number[], includeMax?: Boolean): Number +// Returns the number `num` modulo `range` in such a way so it lies within +// `range[0]` and `range[1]`. The returned value will be always smaller than +// `range[1]` unless `includeMax` is set to `true`. +function wrapNum(x, range, includeMax) { + var max = range[1], + min = range[0], + d = max - min; + return x === max && includeMax ? x : ((x - min) % d + d) % d + min; +} + +// @function falseFn(): Function +// Returns a function which always returns `false`. +function falseFn() { return false; } + +// @function formatNum(num: Number, precision?: Number|false): Number +// Returns the number `num` rounded with specified `precision`. +// The default `precision` value is 6 decimal places. +// `false` can be passed to skip any processing (can be useful to avoid round-off errors). +function formatNum(num, precision) { + if (precision === false) { return num; } + var pow = Math.pow(10, precision === undefined ? 6 : precision); + return Math.round(num * pow) / pow; +} + +// @function trim(str: String): String +// Compatibility polyfill for [String.prototype.trim](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/String/Trim) +function trim(str) { + return str.trim ? str.trim() : str.replace(/^\s+|\s+$/g, ''); +} + +// @function splitWords(str: String): String[] +// Trims and splits the string on whitespace and returns the array of parts. +function splitWords(str) { + return trim(str).split(/\s+/); +} + +// @function setOptions(obj: Object, options: Object): Object +// Merges the given properties to the `options` of the `obj` object, returning the resulting options. See `Class options`. Has an `L.setOptions` shortcut. +function setOptions(obj, options) { + if (!Object.prototype.hasOwnProperty.call(obj, 'options')) { + obj.options = obj.options ? create$2(obj.options) : {}; + } + for (var i in options) { + obj.options[i] = options[i]; + } + return obj.options; +} + +// @function getParamString(obj: Object, existingUrl?: String, uppercase?: Boolean): String +// Converts an object into a parameter URL string, e.g. `{a: "foo", b: "bar"}` +// translates to `'?a=foo&b=bar'`. If `existingUrl` is set, the parameters will +// be appended at the end. If `uppercase` is `true`, the parameter names will +// be uppercased (e.g. `'?A=foo&B=bar'`) +function getParamString(obj, existingUrl, uppercase) { + var params = []; + for (var i in obj) { + params.push(encodeURIComponent(uppercase ? i.toUpperCase() : i) + '=' + encodeURIComponent(obj[i])); + } + return ((!existingUrl || existingUrl.indexOf('?') === -1) ? '?' : '&') + params.join('&'); +} + +var templateRe = /\{ *([\w_ -]+) *\}/g; + +// @function template(str: String, data: Object): String +// Simple templating facility, accepts a template string of the form `'Hello {a}, {b}'` +// and a data object like `{a: 'foo', b: 'bar'}`, returns evaluated string +// `('Hello foo, bar')`. You can also specify functions instead of strings for +// data values — they will be evaluated passing `data` as an argument. +function template(str, data) { + return str.replace(templateRe, function (str, key) { + var value = data[key]; + + if (value === undefined) { + throw new Error('No value provided for variable ' + str); + + } else if (typeof value === 'function') { + value = value(data); + } + return value; + }); +} + +// @function isArray(obj): Boolean +// Compatibility polyfill for [Array.isArray](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray) +var isArray = Array.isArray || function (obj) { + return (Object.prototype.toString.call(obj) === '[object Array]'); +}; + +// @function indexOf(array: Array, el: Object): Number +// Compatibility polyfill for [Array.prototype.indexOf](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf) +function indexOf(array, el) { + for (var i = 0; i < array.length; i++) { + if (array[i] === el) { return i; } + } + return -1; +} + +// @property emptyImageUrl: String +// Data URI string containing a base64-encoded empty GIF image. +// Used as a hack to free memory from unused images on WebKit-powered +// mobile devices (by setting image `src` to this string). +var emptyImageUrl = 'data:image/gif;base64,R0lGODlhAQABAAD/ACwAAAAAAQABAAACADs='; + +// inspired by https://paulirish.com/2011/requestanimationframe-for-smart-animating/ + +function getPrefixed(name) { + return window['webkit' + name] || window['moz' + name] || window['ms' + name]; +} + +var lastTime = 0; + +// fallback for IE 7-8 +function timeoutDefer(fn) { + var time = +new Date(), + timeToCall = Math.max(0, 16 - (time - lastTime)); + + lastTime = time + timeToCall; + return window.setTimeout(fn, timeToCall); +} + +var requestFn = window.requestAnimationFrame || getPrefixed('RequestAnimationFrame') || timeoutDefer; +var cancelFn = window.cancelAnimationFrame || getPrefixed('CancelAnimationFrame') || + getPrefixed('CancelRequestAnimationFrame') || function (id) { window.clearTimeout(id); }; + +// @function requestAnimFrame(fn: Function, context?: Object, immediate?: Boolean): Number +// Schedules `fn` to be executed when the browser repaints. `fn` is bound to +// `context` if given. When `immediate` is set, `fn` is called immediately if +// the browser doesn't have native support for +// [`window.requestAnimationFrame`](https://developer.mozilla.org/docs/Web/API/window/requestAnimationFrame), +// otherwise it's delayed. Returns a request ID that can be used to cancel the request. +function requestAnimFrame(fn, context, immediate) { + if (immediate && requestFn === timeoutDefer) { + fn.call(context); + } else { + return requestFn.call(window, bind(fn, context)); + } +} + +// @function cancelAnimFrame(id: Number): undefined +// Cancels a previous `requestAnimFrame`. See also [window.cancelAnimationFrame](https://developer.mozilla.org/docs/Web/API/window/cancelAnimationFrame). +function cancelAnimFrame(id) { + if (id) { + cancelFn.call(window, id); + } +} + +var Util = { + __proto__: null, + extend: extend, + create: create$2, + bind: bind, + get lastId () { return lastId; }, + stamp: stamp, + throttle: throttle, + wrapNum: wrapNum, + falseFn: falseFn, + formatNum: formatNum, + trim: trim, + splitWords: splitWords, + setOptions: setOptions, + getParamString: getParamString, + template: template, + isArray: isArray, + indexOf: indexOf, + emptyImageUrl: emptyImageUrl, + requestFn: requestFn, + cancelFn: cancelFn, + requestAnimFrame: requestAnimFrame, + cancelAnimFrame: cancelAnimFrame +}; + +// @class Class +// @aka L.Class + +// @section +// @uninheritable + +// Thanks to John Resig and Dean Edwards for inspiration! + +function Class() {} + +Class.extend = function (props) { + + // @function extend(props: Object): Function + // [Extends the current class](#class-inheritance) given the properties to be included. + // Returns a Javascript function that is a class constructor (to be called with `new`). + var NewClass = function () { + + setOptions(this); + + // call the constructor + if (this.initialize) { + this.initialize.apply(this, arguments); + } + + // call all constructor hooks + this.callInitHooks(); + }; + + var parentProto = NewClass.__super__ = this.prototype; + + var proto = create$2(parentProto); + proto.constructor = NewClass; + + NewClass.prototype = proto; + + // inherit parent's statics + for (var i in this) { + if (Object.prototype.hasOwnProperty.call(this, i) && i !== 'prototype' && i !== '__super__') { + NewClass[i] = this[i]; + } + } + + // mix static properties into the class + if (props.statics) { + extend(NewClass, props.statics); + } + + // mix includes into the prototype + if (props.includes) { + checkDeprecatedMixinEvents(props.includes); + extend.apply(null, [proto].concat(props.includes)); + } + + // mix given properties into the prototype + extend(proto, props); + delete proto.statics; + delete proto.includes; + + // merge options + if (proto.options) { + proto.options = parentProto.options ? create$2(parentProto.options) : {}; + extend(proto.options, props.options); + } + + proto._initHooks = []; + + // add method for calling all hooks + proto.callInitHooks = function () { + + if (this._initHooksCalled) { return; } + + if (parentProto.callInitHooks) { + parentProto.callInitHooks.call(this); + } + + this._initHooksCalled = true; + + for (var i = 0, len = proto._initHooks.length; i < len; i++) { + proto._initHooks[i].call(this); + } + }; + + return NewClass; +}; + + +// @function include(properties: Object): this +// [Includes a mixin](#class-includes) into the current class. +Class.include = function (props) { + var parentOptions = this.prototype.options; + extend(this.prototype, props); + if (props.options) { + this.prototype.options = parentOptions; + this.mergeOptions(props.options); + } + return this; +}; + +// @function mergeOptions(options: Object): this +// [Merges `options`](#class-options) into the defaults of the class. +Class.mergeOptions = function (options) { + extend(this.prototype.options, options); + return this; +}; + +// @function addInitHook(fn: Function): this +// Adds a [constructor hook](#class-constructor-hooks) to the class. +Class.addInitHook = function (fn) { // (Function) || (String, args...) + var args = Array.prototype.slice.call(arguments, 1); + + var init = typeof fn === 'function' ? fn : function () { + this[fn].apply(this, args); + }; + + this.prototype._initHooks = this.prototype._initHooks || []; + this.prototype._initHooks.push(init); + return this; +}; + +function checkDeprecatedMixinEvents(includes) { + /* global L: true */ + if (typeof L === 'undefined' || !L || !L.Mixin) { return; } + + includes = isArray(includes) ? includes : [includes]; + + for (var i = 0; i < includes.length; i++) { + if (includes[i] === L.Mixin.Events) { + console.warn('Deprecated include of L.Mixin.Events: ' + + 'this property will be removed in future releases, ' + + 'please inherit from L.Evented instead.', new Error().stack); + } + } +} + +/* + * @class Evented + * @aka L.Evented + * @inherits Class + * + * A set of methods shared between event-powered classes (like `Map` and `Marker`). Generally, events allow you to execute some function when something happens with an object (e.g. the user clicks on the map, causing the map to fire `'click'` event). + * + * @example + * + * ```js + * map.on('click', function(e) { + * alert(e.latlng); + * } ); + * ``` + * + * Leaflet deals with event listeners by reference, so if you want to add a listener and then remove it, define it as a function: + * + * ```js + * function onClick(e) { ... } + * + * map.on('click', onClick); + * map.off('click', onClick); + * ``` + */ + +var Events = { + /* @method on(type: String, fn: Function, context?: Object): this + * Adds a listener function (`fn`) to a particular event type of the object. You can optionally specify the context of the listener (object the this keyword will point to). You can also pass several space-separated types (e.g. `'click dblclick'`). + * + * @alternative + * @method on(eventMap: Object): this + * Adds a set of type/listener pairs, e.g. `{click: onClick, mousemove: onMouseMove}` + */ + on: function (types, fn, context) { + + // types can be a map of types/handlers + if (typeof types === 'object') { + for (var type in types) { + // we don't process space-separated events here for performance; + // it's a hot path since Layer uses the on(obj) syntax + this._on(type, types[type], fn); + } + + } else { + // types can be a string of space-separated words + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + this._on(types[i], fn, context); + } + } + + return this; + }, + + /* @method off(type: String, fn?: Function, context?: Object): this + * Removes a previously added listener function. If no function is specified, it will remove all the listeners of that particular event from the object. Note that if you passed a custom context to `on`, you must pass the same context to `off` in order to remove the listener. + * + * @alternative + * @method off(eventMap: Object): this + * Removes a set of type/listener pairs. + * + * @alternative + * @method off: this + * Removes all listeners to all events on the object. This includes implicitly attached events. + */ + off: function (types, fn, context) { + + if (!arguments.length) { + // clear all listeners if called without arguments + delete this._events; + + } else if (typeof types === 'object') { + for (var type in types) { + this._off(type, types[type], fn); + } + + } else { + types = splitWords(types); + + var removeAll = arguments.length === 1; + for (var i = 0, len = types.length; i < len; i++) { + if (removeAll) { + this._off(types[i]); + } else { + this._off(types[i], fn, context); + } + } + } + + return this; + }, + + // attach listener (without syntactic sugar now) + _on: function (type, fn, context, _once) { + if (typeof fn !== 'function') { + console.warn('wrong listener type: ' + typeof fn); + return; + } + + // check if fn already there + if (this._listens(type, fn, context) !== false) { + return; + } + + if (context === this) { + // Less memory footprint. + context = undefined; + } + + var newListener = {fn: fn, ctx: context}; + if (_once) { + newListener.once = true; + } + + this._events = this._events || {}; + this._events[type] = this._events[type] || []; + this._events[type].push(newListener); + }, + + _off: function (type, fn, context) { + var listeners, + i, + len; + + if (!this._events) { + return; + } + + listeners = this._events[type]; + if (!listeners) { + return; + } + + if (arguments.length === 1) { // remove all + if (this._firingCount) { + // Set all removed listeners to noop + // so they are not called if remove happens in fire + for (i = 0, len = listeners.length; i < len; i++) { + listeners[i].fn = falseFn; + } + } + // clear all listeners for a type if function isn't specified + delete this._events[type]; + return; + } + + if (typeof fn !== 'function') { + console.warn('wrong listener type: ' + typeof fn); + return; + } + + // find fn and remove it + var index = this._listens(type, fn, context); + if (index !== false) { + var listener = listeners[index]; + if (this._firingCount) { + // set the removed listener to noop so that's not called if remove happens in fire + listener.fn = falseFn; + + /* copy array in case events are being fired */ + this._events[type] = listeners = listeners.slice(); + } + listeners.splice(index, 1); + } + }, + + // @method fire(type: String, data?: Object, propagate?: Boolean): this + // Fires an event of the specified type. You can optionally provide a data + // object — the first argument of the listener function will contain its + // properties. The event can optionally be propagated to event parents. + fire: function (type, data, propagate) { + if (!this.listens(type, propagate)) { return this; } + + var event = extend({}, data, { + type: type, + target: this, + sourceTarget: data && data.sourceTarget || this + }); + + if (this._events) { + var listeners = this._events[type]; + if (listeners) { + this._firingCount = (this._firingCount + 1) || 1; + for (var i = 0, len = listeners.length; i < len; i++) { + var l = listeners[i]; + // off overwrites l.fn, so we need to copy fn to a var + var fn = l.fn; + if (l.once) { + this.off(type, fn, l.ctx); + } + fn.call(l.ctx || this, event); + } + + this._firingCount--; + } + } + + if (propagate) { + // propagate the event to parents (set with addEventParent) + this._propagateEvent(event); + } + + return this; + }, + + // @method listens(type: String, propagate?: Boolean): Boolean + // @method listens(type: String, fn: Function, context?: Object, propagate?: Boolean): Boolean + // Returns `true` if a particular event type has any listeners attached to it. + // The verification can optionally be propagated, it will return `true` if parents have the listener attached to it. + listens: function (type, fn, context, propagate) { + if (typeof type !== 'string') { + console.warn('"string" type argument expected'); + } + + // we don't overwrite the input `fn` value, because we need to use it for propagation + var _fn = fn; + if (typeof fn !== 'function') { + propagate = !!fn; + _fn = undefined; + context = undefined; + } + + var listeners = this._events && this._events[type]; + if (listeners && listeners.length) { + if (this._listens(type, _fn, context) !== false) { + return true; + } + } + + if (propagate) { + // also check parents for listeners if event propagates + for (var id in this._eventParents) { + if (this._eventParents[id].listens(type, fn, context, propagate)) { return true; } + } + } + return false; + }, + + // returns the index (number) or false + _listens: function (type, fn, context) { + if (!this._events) { + return false; + } + + var listeners = this._events[type] || []; + if (!fn) { + return !!listeners.length; + } + + if (context === this) { + // Less memory footprint. + context = undefined; + } + + for (var i = 0, len = listeners.length; i < len; i++) { + if (listeners[i].fn === fn && listeners[i].ctx === context) { + return i; + } + } + return false; + + }, + + // @method once(…): this + // Behaves as [`on(…)`](#evented-on), except the listener will only get fired once and then removed. + once: function (types, fn, context) { + + // types can be a map of types/handlers + if (typeof types === 'object') { + for (var type in types) { + // we don't process space-separated events here for performance; + // it's a hot path since Layer uses the on(obj) syntax + this._on(type, types[type], fn, true); + } + + } else { + // types can be a string of space-separated words + types = splitWords(types); + + for (var i = 0, len = types.length; i < len; i++) { + this._on(types[i], fn, context, true); + } + } + + return this; + }, + + // @method addEventParent(obj: Evented): this + // Adds an event parent - an `Evented` that will receive propagated events + addEventParent: function (obj) { + this._eventParents = this._eventParents || {}; + this._eventParents[stamp(obj)] = obj; + return this; + }, + + // @method removeEventParent(obj: Evented): this + // Removes an event parent, so it will stop receiving propagated events + removeEventParent: function (obj) { + if (this._eventParents) { + delete this._eventParents[stamp(obj)]; + } + return this; + }, + + _propagateEvent: function (e) { + for (var id in this._eventParents) { + this._eventParents[id].fire(e.type, extend({ + layer: e.target, + propagatedFrom: e.target + }, e), true); + } + } +}; + +// aliases; we should ditch those eventually + +// @method addEventListener(…): this +// Alias to [`on(…)`](#evented-on) +Events.addEventListener = Events.on; + +// @method removeEventListener(…): this +// Alias to [`off(…)`](#evented-off) + +// @method clearAllEventListeners(…): this +// Alias to [`off()`](#evented-off) +Events.removeEventListener = Events.clearAllEventListeners = Events.off; + +// @method addOneTimeEventListener(…): this +// Alias to [`once(…)`](#evented-once) +Events.addOneTimeEventListener = Events.once; + +// @method fireEvent(…): this +// Alias to [`fire(…)`](#evented-fire) +Events.fireEvent = Events.fire; + +// @method hasEventListeners(…): Boolean +// Alias to [`listens(…)`](#evented-listens) +Events.hasEventListeners = Events.listens; + +var Evented = Class.extend(Events); + +/* + * @class Point + * @aka L.Point + * + * Represents a point with `x` and `y` coordinates in pixels. + * + * @example + * + * ```js + * var point = L.point(200, 300); + * ``` + * + * All Leaflet methods and options that accept `Point` objects also accept them in a simple Array form (unless noted otherwise), so these lines are equivalent: + * + * ```js + * map.panBy([200, 300]); + * map.panBy(L.point(200, 300)); + * ``` + * + * Note that `Point` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function Point(x, y, round) { + // @property x: Number; The `x` coordinate of the point + this.x = (round ? Math.round(x) : x); + // @property y: Number; The `y` coordinate of the point + this.y = (round ? Math.round(y) : y); +} + +var trunc = Math.trunc || function (v) { + return v > 0 ? Math.floor(v) : Math.ceil(v); +}; + +Point.prototype = { + + // @method clone(): Point + // Returns a copy of the current point. + clone: function () { + return new Point(this.x, this.y); + }, + + // @method add(otherPoint: Point): Point + // Returns the result of addition of the current and the given points. + add: function (point) { + // non-destructive, returns a new point + return this.clone()._add(toPoint(point)); + }, + + _add: function (point) { + // destructive, used directly for performance in situations where it's safe to modify existing point + this.x += point.x; + this.y += point.y; + return this; + }, + + // @method subtract(otherPoint: Point): Point + // Returns the result of subtraction of the given point from the current. + subtract: function (point) { + return this.clone()._subtract(toPoint(point)); + }, + + _subtract: function (point) { + this.x -= point.x; + this.y -= point.y; + return this; + }, + + // @method divideBy(num: Number): Point + // Returns the result of division of the current point by the given number. + divideBy: function (num) { + return this.clone()._divideBy(num); + }, + + _divideBy: function (num) { + this.x /= num; + this.y /= num; + return this; + }, + + // @method multiplyBy(num: Number): Point + // Returns the result of multiplication of the current point by the given number. + multiplyBy: function (num) { + return this.clone()._multiplyBy(num); + }, + + _multiplyBy: function (num) { + this.x *= num; + this.y *= num; + return this; + }, + + // @method scaleBy(scale: Point): Point + // Multiply each coordinate of the current point by each coordinate of + // `scale`. In linear algebra terms, multiply the point by the + // [scaling matrix](https://en.wikipedia.org/wiki/Scaling_%28geometry%29#Matrix_representation) + // defined by `scale`. + scaleBy: function (point) { + return new Point(this.x * point.x, this.y * point.y); + }, + + // @method unscaleBy(scale: Point): Point + // Inverse of `scaleBy`. Divide each coordinate of the current point by + // each coordinate of `scale`. + unscaleBy: function (point) { + return new Point(this.x / point.x, this.y / point.y); + }, + + // @method round(): Point + // Returns a copy of the current point with rounded coordinates. + round: function () { + return this.clone()._round(); + }, + + _round: function () { + this.x = Math.round(this.x); + this.y = Math.round(this.y); + return this; + }, + + // @method floor(): Point + // Returns a copy of the current point with floored coordinates (rounded down). + floor: function () { + return this.clone()._floor(); + }, + + _floor: function () { + this.x = Math.floor(this.x); + this.y = Math.floor(this.y); + return this; + }, + + // @method ceil(): Point + // Returns a copy of the current point with ceiled coordinates (rounded up). + ceil: function () { + return this.clone()._ceil(); + }, + + _ceil: function () { + this.x = Math.ceil(this.x); + this.y = Math.ceil(this.y); + return this; + }, + + // @method trunc(): Point + // Returns a copy of the current point with truncated coordinates (rounded towards zero). + trunc: function () { + return this.clone()._trunc(); + }, + + _trunc: function () { + this.x = trunc(this.x); + this.y = trunc(this.y); + return this; + }, + + // @method distanceTo(otherPoint: Point): Number + // Returns the cartesian distance between the current and the given points. + distanceTo: function (point) { + point = toPoint(point); + + var x = point.x - this.x, + y = point.y - this.y; + + return Math.sqrt(x * x + y * y); + }, + + // @method equals(otherPoint: Point): Boolean + // Returns `true` if the given point has the same coordinates. + equals: function (point) { + point = toPoint(point); + + return point.x === this.x && + point.y === this.y; + }, + + // @method contains(otherPoint: Point): Boolean + // Returns `true` if both coordinates of the given point are less than the corresponding current point coordinates (in absolute values). + contains: function (point) { + point = toPoint(point); + + return Math.abs(point.x) <= Math.abs(this.x) && + Math.abs(point.y) <= Math.abs(this.y); + }, + + // @method toString(): String + // Returns a string representation of the point for debugging purposes. + toString: function () { + return 'Point(' + + formatNum(this.x) + ', ' + + formatNum(this.y) + ')'; + } +}; + +// @factory L.point(x: Number, y: Number, round?: Boolean) +// Creates a Point object with the given `x` and `y` coordinates. If optional `round` is set to true, rounds the `x` and `y` values. + +// @alternative +// @factory L.point(coords: Number[]) +// Expects an array of the form `[x, y]` instead. + +// @alternative +// @factory L.point(coords: Object) +// Expects a plain object of the form `{x: Number, y: Number}` instead. +function toPoint(x, y, round) { + if (x instanceof Point) { + return x; + } + if (isArray(x)) { + return new Point(x[0], x[1]); + } + if (x === undefined || x === null) { + return x; + } + if (typeof x === 'object' && 'x' in x && 'y' in x) { + return new Point(x.x, x.y); + } + return new Point(x, y, round); +} + +/* + * @class Bounds + * @aka L.Bounds + * + * Represents a rectangular area in pixel coordinates. + * + * @example + * + * ```js + * var p1 = L.point(10, 10), + * p2 = L.point(40, 60), + * bounds = L.bounds(p1, p2); + * ``` + * + * All Leaflet methods that accept `Bounds` objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: + * + * ```js + * otherBounds.intersects([[10, 10], [40, 60]]); + * ``` + * + * Note that `Bounds` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function Bounds(a, b) { + if (!a) { return; } + + var points = b ? [a, b] : a; + + for (var i = 0, len = points.length; i < len; i++) { + this.extend(points[i]); + } +} + +Bounds.prototype = { + // @method extend(point: Point): this + // Extends the bounds to contain the given point. + + // @alternative + // @method extend(otherBounds: Bounds): this + // Extend the bounds to contain the given bounds + extend: function (obj) { + var min2, max2; + if (!obj) { return this; } + + if (obj instanceof Point || typeof obj[0] === 'number' || 'x' in obj) { + min2 = max2 = toPoint(obj); + } else { + obj = toBounds(obj); + min2 = obj.min; + max2 = obj.max; + + if (!min2 || !max2) { return this; } + } + + // @property min: Point + // The top left corner of the rectangle. + // @property max: Point + // The bottom right corner of the rectangle. + if (!this.min && !this.max) { + this.min = min2.clone(); + this.max = max2.clone(); + } else { + this.min.x = Math.min(min2.x, this.min.x); + this.max.x = Math.max(max2.x, this.max.x); + this.min.y = Math.min(min2.y, this.min.y); + this.max.y = Math.max(max2.y, this.max.y); + } + return this; + }, + + // @method getCenter(round?: Boolean): Point + // Returns the center point of the bounds. + getCenter: function (round) { + return toPoint( + (this.min.x + this.max.x) / 2, + (this.min.y + this.max.y) / 2, round); + }, + + // @method getBottomLeft(): Point + // Returns the bottom-left point of the bounds. + getBottomLeft: function () { + return toPoint(this.min.x, this.max.y); + }, + + // @method getTopRight(): Point + // Returns the top-right point of the bounds. + getTopRight: function () { // -> Point + return toPoint(this.max.x, this.min.y); + }, + + // @method getTopLeft(): Point + // Returns the top-left point of the bounds (i.e. [`this.min`](#bounds-min)). + getTopLeft: function () { + return this.min; // left, top + }, + + // @method getBottomRight(): Point + // Returns the bottom-right point of the bounds (i.e. [`this.max`](#bounds-max)). + getBottomRight: function () { + return this.max; // right, bottom + }, + + // @method getSize(): Point + // Returns the size of the given bounds + getSize: function () { + return this.max.subtract(this.min); + }, + + // @method contains(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle contains the given one. + // @alternative + // @method contains(point: Point): Boolean + // Returns `true` if the rectangle contains the given point. + contains: function (obj) { + var min, max; + + if (typeof obj[0] === 'number' || obj instanceof Point) { + obj = toPoint(obj); + } else { + obj = toBounds(obj); + } + + if (obj instanceof Bounds) { + min = obj.min; + max = obj.max; + } else { + min = max = obj; + } + + return (min.x >= this.min.x) && + (max.x <= this.max.x) && + (min.y >= this.min.y) && + (max.y <= this.max.y); + }, + + // @method intersects(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle intersects the given bounds. Two bounds + // intersect if they have at least one point in common. + intersects: function (bounds) { // (Bounds) -> Boolean + bounds = toBounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xIntersects = (max2.x >= min.x) && (min2.x <= max.x), + yIntersects = (max2.y >= min.y) && (min2.y <= max.y); + + return xIntersects && yIntersects; + }, + + // @method overlaps(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle overlaps the given bounds. Two bounds + // overlap if their intersection is an area. + overlaps: function (bounds) { // (Bounds) -> Boolean + bounds = toBounds(bounds); + + var min = this.min, + max = this.max, + min2 = bounds.min, + max2 = bounds.max, + xOverlaps = (max2.x > min.x) && (min2.x < max.x), + yOverlaps = (max2.y > min.y) && (min2.y < max.y); + + return xOverlaps && yOverlaps; + }, + + // @method isValid(): Boolean + // Returns `true` if the bounds are properly initialized. + isValid: function () { + return !!(this.min && this.max); + }, + + + // @method pad(bufferRatio: Number): Bounds + // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. + // For example, a ratio of 0.5 extends the bounds by 50% in each direction. + // Negative values will retract the bounds. + pad: function (bufferRatio) { + var min = this.min, + max = this.max, + heightBuffer = Math.abs(min.x - max.x) * bufferRatio, + widthBuffer = Math.abs(min.y - max.y) * bufferRatio; + + + return toBounds( + toPoint(min.x - heightBuffer, min.y - widthBuffer), + toPoint(max.x + heightBuffer, max.y + widthBuffer)); + }, + + + // @method equals(otherBounds: Bounds): Boolean + // Returns `true` if the rectangle is equivalent to the given bounds. + equals: function (bounds) { + if (!bounds) { return false; } + + bounds = toBounds(bounds); + + return this.min.equals(bounds.getTopLeft()) && + this.max.equals(bounds.getBottomRight()); + }, +}; + + +// @factory L.bounds(corner1: Point, corner2: Point) +// Creates a Bounds object from two corners coordinate pairs. +// @alternative +// @factory L.bounds(points: Point[]) +// Creates a Bounds object from the given array of points. +function toBounds(a, b) { + if (!a || a instanceof Bounds) { + return a; + } + return new Bounds(a, b); +} + +/* + * @class LatLngBounds + * @aka L.LatLngBounds + * + * Represents a rectangular geographical area on a map. + * + * @example + * + * ```js + * var corner1 = L.latLng(40.712, -74.227), + * corner2 = L.latLng(40.774, -74.125), + * bounds = L.latLngBounds(corner1, corner2); + * ``` + * + * All Leaflet methods that accept LatLngBounds objects also accept them in a simple Array form (unless noted otherwise), so the bounds example above can be passed like this: + * + * ```js + * map.fitBounds([ + * [40.712, -74.227], + * [40.774, -74.125] + * ]); + * ``` + * + * Caution: if the area crosses the antimeridian (often confused with the International Date Line), you must specify corners _outside_ the [-180, 180] degrees longitude range. + * + * Note that `LatLngBounds` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function LatLngBounds(corner1, corner2) { // (LatLng, LatLng) or (LatLng[]) + if (!corner1) { return; } + + var latlngs = corner2 ? [corner1, corner2] : corner1; + + for (var i = 0, len = latlngs.length; i < len; i++) { + this.extend(latlngs[i]); + } +} + +LatLngBounds.prototype = { + + // @method extend(latlng: LatLng): this + // Extend the bounds to contain the given point + + // @alternative + // @method extend(otherBounds: LatLngBounds): this + // Extend the bounds to contain the given bounds + extend: function (obj) { + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof LatLng) { + sw2 = obj; + ne2 = obj; + + } else if (obj instanceof LatLngBounds) { + sw2 = obj._southWest; + ne2 = obj._northEast; + + if (!sw2 || !ne2) { return this; } + + } else { + return obj ? this.extend(toLatLng(obj) || toLatLngBounds(obj)) : this; + } + + if (!sw && !ne) { + this._southWest = new LatLng(sw2.lat, sw2.lng); + this._northEast = new LatLng(ne2.lat, ne2.lng); + } else { + sw.lat = Math.min(sw2.lat, sw.lat); + sw.lng = Math.min(sw2.lng, sw.lng); + ne.lat = Math.max(ne2.lat, ne.lat); + ne.lng = Math.max(ne2.lng, ne.lng); + } + + return this; + }, + + // @method pad(bufferRatio: Number): LatLngBounds + // Returns bounds created by extending or retracting the current bounds by a given ratio in each direction. + // For example, a ratio of 0.5 extends the bounds by 50% in each direction. + // Negative values will retract the bounds. + pad: function (bufferRatio) { + var sw = this._southWest, + ne = this._northEast, + heightBuffer = Math.abs(sw.lat - ne.lat) * bufferRatio, + widthBuffer = Math.abs(sw.lng - ne.lng) * bufferRatio; + + return new LatLngBounds( + new LatLng(sw.lat - heightBuffer, sw.lng - widthBuffer), + new LatLng(ne.lat + heightBuffer, ne.lng + widthBuffer)); + }, + + // @method getCenter(): LatLng + // Returns the center point of the bounds. + getCenter: function () { + return new LatLng( + (this._southWest.lat + this._northEast.lat) / 2, + (this._southWest.lng + this._northEast.lng) / 2); + }, + + // @method getSouthWest(): LatLng + // Returns the south-west point of the bounds. + getSouthWest: function () { + return this._southWest; + }, + + // @method getNorthEast(): LatLng + // Returns the north-east point of the bounds. + getNorthEast: function () { + return this._northEast; + }, + + // @method getNorthWest(): LatLng + // Returns the north-west point of the bounds. + getNorthWest: function () { + return new LatLng(this.getNorth(), this.getWest()); + }, + + // @method getSouthEast(): LatLng + // Returns the south-east point of the bounds. + getSouthEast: function () { + return new LatLng(this.getSouth(), this.getEast()); + }, + + // @method getWest(): Number + // Returns the west longitude of the bounds + getWest: function () { + return this._southWest.lng; + }, + + // @method getSouth(): Number + // Returns the south latitude of the bounds + getSouth: function () { + return this._southWest.lat; + }, + + // @method getEast(): Number + // Returns the east longitude of the bounds + getEast: function () { + return this._northEast.lng; + }, + + // @method getNorth(): Number + // Returns the north latitude of the bounds + getNorth: function () { + return this._northEast.lat; + }, + + // @method contains(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle contains the given one. + + // @alternative + // @method contains (latlng: LatLng): Boolean + // Returns `true` if the rectangle contains the given point. + contains: function (obj) { // (LatLngBounds) or (LatLng) -> Boolean + if (typeof obj[0] === 'number' || obj instanceof LatLng || 'lat' in obj) { + obj = toLatLng(obj); + } else { + obj = toLatLngBounds(obj); + } + + var sw = this._southWest, + ne = this._northEast, + sw2, ne2; + + if (obj instanceof LatLngBounds) { + sw2 = obj.getSouthWest(); + ne2 = obj.getNorthEast(); + } else { + sw2 = ne2 = obj; + } + + return (sw2.lat >= sw.lat) && (ne2.lat <= ne.lat) && + (sw2.lng >= sw.lng) && (ne2.lng <= ne.lng); + }, + + // @method intersects(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle intersects the given bounds. Two bounds intersect if they have at least one point in common. + intersects: function (bounds) { + bounds = toLatLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latIntersects = (ne2.lat >= sw.lat) && (sw2.lat <= ne.lat), + lngIntersects = (ne2.lng >= sw.lng) && (sw2.lng <= ne.lng); + + return latIntersects && lngIntersects; + }, + + // @method overlaps(otherBounds: LatLngBounds): Boolean + // Returns `true` if the rectangle overlaps the given bounds. Two bounds overlap if their intersection is an area. + overlaps: function (bounds) { + bounds = toLatLngBounds(bounds); + + var sw = this._southWest, + ne = this._northEast, + sw2 = bounds.getSouthWest(), + ne2 = bounds.getNorthEast(), + + latOverlaps = (ne2.lat > sw.lat) && (sw2.lat < ne.lat), + lngOverlaps = (ne2.lng > sw.lng) && (sw2.lng < ne.lng); + + return latOverlaps && lngOverlaps; + }, + + // @method toBBoxString(): String + // Returns a string with bounding box coordinates in a 'southwest_lng,southwest_lat,northeast_lng,northeast_lat' format. Useful for sending requests to web services that return geo data. + toBBoxString: function () { + return [this.getWest(), this.getSouth(), this.getEast(), this.getNorth()].join(','); + }, + + // @method equals(otherBounds: LatLngBounds, maxMargin?: Number): Boolean + // Returns `true` if the rectangle is equivalent (within a small margin of error) to the given bounds. The margin of error can be overridden by setting `maxMargin` to a small number. + equals: function (bounds, maxMargin) { + if (!bounds) { return false; } + + bounds = toLatLngBounds(bounds); + + return this._southWest.equals(bounds.getSouthWest(), maxMargin) && + this._northEast.equals(bounds.getNorthEast(), maxMargin); + }, + + // @method isValid(): Boolean + // Returns `true` if the bounds are properly initialized. + isValid: function () { + return !!(this._southWest && this._northEast); + } +}; + +// TODO International date line? + +// @factory L.latLngBounds(corner1: LatLng, corner2: LatLng) +// Creates a `LatLngBounds` object by defining two diagonally opposite corners of the rectangle. + +// @alternative +// @factory L.latLngBounds(latlngs: LatLng[]) +// Creates a `LatLngBounds` object defined by the geographical points it contains. Very useful for zooming the map to fit a particular set of locations with [`fitBounds`](#map-fitbounds). +function toLatLngBounds(a, b) { + if (a instanceof LatLngBounds) { + return a; + } + return new LatLngBounds(a, b); +} + +/* @class LatLng + * @aka L.LatLng + * + * Represents a geographical point with a certain latitude and longitude. + * + * @example + * + * ``` + * var latlng = L.latLng(50.5, 30.5); + * ``` + * + * All Leaflet methods that accept LatLng objects also accept them in a simple Array form and simple object form (unless noted otherwise), so these lines are equivalent: + * + * ``` + * map.panTo([50, 30]); + * map.panTo({lon: 30, lat: 50}); + * map.panTo({lat: 50, lng: 30}); + * map.panTo(L.latLng(50, 30)); + * ``` + * + * Note that `LatLng` does not inherit from Leaflet's `Class` object, + * which means new classes can't inherit from it, and new methods + * can't be added to it with the `include` function. + */ + +function LatLng(lat, lng, alt) { + if (isNaN(lat) || isNaN(lng)) { + throw new Error('Invalid LatLng object: (' + lat + ', ' + lng + ')'); + } + + // @property lat: Number + // Latitude in degrees + this.lat = +lat; + + // @property lng: Number + // Longitude in degrees + this.lng = +lng; + + // @property alt: Number + // Altitude in meters (optional) + if (alt !== undefined) { + this.alt = +alt; + } +} + +LatLng.prototype = { + // @method equals(otherLatLng: LatLng, maxMargin?: Number): Boolean + // Returns `true` if the given `LatLng` point is at the same position (within a small margin of error). The margin of error can be overridden by setting `maxMargin` to a small number. + equals: function (obj, maxMargin) { + if (!obj) { return false; } + + obj = toLatLng(obj); + + var margin = Math.max( + Math.abs(this.lat - obj.lat), + Math.abs(this.lng - obj.lng)); + + return margin <= (maxMargin === undefined ? 1.0E-9 : maxMargin); + }, + + // @method toString(): String + // Returns a string representation of the point (for debugging purposes). + toString: function (precision) { + return 'LatLng(' + + formatNum(this.lat, precision) + ', ' + + formatNum(this.lng, precision) + ')'; + }, + + // @method distanceTo(otherLatLng: LatLng): Number + // Returns the distance (in meters) to the given `LatLng` calculated using the [Spherical Law of Cosines](https://en.wikipedia.org/wiki/Spherical_law_of_cosines). + distanceTo: function (other) { + return Earth.distance(this, toLatLng(other)); + }, + + // @method wrap(): LatLng + // Returns a new `LatLng` object with the longitude wrapped so it's always between -180 and +180 degrees. + wrap: function () { + return Earth.wrapLatLng(this); + }, + + // @method toBounds(sizeInMeters: Number): LatLngBounds + // Returns a new `LatLngBounds` object in which each boundary is `sizeInMeters/2` meters apart from the `LatLng`. + toBounds: function (sizeInMeters) { + var latAccuracy = 180 * sizeInMeters / 40075017, + lngAccuracy = latAccuracy / Math.cos((Math.PI / 180) * this.lat); + + return toLatLngBounds( + [this.lat - latAccuracy, this.lng - lngAccuracy], + [this.lat + latAccuracy, this.lng + lngAccuracy]); + }, + + clone: function () { + return new LatLng(this.lat, this.lng, this.alt); + } +}; + + + +// @factory L.latLng(latitude: Number, longitude: Number, altitude?: Number): LatLng +// Creates an object representing a geographical point with the given latitude and longitude (and optionally altitude). + +// @alternative +// @factory L.latLng(coords: Array): LatLng +// Expects an array of the form `[Number, Number]` or `[Number, Number, Number]` instead. + +// @alternative +// @factory L.latLng(coords: Object): LatLng +// Expects an plain object of the form `{lat: Number, lng: Number}` or `{lat: Number, lng: Number, alt: Number}` instead. + +function toLatLng(a, b, c) { + if (a instanceof LatLng) { + return a; + } + if (isArray(a) && typeof a[0] !== 'object') { + if (a.length === 3) { + return new LatLng(a[0], a[1], a[2]); + } + if (a.length === 2) { + return new LatLng(a[0], a[1]); + } + return null; + } + if (a === undefined || a === null) { + return a; + } + if (typeof a === 'object' && 'lat' in a) { + return new LatLng(a.lat, 'lng' in a ? a.lng : a.lon, a.alt); + } + if (b === undefined) { + return null; + } + return new LatLng(a, b, c); +} + +/* + * @namespace CRS + * @crs L.CRS.Base + * Object that defines coordinate reference systems for projecting + * geographical points into pixel (screen) coordinates and back (and to + * coordinates in other units for [WMS](https://en.wikipedia.org/wiki/Web_Map_Service) services). See + * [spatial reference system](https://en.wikipedia.org/wiki/Spatial_reference_system). + * + * Leaflet defines the most usual CRSs by default. If you want to use a + * CRS not defined by default, take a look at the + * [Proj4Leaflet](https://github.com/kartena/Proj4Leaflet) plugin. + * + * Note that the CRS instances do not inherit from Leaflet's `Class` object, + * and can't be instantiated. Also, new classes can't inherit from them, + * and methods can't be added to them with the `include` function. + */ + +var CRS = { + // @method latLngToPoint(latlng: LatLng, zoom: Number): Point + // Projects geographical coordinates into pixel coordinates for a given zoom. + latLngToPoint: function (latlng, zoom) { + var projectedPoint = this.projection.project(latlng), + scale = this.scale(zoom); + + return this.transformation._transform(projectedPoint, scale); + }, + + // @method pointToLatLng(point: Point, zoom: Number): LatLng + // The inverse of `latLngToPoint`. Projects pixel coordinates on a given + // zoom into geographical coordinates. + pointToLatLng: function (point, zoom) { + var scale = this.scale(zoom), + untransformedPoint = this.transformation.untransform(point, scale); + + return this.projection.unproject(untransformedPoint); + }, + + // @method project(latlng: LatLng): Point + // Projects geographical coordinates into coordinates in units accepted for + // this CRS (e.g. meters for EPSG:3857, for passing it to WMS services). + project: function (latlng) { + return this.projection.project(latlng); + }, + + // @method unproject(point: Point): LatLng + // Given a projected coordinate returns the corresponding LatLng. + // The inverse of `project`. + unproject: function (point) { + return this.projection.unproject(point); + }, + + // @method scale(zoom: Number): Number + // Returns the scale used when transforming projected coordinates into + // pixel coordinates for a particular zoom. For example, it returns + // `256 * 2^zoom` for Mercator-based CRS. + scale: function (zoom) { + return 256 * Math.pow(2, zoom); + }, + + // @method zoom(scale: Number): Number + // Inverse of `scale()`, returns the zoom level corresponding to a scale + // factor of `scale`. + zoom: function (scale) { + return Math.log(scale / 256) / Math.LN2; + }, + + // @method getProjectedBounds(zoom: Number): Bounds + // Returns the projection's bounds scaled and transformed for the provided `zoom`. + getProjectedBounds: function (zoom) { + if (this.infinite) { return null; } + + var b = this.projection.bounds, + s = this.scale(zoom), + min = this.transformation.transform(b.min, s), + max = this.transformation.transform(b.max, s); + + return new Bounds(min, max); + }, + + // @method distance(latlng1: LatLng, latlng2: LatLng): Number + // Returns the distance between two geographical coordinates. + + // @property code: String + // Standard code name of the CRS passed into WMS services (e.g. `'EPSG:3857'`) + // + // @property wrapLng: Number[] + // An array of two numbers defining whether the longitude (horizontal) coordinate + // axis wraps around a given range and how. Defaults to `[-180, 180]` in most + // geographical CRSs. If `undefined`, the longitude axis does not wrap around. + // + // @property wrapLat: Number[] + // Like `wrapLng`, but for the latitude (vertical) axis. + + // wrapLng: [min, max], + // wrapLat: [min, max], + + // @property infinite: Boolean + // If true, the coordinate space will be unbounded (infinite in both axes) + infinite: false, + + // @method wrapLatLng(latlng: LatLng): LatLng + // Returns a `LatLng` where lat and lng has been wrapped according to the + // CRS's `wrapLat` and `wrapLng` properties, if they are outside the CRS's bounds. + wrapLatLng: function (latlng) { + var lng = this.wrapLng ? wrapNum(latlng.lng, this.wrapLng, true) : latlng.lng, + lat = this.wrapLat ? wrapNum(latlng.lat, this.wrapLat, true) : latlng.lat, + alt = latlng.alt; + + return new LatLng(lat, lng, alt); + }, + + // @method wrapLatLngBounds(bounds: LatLngBounds): LatLngBounds + // Returns a `LatLngBounds` with the same size as the given one, ensuring + // that its center is within the CRS's bounds. + // Only accepts actual `L.LatLngBounds` instances, not arrays. + wrapLatLngBounds: function (bounds) { + var center = bounds.getCenter(), + newCenter = this.wrapLatLng(center), + latShift = center.lat - newCenter.lat, + lngShift = center.lng - newCenter.lng; + + if (latShift === 0 && lngShift === 0) { + return bounds; + } + + var sw = bounds.getSouthWest(), + ne = bounds.getNorthEast(), + newSw = new LatLng(sw.lat - latShift, sw.lng - lngShift), + newNe = new LatLng(ne.lat - latShift, ne.lng - lngShift); + + return new LatLngBounds(newSw, newNe); + } +}; + +/* + * @namespace CRS + * @crs L.CRS.Earth + * + * Serves as the base for CRS that are global such that they cover the earth. + * Can only be used as the base for other CRS and cannot be used directly, + * since it does not have a `code`, `projection` or `transformation`. `distance()` returns + * meters. + */ + +var Earth = extend({}, CRS, { + wrapLng: [-180, 180], + + // Mean Earth Radius, as recommended for use by + // the International Union of Geodesy and Geophysics, + // see https://rosettacode.org/wiki/Haversine_formula + R: 6371000, + + // distance between two geographical points using spherical law of cosines approximation + distance: function (latlng1, latlng2) { + var rad = Math.PI / 180, + lat1 = latlng1.lat * rad, + lat2 = latlng2.lat * rad, + sinDLat = Math.sin((latlng2.lat - latlng1.lat) * rad / 2), + sinDLon = Math.sin((latlng2.lng - latlng1.lng) * rad / 2), + a = sinDLat * sinDLat + Math.cos(lat1) * Math.cos(lat2) * sinDLon * sinDLon, + c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a)); + return this.R * c; + } +}); + +/* + * @namespace Projection + * @projection L.Projection.SphericalMercator + * + * Spherical Mercator projection — the most common projection for online maps, + * used by almost all free and commercial tile providers. Assumes that Earth is + * a sphere. Used by the `EPSG:3857` CRS. + */ + +var earthRadius = 6378137; + +var SphericalMercator = { + + R: earthRadius, + MAX_LATITUDE: 85.0511287798, + + project: function (latlng) { + var d = Math.PI / 180, + max = this.MAX_LATITUDE, + lat = Math.max(Math.min(max, latlng.lat), -max), + sin = Math.sin(lat * d); + + return new Point( + this.R * latlng.lng * d, + this.R * Math.log((1 + sin) / (1 - sin)) / 2); + }, + + unproject: function (point) { + var d = 180 / Math.PI; + + return new LatLng( + (2 * Math.atan(Math.exp(point.y / this.R)) - (Math.PI / 2)) * d, + point.x * d / this.R); + }, + + bounds: (function () { + var d = earthRadius * Math.PI; + return new Bounds([-d, -d], [d, d]); + })() +}; + +/* + * @class Transformation + * @aka L.Transformation + * + * Represents an affine transformation: a set of coefficients `a`, `b`, `c`, `d` + * for transforming a point of a form `(x, y)` into `(a*x + b, c*y + d)` and doing + * the reverse. Used by Leaflet in its projections code. + * + * @example + * + * ```js + * var transformation = L.transformation(2, 5, -1, 10), + * p = L.point(1, 2), + * p2 = transformation.transform(p), // L.point(7, 8) + * p3 = transformation.untransform(p2); // L.point(1, 2) + * ``` + */ + + +// factory new L.Transformation(a: Number, b: Number, c: Number, d: Number) +// Creates a `Transformation` object with the given coefficients. +function Transformation(a, b, c, d) { + if (isArray(a)) { + // use array properties + this._a = a[0]; + this._b = a[1]; + this._c = a[2]; + this._d = a[3]; + return; + } + this._a = a; + this._b = b; + this._c = c; + this._d = d; +} + +Transformation.prototype = { + // @method transform(point: Point, scale?: Number): Point + // Returns a transformed point, optionally multiplied by the given scale. + // Only accepts actual `L.Point` instances, not arrays. + transform: function (point, scale) { // (Point, Number) -> Point + return this._transform(point.clone(), scale); + }, + + // destructive transform (faster) + _transform: function (point, scale) { + scale = scale || 1; + point.x = scale * (this._a * point.x + this._b); + point.y = scale * (this._c * point.y + this._d); + return point; + }, + + // @method untransform(point: Point, scale?: Number): Point + // Returns the reverse transformation of the given point, optionally divided + // by the given scale. Only accepts actual `L.Point` instances, not arrays. + untransform: function (point, scale) { + scale = scale || 1; + return new Point( + (point.x / scale - this._b) / this._a, + (point.y / scale - this._d) / this._c); + } +}; + +// factory L.transformation(a: Number, b: Number, c: Number, d: Number) + +// @factory L.transformation(a: Number, b: Number, c: Number, d: Number) +// Instantiates a Transformation object with the given coefficients. + +// @alternative +// @factory L.transformation(coefficients: Array): Transformation +// Expects an coefficients array of the form +// `[a: Number, b: Number, c: Number, d: Number]`. + +function toTransformation(a, b, c, d) { + return new Transformation(a, b, c, d); +} + +/* + * @namespace CRS + * @crs L.CRS.EPSG3857 + * + * The most common CRS for online maps, used by almost all free and commercial + * tile providers. Uses Spherical Mercator projection. Set in by default in + * Map's `crs` option. + */ + +var EPSG3857 = extend({}, Earth, { + code: 'EPSG:3857', + projection: SphericalMercator, + + transformation: (function () { + var scale = 0.5 / (Math.PI * SphericalMercator.R); + return toTransformation(scale, 0.5, -scale, 0.5); + }()) +}); + +var EPSG900913 = extend({}, EPSG3857, { + code: 'EPSG:900913' +}); + +// @namespace SVG; @section +// There are several static functions which can be called without instantiating L.SVG: + +// @function create(name: String): SVGElement +// Returns a instance of [SVGElement](https://developer.mozilla.org/docs/Web/API/SVGElement), +// corresponding to the class name passed. For example, using 'line' will return +// an instance of [SVGLineElement](https://developer.mozilla.org/docs/Web/API/SVGLineElement). +function svgCreate(name) { + return document.createElementNS('http://www.w3.org/2000/svg', name); +} + +// @function pointsToPath(rings: Point[], closed: Boolean): String +// Generates a SVG path string for multiple rings, with each ring turning +// into "M..L..L.." instructions +function pointsToPath(rings, closed) { + var str = '', + i, j, len, len2, points, p; + + for (i = 0, len = rings.length; i < len; i++) { + points = rings[i]; + + for (j = 0, len2 = points.length; j < len2; j++) { + p = points[j]; + str += (j ? 'L' : 'M') + p.x + ' ' + p.y; + } + + // closes the ring for polygons; "x" is VML syntax + str += closed ? (Browser.svg ? 'z' : 'x') : ''; + } + + // SVG complains about empty path strings + return str || 'M0 0'; +} + +/* + * @namespace Browser + * @aka L.Browser + * + * A namespace with static properties for browser/feature detection used by Leaflet internally. + * + * @example + * + * ```js + * if (L.Browser.ielt9) { + * alert('Upgrade your browser, dude!'); + * } + * ``` + */ + +var style = document.documentElement.style; + +// @property ie: Boolean; `true` for all Internet Explorer versions (not Edge). +var ie = 'ActiveXObject' in window; + +// @property ielt9: Boolean; `true` for Internet Explorer versions less than 9. +var ielt9 = ie && !document.addEventListener; + +// @property edge: Boolean; `true` for the Edge web browser. +var edge = 'msLaunchUri' in navigator && !('documentMode' in document); + +// @property webkit: Boolean; +// `true` for webkit-based browsers like Chrome and Safari (including mobile versions). +var webkit = userAgentContains('webkit'); + +// @property android: Boolean +// **Deprecated.** `true` for any browser running on an Android platform. +var android = userAgentContains('android'); + +// @property android23: Boolean; **Deprecated.** `true` for browsers running on Android 2 or Android 3. +var android23 = userAgentContains('android 2') || userAgentContains('android 3'); + +/* See https://stackoverflow.com/a/17961266 for details on detecting stock Android */ +var webkitVer = parseInt(/WebKit\/([0-9]+)|$/.exec(navigator.userAgent)[1], 10); // also matches AppleWebKit +// @property androidStock: Boolean; **Deprecated.** `true` for the Android stock browser (i.e. not Chrome) +var androidStock = android && userAgentContains('Google') && webkitVer < 537 && !('AudioNode' in window); + +// @property opera: Boolean; `true` for the Opera browser +var opera = !!window.opera; + +// @property chrome: Boolean; `true` for the Chrome browser. +var chrome = !edge && userAgentContains('chrome'); + +// @property gecko: Boolean; `true` for gecko-based browsers like Firefox. +var gecko = userAgentContains('gecko') && !webkit && !opera && !ie; + +// @property safari: Boolean; `true` for the Safari browser. +var safari = !chrome && userAgentContains('safari'); + +var phantom = userAgentContains('phantom'); + +// @property opera12: Boolean +// `true` for the Opera browser supporting CSS transforms (version 12 or later). +var opera12 = 'OTransition' in style; + +// @property win: Boolean; `true` when the browser is running in a Windows platform +var win = navigator.platform.indexOf('Win') === 0; + +// @property ie3d: Boolean; `true` for all Internet Explorer versions supporting CSS transforms. +var ie3d = ie && ('transition' in style); + +// @property webkit3d: Boolean; `true` for webkit-based browsers supporting CSS transforms. +var webkit3d = ('WebKitCSSMatrix' in window) && ('m11' in new window.WebKitCSSMatrix()) && !android23; + +// @property gecko3d: Boolean; `true` for gecko-based browsers supporting CSS transforms. +var gecko3d = 'MozPerspective' in style; + +// @property any3d: Boolean +// `true` for all browsers supporting CSS transforms. +var any3d = !window.L_DISABLE_3D && (ie3d || webkit3d || gecko3d) && !opera12 && !phantom; + +// @property mobile: Boolean; `true` for all browsers running in a mobile device. +var mobile = typeof orientation !== 'undefined' || userAgentContains('mobile'); + +// @property mobileWebkit: Boolean; `true` for all webkit-based browsers in a mobile device. +var mobileWebkit = mobile && webkit; + +// @property mobileWebkit3d: Boolean +// `true` for all webkit-based browsers in a mobile device supporting CSS transforms. +var mobileWebkit3d = mobile && webkit3d; + +// @property msPointer: Boolean +// `true` for browsers implementing the Microsoft touch events model (notably IE10). +var msPointer = !window.PointerEvent && window.MSPointerEvent; + +// @property pointer: Boolean +// `true` for all browsers supporting [pointer events](https://msdn.microsoft.com/en-us/library/dn433244%28v=vs.85%29.aspx). +var pointer = !!(window.PointerEvent || msPointer); + +// @property touchNative: Boolean +// `true` for all browsers supporting [touch events](https://developer.mozilla.org/docs/Web/API/Touch_events). +// **This does not necessarily mean** that the browser is running in a computer with +// a touchscreen, it only means that the browser is capable of understanding +// touch events. +var touchNative = 'ontouchstart' in window || !!window.TouchEvent; + +// @property touch: Boolean +// `true` for all browsers supporting either [touch](#browser-touch) or [pointer](#browser-pointer) events. +// Note: pointer events will be preferred (if available), and processed for all `touch*` listeners. +var touch = !window.L_NO_TOUCH && (touchNative || pointer); + +// @property mobileOpera: Boolean; `true` for the Opera browser in a mobile device. +var mobileOpera = mobile && opera; + +// @property mobileGecko: Boolean +// `true` for gecko-based browsers running in a mobile device. +var mobileGecko = mobile && gecko; + +// @property retina: Boolean +// `true` for browsers on a high-resolution "retina" screen or on any screen when browser's display zoom is more than 100%. +var retina = (window.devicePixelRatio || (window.screen.deviceXDPI / window.screen.logicalXDPI)) > 1; + +// @property passiveEvents: Boolean +// `true` for browsers that support passive events. +var passiveEvents = (function () { + var supportsPassiveOption = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { // eslint-disable-line getter-return + supportsPassiveOption = true; + } + }); + window.addEventListener('testPassiveEventSupport', falseFn, opts); + window.removeEventListener('testPassiveEventSupport', falseFn, opts); + } catch (e) { + // Errors can safely be ignored since this is only a browser support test. + } + return supportsPassiveOption; +}()); + +// @property canvas: Boolean +// `true` when the browser supports [``](https://developer.mozilla.org/docs/Web/API/Canvas_API). +var canvas$1 = (function () { + return !!document.createElement('canvas').getContext; +}()); + +// @property svg: Boolean +// `true` when the browser supports [SVG](https://developer.mozilla.org/docs/Web/SVG). +var svg$1 = !!(document.createElementNS && svgCreate('svg').createSVGRect); + +var inlineSvg = !!svg$1 && (function () { + var div = document.createElement('div'); + div.innerHTML = ''; + return (div.firstChild && div.firstChild.namespaceURI) === 'http://www.w3.org/2000/svg'; +})(); + +// @property vml: Boolean +// `true` if the browser supports [VML](https://en.wikipedia.org/wiki/Vector_Markup_Language). +var vml = !svg$1 && (function () { + try { + var div = document.createElement('div'); + div.innerHTML = ''; + + var shape = div.firstChild; + shape.style.behavior = 'url(#default#VML)'; + + return shape && (typeof shape.adj === 'object'); + + } catch (e) { + return false; + } +}()); + + +// @property mac: Boolean; `true` when the browser is running in a Mac platform +var mac = navigator.platform.indexOf('Mac') === 0; + +// @property mac: Boolean; `true` when the browser is running in a Linux platform +var linux = navigator.platform.indexOf('Linux') === 0; + +function userAgentContains(str) { + return navigator.userAgent.toLowerCase().indexOf(str) >= 0; +} + + +var Browser = { + ie: ie, + ielt9: ielt9, + edge: edge, + webkit: webkit, + android: android, + android23: android23, + androidStock: androidStock, + opera: opera, + chrome: chrome, + gecko: gecko, + safari: safari, + phantom: phantom, + opera12: opera12, + win: win, + ie3d: ie3d, + webkit3d: webkit3d, + gecko3d: gecko3d, + any3d: any3d, + mobile: mobile, + mobileWebkit: mobileWebkit, + mobileWebkit3d: mobileWebkit3d, + msPointer: msPointer, + pointer: pointer, + touch: touch, + touchNative: touchNative, + mobileOpera: mobileOpera, + mobileGecko: mobileGecko, + retina: retina, + passiveEvents: passiveEvents, + canvas: canvas$1, + svg: svg$1, + vml: vml, + inlineSvg: inlineSvg, + mac: mac, + linux: linux +}; + +/* + * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. + */ + +var POINTER_DOWN = Browser.msPointer ? 'MSPointerDown' : 'pointerdown'; +var POINTER_MOVE = Browser.msPointer ? 'MSPointerMove' : 'pointermove'; +var POINTER_UP = Browser.msPointer ? 'MSPointerUp' : 'pointerup'; +var POINTER_CANCEL = Browser.msPointer ? 'MSPointerCancel' : 'pointercancel'; +var pEvent = { + touchstart : POINTER_DOWN, + touchmove : POINTER_MOVE, + touchend : POINTER_UP, + touchcancel : POINTER_CANCEL +}; +var handle = { + touchstart : _onPointerStart, + touchmove : _handlePointer, + touchend : _handlePointer, + touchcancel : _handlePointer +}; +var _pointers = {}; +var _pointerDocListener = false; + +// Provides a touch events wrapper for (ms)pointer events. +// ref https://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890 + +function addPointerListener(obj, type, handler) { + if (type === 'touchstart') { + _addPointerDocListener(); + } + if (!handle[type]) { + console.warn('wrong event specified:', type); + return falseFn; + } + handler = handle[type].bind(this, handler); + obj.addEventListener(pEvent[type], handler, false); + return handler; +} + +function removePointerListener(obj, type, handler) { + if (!pEvent[type]) { + console.warn('wrong event specified:', type); + return; + } + obj.removeEventListener(pEvent[type], handler, false); +} + +function _globalPointerDown(e) { + _pointers[e.pointerId] = e; +} + +function _globalPointerMove(e) { + if (_pointers[e.pointerId]) { + _pointers[e.pointerId] = e; + } +} + +function _globalPointerUp(e) { + delete _pointers[e.pointerId]; +} + +function _addPointerDocListener() { + // need to keep track of what pointers and how many are active to provide e.touches emulation + if (!_pointerDocListener) { + // we listen document as any drags that end by moving the touch off the screen get fired there + document.addEventListener(POINTER_DOWN, _globalPointerDown, true); + document.addEventListener(POINTER_MOVE, _globalPointerMove, true); + document.addEventListener(POINTER_UP, _globalPointerUp, true); + document.addEventListener(POINTER_CANCEL, _globalPointerUp, true); + + _pointerDocListener = true; + } +} + +function _handlePointer(handler, e) { + if (e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse')) { return; } + + e.touches = []; + for (var i in _pointers) { + e.touches.push(_pointers[i]); + } + e.changedTouches = [e]; + + handler(e); +} + +function _onPointerStart(handler, e) { + // IE10 specific: MsTouch needs preventDefault. See #2000 + if (e.MSPOINTER_TYPE_TOUCH && e.pointerType === e.MSPOINTER_TYPE_TOUCH) { + preventDefault(e); + } + _handlePointer(handler, e); +} + +/* + * Extends the event handling code with double tap support for mobile browsers. + * + * Note: currently most browsers fire native dblclick, with only a few exceptions + * (see https://github.com/Leaflet/Leaflet/issues/7012#issuecomment-595087386) + */ + +function makeDblclick(event) { + // in modern browsers `type` cannot be just overridden: + // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Errors/Getter_only + var newEvent = {}, + prop, i; + for (i in event) { + prop = event[i]; + newEvent[i] = prop && prop.bind ? prop.bind(event) : prop; + } + event = newEvent; + newEvent.type = 'dblclick'; + newEvent.detail = 2; + newEvent.isTrusted = false; + newEvent._simulated = true; // for debug purposes + return newEvent; +} + +var delay = 200; +function addDoubleTapListener(obj, handler) { + // Most browsers handle double tap natively + obj.addEventListener('dblclick', handler); + + // On some platforms the browser doesn't fire native dblclicks for touch events. + // It seems that in all such cases `detail` property of `click` event is always `1`. + // So here we rely on that fact to avoid excessive 'dblclick' simulation when not needed. + var last = 0, + detail; + function simDblclick(e) { + if (e.detail !== 1) { + detail = e.detail; // keep in sync to avoid false dblclick in some cases + return; + } + + if (e.pointerType === 'mouse' || + (e.sourceCapabilities && !e.sourceCapabilities.firesTouchEvents)) { + + return; + } + + // When clicking on an , the browser generates a click on its + //