From b1217f030262d8db12a197247f997aed17b1732a Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 9 Aug 2021 11:11:08 -0700 Subject: [PATCH 01/85] Search limit and fix globe elev coords --- .../great_circle_calculator/__conversion.pyc | Bin 0 -> 1476 bytes .../__error_checking.pyc | Bin 0 -> 916 bytes .../great_circle_calculator/_constants.pyc | Bin 0 -> 2173 bytes .../great_circle_calculator.pyc | Bin 0 -> 6194 bytes src/css/mmgis.css | 2 +- src/css/mmgisUI.css | 2 +- src/essence/Ancillary/Coordinates.js | 12 +++- src/essence/Ancillary/Search.js | 54 ++++++------------ src/essence/Basics/Globe_/Globe_.js | 8 ++- 9 files changed, 36 insertions(+), 42 deletions(-) create mode 100644 private/api/great_circle_calculator/__conversion.pyc create mode 100644 private/api/great_circle_calculator/__error_checking.pyc create mode 100644 private/api/great_circle_calculator/_constants.pyc create mode 100644 private/api/great_circle_calculator/great_circle_calculator.pyc diff --git a/private/api/great_circle_calculator/__conversion.pyc b/private/api/great_circle_calculator/__conversion.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9867d83b57dc84d34accd41de72455ae0b58a1a9 GIT binary patch literal 1476 zcmc&!U2oGc6un75)>Q+I@gX53l*ejF{D2A#M3E2=n@|cbQ$%JtW;3L5WV@3l!4v!> z{sg~=Kft+;yB2Biz{8f-x5swsd(X+a>HWGje)9b1iKKX?_W0X>z z&?2Sdl#;4P--(WURP_VsQ#A-+K-DmSAyr#6pNw#fP7o#>Jcs=b?g5s{T4PIjrsU_c zHM;SV@8H3O%rM*zf+zYybPvVcpHFzlogid0)0`{oUFOeJR;g2~l*@34$*icfXxuo% zHEo3zi`D)VKRlO^f$VSyy;x zYUF5&S4J)us`0LPYt1Jm0S*seznK@U)#t*iLbSR--NKhrTUo18idrsf;f*cIQU-!f zo91bI;qM|v88esOl#%2R%Z>}A!PV+PHdYTJ{$0IzR;OOfv8i6%|1b4&E^e(|Jn9Ct ziQDA`FaopZ_lF*Z8(E5@M-|HU|vWjhA4IXB8p@{G^; z5z6TLBRQIIO@55Pz2&?>Yx-TDZoZ0ibGm+TITOl99JUeGgaW#bzUSP}7N%O(>VQq< Oxc+gn+uI)DGx!bsyK}t& literal 0 HcmV?d00001 diff --git a/private/api/great_circle_calculator/__error_checking.pyc b/private/api/great_circle_calculator/__error_checking.pyc new file mode 100644 index 0000000000000000000000000000000000000000..7c5fecc02b7db32e94c1fdde0229adf0501dbeae GIT binary patch literal 916 zcmcgq&2G~`5T3Q&QbMbuDj*?oaBda{&J{waQV<1+RuzFuWy!2}H|Y|`Ywb>oDmlHt zmA61V0S~|%ap(ht*^Q&7FMy@l{pQEtd^2`@v)8-+ik}5^Pek_-nR`fw0+0aT8Jsha z3`UvH3V&>oC1gV~x6c3&pau9A>ZUQ+XCNa$whqQHj^X$%MlizI2W0|JsJe5uf)gzw zSi~T=p^YJlrwmL9@*WVVBZ!#&0dfc0sLNf0yuX>F1id$=7M@{U_45wHO<-8F|GC3J zxlPHvmE@Lz{p*Q|k+>HLv(F)qs7JUR+92f(ubc{KTp5m;mlxc|Ys5WrJ9)(_5=hL7q~eJCR1q>o zSEpn~Aqa;n2@PN5pBzcd(V0rmc%8pCVm>1wEDlB3Fbqw|SX z91EeXs8k_%CFa!5*t{r|wZ<0WLW!xaC(oNJJfJq4;gwduZ}*fAU; r-e$YxCsCiBhTj4%|0|zHx_IGfCiGwZ+v z$vFoaBriMABzeVwNoKUuz6y5w8=md92Wac4dLmWQ4*H4G@0JDGD*94oRc_qyp-!@4 zv%(`fQO1^m9xG)ncO8jb8p}7>69cPbkwnET9^CC|YwQHi*D8?_pJw#u5>fZT?KkUt zH{Y&xKW)CRFRa$r^vW2zKdjeorLVrM#;hTW57~g2CMt{j_vn~#tKh@K+ijlUR7!>2 zx7eDD?iB=i!t*vNa+L{zHtvMG2J}K}vP7q%7j9c#$1z&CmwVpu8i{*6RX!x~2*&Ws}v z@Xd`<{|3&Rhn%bbH4MTCg#}&!dvxIcW)L=k<((o6XNhE%3f(KnvFC^%<{3FVcG4RV z!)lP%_=A1^mS4c$c!tw|v)B~$Sb&^zV%K9~Gq}KM0sIV{V~5wR&XRw3z zPMfW_t=SANV;4z)n?Z-=wF|@31UZ^4 pZ^v=+N}9<*qV6(H!{;`pyA{a@S7 zpMLze--lHG)$#iYzQv!AMEH1=5RE)K@n}?|lNyccbW*2LgH9UcagQ1$D>PcAlT}x) zQ?f>nq6V3DidN_aMr}~EN-u~`niQ=`W|N|I$!t-C)+W8c65E7P(Wc~YQM5(J{x-G| zdr15S68i%r{c#qjwr{h3uA^9|#g*E~oae?A_6_b^cH!Pj^<`mU7N1wKcX^P>^DOU& zLlgeNE#}&|!-sYi>Bv}<7a?!y7QS5d5Z~fGbg}q&G$nfO@#nNgmkqjHsp_S&tY4+e zHL^9bb(+>#)X(d5xlYqM<$tH?8ckPdZ@Nm;2JO`@H|VlSwn0;ft42GRVyV!wE8L%} zky+zRi#tH#uJ@Hv`w~}xrB}&fp-maMMiF+hNqZRlyhg3dEt+CGTgYwGbeoRtx-9CJ z!Q|yK*Q|^xw{hM_8wn<=W|6Bbx-}y8Xc!l2FiArjXQ>La(RgA_q3qD8C@!o{L!-`& zy)Y(K_99bq^@WO2LYGMzTXh~kMdM=4Sm#=9=uoN8t-6Slq^a;1>Li>b+M4D0Cqr)(HANk;2b|~r6cP1X@Cs}%cIqd#Y$L{~wk)_ddGQngcql-yyMkcj~>I=vc z$4_}9gKUyUEUz#FbaZNqLzBek@mXT}JcZkKxy#vUd+Jd>G0Kn3Ku;38&*xbbMs-^U zP9U!N8gcY;V<&mqQ=eYF-f>51Y;4?Jyvt%H`RGuD5-`?cs7}cW8^{ItQXu@WhTOTa z+S=T1AX6)JL_fk6f05FL)=MhB6IH(?^LUDPrUv_D+8X zO)O4rktOj+r>CE0;e@ZZIQ>nYJvJdSUw--7=f|hxJbnr-Kh@*-6jZ2fKaBGb*INM~ z%U@Q1IDTf^SgpFwehEHDgT*?UihD??x##V9cfHlxj`yZ_-r&$dyuI$J( zD|7`?0*mkgv;1fvtDTBr;N z9CtwrxU&*#k1LkDi0x2xc@#&&Xa0wnNiYekGBU7f)|7S!Eufh}j8-N*x31FA8OK<8 z2EHtpDYw|ieUH05=idJ~fBY6(ppvgsn z^Cst5jeIFG6ocEGuyGF9tOqSlc8~~YzLNBrm}V!U8v_sfD~lJ=c^?%8QxUB*WPah@ z^KLtk@CliU1SE16qN(#7#2IMAJntU++@*N(+UnVzsVB%jhkl;V4bHf8a~j(D{%dIb zSBO3yLiEBBfkM&eTMK3?`MuGz?h*D?@aAY;D40Ps^GpAY!s}45bM%&2mPxka)g`uV zIg*{zbj93la4ioJ@&*C7mkKTRbJv`Y=%^Wd?#OznAKKdRfq`+y+sxs}Z!m|$a~80` zd)-4HRHDxSJl|yh_t^QH-#`YA;o)*J{|$9A_}PViR^q{ts#an#m9v;?tnCm^Q|W+W z(A)`i{>XRW%~iZ9w&AK%7{7%(7M&FB^x3m`If*jwI3^WNovH1$Ov*%a*8d6@$iL4j zf9A+#vh)b|0e|S|#&n*&kIH6#gnY4!gjShW@8SQ)-aFpg-WEz*-Z{4r{o~`1Ps7Gz zhJ{an=WDQl$g5G+FS;WuRBF7CGqe!$dEB5K*7gK!6InI~Eo!{(Oy5szNLWF*w^Zk7fyG3(icU z<4D1cQD;D6hn*I2oCdjeL1Bs3sw}<(yepoe@=|9Aoy8Cb>SAbeqaG*>A9oJagTtS5 z);yWOH%{O+^Foy}!4w^c2iB49-R}(AF7&I8g18Qcs7f3GE*)y_2oi%^0vgbWi8YsL`J4Wepm*V2W=F($D(_#wKA2X+>`&FkE+ z%6|+#;PQ`<+!$%F&$y_D&awV2Y8`!uSGMcj2Z40)f8TqT{WA^-Su{+q54rC@kzB(X zvtUIi!v!F0yz13!4uB>kP%;7o+!<9gNc_=aEV?SR&8teV0&Q&3KuwMUq?%`$_jI7= zX{2tx1bT^iZ0(8h#Oo1e0;FLuVN78xck$e|=ZqvbNoO{j!Uo4a-*E9YgZwjjW6?@n zNC#y0=VKdde%z4I$RVhL7$9|Sqtz0;HvDx2dy zCP~<3t&Fo@46__BM0SS#{bhr#^YHc1>*9u`de6%6y{VQ^PJ`B zdBA2k*yn_!7#Eu{o7@=YnT15L`tmr~7q#s}$?%*Zx;j9IqJ@Mu*ju=Z*NYzBFg}ns zjbHn`d3iqS_wh(3Z-QCsyey_l@u&ips%4S%7vGDatnMX>?|?_UCpHllzo0ofR%i^~ z<>V)v9B}dg$y{QR`#(SY@MZsUltq)oe8kF7@af*G-SL|B+iz~%+1T88V{7L>R09_r literal 0 HcmV?d00001 diff --git a/src/css/mmgis.css b/src/css/mmgis.css index 74e2588c..144dfa23 100644 --- a/src/css/mmgis.css +++ b/src/css/mmgis.css @@ -434,7 +434,7 @@ body { } .leaflet-popup-content-wrapper::-webkit-scrollbar { - width: 2px; + width: 4px; height: 2px; background-color: var(--color-a); } diff --git a/src/css/mmgisUI.css b/src/css/mmgisUI.css index 5805fde6..eec27a87 100644 --- a/src/css/mmgisUI.css +++ b/src/css/mmgisUI.css @@ -606,7 +606,7 @@ } .mmgisScrollbar::-webkit-scrollbar { - width: 2px; + width: 4px; height: 2px; background-color: var(--color-a); } diff --git a/src/essence/Ancillary/Coordinates.js b/src/essence/Ancillary/Coordinates.js index 5395a96f..a7f53e26 100644 --- a/src/essence/Ancillary/Coordinates.js +++ b/src/essence/Ancillary/Coordinates.js @@ -361,6 +361,8 @@ var Coordinates = { if (Coordinates.elevQueryTimes.length >= 10) delay = 400 if (Coordinates.elevQueryTimes.length >= 20) delay = 200 + Coordinates.showElevation() + Coordinates.elevationTimeout = setTimeout(() => { const now = new Date().getTime() Coordinates.elevQueryTimes.push(now) @@ -370,6 +372,9 @@ var Coordinates = { let url = L_.configData.look.coordelevurl if (!F_.isUrlAbsolute(url)) url = L_.missionPath + url + + if ($('#mouseElev').css('display') === 'none') return + calls.api( 'getbands', { @@ -388,7 +393,6 @@ var Coordinates = { data = JSON.parse(data) if (data[0] && data[0][1] != null) { Coordinates.elevation = data[0][1] - Coordinates.refresh(true) } } @@ -400,6 +404,12 @@ var Coordinates = { ) }, delay) }, + hideElevation: function () { + $('#mouseElev').css({ display: 'none' }) + }, + showElevation: function () { + $('#mouseElev').css({ display: 'block' }) + }, remove: function () { //Clear all the stuffes $('#changeLngLat').off('click', mouseLngLatClick) diff --git a/src/essence/Ancillary/Search.js b/src/essence/Ancillary/Search.js index 93c2177d..dacdf347 100644 --- a/src/essence/Ancillary/Search.js +++ b/src/essence/Ancillary/Search.js @@ -128,6 +128,8 @@ function escapeRegex(value) { function initializeSearch() { $('#auto_search').autocomplete({ lookup: Search.arrayToSearch, + lookupLimit: 100, + minChars: 2, onSelect: function (event) { searchBoth(event.value) }, @@ -137,16 +139,14 @@ function initializeSearch() { if (e.keyCode == 13) searchBoth() }) - $('.autocomplete-suggestions') - .css({ - 'max-height': '60vh', - 'overflow-y': 'auto', - 'overflow-x': 'hidden', - border: '1px solid var(--color-mmgis)', - 'border-top': 'none', - 'background-color': 'var(--color-a)', - }) - .addClass('mmgisScrollbar') + $('.autocomplete-suggestions').css({ + 'max-height': '60vh', + 'overflow-y': 'auto', + 'overflow-x': 'hidden', + border: '1px solid var(--color-mmgis)', + 'border-top': 'none', + 'background-color': 'var(--color-a)', + }) } function changeSearchField(val, selectedPlaceholder) { @@ -170,9 +170,8 @@ function changeSearchField(val, selectedPlaceholder) { $('#SearchSelect').css({ display: 'inherit' }) $('#SearchBoth').css({ display: 'inherit' }) if (document.getElementById('auto_search') != null) { - document.getElementById( - 'auto_search' - ).placeholder = getSearchFieldKeys(Search.lname) + document.getElementById('auto_search').placeholder = + getSearchFieldKeys(Search.lname) } initializeSearch() @@ -200,9 +199,8 @@ function changeSearchField(val, selectedPlaceholder) { else Search.arrayToSearch.sort() } if (document.getElementById('auto_search') != null) { - document.getElementById( - 'auto_search' - ).placeholder = getSearchFieldKeys(Search.lname) + document.getElementById('auto_search').placeholder = + getSearchFieldKeys(Search.lname) } initializeSearch() @@ -446,28 +444,8 @@ function searchWithURLParams() { function getMapZoomCoordinate(layers) { //The zoom levels are defined at http://wiki.openstreetmap.org/wiki/Zoom_levels var zoomLevels = [ - 360, - 180, - 90, - 45, - 22.5, - 11.25, - 5.625, - 2.813, - 1.406, - 0.703, - 0.352, - 0.176, - 0.088, - 0.044, - 0.022, - 0.011, - 0.005, - 0.003, - 0.001, - 0.0005, - 0.0003, - 0.0001, + 360, 180, 90, 45, 22.5, 11.25, 5.625, 2.813, 1.406, 0.703, 0.352, 0.176, + 0.088, 0.044, 0.022, 0.011, 0.005, 0.003, 0.001, 0.0005, 0.0003, 0.0001, ] var boundingBoxNorth = 90 var boundingBoxSouth = -90 diff --git a/src/essence/Basics/Globe_/Globe_.js b/src/essence/Basics/Globe_/Globe_.js index 559812b3..0658e073 100644 --- a/src/essence/Basics/Globe_/Globe_.js +++ b/src/essence/Basics/Globe_/Globe_.js @@ -1,15 +1,17 @@ import F_ from '../Formulae_/Formulae_' import L_ from '../Layers_/Layers_' +import $ from 'jquery' import LithoSphere from 'lithosphere' let Globe_ = { litho: null, + id: 'globe', controls: { link: null, }, init: function () { - const containerId = 'globe' + const containerId = this.id let initialView = null if (L_.FUTURES.globeView != null) { initialView = L_.FUTURES.globeView @@ -127,6 +129,10 @@ let Globe_ = { fina: function (coordinates) { // Passes in Coordinates so that LithoSphere can share the same coordinate ui element // as the rest of the application + console.log(coordinates) + $(`#${this.id}`).on('mousemove', () => { + coordinates.hideElevation() + }) }, reset: function () {}, setLink: function () {}, From 862bdf8157647d261d31b0b05bbabc9a32bff06d Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 16 Aug 2021 08:38:18 -0700 Subject: [PATCH 02/85] Smarter short link, draw tool buffer compile inward --- API/Backend/Draw/routes/files.js | 4 ++-- API/Backend/Shortener/routes/shortener.js | 4 +++- src/external/Leaflet/leaflet-src_DEBUG.js | 1 + 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/API/Backend/Draw/routes/files.js b/API/Backend/Draw/routes/files.js index 79c9baf2..2b2ddf3b 100644 --- a/API/Backend/Draw/routes/files.js +++ b/API/Backend/Draw/routes/files.js @@ -775,11 +775,11 @@ const compile = function (req, res, callback) { " " + "AND a.id != b.id" + " " + - "AND ((ST_OVERLAPS(a.geom, b.geom)" + + "AND ((ST_OVERLAPS(ST_BUFFER(a.geom, -0.000005, 'join=mitre'), b.geom)" + " " + "AND NOT ST_Touches(a.geom, b.geom))" + " " + - "OR ST_CROSSES(a.geom, b.geom))" + + "OR ST_CROSSES(ST_BUFFER(a.geom, -0.000005, 'join=mitre'), b.geom))" + " " + "UNION ALL" + " " + diff --git a/API/Backend/Shortener/routes/shortener.js b/API/Backend/Shortener/routes/shortener.js index de0b9427..4134a65c 100644 --- a/API/Backend/Shortener/routes/shortener.js +++ b/API/Backend/Shortener/routes/shortener.js @@ -30,7 +30,9 @@ router.post("/shorten", function (req, res, next) { shorten(); function shorten() { - var short = Math.random().toString(36).substr(2, 4); + var short = Math.random() + .toString(36) + .substr(2, 5 + loop); let newUrlShortened = { full: encodeURIComponent(req.body.url), diff --git a/src/external/Leaflet/leaflet-src_DEBUG.js b/src/external/Leaflet/leaflet-src_DEBUG.js index 815a5ae2..4b1f348f 100644 --- a/src/external/Leaflet/leaflet-src_DEBUG.js +++ b/src/external/Leaflet/leaflet-src_DEBUG.js @@ -4326,6 +4326,7 @@ // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin), // returns the corresponding geographical coordinate (for the current zoom level). layerPointToLatLng: function (point) { + console.log('layerPointToLatLng', point, this.getPixelOrigin()) var projectedPoint = toPoint(point).add(this.getPixelOrigin()) return this.unproject(projectedPoint) }, From 0c076557ec46e76846fb5bb4ae92251a99660cfc Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 19 Aug 2021 13:58:50 -0700 Subject: [PATCH 03/85] Upgrade lithosphere --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index fdcae73c..0b51e6e2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.1", + "lithosphere": "^1.0.2", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", @@ -11766,10 +11766,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/lithosphere": { - "version": "1.0.1", - "resolved": "file:../../npm-local/lithosphere-1.0.1.tgz", - "integrity": "sha512-gCNoVzERhWxWvHzbxiuq6nPg51s/BM6F3g1YP/YIrDRljHxr580NLT/I2wH9DMbcm71kOIsCEPvs5X3x4jbZ6w==", - "license": "Apache-2.0", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.2.tgz", + "integrity": "sha512-FmW7+9V/JTrwbgzT6GmNGeswd0sZnZN5tQ0skA5GTxehoEyYYyNZ5Hfyfqs56JuvtxZh68DmJXeSN6rRUOqLYw==", "dependencies": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", @@ -30397,8 +30396,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "lithosphere": { - "version": "1.0.1", - "integrity": "sha512-gCNoVzERhWxWvHzbxiuq6nPg51s/BM6F3g1YP/YIrDRljHxr580NLT/I2wH9DMbcm71kOIsCEPvs5X3x4jbZ6w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.2.tgz", + "integrity": "sha512-FmW7+9V/JTrwbgzT6GmNGeswd0sZnZN5tQ0skA5GTxehoEyYYyNZ5Hfyfqs56JuvtxZh68DmJXeSN6rRUOqLYw==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/package.json b/package.json index f7bebebf..5bf998e6 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.1", + "lithosphere": "^1.0.2", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", From 23bd49952e58fc488a2fda146f5f0a745fbdde78 Mon Sep 17 00:00:00 2001 From: Cameron Fraser Date: Wed, 14 Jul 2021 09:44:42 -0500 Subject: [PATCH 04/85] Add isochrone tool --- docs/docs.js | 1 + docs/pages/markdowns/Isochrone.md | 78 +++ src/essence/Tools/Isochrone/IsochroneTool.css | 206 ++++++ src/essence/Tools/Isochrone/IsochroneTool.js | 588 ++++++++++++++++++ .../Isochrone/IsochroneTool_Algorithm.js | 232 +++++++ .../Tools/Isochrone/IsochroneTool_Manager.js | 430 +++++++++++++ .../Tools/Isochrone/IsochroneTool_Query.js | 201 ++++++ src/essence/Tools/Isochrone/config.json | 36 ++ src/essence/Tools/Isochrone/models/Model.js | 67 ++ .../Tools/Isochrone/models/Model_Example.js | 21 + .../Isochrone/models/Model_Isodistance.js | 46 ++ .../Tools/Isochrone/models/Model_Traverse.js | 53 ++ src/essence/Tools/Isochrone/models/index.js | 11 + src/essence/Tools/Isochrone/ui.js | 42 ++ 14 files changed, 2012 insertions(+) create mode 100644 docs/pages/markdowns/Isochrone.md create mode 100644 src/essence/Tools/Isochrone/IsochroneTool.css create mode 100644 src/essence/Tools/Isochrone/IsochroneTool.js create mode 100644 src/essence/Tools/Isochrone/IsochroneTool_Algorithm.js create mode 100644 src/essence/Tools/Isochrone/IsochroneTool_Manager.js create mode 100644 src/essence/Tools/Isochrone/IsochroneTool_Query.js create mode 100644 src/essence/Tools/Isochrone/config.json create mode 100644 src/essence/Tools/Isochrone/models/Model.js create mode 100644 src/essence/Tools/Isochrone/models/Model_Example.js create mode 100644 src/essence/Tools/Isochrone/models/Model_Isodistance.js create mode 100644 src/essence/Tools/Isochrone/models/Model_Traverse.js create mode 100644 src/essence/Tools/Isochrone/models/index.js create mode 100644 src/essence/Tools/Isochrone/ui.js diff --git a/docs/docs.js b/docs/docs.js index b8d64938..4ee5ea4e 100644 --- a/docs/docs.js +++ b/docs/docs.js @@ -28,6 +28,7 @@ let tools = [ "Draw", "Identifier", "Info", + "Isochrone", "Layers", "Legend", "Measure", diff --git a/docs/pages/markdowns/Isochrone.md b/docs/pages/markdowns/Isochrone.md new file mode 100644 index 00000000..35a5a188 --- /dev/null +++ b/docs/pages/markdowns/Isochrone.md @@ -0,0 +1,78 @@ +# Isochrone + +The Isochrone tool shades regions of the map based on traverse time (or other "costs") from user-defined source points. Analysis is done by one of several selectable models and based on user-defined constraints. Hover over the generated shape to view the least-cost path to any given point from the start point. Users may view multiple isochrones simultaneously, and change the size, resolution, color ramp, color steps, and opacity of each one. + +## Tool Configuration + +### Example + +```javascript +{ + "data": { + "DEM": [ + { + "name": "Unique Name 1", + "tileurl": "Layers/Example/{z}/{x}/{y}.png", + "minZoom": 8, + "maxNativeZoom": 18, + "resolution": 256, + "interpolateSeams": true + }, + { "...": "..." } + ], + "slope": [ + { "...": "..." } + ], + "cost": [ + { "...": "..." } + ] + }, + "interpolateSeams": false, + "models": ["Traverse Time", "Isodistance", "..."] +} +``` + +_**data**_ - Each key in the "data" field should be the name of a type of data to be used in analysis. Examples of data types may include "DEM", "slope", "obstacle", "cost", or "shade". Values are an array of data source objects. + +Data source objects must include a unique _**name**_, a _**tileurl**_, _**minZoom**_ and _**maxNativeZoom**_, and a _**resolution**_ indicating a power of 2 tile size between 32 and 256. Sources may also include an optional _**interpolateSeams**_ property, indicating per-source whether to correct tile seams (see global `interpolateSeams` property, below). Tiles should be in the same format as a DEM tileset (see `/auxiliary/1bto4b`). Note that the tool has no means of verifying that the tileset it is pointed to contains the right kind of data, so configure carefully. + +Each model may require one or more of these data types to operate. Users will be prompted to select one of the configured sources for each of these data types. If no valid sources are configured for a data type a model needs, the tool will display an error message. + +_**interpolateSeams**_ - Because `1bto4b` generates tiles with matching edges, data loaded and passed to models may have "seams," or regularly-spaced pairs of identical rows and columns. Depending on the data type and model, these seams may or may not cause inaccurate results. The default behavior of the tool is therefore to attempt to correct these seams. Set this property to false to disable this behavior for all sources that do not explicitly set their own `interpolateSeams` property to `true`. + +_**models**_ - An optional list of models to make available. If not configured, a default list will be used. + +## Tool Use + +With the isochrone tool active, click on the map to generate an isochrone starting from the clicked point. This isochrone will update dynamically as its properties are changed. Hover over the isochrone to view least-cost paths and total accumulated costs at any shaded point. Note that while many isochrones may be visible at once, only one "focused" isochrone will render least-cost paths. An isochrone may be brought into "focus" by clicking its marker on the map, its name in the toolbar, or by modifying any of its properties. + +### General Properties +General display options available to all isochrones. + +_**Max Radius**_ - The radius of data to fetch around the start point. Note that, depending on the max cost setting, isochrones may run into this boundary. If the edge of the isochrone appears jagged, this property should be increased. + +_**Color**_ - Selects a color ramp for the isochrone. + +_**Opacity**_ - Changes the opacity of the isochrone. + +_**Steps**_ - Picks the number of color steps in the isochrone, to reveal contours inside the shape. Set to 0 for a continuous ramp. + +_**Model**_ - Selects which model to use to generate the isochrone. See `/src/essence/Tools/Isochrone/models` to create custom models. + +### Data Properties +Options related to how data is retrieved and displayed. + +_**Resolution**_ - Changes the resolution of the isochrone. This number represents the zoom level at which the resulting layer will be rendered. + +**Data Sources** - Options to set the source for every data set required by the selected model. If no valid source has been listed for one or more required data set, an error message will appear and the isochrone will not render. + +### Model properties +Options specific to the selected model. + +**Max Cost** - This section will always include a max cost option, in units relevant to the selected model. This represents the cost to reach the edges of the isochrone from the start point, and will thus determine the ultimate size of the shape. + +This section may have additional options specified by the selected model. + +## Technical + +The Isochrone tool runs a version of Dijkstra's algorithm on tiled data to generate results. In this implementation, every pixel is a vertex which is implicitly connected by an edge to 16 of its neighbors: its 8 immediate neighbors, plus neigbors that can be reached by the "knight's move" - i.e. the move a knight makes on a chessboard. Analysis is performed entirely in-browser in JavaScript. diff --git a/src/essence/Tools/Isochrone/IsochroneTool.css b/src/essence/Tools/Isochrone/IsochroneTool.css new file mode 100644 index 00000000..6de5fca9 --- /dev/null +++ b/src/essence/Tools/Isochrone/IsochroneTool.css @@ -0,0 +1,206 @@ +#isochroneTool { + width: 100%; + height: 100%; + color: white; + background-color: var(--color-k); +} + +#isochroneToolHeader { + display: flex; + justify-content: space-between; + height: 40px; + padding-left: 6px; + line-height: 40px; + font-size: 16px; + color: var(--color-l); + background-color: var(--color-a); + border-bottom: 1px solid var(--color-i); +} + +#isochroneToolTitle { + font-family: lato-light; + text-transform: uppercase; +} + +#isochroneToolHeader #iscNew { + display: flex; + cursor: pointer; + height: 40px; + line-height: 40px; + font-size: 14px; + padding-right: 6px; + transition: color 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95); +} +#isochroneTool #iscNew:hover { + color: var(--color-mmgis); +} + +#isochroneOptionsContainer { + height: calc(100% - 40px); + overflow-y: auto; + margin: 0; + padding: 0; +} + +li.focused { + background: linear-gradient(180deg, var(--color-i), rgba(0, 0, 0, 0) 75%); +} + +.isochroneHeader { + display: flex; + justify-content: space-between; + align-items:center; + height: 28px; + border-bottom: 1px solid var(--color-e); +} + +.isochroneHeader .checkbox.on { + background: white; + border: 0px solid #777; +} +.isochroneHeader .checkbox { + margin: 5px; + width: 14px; + height: 14px; + border: 2px solid #777; + border-radius: 3px; + cursor: pointer; + transition: background 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), + border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1); +} +.isochroneHeader .iscicon { + cursor: pointer; + margin-top: 2px; +} + +.isochroneHeader .title { + flex: 1; +} + +.focused .isochroneHeader { + background-color: var(--color-b); +} +.focused .isochroneOptions { + border-left-color: #e0e0e0; +} +.focused .isochroneOptions > div, .focused .isochroneOptions > section > div { + color: #cfcfcf; +} + +.isochroneOptions { + position: relative; + border-left: 5px solid var(--color-e); + overflow: hidden; + transition: height 0.2s linear; +} +.isochroneOptions.collapsed { + height: 0px; +} + +.isochroneOptions > div, .isochroneOptions > section > div { + display: flex; + justify-content: space-between; + height: 26px; + line-height: 26px; + padding-left: 5px; + border-bottom: 1px solid var(--color-e); + font-size: 15px; + overflow: clip; + color: #909090; +} + +#isochroneTool .dropdown { + background-color: var(--color-i); + color: #ededed; + border: none; + border-radius: 0; + width: 120px; + height: 25px; + font-size: 14px; + transition: height 0.2s linear; +} + +#isochroneTool .dropdown.color { + position: absolute; + right: 0; + border: none; +} + +#isochroneTool .dropdown.color canvas { + vertical-align: top; +} + +#isochroneTool .dropdown.color:hover canvas.selected { + outline: 3px solid #fff; + outline-offset: -3px; +} + +#isochroneTool .dropdown.color:not(:hover) canvas:not(.selected) { + height: 0px; +} + +#isochroneTool .unit { + width: 33px; + text-align: center; + background: var(--color-i); + border-left: 1px solid var(--color-e); + color: #bfbfbf; + font-size: 14px; + line-height: 26px; +} + +#isochroneTool input[type='number'] { + border: none; + border-bottom: 1px solid rgba(0, 0, 0, 0.3); + border-radius: 0; + padding: 0px 6px; + height: 26px; + width: 87px; + background: var(--color-i); + text-align: right; + color: #ededed; +} + +#isochroneTool input[type='number'].nounit { + width: 120px; +} + +#isochroneTool .slider2 { + width: 120px !important; + height: 25px; + background: var(--color-i); + opacity: 1 !important; + margin: 0; + border-radius: 0; +} + +#isochroneTool .sectionhead { + font-variant: small-caps; + font-size: 16px; + height: 21px; + line-height: 20px; + background: linear-gradient(90deg, var(--color-b) 0%, rgba(0, 0, 0, 0) 100%); +} + +#isochroneTool div.loading { + width: 100%; + overflow: visible; + padding-left: 0px; +} + +#isochroneTool div.loading div { + width: 0%; + position: absolute; + left: 0; + height: 25px; + background: #486f9d; +} +#isochroneTool div.loading div.error { + width: 100%; + background: #c72323; +} + +#isochroneTool div.loading span { + margin-left: 5px; + z-index: 100; +} diff --git a/src/essence/Tools/Isochrone/IsochroneTool.js b/src/essence/Tools/Isochrone/IsochroneTool.js new file mode 100644 index 00000000..5b94f73c --- /dev/null +++ b/src/essence/Tools/Isochrone/IsochroneTool.js @@ -0,0 +1,588 @@ +import $ from 'jquery'; +import L_ from '../../Basics/Layers_/Layers_'; +import Map_ from '../../Basics/Map_/Map_'; +import CursorInfo from '../../Ancillary/CursorInfo'; + +import IsochroneManager from './IsochroneTool_Manager'; +import models from './models'; + +import './IsochroneTool.css'; +const L = window.L; + +/* +Handles map events, sidebar management, drawing layers and markers. +Individual isochrones, from data gathering to modeling to analysis, +are handled in IsochroneTool_Manager and its imports. +*/ + +const markup = +`
+
+ Isochrone + + New + + +
+
    +
    `; + +//Legacy color mapping function +function hueMap(val) { + const hueToChannel = h => { + h = (h + 1530) % 1530; + if (h < 255) return h; + if (h < 765) return 255; + if (h < 1020) return 255 - (h % 255); + return 0; + } + const hue = Math.floor(val * 1050); + const r = hueToChannel(hue + 510); + const g = hueToChannel(hue); + const b = hueToChannel(hue - 510); + return [r, g, b]; +} + +//https://leafletjs.com/reference-1.7.1.html#gridlayer +L.IsochroneLayer = L.GridLayer.extend({ + //Override to make layer accept Bounds in place of LatLngBounds + // (cleaner, supports polar projections better) + _isValidTile(coords) { + const bounds = this.options.bounds; + return coords.x >= bounds.min.x + && coords.y >= bounds.min.y + && coords.x < bounds.max.x + && coords.y < bounds.max.y; + }, + createTile: function(coords) { + const tile = L.DomUtil.create('canvas', 'leaflet-tile'); + + const size = this.getTileSize(); + tile.width = size.x; + tile.height = size.y; + + const ctx = tile.getContext('2d'); + const img = ctx.getImageData(0, 0, size.x, size.y); + + const bounds = this.options.bounds; + const tXOffset = coords.x - bounds.min.x; + const tYOffset = coords.y - bounds.min.y; + + const alpha = Math.floor(this.options.opacity * 255); + + let di = 0; //img data index + for (let y = 0; y < size.y; y++) { + const yIndex = tYOffset * size.y + y; + for (let x = 0; x < size.x; x++) { + const xIndex = tXOffset * size.x + x; + const currentData = this.options.data[yIndex][xIndex]; + if (isFinite(currentData) && currentData <= this.options.maxCost) { + const color = IsochroneTool.valueToColor( + currentData / this.options.maxCost, + this.options.color, + this.options.steps + ); + img.data[di] = color[0]; + img.data[di + 1] = color[1]; + img.data[di + 2] = color[2]; + img.data[di + 3] = alpha; + } else { + img.data[di] = 0; + img.data[di + 1] = 0; + img.data[di + 2] = 0; + img.data[di + 3] = 0; + } + di += 4; + } + } + + ctx.putImageData(img, 0, 0); + return tile; + } +}); + +//See IsochroneTool_Algorithm.js +const backlinkToMove = [ + [0, 1], + [1, 2], + [1, 1], + [2, 1], + [1, 0], + [2, -1], + [1, -1], + [1, -2], + [0, -1], + [-1, -2], + [-1, -1], + [-2, -1], + [-1, 0], + [-2, 1], + [-1, 1], + [-1, 2] +]; + + + + +const IsochroneTool = { + height: 0, + width: 250, + MMGISInterface: null, + vars: null, + + dataSources: {}, + enabledModels: [], + containerEl: null, + + managers: [], + activeManager: null, + managerCounter: 0, + + hovered: false, + lastHoverCall: 0, + hoverPolyline: null, + + //https://developers.arcgis.com/javascript/latest/visualization/symbols-color-ramps/esri-color-ramps/ + colorRamps: [ + [ //Red 5 + [254, 229, 217], + [252, 187, 161], + [252, 106, 74], + [222, 45, 38], + [165, 15, 21] + ], + [ //Orange 4 + [255, 255, 178], + [254, 204, 92], + [253, 141, 60], + [240, 59, 32], + [189, 0, 38] + ], + [ //Green 1 + [237, 248, 233], + [186, 228, 179], + [116, 196, 118], + [49, 163, 84], + [0, 109, 44] + ], + [ //Blue 4 + [240, 249, 232], + [186, 228, 188], + [123, 204, 196], + [67, 162, 202], + [8, 104, 172] + ], + [ //Purple 4 + [237, 248, 251], + [179, 205, 227], + [140, 150, 198], + [136, 86, 167], + [129, 15, 124] + ] + ], + + initialize: function() { + this.vars = L_.getToolVars('isochrone'); + const globalIS = this.vars.interpolateSeams !== false; + + //add info for scaling low-res tiles + for (const dataType in this.vars.data) { + const lcDataType = dataType.toLowerCase(); + this.dataSources[lcDataType] = []; + for (const src of this.vars.data[dataType]) { + const {name, tileurl, minZoom, maxNativeZoom, resolution} = src; + + const sourceIS = src.interpolateSeams; + const interpolateSeams = sourceIS === undefined ? globalIS : sourceIS; + + let zoomOffset = null; + switch (resolution) { + case 256: + zoomOffset = 0; + break; + case 128: + zoomOffset = 1; + break; + case 64: + zoomOffset = 2; + break; + case 32: + zoomOffset = 3; + break; + case undefined: + console.warn(`IsochroneTool: ${dataType} source "${name}" has no defined resolution!`); + break; + default: + console.warn(`IsochroneTool: ${dataType} source "${name}" has nonstandard resolution: ${resolution}!`); + } + + const minResolution = Math.max(minZoom - zoomOffset, 0); + const maxResolution = maxNativeZoom - zoomOffset; + + if (zoomOffset !== null) { + //Data source interface + this.dataSources[lcDataType].push({ + name, //string + tileurl, //string + minZoom, //number + maxNativeZoom, //number + resolution, //number + minResolution, //number + maxResolution, //number + zoomOffset, //number + interpolateSeams //boolean + }); + } + } + } + + if (this.vars.models) { + const lcModelNames = this.vars.models.map(m => m.toLowerCase()); + const modelIndex = m => lcModelNames.indexOf(m.nameString.toLowerCase()); + this.enabledModels = models.filter(m => modelIndex(m) > -1); + this.enabledModels.sort((a, b) => modelIndex(a) - modelIndex(b)); + } else { + this.enabledModels = models.filter(m => m.enabledByDefault); + } + }, + + make: function() { + this.MMGISInterface = new interfaceWithMMGIS(); + + $('#iscNew').on('click', () => this.addIsochrone()); + this.containerEl = $('#isochroneOptionsContainer'); + this.addIsochrone(); + }, + + destroy: function() { + for (const {marker, layerName} of this.managers) { + Map_.rmNotNull(marker); + Map_.rmNotNull(L_.layersGroup[layerName]); + } + + if (this.hoverPolyline !== null) { + this.hoverPolyline.remove(Map_.map); + } + + this.managers = []; + this.activeManager = null; + this.managerCounter = 0; + this.MMGISInterface.separateFromMMGIS(); + }, + + /** + * Applies a color ramp to a value, using one of the ramps from `IsochroneTool.colorRamps` + * @param {number} val Value to convert, between 0 and 1 + * @param {number} rampIndex Index of color ramp to use + * @param {number} steps Optional number of discrete color steps to apply to the ramp + * @returns {number[]} Array `[r, g, b]` of color channels + */ + valueToColor: function(val, rampIndex, steps = 0) { + val = Math.min(val, 1); + if (steps) { + val = Math.floor(val * steps) / steps; + } + + const ramp = this.colorRamps[rampIndex]; + const color = val * (ramp.length - 1); + const i = Math.min(Math.floor(color), ramp.length - 2); + const off = color % 1; + const getChan = chan => Math.floor(ramp[i][chan] * (1 - off) + ramp[i + 1][chan] * off); + return [getChan(0), getChan(1), getChan(2)]; + }, + + /** Create canvases for use in color ramp dropdown */ + makeGradientEls: function() { + const C_WIDTH = 120, C_HEIGHT = 25; + const numRamps = this.colorRamps.length; + let colorEls = []; + for (let i = 0; i < numRamps; i++) { + let canvas = document.createElement('canvas'); + canvas.width = C_WIDTH; + canvas.height = C_HEIGHT; + let ctx = canvas.getContext('2d'); + let image = ctx.getImageData(0, 0, C_WIDTH, C_HEIGHT); + let data = image.data; + for (let x = 0; x < C_WIDTH; x++) { + const color = this.valueToColor(x / C_WIDTH, i); + for (let y = 0; y < C_HEIGHT; y++) { + const di = (y * C_WIDTH * 4) + (x * 4); + data[di] = color[0]; + data[di + 1] = color[1]; + data[di + 2] = color[2]; + data[di + 3] = 255; + } + } + ctx.putImageData(image, 0, 0); + colorEls.push(canvas); + } + return colorEls; + }, + + managerOnChange: function(manager) { + this.makeMarker(manager); + manager.marker.dragging.enable(); + this.makeDataLayer(manager); + }, + managerOnFocus: function(manager) { + if (this.activeManager === manager) return; + if (this.activeManager !== null) { + this.activeManager.unfocus(); + } + this.activeManager = manager; + this.activeManager.focus(); + }, + managerOnDelete: function(manager) { + manager.optionEls.root.remove(); + Map_.rmNotNull(L_.layersGroup[manager.layerName]); + Map_.rmNotNull(manager.marker); + + const managerIndex = this.managers.indexOf(manager); + this.managers.splice(managerIndex, 1); + if (this.activeManager === manager) { + if (this.managers.length === 0) { + this.activeManager = null; + } else { + const newIndex = Math.min(managerIndex, this.managers.length - 1); + this.activeManager = this.managers[newIndex]; + this.activeManager.focus(); + } + } + }, + + addIsochrone: function() { + const newManager = new IsochroneManager( + this.managerCounter + 1, + this.dataSources, + this.enabledModels, + {color: this.managerCounter % this.colorRamps.length} + ); + this.managerCounter++; + + newManager.onChange = () => this.managerOnChange(newManager); + newManager.onFocus = () => this.managerOnFocus(newManager); + newManager.onDelete = () => this.managerOnDelete(newManager); + + this.managers.push(newManager); + + const optionsEl = newManager.makeElement(this.makeGradientEls()); + this.containerEl.append(optionsEl); + this.managerOnFocus(newManager); + + return newManager; + }, + + /** Create an isochrone data layer for a given isochrone manager */ + makeDataLayer: function(manager) { + const {layerName, cost, tileBounds, options} = manager; + + Map_.rmNotNull(L_.layersGroup[layerName]); + + if (!manager.options.visible) return; + + L_.layersGroup[layerName] = new L.IsochroneLayer({ + className: 'nofade', //Borrowed from viewshed... but is it actually doing anything? + minZoom: Math.min(options.resolution, Map_.map.getMinZoom()), + maxZoom: Map_.map.getMaxZoom(), + minNativeZoom: options.resolution, + maxNativeZoom: options.resolution, + bounds: tileBounds, + tileSize: 256, + opacity: options.opacity, + color: options.color, + maxCost: options.maxCost, + steps: options.steps, + data: cost + }); + + L_.layersGroup[layerName].setZIndex(1000); + Map_.map.addLayer(L_.layersGroup[layerName]); + }, + + /** Create a start point marker for a given isochrone manager */ + makeMarker: function(manager) { //ViewshedTool.js, function viewshed + const {start, options} = manager; + let canvas = document.createElement('canvas'); + canvas.width = 16; + canvas.height = 16; + let ctx = canvas.getContext('2d'); + + const radius = 7 + const strokeWeight = 2 + const ramp = IsochroneTool.colorRamps[options.color]; + const c = ramp[ramp.length - 1]; + + ctx.fillStyle = `rgba(${c[0]}, ${c[1]}, ${c[2]}, 255)`; + + ctx.strokeStyle = 'rgba(255, 255, 255, 255)'; + ctx.beginPath(); + ctx.arc( + canvas.width / 2, + canvas.height / 2, + radius, + 0, + 2 * Math.PI + ); + + ctx.fill(); + ctx.lineWidth = strokeWeight; + ctx.stroke(); + ctx.strokeStyle = 'rgba(0, 0, 0, 255)'; + ctx.beginPath(); + ctx.arc( + canvas.width / 2, + canvas.height / 2, + radius - strokeWeight, + 0, + 2 * Math.PI + ); + + ctx.fill(); + ctx.lineWidth = strokeWeight; + ctx.stroke(); + + let isochroneIcon = L.icon({ + iconUrl: canvas.toDataURL(), + iconSize: [canvas.width, canvas.height], + iconAnchor: [canvas.width / 2, canvas.height / 2], + popupAnchor: [-3, -76], + shadowSize: [68, 95], + shadowAnchor: [22, 94], + }); + + Map_.rmNotNull(manager.marker); + manager.marker = new L.marker([start.lat, start.lng], {icon: isochroneIcon}); + + manager.marker.on('click', e => this.managerOnFocus(manager)); + manager.marker.on('dragend', e => { + manager.marker.dragging.disable(); + manager.start = e.target._latlng; + manager.setBounds(); + this.managerOnFocus(manager); + }); + + manager.marker.addTo(Map_.map); + }, + + //Click event handler + handleClick: function(e) { + if (e && e.latlng && this.activeManager.currentStage < 4) { + this.activeManager.start = e.latlng; + this.makeMarker(this.activeManager); + this.activeManager.setBounds(); + } + }, + + //Mouse move event handler + handleMouseMove: function(e) { + const MAX_STEPS = 5000; + const manager = this.activeManager; + + if (!e || !manager || !manager.backlink || manager.currentStage > 0 || !manager.options.visible) { + return; + } + + const now = Date.now(); + if (this.lastHoverCall + 65 > now) return; + this.lastHoverCall = now; + + Map_.rmNotNull(this.hoverPolyline); + + const toLinePoint = (x, y) => { + const point = manager.tileBounds.min + .multiplyBy(256) + .add([x + 0.5, y + 0.5]); + const latlng = Map_.map.unproject(point, manager.options.resolution); + return [latlng.lat, latlng.lng]; + } + + let hoveredPx, width, height, startVal = 0; + if (e.latlng) { + hoveredPx = Map_.map + .project(e.latlng, manager.options.resolution) + .subtract(manager.tileBounds.min.multiplyBy(256)) + .floor(); + width = manager.backlink[0].length; + height = manager.backlink.length; + if (hoveredPx.x >= 0 && hoveredPx.y >= 0 && hoveredPx.x < width && hoveredPx.y < height) { + startVal = manager.backlink[hoveredPx.y][hoveredPx.x]; + } + } + + if (startVal !== 0) { + this.hovered = true; + const hoveredCost = manager.cost[hoveredPx.y][hoveredPx.x]; + const tooltipMsg = manager.modelProto.costToString(hoveredCost); + CursorInfo.update(tooltipMsg, null, false); + + let cx = hoveredPx.x; + let cy = hoveredPx.y; + let step = startVal; + let line = [toLinePoint(cx, cy)]; + let lastStep = 0; + let count = 0; + while (step !== 0 && count < MAX_STEPS) { + let move = backlinkToMove[step - 1]; + cx += move[1]; + cy += move[0]; + if(step === lastStep) { //Extend line + line[line.length - 1] = toLinePoint(cx, cy); + } else { //Begin new line + line.push(toLinePoint(cx, cy)); + } + lastStep = step; + step = manager.backlink[cy][cx]; + count++; + } + this.hoverPolyline = L.polyline(line, {interactive: false}); + this.hoverPolyline.addTo(Map_.map); + } else if (this.hovered) { + this.hovered = false; + CursorInfo.hide(); + } + }, + + //Mouse out event container + handleMouseOut: function(e) { + if (this.hovered) { + this.hovered = false; + Map_.rmNotNull(this.hoverPolyline); + CursorInfo.hide(); + } + } +} + + + +function interfaceWithMMGIS() { + this.separateFromMMGIS = function() { + separateFromMMGIS() + } + + const tools = $('#toolPanel'); + tools.empty(); + const toolContainer = $('
    ') + .attr('class', 'center aligned ui padded grid') + .css({'height': '100%'}); + tools.append(toolContainer) + toolContainer.html(markup); + + const clickEventContainer = e => IsochroneTool.handleClick(e); + Map_.map.on('click', clickEventContainer); + + const moveEventContainer = e => IsochroneTool.handleMouseMove(e); + Map_.map.on('mousemove', moveEventContainer); + + const outEventContainer = e => IsochroneTool.handleMouseOut(e); + Map_.map.on('mouseout', outEventContainer); + + //Share everything. Don't take things that aren't yours. + // Put things back where you found them. + function separateFromMMGIS() { + Map_.map.off('click', clickEventContainer); + Map_.map.off('mousemove', moveEventContainer); + Map_.map.off('mouseout', outEventContainer); + } +} + +export default IsochroneTool; diff --git a/src/essence/Tools/Isochrone/IsochroneTool_Algorithm.js b/src/essence/Tools/Isochrone/IsochroneTool_Algorithm.js new file mode 100644 index 00000000..d45da57d --- /dev/null +++ b/src/essence/Tools/Isochrone/IsochroneTool_Algorithm.js @@ -0,0 +1,232 @@ + +import Map_ from "../../Basics/Map_/Map_"; + +/* +Runs Dijkstra's Algorithm on a given subsection of the map + +Dijkstra's Algorithm operates on a weighted graph, and finds the lowest-weight path between a given +starting vertex and all other vertices. + +In this implementation, values in a 2D array (representing pixels of a raster) are treated as +vertices of the graph and are considered to be implicitly connected to their immediate neighbors. +A cost function is run between connected pixels to determine edge weights. The result of the +algorithm is returned as two arrays: a cost array which stores the minimum cost of reaching every +pixel, and a backlink array whose values encode which of a pixel's neighbors is its parent in the +shortest-path tree. Informally, the backlink saves the final "step" in the path from the start to +that pixel. The backlink array may thus be followed recursively to reconstruct the shortest path +from any given pixel back to the starting point. + +Note that connecting pixels in this way limits directions of movement, and thus the final shape +will be biased towards these directions (see queenMoves and knightMoves, below). +*/ + +//Indexes of X and Y values within px coordinate tuples +const X = 1, Y = 0; + +//px contains array indexes [y, x] +const getPx = (arr, px) => arr[px[Y]][px[X]]; +const setPx = (arr, px, val) => arr[px[Y]][px[X]] = val; + +//Helpers to get array indexes of parent and child elements within an implicitly-structured heap +const h_getParentIndex = i => Math.ceil(i / 2) - 1; +const h_getChildIndex = i => i * 2 + 1; + +function pxToLatLng(px, tileBounds, zoom) { + const point = tileBounds.min + .multiplyBy(256) + .add([px[X] + 0.5, px[Y] + 0.5]); + return Map_.map.unproject(point, zoom); +} + +/** Min-heap priority queue for pixels of the cost array */ +class PxHeap { + /** + * Create a new min-heap for pixels of the analyzed area. + * @param {Float32Array[]} valueArr 2D array storing the values of each pixel for the purposes of sorting + * @param {Int32Array[]} indexArr 2D array storing the index of each pixel within this heap, to eliminate the need for searching + */ + constructor(valueArr, indexArr) { + this.contents = []; + this.valueArr = valueArr; + this.indexArr = indexArr; + } + + /** + * Compare the cost of the pixels at indexes `i` and `j`. + * Return `true` if `i > j`, `false` otherwise. + */ + compare(i, j) { + const iVal = this.contents[i]; + const jVal = this.contents[j]; + return getPx(this.valueArr, iVal) > getPx(this.valueArr, jVal); + } + + /** Swap the pixels at indexes `i` and `j` */ + swap(i, j) { + const iVal = this.contents[i]; + const jVal = this.contents[j]; + setPx(this.indexArr, iVal, j); + setPx(this.indexArr, jVal, i); + this.contents[i] = jVal; + this.contents[j] = iVal; + } + + /** Move the pixel at `index` up to a correct position within the heap */ + bubbleUp(index) { + let parentIndex = h_getParentIndex(index); + while (parentIndex >= 0 && this.compare(parentIndex, index)) { + this.swap(index, parentIndex); + index = parentIndex; + parentIndex = h_getParentIndex(index); + } + } + + /** Move the pixel at the head of the heap down to a correct position within the heap */ + bubbleDown() { + let index = 0, childIndex = 1; + let swapped = true; + const length = this.contents.length; + while (swapped && childIndex < length) { + swapped = false; + if (childIndex !== length - 1 && this.compare(childIndex, childIndex + 1)) { + childIndex++; + } + if (this.compare(index, childIndex)) { + this.swap(index, childIndex); + swapped = true; + index = childIndex; + childIndex = h_getChildIndex(index); + } + } + } + + /** Insert a pixel coordinate tuple into the heap */ + insert(px) { + let index = this.contents.length; + this.contents.push(px); + setPx(this.indexArr, px, index); + this.bubbleUp(index); + } + + /** Remove the pixel coordinate tuple with the lowest cost from the heap */ + remove() { + const result = this.contents[0]; + setPx(this.indexArr, result, -1); //Mark pixel as removed + const lastPx = this.contents.pop(); + if (this.contents.length > 0) { + this.contents[0] = lastPx; + setPx(this.indexArr, lastPx, 0); + this.bubbleDown(); + } + return result; + } +} + +/** + * Values to return in the backlink array. Direction back to the start ordered ascending clockwise + * from the right. + */ +const moveToBacklink = [ + [ 0, 4, 0, 6, 0], + [ 2, 3, 5, 7, 8], + [ 0, 1, 0, 9, 0], + [16, 15, 13, 11, 10], + [ 0, 14, 0, 12, 0] +]; + +/** + * Moves from a pixel to its 8 immediate neighbors. + * A purely distance-based model will produce an octagon with these moves. + */ +const queenMoves = [ + [-1, -1], [-1, 0], [-1, 1], + [0, -1], [0, 1], + [1, -1], [1, 0], [1, 1] +]; + +/** + * In addition to queenMoves, all moves between pixels that a knight could make on a chessboard. + * This improves accuracy by allowing more angles of movement at the expense of greater running time. + * A purely distance-based model will produce a 16-sided polygon with these moves. + */ +const knightMoves = [ + ...queenMoves, + [-2, -1], [-2, 1], + [-1, -2], [-1, 2], + [1, -2], [1, 2], + [2, -1], [2, 1] +]; + +/** + * Runs Dijkstra's Algorithm over an array of map data. + * @param {L.Point} startPx Location of starting pixel, as a Leaflet point + * @param {L.Bounds} tileBounds Tile bounds of the analyzed area + * @param {Model} model Model used to calculate cost + * @param {number} zoom Zoom level of the analyzed data + * @param {number} maxCost Max cost to analyze out to. + * @param {boolean} knightsMove Whether to use the knight's move for improved accuracy. Default `true`. + * @returns An object containing an accumulated cost array and a backlink array. + */ +export default function generateIsochrone( + startPx, + tileBounds, + model, + zoom, + maxCost = Infinity, + knightsMove = true +) { + const moves = knightsMove ? knightMoves : queenMoves; + const size = tileBounds.getSize().multiplyBy(256); + + //Set up dijkstra's + const makeDataArray = (type, fillWith) => { + let arr = []; + for (let y = 0; y < size.y; y++) { + arr.push(new type(size.x).fill(fillWith)); + } + return arr; + } + let costArr = makeDataArray(Float32Array, Infinity); + let linkArr = makeDataArray(Uint8Array, 0); + let indexArr = makeDataArray(Int32Array, -2); + //-2: px is unvisited; -1: px has been removed + + let heap = new PxHeap(costArr, indexArr); + + costArr[startPx.y][startPx.x] = 0; + heap.insert([startPx.y, startPx.x]); + + while (heap.contents.length > 0) { + const cPx = heap.remove(); //current pixel + const cCost = getPx(costArr, cPx); + const cLatLng = pxToLatLng(cPx, tileBounds, zoom); + + for (const m of moves) { + const tPx = [cPx[Y] + m[Y], cPx[X] + m[X]]; //target pixel + + //Check that target pixel is within bounds + if (tPx[Y] < 0 || tPx[X] < 0 || tPx[Y] >= size.y || tPx[X] >= size.x) + continue; + + //Check that target pixel hasn't already been visited + const tPxIndex = getPx(indexArr, tPx); + if (tPxIndex === -1) continue; + + //Check that target pixel can be reached within cost budget + const tLatLng = pxToLatLng(tPx, tileBounds, zoom); + const cost = model.costFunction(cPx, tPx, cLatLng, tLatLng) + cCost; + if (cost > maxCost || !isFinite(cost)) continue; + + if (tPxIndex === -2) { //tPx is unvisited + setPx(costArr, tPx, cost); + setPx(linkArr, tPx, moveToBacklink[m[Y] + 2][m[X] + 2]); + heap.insert(tPx); + } else if (cost < getPx(costArr, tPx)) { //tPx is visited but this path is better + setPx(costArr, tPx, cost); + setPx(linkArr, tPx, moveToBacklink[m[Y] + 2][m[X] + 2]); + heap.bubbleUp(tPxIndex); //Cost has decreased; pixel's heap position must be updated + } + } + } + return {cost: costArr, backlink: linkArr}; +} diff --git a/src/essence/Tools/Isochrone/IsochroneTool_Manager.js b/src/essence/Tools/Isochrone/IsochroneTool_Manager.js new file mode 100644 index 00000000..0fd83140 --- /dev/null +++ b/src/essence/Tools/Isochrone/IsochroneTool_Manager.js @@ -0,0 +1,430 @@ +import $ from 'jquery'; + +import Map_ from '../../Basics/Map_/Map_'; +import F_ from '../../Basics/Formulae_/Formulae_'; + +import generateIsochrone from './IsochroneTool_Algorithm'; +import QueryJob from './IsochroneTool_Query'; +import { addOption, addSection, createInput, createDropdown, createLoadBar } from './ui.js'; + +const GLOBAL_MIN_RESOLUTION = 4; +const GLOBAL_MAX_RESOLUTION = 20; + +class IsochroneManager { + constructor(id, dataSources, models, options = {}) { + this.id = id; + this.dataSources = dataSources; + this.models = models; + + this.options = { + visible: true, + color: 0, + opacity: 0.8, + maxRadius: 5000, + resolution: GLOBAL_MIN_RESOLUTION, + model: 0, + maxCost: 5000 + }; + Object.assign(this.options, options); + + this.optionEls = {}; + this.sections = { + data: null, + model: null + }; + + this.onChange = () => {}; + this.onDelete = () => {}; + this.onFocus = () => {}; + + this.minResolution = GLOBAL_MIN_RESOLUTION; + this.maxResolution = GLOBAL_MAX_RESOLUTION; + this.start = null; //L.LatLng + this.startPx = null; //L.Point + this.tileBounds = null; //L.Bounds + + this.currentStage = 0; + this.queryJobs = []; + + this.modelProto = null; + this.model = null; //Model + + this.updateTimeout = 0; + + this.cost = null; + this.backlink = null; + + this.layerName = 'isochrone_' + this.id; + //assigned by IsochroneTool + this.marker = null; + } + + /******************** UI AND INPUT ********************/ + + handleInput(e, option, action = 0) { + window.clearTimeout(this.updateTimeout); + this.updateTimeout = window.setTimeout(() => this._handleInput(e, option, action), 100); + } + _handleInput(e, option, action) { + if (option !== null) { + if (typeof e === 'object') { + this.options[option] = parseFloat(e.target.value); + } else { + this.options[option] = e; + } + } + + this.onFocus(); + + if (this.start !== null && action >= this.currentStage) { + switch (action) { + case 3: //Change requires getting new data + this.setBounds(); + break; + case 2: //Change requires generating new shape on same data + this.analyze(); + break; + case 1: //Change requires redrawing same shape + this.onChange(); + break; + default: //Change changes nothing! + } + } + } + + makeElement(gradientEls) { + let root = $('
  • '); + let header = $('
    ').appendTo(root); + let options = $('
    ').appendTo(root); + this.optionEls.options = options; + this.optionEls.root = root; + + header.on('click', () => this.onFocus()); + + $('
    ').appendTo(header).on('click', e => { + let target = $(e.target); + const visible = !target.hasClass('on'); + if (visible) { + target.addClass('on'); + } else { + target.removeClass('on'); + } + this.handleInput(visible, 'visible', 1); + }); + $(`
    Isochrone ${this.id}
    `).appendTo(header); + $('').appendTo(header).on('click', e => { + this.onDelete(); + }); + $('').appendTo(header).on('click', e => { + let target = $(e.target); + const collapsed = this.optionEls.options.hasClass('collapsed'); + if (collapsed) { + this.optionEls.options.removeClass('collapsed'); + target.removeClass('mdi-menu-right'); + target.addClass('mdi-menu-down'); + } else { + this.optionEls.options.addClass('collapsed'); + target.removeClass('mdi-menu-down'); + target.addClass('mdi-menu-right'); + } + }); + + this.optionEls.maxRadius = createInput( + 'Max radius', + options, + 'km', + this.options.maxRadius / 1000, + `min="1" step="1" default="250"` + ).on('change', e => { + const inMeters = parseFloat(e.target.value) * 1000; + this.handleInput(inMeters, 'maxRadius', inMeters > this.options.maxRadius ? 3 : 0); + }); + + this.optionEls.color = gradientEls; + $(this.optionEls.color[this.options.color]).addClass('selected'); + const colorContainer = $('') + .appendTo(addOption('Color', options)); + for (const i in gradientEls) { + $(gradientEls[i]).appendTo(colorContainer).on('click', e => { + if(this.options.color !== i) { + $(this.optionEls.color[this.options.color]).removeClass('selected'); + $(e.target).addClass('selected'); + this.handleInput(i, 'color', 1); + } + }); + } + + this.optionEls.opacity = + $(``) + .appendTo(addOption('Opacity', options)) + .on('change', e => this.handleInput(e, 'opacity', 1)); + + this.optionEls.steps = createInput( + 'Steps', + options, + false, + 0, + 'min="0" step="1" default="0"' + ).on('change', e => this.handleInput(e, 'steps', 1)); + + this.optionEls.model = createDropdown( + 'Model', + options, + this.models.map(m => m.nameString) + ).on( + 'change', + e => { + if (this.currentStage > 3) { + //Recover from misconfigured model + this.currentStage = 0; + if (this.marker !== null) { + this.marker.dragging.enable(); + } + } + const reuseData = this.setupModel(e.target.value); + this.handleInput(e, 'model', reuseData ? 2 : 3); + } + ); + + this.sections.data = addSection('Data Properties', options); + this.sections.model = addSection('Model Properties', options); + this.setupModel(); + + return root; + } + + setupModel(modelIndex = this.options.model) { + const newModelProto = this.models[modelIndex]; + + let reuseData = false; + if (this.modelProto !== null) { + reuseData = newModelProto.requiredData.reduce( + (a, c) => a && this.modelProto.requiredData.indexOf(c) > -1 && this.model.data[c], + true + ); + } + + let newModel = new newModelProto(); + if (reuseData) { + for (const d of newModelProto.requiredData) { + newModel.data[d] = this.model.data[d]; + } + } + this.modelProto = newModelProto; + this.model = newModel; + + this.sections.data.empty(); + this.sections.model.empty(); + + this.optionEls.resolution = createDropdown( + 'Resolution', + this.sections.data + ).on('change', e => this.handleInput(e, 'resolution', 3)); + + for (const dataType of this.modelProto.requiredData) { + const lcDataType = dataType.toLowerCase(); + if (this.dataSources[lcDataType] === undefined || this.dataSources[lcDataType].length === 0) { + //Tool is misconfigured for this model; disable + this.sections.data.empty(); + createLoadBar( + `No valid source for ${dataType}!`, + this.sections.data, + true + ); + this.currentStage = 4; + if (this.marker !== null) { + this.marker.dragging.disable(); + } + return false; + } + this.options[lcDataType + '_source'] = 0; + createDropdown( + dataType + ' source', + this.sections.data, + this.dataSources[lcDataType].map(s => s.name) + ).on('change', e => { + this.options[lcDataType + '_source'] = parseInt(e.target.value); + this.updateResolutionRange(); + this.handleInput(e, null, 3); + }); + } + + this.updateResolutionRange(); + + createInput( + 'Max ' + this.modelProto.costName, + this.sections.model, + this.modelProto.costUnitSymbol, + this.modelProto.defaultCost, + `min="0" step="1"` + ).on('change', e => this.handleInput(e, 'maxCost', parseFloat(e.target.value) < this.options.maxCost ? 1 : 2)); + this.options.maxCost = this.modelProto.defaultCost; + + this.model.createOptions(this.sections.model, (action) => this.handleInput(null, null, action)); + + return reuseData; + } + + focus() { + this.optionEls.root.addClass('focused'); + } + + unfocus() { + this.optionEls.root.removeClass('focused'); + } + + updateResolutionRange() { + let max = GLOBAL_MAX_RESOLUTION; + let min = GLOBAL_MIN_RESOLUTION; + for (const dataType of this.modelProto.requiredData) { + const lcDataType = dataType.toLowerCase(); + const sourceObj = this.dataSources[lcDataType][this.options[lcDataType + '_source']]; + max = Math.min(max, sourceObj.maxResolution); + min = Math.max(min, sourceObj.minResolution); + } + const newVal = Math.max(min, Math.min(max, this.options.resolution)); + this.optionEls.resolution.empty(); + for (let e = min; e <= max; e++) { + $(``) + .appendTo(this.optionEls.resolution); + } + this.minResolution = min; + this.maxResolution = max; + this.optionEls.resolution.value = newVal; + this.options.resolution = newVal; + } + + /******************** ISOCHRONE GENERATION ********************/ + + setBounds() { + this.currentStage = 3; + + const startPoint = Map_.map.project(this.start, this.options.resolution); + const measureLatLng = Map_.map.unproject(startPoint.add([1, 0]), this.options.resolution); + const pxRadius = this.options.maxRadius / this.start.distanceTo(measureLatLng); + + const min = startPoint.subtract([pxRadius, pxRadius]).divideBy(256).floor(); + const max = startPoint.add([pxRadius, pxRadius]).divideBy(256).ceil(); + this.tileBounds = new window.L.Bounds(min, max); + + this.startPx = Map_.map + .project(this.start, this.options.resolution) + .subtract(min.multiplyBy(256)) + .floor(); + + this.getData(); + } + + getRequiredTilesList(source) { + const {zoomOffset} = source; + const zoom = this.options.resolution + zoomOffset; + let bounds = this.tileBounds; + if (zoomOffset !== 0) { //Handle lower-res tiles + const scaleFactor = Math.pow(2, zoomOffset); + bounds = window.L.bounds( + this.tileBounds.min.multiplyBy(scaleFactor), + this.tileBounds.max.multiplyBy(scaleFactor) + ); + } + const startPoint = Map_.map.project(this.start, zoom); + const startTile = startPoint.clone().divideBy(256).floor(); + + let tileList = []; + for (let y = bounds.min.y; y < bounds.max.y; y++) { + for (let x = bounds.min.x; x < bounds.max.x; x++) { + //Measure distance to start from nearest corner/edge + let measureX = startPoint.x; + if (x > startTile.x) { + measureX = x * 256; + } else if (x < startTile.x) { + measureX = (x + 1) * 256; + } + + let measureY = startPoint.y; + if (y > startTile.y) { + measureY = y * 256; + } else if (y < startTile.y) { + measureY = (y + 1) * 256; + } + + const measureLatLng = Map_.map.unproject([measureX, measureY], zoom); + const dist = F_.lngLatDistBetween( + this.start.lng, + this.start.lat, + measureLatLng.lng, + measureLatLng.lat + ); + + if (dist <= this.options.maxRadius) { + tileList.push({ + x, + y, + z: zoom, + relX: x - bounds.min.x, + relY: y - bounds.min.y, + dist + }); + } + } + } + + tileList.sort((a, b) => a.dist - b.dist); + return tileList; + } + + getData() { + this.queryJobs.map(job => job.stop()); + this.queryJobs = []; + + let promises = []; + for (const dataType of this.modelProto.requiredData) { + const lcDataType = dataType.toLowerCase(); + const sourceIndex = this.options[lcDataType + '_source']; + const source = this.dataSources[lcDataType][sourceIndex]; + const requiredTiles = this.getRequiredTilesList(source); + + const job = new QueryJob(source, requiredTiles, this.tileBounds); + this.queryJobs.push(job); + let bar; + const promise = job.start( + () => bar = createLoadBar(`Loading ${dataType}...`, this.optionEls.options), + (prog) => bar.css({width: `${prog * 100}%`}), + () => bar.parent().remove() + ); + promises.push(promise); + } + + Promise.all(promises).then(result => { + const dataArr = this.modelProto.requiredData.map((d, i) => [d, result[i]]); + const dataObj = Object.fromEntries(dataArr); + this.model.setData(dataObj); + this.queryJobs = []; + this.analyze(); + }).catch(msg => { + if (msg !== "Query job stopped.") { + console.log(msg); + } + }); + } + + analyze() { + this.currentStage = 2; + const result = generateIsochrone( + this.startPx, + this.tileBounds, + this.model, + this.options.resolution, + this.options.maxCost + ); + this.cost = result.cost; + this.backlink = result.backlink; + + this.currentStage = 1; + this.onChange(); + this.marker.dragging.enable(); + + this.currentStage = 0; + } +} + +export default IsochroneManager; diff --git a/src/essence/Tools/Isochrone/IsochroneTool_Query.js b/src/essence/Tools/Isochrone/IsochroneTool_Query.js new file mode 100644 index 00000000..836af9cc --- /dev/null +++ b/src/essence/Tools/Isochrone/IsochroneTool_Query.js @@ -0,0 +1,201 @@ +import Map_ from "../../Basics/Map_/Map_"; +import F_ from "../../Basics/Formulae_/Formulae_"; +import L_ from "../../Basics/Layers_/Layers_"; + +const MAX_WORKERS = 8; + +const QueryManager = { + cache: {}, + //TODO: queue jobs here + //(so e.g. two isochrones will load in sequence w/o slowing each other down) + jobQueue: [], + jobInProgress: false, + numWorkers: 0, + currentJob: null, + + //These may be expanded to maintain a max cache size + isInCache: url => QueryManager.cache[url] !== undefined, + addToCache: (url, data) => QueryManager.cache[url] = data, + + fillUrl: function(url, tile) { + const pxWorldBound = Map_.map.getPixelWorldBounds(tile.z); + const yTileWorldBound = Math.ceil(pxWorldBound.max.y / 256) - 1; + + let filledUrl = url.replace('{x}', tile.x); + filledUrl = filledUrl.replace('{y}', yTileWorldBound - tile.y); + filledUrl = filledUrl.replace('{z}', tile.z); + return filledUrl; + }, + + getPNG: function(url) { + //just promisifying png.js + const queryPromise = new Promise((resolve, reject) => { + window.PNG.load(url, resolve, reject); + }); + + //PNG.js has no native error callback! + //This workaround will at least keep things moving + const timeoutPromise = new Promise((resolve, reject) => { + window.setTimeout(() => reject(url + ": timed out"), 10000); + }); + return Promise.race([queryPromise, timeoutPromise]); + }, + + decodePNG: function(img) { + if (!img) return null; + let rgbaArr = img.decode(); + + const length = rgbaArr.length / 4; + let heights = new Float32Array(length); + let p = 0; + for (let i = 0; i < length; i++) { + heights[i] = F_.RGBAto32({ + r: rgbaArr[p], + g: rgbaArr[p + 1], + b: rgbaArr[p + 2], + a: rgbaArr[p + 3] + }); + p += 4; + } + return heights; + }, + + getTile: async function(urlTemplate, tile) { + const url = this.fillUrl(urlTemplate, tile); + if (this.isInCache(url)) { + return this.cache[url]; + } else { + const png = await this.getPNG(url).catch(msg => { + console.log(msg); + return null; + }); + const data = this.decodePNG(png); + this.addToCache(url, data); + return data; + } + } +} + +class QueryJob { + constructor({tileurl, resolution, interpolateSeams}, tileList, bounds) { + this.tileurl = F_.isUrlAbsolute(tileurl) ? tileurl : L_.missionPath + tileurl; + this.tileList = tileList; + this.bounds = bounds; + this.resolution = resolution; + this.interpolateSeams = interpolateSeams; + + this.active = false; + this.tilesQueried = 0; + this.tilesLoaded = 0; + this.numWorkers = 0; + this.numTiles = tileList.length; + + this.onStop = () => {}; + + this.size = bounds.getSize().multiplyBy(256); + this.result = []; + for (let y = 0; y < this.size.y; y++) { + this.result.push(new Float32Array(this.size.x).fill(Infinity)); + } + } + + /** + * Start this job loading tiles + * @param {Function} onStart Function to call when the job starts + * @param {Function} onProgress Function to call to update progress on the job + * @param {Function} onEnd Function to call when the job ends + * @returns + */ + start(onStart = () => {}, onProgress = () => {}, onEnd = () => {}) { + this.active = true; + this.onStop = onEnd; + + return new Promise((resolve, reject) => { + const createHandler = tile => result => { + if (result) { + this.handleTileData(tile, result); + } + this.numWorkers--; + this.tilesLoaded++; + onProgress(this.tilesLoaded / this.numTiles); + startNextQuery(); + }; + + const startNextQuery = () => { + if (!this.active) { + reject("Query job stopped."); + } else if (this.numWorkers < MAX_WORKERS && this.tilesQueried < this.numTiles) { + const currentTile = this.tileList[this.tilesQueried]; + QueryManager.getTile(this.tileurl, currentTile) + .then(createHandler(currentTile)); + + this.tilesQueried++; + this.numWorkers++; + startNextQuery(); + } else if (this.numWorkers === 0 && this.tilesQueried === this.numTiles) { + this.processLoadedData(); + this.active = false; + onEnd(); + resolve(this.result); + } + }; + + onStart(); + startNextQuery(); + }); + } + + handleTileData(tile, data) { + const startX = tile.relX * this.resolution; + const startY = tile.relY * this.resolution; + for (let y = 0; y < this.resolution; y++) { + const yResult = y + startY; + const dataRow = data.slice(y * this.resolution, (y + 1) * this.resolution); + this.result[yResult].set(dataRow, startX); + } + } + + processLoadedData() { //ViewshedTool_Manager.js (function interpolateSeams) + if(!this.interpolateSeams) return; + + // Vertical | | + const maxX = this.size.x - this.resolution; + for (let x = this.resolution; x < maxX; x += this.resolution) { + for (let y = 0; y < this.size.y; y++) { + if (this.result[y][x - 1] === this.result[y][x] && isFinite(this.result[y][x])) { + const a = this.result[y][x - 2]; + const b = this.result[y][x + 1]; + + const inc = (a - b) / 3; + + this.result[y][x - 1] = a - inc; + this.result[y][x] = b + inc; + } + } + } + + // Horizontal _ _ + const maxY = this.size.y - this.resolution; + for (let y = this.resolution; y < maxY; y += this.resolution) { + for (let x = 0; x < this.size.x; x++) { + if (this.result[y - 1][x] === this.result[y][x] && isFinite(this.result[y][x])) { + const a = this.result[y - 2][x]; + const b = this.result[y + 1][x]; + + const inc = (a - b) / 3; + + this.result[y - 1][x] = a - inc; + this.result[y][x] = b + inc; + } + } + } + } + + /** Stop a job in progress */ + stop() { + this.onStop(); + this.active = false; + } +} + +export default QueryJob; diff --git a/src/essence/Tools/Isochrone/config.json b/src/essence/Tools/Isochrone/config.json new file mode 100644 index 00000000..042fc0b2 --- /dev/null +++ b/src/essence/Tools/Isochrone/config.json @@ -0,0 +1,36 @@ +{ + "defaultIcon": "circle-double", + "description": "Find the range of locations accessible to an explorer within a given time.", + "descriptionFull": { + "title": "Given a user-defined starting point, render a shaded region where colors indicate minimum travel time or resource expenditure to reach a given location. Hover over the region to view the least costly path from the start to the cursor. Costs are calculated based on selectable and configurable models, which may each require multiple different tilesets as input.", + "example": { + "data": { + "DEM": [ + { + "name": "Unique Name 1", + "tileurl": "Layers/Example/{z}/{x}/{y}.png", + "minZoom": 8, + "maxNativeZoom": 18, + "resolution": 256, + "interpolateSeams": true + }, + { "...": "..." } + ], + "slope": [ + { "...": "..." } + ], + "cost": [ + { "...": "..." } + ] + }, + "interpolateSeams": false, + "models": ["Traverse Time", "Isodistance", "..."] + } + }, + "hasVars": true, + "name": "Isochrone", + "toolbarPriority": 10, + "paths": { + "IsochroneTool": "essence/Tools/Isochrone/IsochroneTool" + } +} diff --git a/src/essence/Tools/Isochrone/models/Model.js b/src/essence/Tools/Isochrone/models/Model.js new file mode 100644 index 00000000..d3dd16c5 --- /dev/null +++ b/src/essence/Tools/Isochrone/models/Model.js @@ -0,0 +1,67 @@ +/** Class representing a model of resource expenditure (time, power, etc.) on a traverse */ +export default class Model { + /** Name of this model, as it will appear in the model selection dropdown */ + static nameString = 'Model'; + + /** Names of all data types required for this model (e.g. "DEM", "Slope", "Cost") */ + static requiredData = ['DEM']; + + /** Name of the resource this class models, as it will appear in the name of the "max cost" option */ + static costName = 'distance'; + + /** Units of the resource this class models, as it will appear in the "max cost" option */ + static costUnitSymbol = 'm'; + + /** Default setting of the "max cost" option */ + static defaultCost = 1000; + + /** Determines whether this model is available by default (if "models" property is not set in the tool configuration) */ + static enabledByDefault = true; + + /** + * Converts a cost value produced by this model to a human-readable string. + * Override to specify how this model's costs are displayed (e.g. hh:mm:ss for time models) + * @param {number} cost Cost to convert to string + * @returns {string} `cost` as a properly-formatted string + */ + static costToString(cost) { + return cost.toFixed(1) + this.costUnitSymbol; + } + + constructor() { + /** + * Will be filled before costFunction is run with 2D data arrays for all keys listed in `requiredData`, e.g.: + * `{ "DEM": Float32Array[], "Slope": Float32Array[] }`. + * All data arrays are guaranteed to be the same size and to represent the same area of the map. + */ + this.data = {}; + } + + /** + * Called to set or update data. Override to perform custom preprocessing on all new input data. + * @param {Object} data Object containing data arrays + */ + setData(data) { + this.data = data; + } + + /** + * Compute the cost of moving from a "current" pixel to a "target" pixel, based on data from `this.data`. + * This is the core of a model and must be overridden to produce a new and useful model. + * @param {number[]} cPx Index tuple [y, x] for the current pixel + * @param {number[]} tPx Index tuple [y, x] for the target pixel + * @param {L.LatLng} cLatLng Lat/long position of the current pixel + * @param {L.LatLng} tLatLng Lat/long position of the target pixel + * @returns {number} Cost of moving from `cPx` to `tPx`. + */ + costFunction(cPx, tPx, cLatLng, tLatLng) { + return 10; + } + + /** + * Create a custom interface in the left toolbar for modifying model-specific options + * @param {Element} root The root element within which to build the UI + * @param {(action: number) => void} onChange Function to signal the manager to update when a parameter changes. Accepts an action number (see `IsochroneManager._handleInput`) + */ + createOptions(root, onChange) {} +} diff --git a/src/essence/Tools/Isochrone/models/Model_Example.js b/src/essence/Tools/Isochrone/models/Model_Example.js new file mode 100644 index 00000000..1625ca44 --- /dev/null +++ b/src/essence/Tools/Isochrone/models/Model_Example.js @@ -0,0 +1,21 @@ +import Model from "./Model"; +import { createDropdown, createInput } from "../ui"; + +/** Empty model demonstrating the ability of the model interface (multiple data sources, custom options, etc.) */ +class Model_Example extends Model { + static nameString = "Example"; + static requiredData = ["DEM", "Slope"]; + + static costName = "energy use"; + static costUnitSymbol = "Kcal"; + static defaultCost = 100; + + static enabledByDefault = false; + + createOptions(root, onChange) { + createDropdown("Model prop 1", root, ["dropdown"]); + createInput("Model prop 2", root, "unit", 15); + } +} + +export default Model_Example; diff --git a/src/essence/Tools/Isochrone/models/Model_Isodistance.js b/src/essence/Tools/Isochrone/models/Model_Isodistance.js new file mode 100644 index 00000000..b4614d1c --- /dev/null +++ b/src/essence/Tools/Isochrone/models/Model_Isodistance.js @@ -0,0 +1,46 @@ +import F_ from "../../../Basics/Formulae_/Formulae_"; +import Model from "./Model"; +import { createInput } from "../ui"; + +const getPx = (arr, px) => arr[px[0]][px[1]]; + +/** Terrain-aware distance model, with scale option to emphasize or ignore terrain */ +class Model_Isodistance extends Model { + static nameString = "Isodistance"; + static requiredData = ["DEM"]; + static defaultCost = 5000; + + constructor() { + super(); + this.terrainScale = 1; + } + + costFunction(cPx, tPx, cLatLng, tLatLng) { + const dist2d = F_.lngLatDistBetween( + cLatLng.lng, + cLatLng.lat, + tLatLng.lng, + tLatLng.lat + ); + const cEl = getPx(this.data.DEM, cPx); + const tEl = getPx(this.data.DEM, tPx); + const vDist = (cEl - tEl) * this.terrainScale; + const result = Math.sqrt(vDist * vDist + dist2d * dist2d); + return result; + } + + createOptions(root, onChange) { + createInput( + "Terrain scale", + root, + "X", + 1, + `min="0" default="1" step="0.2"` + ).on("change", e => { + this.terrainScale = parseFloat(e.target.value); + onChange(2); + }); + } +} + +export default Model_Isodistance; diff --git a/src/essence/Tools/Isochrone/models/Model_Traverse.js b/src/essence/Tools/Isochrone/models/Model_Traverse.js new file mode 100644 index 00000000..ad5ff2fd --- /dev/null +++ b/src/essence/Tools/Isochrone/models/Model_Traverse.js @@ -0,0 +1,53 @@ +import F_ from "../../../Basics/Formulae_/Formulae_"; +import Model from "./Model"; + +const getPx = (arr, px) => arr[px[0]][px[1]]; + +/** Naive lunar EVA traverse time model, based on Apollo */ +class Model_Traverse extends Model { + static nameString = "Traverse Time"; + static requiredData = ["DEM"]; + + static costName = "time"; + static costUnitSymbol = "min"; + static defaultCost = 60; + + static costToString(cost) { + const roundCost = Math.round(cost); + const hours = Math.floor(roundCost / 60); + const mins = roundCost % 60; + if (hours) { + const hourString = hours.toString().padStart(2, '0'); + const minString = mins.toString().padStart(2, '0'); + return hourString + ':' + minString; + } else { + return mins + 'min'; + } + } + + costFunction(cPx, tPx, cLatLng, tLatLng) { + const dist2d = F_.lngLatDistBetween( + cLatLng.lng, + cLatLng.lat, + tLatLng.lng, + tLatLng.lat + ); + const distVert = getPx(this.data.DEM, cPx) - getPx(this.data.DEM, tPx); + const distTotal = Math.sqrt(distVert * distVert + dist2d * dist2d); + const slope = Math.tan(distVert / dist2d) * (180 / Math.PI); + + //https://dspace.mit.edu/bitstream/handle/1721.1/38526/162623870-MIT.pdf (pg. 73) + let velocity; // m/s + if (slope < -15) velocity = 0; + else if (slope < -10) velocity = 0.095 * slope + 1.95; + else if (slope < 0) velocity = 0.06 * slope + 1.6; + else if (slope < 6) velocity = -0.2 * slope + 1.6; + else if (slope < 15) velocity = -0.039 * slope + 0.634; + else velocity = 0; + + const result = distTotal / velocity / 60; + return result; + } +} + +export default Model_Traverse; diff --git a/src/essence/Tools/Isochrone/models/index.js b/src/essence/Tools/Isochrone/models/index.js new file mode 100644 index 00000000..3cd0978b --- /dev/null +++ b/src/essence/Tools/Isochrone/models/index.js @@ -0,0 +1,11 @@ +import Model_Isodistance from "./Model_Isodistance"; +import Model_Traverse from "./Model_Traverse"; +import Model_Example from "./Model_Example"; + +const models = [ + Model_Isodistance, + Model_Traverse, + Model_Example +]; + +export default models; diff --git a/src/essence/Tools/Isochrone/ui.js b/src/essence/Tools/Isochrone/ui.js new file mode 100644 index 00000000..504dd411 --- /dev/null +++ b/src/essence/Tools/Isochrone/ui.js @@ -0,0 +1,42 @@ +import $ from 'jquery'; + +export function addOption(title, root) { + return $(`
    ${title}
    `).appendTo(root); +} +export function addSection(title, root) { + $(`
    ${title}
    `).appendTo(root); + return $(`
    `).appendTo(root); +} + +export function createInput(title, root, unit, value, attr = "") { + const innerContainer = $(`
    `) + .appendTo(addOption(title, root)); + const el = $( ``) + .appendTo(innerContainer); + if (unit) { + $(`
    ${unit}
    `).appendTo(innerContainer); + } else { + el.addClass('nounit'); + } + return el; +} + +export function createDropdown(title, root, options = []) { + let el = $(``) + .appendTo(addOption(title, root)) + const numOptions = options.length; + let selStr = ' selected'; + for(let i = 0; i < numOptions; i++) { + const optionEl = + $(``).appendTo(el); + optionEl.html(options[i]); + selStr = ''; + } + return el; +} + +export function createLoadBar(msg, root, error = false) { + const container = $(`
    `).appendTo(root); + $(`${msg}`).appendTo(container); + return $(``).appendTo(container); +} From 8aca6abaa064699b86ee1ff7c053bac41cf5aa91 Mon Sep 17 00:00:00 2001 From: Cameron Fraser Date: Wed, 11 Aug 2021 15:07:54 -0500 Subject: [PATCH 05/85] Convince viewshed to play nice w/ polar maps (& non-integer zoom levels) --- src/essence/Tools/Viewshed/ViewshedTool.js | 43 +++----- .../Tools/Viewshed/ViewshedTool_Manager.js | 99 +++++++------------ 2 files changed, 47 insertions(+), 95 deletions(-) diff --git a/src/essence/Tools/Viewshed/ViewshedTool.js b/src/essence/Tools/Viewshed/ViewshedTool.js index 739d26b6..7834b443 100644 --- a/src/essence/Tools/Viewshed/ViewshedTool.js +++ b/src/essence/Tools/Viewshed/ViewshedTool.js @@ -1157,6 +1157,14 @@ let ViewshedTool = { dlc[z] = dlc[z] || {} dlc[z][Math.floor(x)] = dlc[z][Math.floor(x)] || {} + const tileRow = + (y - Math.floor(data.outputTopLeftTile.y) + - (Math.abs(data.outputTopLeftTile.y) % 1) * 2) * res + + const tileCol = + (x - Math.floor(data.outputTopLeftTile.x) + - (Math.abs(data.outputTopLeftTile.x) % 1) * 2) * res + // Draw canvas let px = 0 let val = null @@ -1166,26 +1174,9 @@ let ViewshedTool = { p / 4 > cData.length - res - 1 || (p / 4) % res == 0 || (p / 4 + 1) % res == 0 - val = - data.result[ - (y - - Math.floor(data.outputTopLeftTile.y) - - (data.outputTopLeftTile.y % 1) * 2) * - res + - Math.floor(px / res) - ] + val = data.result[tileRow + Math.floor(px / res)] if (val != null) { - val = - val[ - (x - - Math.floor( - data.outputTopLeftTile.x - ) - - (data.outputTopLeftTile.x % 1) * - 2) * - res + - (px % res) - ] + val = val[tileCol + (px % res)] let c switch (val) { case 0: @@ -1210,20 +1201,10 @@ let ViewshedTool = { c = { r: 0, g: 255, b: 0, a: 0 } break case 8: - c = { - r: 0, - g: 0, - b: 0, - a: 0, - } + c = { r: 0, g: 0, b: 0, a: 0 } break case 9: - c = { - r: 255, - g: 0, - b: 0, - a: 35, - } + c = { r: 255, g: 0, b: 0, a: 35 } break default: c = { r: 0, g: 0, b: 0, a: 0 } diff --git a/src/essence/Tools/Viewshed/ViewshedTool_Manager.js b/src/essence/Tools/Viewshed/ViewshedTool_Manager.js index c6b44906..36e161a2 100644 --- a/src/essence/Tools/Viewshed/ViewshedTool_Manager.js +++ b/src/essence/Tools/Viewshed/ViewshedTool_Manager.js @@ -53,14 +53,14 @@ let ViewshedTool_Manager = { : true, hasDataCurved: false, zoom: Math.min( - Map_.map.getZoom() + resolution, + Math.round(Map_.map.getZoom()) + resolution, dataLayer.maxNativeZoom ), options: options, result: [], } this.data[viewshedId].resolution = - this.data[viewshedId].zoom - Map_.map.getZoom() + this.data[viewshedId].zoom - Math.round(Map_.map.getZoom()) this.updateDesiredTiles(viewshedId) this.refreshData(viewshedId) @@ -69,12 +69,9 @@ let ViewshedTool_Manager = { ViewshedTool_Manager.interpolateSeams(viewshedId) ViewshedTool_Manager.finishUp(viewshedId) ViewshedTool_Manager.data[viewshedId].result = - ViewshedTool_Manager.cleanupSeams( - viewshedId, - ViewshedTool_Algorithm.viewshed( - ViewshedTool_Manager.data[viewshedId], - options - ) + ViewshedTool_Algorithm.viewshed( + ViewshedTool_Manager.data[viewshedId], + options ) cb(dv) }) @@ -83,12 +80,9 @@ let ViewshedTool_Manager = { this.data[viewshedId].options = options this.locateSource(viewshedId) ViewshedTool_Manager.data[viewshedId].result = - ViewshedTool_Manager.cleanupSeams( - viewshedId, - ViewshedTool_Algorithm.viewshed( - ViewshedTool_Manager.data[viewshedId], - options - ) + ViewshedTool_Algorithm.viewshed( + ViewshedTool_Manager.data[viewshedId], + options ) cb(this.data[viewshedId]) } @@ -101,18 +95,15 @@ let ViewshedTool_Manager = { // Find all tiles between the bounds of the viewport and the bounds of the source point //viewport - let bounds = Map_.map.getBounds() - let viewportCenter = bounds.getCenter() + let viewBounds = Map_.map.getPixelBounds() let zoom = this.data[viewshedId].zoom + let boundsNW = Map_.map.unproject(viewBounds.getTopLeft()) + let boundsSE = Map_.map.unproject(viewBounds.getBottomRight()) + let minPx = Map_.map.project(boundsNW, zoom) + let maxPx = Map_.map.project(boundsSE, zoom) - let min = Map_.map - .project(bounds.getNorthWest(), zoom) - .divideBy(256) - .floor() - let max = Map_.map - .project(bounds.getSouthEast(), zoom) - .divideBy(256) - .floor() + let min = minPx.divideBy(256).floor() + let max = maxPx.divideBy(256).floor() let viewportDesiredTiles = [] for (let i = min.x; i <= max.x; i++) { @@ -124,28 +115,10 @@ let ViewshedTool_Manager = { } //source - let boundsNW = bounds.getNorthWest() - let boundsSE = bounds.getSouthEast() - let halfLat = (boundsNW.lat - boundsSE.lat) / 2 - let halfLng = (boundsSE.lng - boundsNW.lng) / 2 - let sourceCenter = this.data[viewshedId].source - let sourceBoundsNW = { - lat: sourceCenter.lat + halfLat, - lng: sourceCenter.lng - halfLng, - } - let sourceBoundsSE = { - lat: sourceCenter.lat - halfLat, - lng: sourceCenter.lng + halfLng, - } - - let sourceMin = Map_.map - .project(sourceBoundsNW, zoom) - .divideBy(256) - .floor() - let sourceMax = Map_.map - .project(sourceBoundsSE, zoom) - .divideBy(256) - .floor() + let halfViewport = L.bounds(minPx, maxPx).getSize().divideBy(2) + let sourceCenter = Map_.map.project(this.data[viewshedId].source, zoom) + let sourceMin = sourceCenter.subtract(halfViewport).divideBy(256).floor() + let sourceMax = sourceCenter.add(halfViewport).divideBy(256).floor() let sourceDesiredTiles = [] for (let i = sourceMin.x; i <= sourceMax.x; i++) { @@ -248,17 +221,13 @@ let ViewshedTool_Manager = { locateSource: function (viewshedId) { // Locate source let dv = this.data[viewshedId] - let tileXYZ = G_.litho.projection.latLngZ2TileXYZ( - dv.source.lat, - dv.source.lng, - dv.zoom, - true - ) - this.data[viewshedId].dataSource = { - x: Math.floor((tileXYZ.x - dv.topLeftTile.x) * dv.tileResolution), - y: Math.floor((tileXYZ.y - dv.topLeftTile.y) * dv.tileResolution), - } + let topLeftTile = new L.Point(dv.topLeftTile.x, dv.topLeftTile.y) + let sourcePoint = Map_.map.project(dv.source, dv.zoom).divideBy(256) + this.data[viewshedId].dataSource = sourcePoint + .subtract(topLeftTile) + .multiplyBy(dv.tileResolution) + .floor() }, queryDesiredTiles: function (viewshedId, progcb, cb) { let url = this.data[viewshedId].dataLayer.demtileurl @@ -354,12 +323,15 @@ let ViewshedTool_Manager = { if (existingHeights) { eachTile(d, start, existingHeights) } else { + const tile = this.data[viewshedId].desiredTiles[d] + const pxWorldBound = Map_.map.getPixelWorldBounds(tile.z) + const yTileWorldBound = Math.ceil(pxWorldBound.max.y / 256) - 1 + + let filledUrl = url.replace('{x}', tile.x) + filledUrl = filledUrl.replace('{y}', yTileWorldBound - tile.y) + filledUrl = filledUrl.replace('{z}', tile.z) PNG.load( - F_.populateUrl( - url, - this.data[viewshedId].desiredTiles[d], - true - ), + filledUrl, (function (d) { return function (img) { const tileResolution = @@ -456,7 +428,7 @@ let ViewshedTool_Manager = { } }, finishUp(viewshedId) { - const outputZoom = Map_.map.getZoom() + const outputZoom = Math.round(Map_.map.getZoom()) const zoom = this.data[viewshedId].zoom const dif = zoom - outputZoom @@ -482,7 +454,7 @@ let ViewshedTool_Manager = { }, getTilesetBounds: function (tiles) { //Assumes tiles are a grid - let bounds = { minX: Infinity, maxX: 0, minY: Infinity, maxY: 0 } + let bounds = { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity } for (let i = 0; i < tiles.length; i++) { if (tiles[i].x < bounds.minX) bounds.minX = tiles[i].x if (tiles[i].x > bounds.maxX) bounds.maxX = tiles[i].x @@ -492,7 +464,6 @@ let ViewshedTool_Manager = { return bounds }, cleanupSeams: function (viewshedId, result) { - return result const tileRes = this.data[viewshedId].tileResolution // Vertical fill | | From c614bc9e591e514b5125fa388d181bc9023283f7 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 1 Sep 2021 16:10:02 -0700 Subject: [PATCH 06/85] Fix Globe geodatasets and integrate demFallback --- config/js/config.js | 24 +++++++ package-lock.json | 68 ++++++++------------ package.json | 2 +- src/essence/Basics/Globe_/Globe_.js | 24 ++++++- src/essence/Basics/Layers_/Layers_.js | 82 ++++++++++++++++++------ src/essence/Tools/Draw/DrawTool_Files.js | 22 +++---- views/configure.pug | 16 +++++ 7 files changed, 163 insertions(+), 75 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 9b61c9cf..207b0e3d 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -451,6 +451,17 @@ function initialize() { true ); } + $("#tab_panels #panels_globeDemFallbackPath").val( + cData.panelSettings ? cData.panelSettings.demFallbackPath : "" + ); + $("#tab_panels #panels_globeDemFallbackFormat").val( + cData.panelSettings + ? cData.panelSettings.demFallbackFormat + : "" + ); + $("#tab_panels #panels_globeDemFallbackType").val( + cData.panelSettings ? cData.panelSettings.demFallbackType : "" + ); //time if (typeof cData.time != "undefined") { @@ -1649,6 +1660,7 @@ function save() { projection: {}, look: {}, panels: [], + panelSettings: {}, tools: [], layers: [], time: {}, @@ -1733,6 +1745,7 @@ function save() { json.look["help"] = $("#tab_look #look_help").prop("checked"); json.look["logourl"] = $("#tab_look #look_logourl").val(); json.look["helpurl"] = $("#tab_look #look_helpurl").val(); + json.look["highlightcolor"] = $("#tab_look #look_highlightcolor").val(); //Panels if ($("#tab_panels #panels_viewer").prop("checked")) @@ -1740,6 +1753,17 @@ function save() { if ($("#tab_panels #panels_map").prop("checked")) json.panels.push("map"); if ($("#tab_panels #panels_globe").prop("checked")) json.panels.push("globe"); + + json.panelSettings["demFallbackPath"] = $( + "#tab_panels #panels_globeDemFallbackPath" + ).val(); + json.panelSettings["demFallbackFormat"] = $( + "#tab_panels #panels_globeDemFallbackFormat" + ).val(); + json.panelSettings["demFallbackType"] = $( + "#tab_panels #panels_globeDemFallbackType" + ).val(); + //Time if ($("#tab_time #time_enabled").prop("checked")) { json.time.enabled = true; diff --git a/package-lock.json b/package-lock.json index 0b51e6e2..9da68e32 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.2", + "lithosphere": "^1.0.3", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", @@ -2110,27 +2110,15 @@ } }, "node_modules/@turf/boolean-intersects/node_modules/geojson-rbush": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.1.2.tgz", - "integrity": "sha512-grkfdg3HIeTjwTfiJe5FT8+fGU3fABCc+vRJDBwdQz9kkLF0Sbif2gs2JUzjewwgmnvLGy9fInySDeADoNuk7w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", + "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", "dependencies": { "@turf/bbox": "*", "@turf/helpers": "6.x", "@turf/meta": "6.x", - "rbush": "^2.0.0" - } - }, - "node_modules/@turf/boolean-intersects/node_modules/quickselect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", - "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" - }, - "node_modules/@turf/boolean-intersects/node_modules/rbush": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz", - "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", - "dependencies": { - "quickselect": "^1.0.1" + "@types/geojson": "7946.0.8", + "rbush": "^3.0.1" } }, "node_modules/@turf/boolean-overlap": { @@ -3375,6 +3363,11 @@ "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" }, + "node_modules/@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" + }, "node_modules/@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -11766,9 +11759,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/lithosphere": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.2.tgz", - "integrity": "sha512-FmW7+9V/JTrwbgzT6GmNGeswd0sZnZN5tQ0skA5GTxehoEyYYyNZ5Hfyfqs56JuvtxZh68DmJXeSN6rRUOqLYw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.3.tgz", + "integrity": "sha512-4hqkSABR8mHyNWkm33VMQQi7n+QOa5jvTn9Rc5WcAbKLPPHfqRQWTst6QfLcIlPCK/IEW8/SOpMrgck7xwD6Bw==", "dependencies": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", @@ -22072,27 +22065,15 @@ } }, "geojson-rbush": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.1.2.tgz", - "integrity": "sha512-grkfdg3HIeTjwTfiJe5FT8+fGU3fABCc+vRJDBwdQz9kkLF0Sbif2gs2JUzjewwgmnvLGy9fInySDeADoNuk7w==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", + "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", "requires": { "@turf/bbox": "*", "@turf/helpers": "6.x", "@turf/meta": "6.x", - "rbush": "^2.0.0" - } - }, - "quickselect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", - "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" - }, - "rbush": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz", - "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", - "requires": { - "quickselect": "^1.0.1" + "@types/geojson": "7946.0.8", + "rbush": "^3.0.1" } } } @@ -23349,6 +23330,11 @@ "resolved": "https://registry.npmjs.org/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz", "integrity": "sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag==" }, + "@types/geojson": { + "version": "7946.0.8", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.8.tgz", + "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" + }, "@types/glob": { "version": "7.1.3", "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.3.tgz", @@ -30396,9 +30382,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "lithosphere": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.2.tgz", - "integrity": "sha512-FmW7+9V/JTrwbgzT6GmNGeswd0sZnZN5tQ0skA5GTxehoEyYYyNZ5Hfyfqs56JuvtxZh68DmJXeSN6rRUOqLYw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.3.tgz", + "integrity": "sha512-4hqkSABR8mHyNWkm33VMQQi7n+QOa5jvTn9Rc5WcAbKLPPHfqRQWTst6QfLcIlPCK/IEW8/SOpMrgck7xwD6Bw==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/package.json b/package.json index 5bf998e6..b6e011c0 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.2", + "lithosphere": "^1.0.3", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", diff --git a/src/essence/Basics/Globe_/Globe_.js b/src/essence/Basics/Globe_/Globe_.js index 0658e073..3e9263e1 100644 --- a/src/essence/Basics/Globe_/Globe_.js +++ b/src/essence/Basics/Globe_/Globe_.js @@ -49,7 +49,7 @@ let Globe_ = { reszoomlevel: 0, } - this.litho = new LithoSphere(containerId, { + const lithoConfig = { initialView, //opt tileMapResource: tmr, @@ -67,7 +67,26 @@ let Globe_ = { }, highlightColor: 'yellow', //css color for vector hover highlights | default 'yellow' activeColor: 'red', //css color for active vector features | default 'red' - }) + } + + if ( + L_.configData.panelSettings && + L_.configData.panelSettings.demFallbackPath + ) + lithoConfig.demFallback = { + demPath: !F_.isUrlAbsolute( + L_.configData.panelSettings.demFallbackPath + ) + ? L_.missionPath + + L_.configData.panelSettings.demFallbackPath + : L_.configData.panelSettings.demFallbackPath, + format: L_.configData.panelSettings.demFallbackFormat || 'tms', + parserType: + L_.configData.panelSettings.demFallbackType || 'rgba', + } + + // CONSTRUCTOR + this.litho = new LithoSphere(containerId, lithoConfig) this.litho.addControl('mmgisLithoHome', this.litho.controls.home) this.litho.addControl( @@ -129,7 +148,6 @@ let Globe_ = { fina: function (coordinates) { // Passes in Coordinates so that LithoSphere can share the same coordinate ui element // as the rest of the application - console.log(coordinates) $(`#${this.id}`).on('mousemove', () => { coordinates.hideElevation() }) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 111b1e96..19cbb423 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -186,11 +186,7 @@ var L_ = { if (L_.Map_.map.hasLayer(L_.layersGroup[s.name])) { L_.Map_.map.removeLayer(L_.layersGroup[s.name]) } - if (s.type == 'tile') { - L_.Globe_.litho.removeLayer(s.name) - } else { - L_.Globe_.litho.toggleLayer(s.name, false) - } + L_.Globe_.litho.removeLayer(s.name) } else { if (L_.layersGroup[s.name]) { L_.Map_.map.addLayer(L_.layersGroup[s.name]) @@ -230,7 +226,35 @@ var L_ = { //time: s.time == null ? '' : s.time.end, }) } else { - L_.Globe_.litho.toggleLayer(s.name, true) + L_.Globe_.litho.addLayer( + s.type == 'vector' ? 'clamped' : s.type, + { + name: s.name, + order: 1000 - L_.layersIndex[s.name], // Since higher order in litho is on top + on: L_.opacityArray[s.name] ? true : false, + geojson: L_.layersGroup[s.name].toGeoJSON(), + onClick: (feature, lnglat, layer) => { + this.selectFeature(layer.name, feature) + }, + useKeyAsHoverName: s.useKeyAsName, + style: { + // Prefer feature[f].properties.style values + letPropertiesStyleOverride: true, // default false + default: { + fillColor: s.style.fillColor, //Use only rgb and hex. No css color names + fillOpacity: parseFloat( + s.style.fillOpacity + ), + color: s.style.color, + weight: s.style.weight, + radius: s.radius, + }, + }, + opacity: L_.opacityArray[s.name], + minZoom: 0, //s.minZoom, + maxZoom: 100, //s.maxNativeZoom, + } + ) } } } @@ -437,7 +461,7 @@ var L_ = { name: s.name, order: 1000 - L_.layersIndex[s.name], // Since higher order in litho is on top on: L_.opacityArray[s.name] ? true : false, - geojsonPath: layerUrl, + geojson: L_.layersGroup[s.name].toGeoJSON(), onClick: (feature, lnglat, layer) => { this.selectFeature(layer.name, feature) }, @@ -475,7 +499,11 @@ var L_ = { try { if (layer.feature?.properties?.annotation) { // Annotation - let id = '#DrawToolAnnotation_' + layer.feature.properties._.file_id + '_' + layer.feature.properties._.id + let id = + '#DrawToolAnnotation_' + + layer.feature.properties._.file_id + + '_' + + layer.feature.properties._.id d3.select(id).style('color', color) } else if (layer.hasOwnProperty('_layers')) { // Arrow @@ -545,10 +573,10 @@ var L_ = { var onId = s[1] != 'master' ? parseInt(s[1]) : s[1] if ( (this.layersNamed[key] && - (this.layersNamed[key].type == 'point' || - (key.toLowerCase().indexOf('draw') == -1 && - this.layersNamed[key].type == 'vector'))) || - (s[0] == 'DrawTool' && !Number.isNaN(onId)) + (this.layersNamed[key].type == 'point' || + (key.toLowerCase().indexOf('draw') == -1 && + this.layersNamed[key].type == 'vector'))) || + (s[0] == 'DrawTool' && !Number.isNaN(onId)) ) { if ( this.layersGroup.hasOwnProperty(key) && @@ -581,22 +609,38 @@ var L_ = { let layer = this.layersGroup[key][k] if (!layer?.feature?.properties?.arrow) { // Polygons and lines - layer.eachLayer(function(l) { + layer.eachLayer(function (l) { setLayerStyle(l) }) } else { // Arrow let layers = this.layersGroup[key][k]._layers - const style = this.layersGroup[key][k].feature.properties.style + const style = + this.layersGroup[key][k].feature.properties + .style const color = style.color - layers[Object.keys(layers)[0]].setStyle({ color }) - layers[Object.keys(layers)[1]].setStyle({ color }) + layers[Object.keys(layers)[0]].setStyle({ + color, + }) + layers[Object.keys(layers)[1]].setStyle({ + color, + }) } - } else if (this.layersGroup[key][k].feature?.properties?.annotation) { + } else if ( + this.layersGroup[key][k].feature?.properties + ?.annotation + ) { // Annotation let layer = this.layersGroup[key][k] - let id = '#DrawToolAnnotation_' + layer.feature.properties._.file_id + '_' + layer.feature.properties._.id - d3.select(id).style('color', layer.feature.properties.style.fillColor) + let id = + '#DrawToolAnnotation_' + + layer.feature.properties._.file_id + + '_' + + layer.feature.properties._.id + d3.select(id).style( + 'color', + layer.feature.properties.style.fillColor + ) } else if ('feature' in this.layersGroup[key][k]) { // Points (that are not annotations) let layer = this.layersGroup[key][k] diff --git a/src/essence/Tools/Draw/DrawTool_Files.js b/src/essence/Tools/Draw/DrawTool_Files.js index 64b32fdc..9cd63595 100644 --- a/src/essence/Tools/Draw/DrawTool_Files.js +++ b/src/essence/Tools/Draw/DrawTool_Files.js @@ -1322,18 +1322,18 @@ var Files = { } } if (coreFeatures.features.length > 0) { - Globe_.litho.addLayer( - 'clamped', - { - name: 'camptool_' + layerId + '_' + last, - on: true, - geojson: coreFeatures, - opacity: 1, - minZoom: 0, - maxZoom: 30, + Globe_.litho.addLayer('clamped', { + name: 'camptool_' + layerId + '_' + last, + on: true, + geojson: coreFeatures, + opacity: 1, + minZoom: 0, + maxZoom: 30, + style: { + // Prefer feature[f].properties.style values + letPropertiesStyleOverride: true, }, - true - ) + }) } if (populateShapesAfter) diff --git a/views/configure.pug b/views/configure.pug index 22ceabc9..406442e7 100644 --- a/views/configure.pug +++ b/views/configure.pug @@ -351,6 +351,22 @@ script(type='text/javascript' src='src/pre/RefreshAuth.js') p input#panels_globe.filled-in.checkbox-color(type='checkbox') label(for='panels_globe' style='color: black;') Globe + ul + li.row + #panels_globeDemFallbackPathEl.input-field.col.s8 + input#panels_globeDemFallbackPath.validate(type='text' value='') + label(for='panels_globeDemFallbackPath') DEM Fallback URL + #panels_globeDemFallbackFormatEL.input-field.col.s2 + select#panels_globeDemFallbackFormat + option(value='tms') TMS + option(value='wmts') WMTS + option(value='wms') WMS + label(for='panels_globeDemFallbackFormat') Fallback Format + #panels_globeDemFallbackTypeEL.input-field.col.s2 + select#panels_globeDemFallbackType + option(value='rgba') RGBA + option(value='tif') TIF + label(for='panels_globeDemFallbackType') Fallback Type #tab_time.col.s12 a.helpFromDocs(href='docs/?page=Time_Tab' target='__blank' rel='noopener') From 41a54e93035d5bc23882dc7f8fb3f4f555344c3a Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 1 Sep 2021 17:24:41 -0700 Subject: [PATCH 07/85] Fix DrawTool litho layer removal --- package-lock.json | 14 +++++++------- package.json | 2 +- src/essence/Tools/Draw/DrawTool_Files.js | 20 +++++++++----------- 3 files changed, 17 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9da68e32..b0d66093 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.3", + "lithosphere": "^1.0.4", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", @@ -11759,9 +11759,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/lithosphere": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.3.tgz", - "integrity": "sha512-4hqkSABR8mHyNWkm33VMQQi7n+QOa5jvTn9Rc5WcAbKLPPHfqRQWTst6QfLcIlPCK/IEW8/SOpMrgck7xwD6Bw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.4.tgz", + "integrity": "sha512-mFouJ52FhXhJl0bE6ICiEXL0nOwpymOPiiptxjMyVaMGaTt+Hkm1PnARUrvSjpggep+lynxOAb4Tb0xAuQtXZw==", "dependencies": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", @@ -30382,9 +30382,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "lithosphere": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.3.tgz", - "integrity": "sha512-4hqkSABR8mHyNWkm33VMQQi7n+QOa5jvTn9Rc5WcAbKLPPHfqRQWTst6QfLcIlPCK/IEW8/SOpMrgck7xwD6Bw==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.4.tgz", + "integrity": "sha512-mFouJ52FhXhJl0bE6ICiEXL0nOwpymOPiiptxjMyVaMGaTt+Hkm1PnARUrvSjpggep+lynxOAb4Tb0xAuQtXZw==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/package.json b/package.json index b6e011c0..ed2e5a17 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.3", + "lithosphere": "^1.0.4", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", diff --git a/src/essence/Tools/Draw/DrawTool_Files.js b/src/essence/Tools/Draw/DrawTool_Files.js index 9cd63595..c075ab3d 100644 --- a/src/essence/Tools/Draw/DrawTool_Files.js +++ b/src/essence/Tools/Draw/DrawTool_Files.js @@ -967,11 +967,11 @@ var Files = { Map_.rmNotNull( L_.layersGroup[layerId][i] ) - //And from the Globe - Globe_.litho.removeLayer( - 'camptool_' + layerId + '_' + i - ) } + //And from the Globe + Globe_.litho.removeLayer( + 'camptool_' + layerId + ) } //Remove from filesOn let f = DrawTool.filesOn.indexOf( @@ -1162,11 +1162,9 @@ var Files = { Map_.rmNotNull(L_.layersGroup[layerId][i]) L_.layersGroup[layerId][i] = null - //And from the Globe - Globe_.litho.removeLayer( - 'camptool_' + layerId + '_' + i - ) } + //And from the Globe + Globe_.litho.removeLayer('camptool_' + layerId) } let features = data.geojson.features @@ -1323,7 +1321,7 @@ var Files = { } if (coreFeatures.features.length > 0) { Globe_.litho.addLayer('clamped', { - name: 'camptool_' + layerId + '_' + last, + name: 'camptool_' + layerId, on: true, geojson: coreFeatures, opacity: 1, @@ -1398,9 +1396,9 @@ var Files = { if (L_.layersGroup.hasOwnProperty(layerId)) { for (var i = 0; i < L_.layersGroup[layerId].length; i++) { Map_.rmNotNull(L_.layersGroup[layerId][i]) - //And from the Globe - Globe_.litho.removeLayer('camptool_' + layerId + '_' + i) } + //And from the Globe + Globe_.litho.removeLayer('camptool_' + layerId) } DrawTool.refreshMasterCheckbox() From 5b88309ed19508c10a30e36b02dfe698976d67dd Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 17:21:05 -0700 Subject: [PATCH 08/85] Ignore pycache, ds_store, and extra data dir --- .dockerignore | 5 ++++- .gitignore | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/.dockerignore b/.dockerignore index b885538d..91555831 100644 --- a/.dockerignore +++ b/.dockerignore @@ -5,4 +5,7 @@ Missions Missions_rel Missions_dev .env -**/.git \ No newline at end of file +**/.git +data +*DS_Store +*__pycache__ \ No newline at end of file diff --git a/.gitignore b/.gitignore index d75c3426..21fa8da7 100644 --- a/.gitignore +++ b/.gitignore @@ -17,6 +17,8 @@ /src/pre/tools.js /build/* +/data/* +*__pycache__ sessions From 41b93736d9d7b8c73a111822630895dc8b0b903d Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 17:24:34 -0700 Subject: [PATCH 09/85] Allow processing without colormap and include prefix in output filename --- auxiliary/bulk_tiles/bulk_tiles.py | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/auxiliary/bulk_tiles/bulk_tiles.py b/auxiliary/bulk_tiles/bulk_tiles.py index e099401b..67fac65e 100755 --- a/auxiliary/bulk_tiles/bulk_tiles.py +++ b/auxiliary/bulk_tiles/bulk_tiles.py @@ -28,8 +28,9 @@ def process_tiffs(input_dir, process_dir, colormap_dir, legends_dir, prefix=''): colormap_key = os.path.basename(colormap_file).split('_')[1].split('.')[0] colormap_dict[colormap_key] = colormap_file else: - print('Error: ' + colormap_dir + ' directory does not exist') - sys.exit() + print('Warning: ' + colormap_dir + ' directory does not exist') + print('Processing without colormap') + # sys.exit() if not os.path.exists(process_dir): os.makedirs(process_dir) for input_file in input_files: @@ -203,6 +204,10 @@ def create_configs(output_dirs, json_config, prefix): # Generate JSON layer configurations if specified if args.json_config is not None: - create_configs(output_dirs, args.json_config, args.prefix) + if args.prefix != '': + json_config = args.json_config.replace('.json', '_' + args.prefix + '.json') + else: + json_config = args.json_config + create_configs(output_dirs, json_config, args.prefix) sys.exit() From c685a471f0bbfadccff76b125ac3c7ed1ec9edbb Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 17:37:22 -0700 Subject: [PATCH 10/85] Fixed epsg typo --- auxiliary/rasterstotiles/rasterstotiles.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/auxiliary/rasterstotiles/rasterstotiles.py b/auxiliary/rasterstotiles/rasterstotiles.py index d714fd01..de8ee065 100644 --- a/auxiliary/rasterstotiles/rasterstotiles.py +++ b/auxiliary/rasterstotiles/rasterstotiles.py @@ -85,9 +85,9 @@ def tile(raster, outputDir=None): # reproject to EPSG:4326 if it's a projection we can't handle downstream projection = osr.SpatialReference(wkt=ds.GetProjection()).GetName() if projection == "unnamed": - gdal_warp = "gdalwarp -t_srs EPSG:4326 " + raster + " " + raster[:-4] + "_espg4326" + raster[-4:] + gdal_warp = "gdalwarp -t_srs EPSG:4326 " + raster + " " + raster[:-4] + "_epsg4326" + raster[-4:] print(gdal_warp) - raster = raster[:-4] + "_espg4326" + raster[-4:] + raster = raster[:-4] + "_epsg4326" + raster[-4:] gdal_warp_process = subprocess.Popen(gdal_warp, shell=True) gdal_warp_process.wait() ds = gdal.Open(raster) From 04e4b8732866fb972c1a860a099a8912ccc3359e Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 17:38:34 -0700 Subject: [PATCH 11/85] Use percentages for sample color table --- .../rastertolegend/color_relief_slope.txt | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/auxiliary/rastertolegend/color_relief_slope.txt b/auxiliary/rastertolegend/color_relief_slope.txt index 2cea1610..7f14ef60 100644 --- a/auxiliary/rastertolegend/color_relief_slope.txt +++ b/auxiliary/rastertolegend/color_relief_slope.txt @@ -1,11 +1,11 @@ -95 158 1 66 -85 213 62 79 -75 244 109 67 -65 253 174 97 -55 254 224 139 -45 230 245 152 -35 171 221 164 -25 102 194 165 -15 50 136 189 -5 94 79 162 +95% 158 1 66 +85% 213 62 79 +75% 244 109 67 +65% 253 174 97 +55% 254 224 139 +45% 230 245 152 +35% 171 221 164 +25% 102 194 165 +15% 50 136 189 +5% 94 79 162 nv 0 0 0 0 \ No newline at end of file From 82ba754cda4a26815b06f0b540ba45a15f228a6e Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 17:40:14 -0700 Subject: [PATCH 12/85] Allow for optional help page route --- run/server.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/run/server.js b/run/server.js index f105c3be..be87ef1f 100644 --- a/run/server.js +++ b/run/server.js @@ -527,6 +527,11 @@ setups.getBackendSetups(function (setups) { app.get("/docs", ensureUser(), ensureGroup(permissions.users), (req, res) => { res.render("docs", {}); }); + + //help + app.get("/help", ensureUser(), ensureGroup(permissions.users), (req, res) => { + res.render("help", {}); + }); // API //TEST From 0a726e220e46128b47251eb2837106b59884849f Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 17:52:11 -0700 Subject: [PATCH 13/85] Option to calculate distance between points with Vincenty's formulae --- .../great_circle_calculator.py | 67 ++++++++++++++++++- 1 file changed, 64 insertions(+), 3 deletions(-) diff --git a/private/api/great_circle_calculator/great_circle_calculator.py b/private/api/great_circle_calculator/great_circle_calculator.py index 3f9c30b8..dcf96522 100644 --- a/private/api/great_circle_calculator/great_circle_calculator.py +++ b/private/api/great_circle_calculator/great_circle_calculator.py @@ -3,9 +3,15 @@ _degrees_to_radians from .__error_checking import _error_check_point from ._constants import * +from math import atan +from math import atan2 +from math import cos +from math import radians +from math import sin +from math import sqrt +from math import tan - -def distance_between_points(p1, p2, unit='meters', haversine=True): +def distance_between_points(p1, p2, unit='meters', haversine=True, vincenty=False): """ This function computes the distance between two points in the unit given in the unit parameter. It will calculate the distance using the haversine unless the user specifies haversine to be False. Then law of cosines will be used @@ -13,11 +19,66 @@ def distance_between_points(p1, p2, unit='meters', haversine=True): :param p2: tuple point of (lon, lat) :param unit: unit of measurement. List can be found in constants.eligible_units :param haversine: True (default) uses haversine distance, False uses law of cosines + :param vincenty: False (default) uses vincenty distance, False haversine :return: Distance between p1 and p2 in the units specified. """ lon1, lat1 = _point_to_radians(_error_check_point(p1)) lon2, lat2 = _point_to_radians(_error_check_point(p2)) r_earth = getattr(radius_earth, unit, 'meters') + + + if vincenty: # from https://nathanrooy.github.io/posts/2016-12-18/vincenty-formula-with-python/ + + maxIter=200 + tol=10**-12 + a=6378137.0 # radius at equator in meters (WGS-84) + f=1/298.257223563 # flattening of the ellipsoid (WGS-84) + b=(1-f)*a + + phi_1,L_1,=[lon1, lat1] # (lat=L_?,lon=phi_?) + phi_2,L_2,=[lon2, lat2] + + u_1=atan((1-f)*tan(radians(phi_1))) + u_2=atan((1-f)*tan(radians(phi_2))) + + L=radians(L_2-L_1) + + Lambda=L # set initial value of lambda to L + + sin_u1=sin(u_1) + cos_u1=cos(u_1) + sin_u2=sin(u_2) + cos_u2=cos(u_2) + + #--- BEGIN ITERATIONS -----------------------------+ + iters=0 + for i in range(0,maxIter): + iters+=1 + + cos_lambda=cos(Lambda) + sin_lambda=sin(Lambda) + sin_sigma=sqrt((cos_u2*sin(Lambda))**2+(cos_u1*sin_u2-sin_u1*cos_u2*cos_lambda)**2) + cos_sigma=sin_u1*sin_u2+cos_u1*cos_u2*cos_lambda + sigma=atan2(sin_sigma,cos_sigma) + sin_alpha=(cos_u1*cos_u2*sin_lambda)/sin_sigma + cos_sq_alpha=1-sin_alpha**2 + cos2_sigma_m=cos_sigma-((2*sin_u1*sin_u2)/cos_sq_alpha) + C=(f/16)*cos_sq_alpha*(4+f*(4-3*cos_sq_alpha)) + Lambda_prev=Lambda + Lambda=L+(1-C)*f*sin_alpha*(sigma+C*sin_sigma*(cos2_sigma_m+C*cos_sigma*(-1+2*cos2_sigma_m**2))) + + # successful convergence + diff=abs(Lambda_prev-Lambda) + if diff<=tol: + break + + u_sq=cos_sq_alpha*((a**2-b**2)/b**2) + A=1+(u_sq/16384)*(4096+u_sq*(-768+u_sq*(320-175*u_sq))) + B=(u_sq/1024)*(256+u_sq*(-128+u_sq*(74-47*u_sq))) + delta_sig=B*sin_sigma*(cos2_sigma_m+0.25*B*(cos_sigma*(-1+2*cos2_sigma_m**2)-(1/6)*B*cos2_sigma_m*(-3+4*sin_sigma**2)*(-3+4*cos2_sigma_m**2))) + + return b*A*(sigma-delta_sig) # output distance in meters + if haversine: # Haversine d_lat, d_lon = lat2 - lat1, lon2 - lon1 @@ -88,7 +149,7 @@ def intermediate_point(p1, p2, fraction=0.5): """ lon1, lat1 = _point_to_radians(_error_check_point(p1)) lon2, lat2 = _point_to_radians(_error_check_point(p2)) - delta = distance_between_points(p1, p2) / radius_earth.meters + delta = distance_between_points(p1, p2, vincenty=False) / radius_earth.meters a = sin((1 - fraction) * delta) / sin(delta) b = sin(fraction * delta) / sin(delta) x = a * cos(lat1) * cos(lon1) + b * cos(lat2) * cos(lon2) From 3ee5f16660a950983a8ea4ca6316f5f9adf8e573 Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 13 Sep 2021 19:14:25 -0700 Subject: [PATCH 14/85] Allow marker radius to be set by feature radius property --- src/essence/Basics/Map_/Map_.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index b3241808..6f80f3d5 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -953,6 +953,13 @@ function makeLayer(layerObj) { feature.style.fillopacity != null ? feature.style.fillopacity : fiO + + // Check for radius property if radius=1 (default/prop:radius) + layerObj.style.radius = + layerObj.radius == 1 + ? parseFloat(feature.properties['radius']) + : layerObj.radius + var noPointerEventsClass = feature.style && feature.style.nointeraction ? ' noPointerEvents' @@ -1095,8 +1102,8 @@ function makeLayer(layerObj) { icon: L.divIcon({ className: 'leafletMarkerShape', iconSize: [ - (layerObj.radius + pixelBuffer) * 2, - (layerObj.radius + pixelBuffer) * 2, + (featureStyle.radius + pixelBuffer) * 2, + (featureStyle.radius + pixelBuffer) * 2, ], html: svg, }), From 04b2041a575eb44dd6feff0ec4e0fd599b8c251f Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 16 Sep 2021 09:58:50 -0700 Subject: [PATCH 15/85] #105 Deep Linking - centerPin --- docs/pages/markdowns/Deep_Linking.md | 8 ++++++ src/essence/Ancillary/CursorInfo.js | 2 +- src/essence/Ancillary/QueryURL.js | 17 +++++++------ src/essence/Basics/Globe_/Globe_.js | 2 +- src/essence/Basics/Layers_/Layers_.js | 1 + src/essence/Basics/Map_/Map_.js | 35 ++++++++++++++++++++++++--- 6 files changed, 53 insertions(+), 12 deletions(-) diff --git a/docs/pages/markdowns/Deep_Linking.md b/docs/pages/markdowns/Deep_Linking.md index cc017f25..a75013c5 100644 --- a/docs/pages/markdowns/Deep_Linking.md +++ b/docs/pages/markdowns/Deep_Linking.md @@ -80,6 +80,14 @@ The name of the layer that's on and its opacity. When using the on parameter, al - _dependencies_: NONE - _unset:_ Only layers visible by default will be on +### centerPin=
    `` + +If a map latitude and longitude is set and centerPin has a value, then render a pin on the map at the its center. The value of centerPin becomes the pin/marker's mouse over text. If centerPin=true (or ''), then there is no mouse over text for the pin. This parameter is useful when you want to link to a specific coordinate on the map and maintain its location for the user rather than just setting the initial map view. + +- _form:_ ` || true || ''` +- _dependencies_: mapLon, mapLat +- _unset:_ No center point pin will be displayed + ### selected=
    `,,,,`
    `,,,,` The feature of a layer to have selected. If `lat` and `lon` are both numbers, the first _point_ in `layer name` with coordinates `lat` `lon` will be selected. Otherwise it'll be treated as a `key` `value` search. Under `key` `value` the first _feature_ in `layer name` whose `properties.` matches `value` gets selected. `key` supports nested properties with dot notation ("buildings.stores.candy"). The selected `layer name` layer will always be turned on regardless of what the other parameters may say. `view` and `zoom level` are _optional_. If `view` is set to "go", the selection would not only be made but also panned to. `zoom level` sets the zoom of `view's` "go". If `zoom level` is unset but `view` is set, it will default to the `Zoom Level of Map Scale` configuration value if set or finally the `Initial Zoom Level` configuration variable. diff --git a/src/essence/Ancillary/CursorInfo.js b/src/essence/Ancillary/CursorInfo.js index b3725a08..f091aa79 100644 --- a/src/essence/Ancillary/CursorInfo.js +++ b/src/essence/Ancillary/CursorInfo.js @@ -76,7 +76,7 @@ var CursorInfo = { return isError ? '1px solid var(--color-a)' : 'none' }) .style('display', 'block') - .html(message) + .text(message) if (time != null) { setTimeout(function () { diff --git a/src/essence/Ancillary/QueryURL.js b/src/essence/Ancillary/QueryURL.js index 22567f15..88a57d11 100644 --- a/src/essence/Ancillary/QueryURL.js +++ b/src/essence/Ancillary/QueryURL.js @@ -19,6 +19,8 @@ var QueryURL = { var urlPanePercents = this.getSingleQueryVariable('panePercents') var urlToolsObj = this.getSingleQueryVariable('tools') + var urlCenterPin = this.getSingleQueryVariable('centerPin') + var searchFile = this.getSingleQueryVariable('searchFile') var searchStrings = this.getMultipleQueryVariable('searchstr') var layersOn = this.getSingleQueryVariable('on') @@ -33,16 +35,12 @@ var QueryURL = { L_.FUTURES.site = urlSite } - if ( - urlMapLat !== false && - urlMapLon !== false && - urlMapZoom !== false - ) { + if (urlMapLat !== false && urlMapLon !== false) { // lat, lon, zoom L_.FUTURES.mapView = [ parseFloat(urlMapLat), parseFloat(urlMapLon), - parseInt(urlMapZoom), + urlMapZoom !== false ? parseInt(urlMapZoom) : null, ] } @@ -82,6 +80,10 @@ var QueryURL = { L_.FUTURES.tools = urlToolsObj.split(',') } + if (urlCenterPin !== false) { + L_.FUTURES.centerPin = urlCenterPin + } + if (searchFile !== false) { L_.searchFile = searchFile } @@ -349,7 +351,8 @@ var QueryURL = { }, function (s) { //Set and update the short url - L_.url = window.location.href.split('?')[0] + '?s=' + s.body.url + L_.url = + window.location.href.split('?')[0] + '?s=' + s.body.url window.history.replaceState('', '', L_.url) if (typeof callback === 'function') callback() }, diff --git a/src/essence/Basics/Globe_/Globe_.js b/src/essence/Basics/Globe_/Globe_.js index 3e9263e1..f2b6530e 100644 --- a/src/essence/Basics/Globe_/Globe_.js +++ b/src/essence/Basics/Globe_/Globe_.js @@ -24,7 +24,7 @@ let Globe_ = { initialView = { lat: initialView[0], lng: initialView[1], - zoom: initialView[2], + zoom: initialView[2] != null ? initialView[2] : L_.view[2], } const tmr = diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 19cbb423..6efe8ac2 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -126,6 +126,7 @@ var L_ = { globeCamera: null, panelPercents: null, activePoint: null, + centerPin: null, } L_.searchStrings = null L_.searchFile = null diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 6f80f3d5..5083fa22 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -180,9 +180,34 @@ let Map_ = { //Initialize the view to that set in config if (L_.FUTURES.mapView != null) { this.resetView(L_.FUTURES.mapView) + if (L_.FUTURES.centerPin != null) { + this._centerPin = new L.circleMarker( + [L_.FUTURES.mapView[0], L_.FUTURES.mapView[1]], + { + fillColor: '#000', + fillOpacity: 0, + color: 'lime', + weight: 2, + } + ) + .setRadius(4) + .addTo(this.map) + if ( + L_.FUTURES.centerPin.length > 0 && + L_.FUTURES.centerPin != 'true' + ) { + this._centerPin.on('mouseover', function () { + CursorInfo.update(L_.FUTURES.centerPin, null, false) + }) + this._centerPin.on('mouseout', function () { + CursorInfo.hide() + }) + } + } } else { this.resetView(L_.view) } + //Remove attribution d3.select('.leaflet-control-attribution').remove() @@ -261,7 +286,11 @@ let Map_ = { var lon = parseFloat(latlonzoom[1]) if (isNaN(lon)) lon = 0 var zoom = parseInt(latlonzoom[2]) - if (isNaN(zoom)) zoom = this.map.getZoom() + if (zoom == null || isNaN(zoom)) + zoom = + this.map.getZoom() || + L_.configData.msv.mapscale || + L_.configData.msv.view[2] this.map.setView([lat, lon], zoom) this.map.invalidateSize() }, @@ -955,11 +984,11 @@ function makeLayer(layerObj) { : fiO // Check for radius property if radius=1 (default/prop:radius) - layerObj.style.radius = + layerObj.style.radius = layerObj.radius == 1 ? parseFloat(feature.properties['radius']) : layerObj.radius - + var noPointerEventsClass = feature.style && feature.style.nointeraction ? ' noPointerEvents' From fb3e13b8ec8bb3e32726b5375d32928d0e817367 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 16 Sep 2021 10:10:19 -0700 Subject: [PATCH 16/85] Add yes flag to Dockfile apt-get update --- Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Dockerfile b/Dockerfile index 2107a850..cb388939 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,7 +1,7 @@ FROM node:12 # Install GDAL with Python bindings -RUN apt-get update +RUN apt-get -y update RUN apt-get install -y gdal-bin libgdal-dev python3-pip python3-gdal # Use Python3 for python From d4bbf5db4caffa494b769403c69f1470cd3e42ae Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 16 Sep 2021 13:28:02 -0700 Subject: [PATCH 17/85] Use svg as logo --- src/essence/Ancillary/Stylize.js | 5 ++++- src/essence/Basics/UserInterface_/UserInterface_.js | 8 ++++++-- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/essence/Ancillary/Stylize.js b/src/essence/Ancillary/Stylize.js index 26931314..890a9001 100644 --- a/src/essence/Ancillary/Stylize.js +++ b/src/essence/Ancillary/Stylize.js @@ -64,7 +64,10 @@ export function stylize() { if (L_.configData.look.mapcolor && L_.configData.look.mapcolor != '') $('#map').css({ background: L_.configData.look.mapcolor }) if (L_.configData.look.logourl && L_.configData.look.logourl != '') { - $('#mmgislogo img').attr('src', L_.configData.look.logourl) + $('#mmgislogo').css({ padding: '7px 3px' }) + $('#mmgislogo').html( + `Logo` + ) $('#favicon').attr('href', L_.configData.look.logourl) } if (L_.configData.look.helpurl && L_.configData.look.helpurl != '') { diff --git a/src/essence/Basics/UserInterface_/UserInterface_.js b/src/essence/Basics/UserInterface_/UserInterface_.js index c84bb155..b56c3766 100644 --- a/src/essence/Basics/UserInterface_/UserInterface_.js +++ b/src/essence/Basics/UserInterface_/UserInterface_.js @@ -736,7 +736,7 @@ var UserInterface = { .append('div') .attr('id', 'mmgislogo') .style('display', this.topSize == 0 ? 'inherit' : 'none') - .style('padding', '7px 3px') + .style('padding', '9px 6px') .style('cursor', 'pointer') .style('width', '40px') .style('height', '40px') @@ -745,7 +745,11 @@ var UserInterface = { .style('left', '0px') .style('z-index', '2005') .style('image-rendering', 'pixelated') - .html("Logo") + .html( + ` + +` + ) .on('click', F_.toHostForceLanding) //ViewerSplit is immovable From c79b690f8eb2b031cf792299cca66fa6f6e3bd36 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 23 Sep 2021 10:00:03 -0700 Subject: [PATCH 18/85] #107 part 1 --- API/Backend/Draw/models/published.js | 26 +- API/Backend/Draw/routes/files.js | 20 +- API/Backend/Draw/setup.js | 11 +- src/essence/Basics/Layers_/LayerCapturer.js | 193 ++++++ src/essence/Basics/Layers_/Layers_.js | 427 ++++++++---- src/essence/Basics/Map_/Map_.js | 693 ++++++++------------ src/essence/Tools/Draw/DrawTool_Drawing.js | 16 +- src/essence/Tools/Layers/LayersTool.css | 16 +- src/essence/Tools/Layers/LayersTool.js | 12 +- 9 files changed, 840 insertions(+), 574 deletions(-) create mode 100644 src/essence/Basics/Layers_/LayerCapturer.js diff --git a/API/Backend/Draw/models/published.js b/API/Backend/Draw/models/published.js index dd06cb91..c55507c2 100644 --- a/API/Backend/Draw/models/published.js +++ b/API/Backend/Draw/models/published.js @@ -25,39 +25,47 @@ const { sequelize } = require("../../../connection"); const attributes = { intent: { type: Sequelize.ENUM, - values: ["roi", "campaign", "campsite", "trail", "signpost"], + values: [ + "roi", + "campaign", + "campsite", + "trail", + "signpost", + "text", + "arrow", + ], allowNull: false, unique: false, - defaultValue: null + defaultValue: null, }, parent: { type: Sequelize.DataTypes.INTEGER, unique: false, - allowNull: true + allowNull: true, }, children: { type: Sequelize.DataTypes.ARRAY(Sequelize.DataTypes.INTEGER), unique: false, - allowNull: true + allowNull: true, }, level: { type: Sequelize.INTEGER, unique: false, - allowNull: false + allowNull: false, }, properties: { type: Sequelize.JSON, allowNull: true, - defaultValue: {} + defaultValue: {}, }, geom: { type: Sequelize.GEOMETRY, - allowNull: true - } + allowNull: true, + }, }; const options = { - timestamps: false + timestamps: false, }; var Published = sequelize.define("publisheds", attributes, options); diff --git a/API/Backend/Draw/routes/files.js b/API/Backend/Draw/routes/files.js index 2b2ddf3b..8df8cf7d 100644 --- a/API/Backend/Draw/routes/files.js +++ b/API/Backend/Draw/routes/files.js @@ -698,7 +698,14 @@ const compile = function (req, res, callback) { where: { is_master: true, intent: { - [Sequelize.Op.in]: ["roi", "campaign", "campsite", "trail", "signpost"], + [Sequelize.Op.in]: [ + "roi", + "campaign", + "campsite", + "trail", + "signpost", + "all", + ], }, }, }).then((files) => { @@ -1478,7 +1485,7 @@ router.post("/publish", function (req, res, next) { logger("error", "Failed to publish. " + message, req.originalUrl, req); res.send({ status: "failure", - message: "Failed to publish." + message, + message: "Failed to publish. " + message, body: {}, }); } @@ -1580,7 +1587,14 @@ router.post("/publish", function (req, res, next) { cb(true); return null; }) - .catch(function (error) { + .catch(function (err) { + logger( + "error", + "Error adding to published.", + req.originalUrl, + req, + err + ); cb(false); return null; }); diff --git a/API/Backend/Draw/setup.js b/API/Backend/Draw/setup.js index bcd5c620..90df3c54 100644 --- a/API/Backend/Draw/setup.js +++ b/API/Backend/Draw/setup.js @@ -4,7 +4,7 @@ const routerDraw = require("./routes/draw").router; let setup = { //Once the app initializes - onceInit: s => { + onceInit: (s) => { s.app.use( "/API/files", s.ensureUser(), @@ -24,17 +24,18 @@ let setup = { ); }, //Once the server starts - onceStarted: s => {}, + onceStarted: (s) => {}, //Once all tables sync - onceSynced: s => { + onceSynced: (s) => { routeFiles.makeMasterFiles([ "roi", "campaign", "campsite", "trail", - "signpost" + "signpost", + "all", ]); - } + }, }; module.exports = setup; diff --git a/src/essence/Basics/Layers_/LayerCapturer.js b/src/essence/Basics/Layers_/LayerCapturer.js new file mode 100644 index 00000000..1aa138a8 --- /dev/null +++ b/src/essence/Basics/Layers_/LayerCapturer.js @@ -0,0 +1,193 @@ +import $ from 'jquery' +import * as d3 from 'd3' +import F_ from '../Formulae_/Formulae_' +import L_ from '../Layers_/Layers_' +import calls from '../../../pre/calls' +import TimeControl from '../../Ancillary/TimeControl' + +export const captureVector = (layerObj, options, cb) => { + options = options || {} + let layerUrl = layerObj.url + + if (options.evenIfOff !== true && !layerObj.visibility) { + cb('off') + return + } + + if (typeof layerUrl !== 'string' || layerUrl.length === 0) { + cb(null) + return + } + + // Give time enabled layers a default start and end time to avoid errors + const layerTimeFormat = + layerObj.time == null + ? d3.utcFormat('%Y-%m-%dT%H:%M:%SZ') + : d3.utcFormat(layerObj.time.format) + const startTime = layerTimeFormat(Date.parse(TimeControl.getStartTime())) + const endTime = layerTimeFormat(Date.parse(TimeControl.getEndTime())) + if (typeof layerObj.time != 'undefined') { + layerUrl = layerObj.url + .replace('{starttime}', startTime) + .replace('{endtime}', endTime) + .replace('{time}', endTime) + } + if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl + + let done = true + let urlSplit = layerObj.url.toLowerCase().split(':') + + switch (urlSplit[0]) { + case 'geodatasets': + calls.api( + 'geodatasets_get', + { + layer: urlSplit[1], + type: 'geojson', + }, + function (data) { + cb(data.body) + }, + function (data) { + console.warn( + 'ERROR! ' + + data.status + + ' in ' + + layerUrl + + ' /// ' + + data.message + ) + cb(null) + } + ) + break + case 'api': + switch (urlSplit[1]) { + case 'publishedall': + calls.api( + 'files_getfile', + { + quick_published: true, + }, + function (data) { + data.body.features.sort((a, b) => { + let intentOrder = [ + 'all', + 'roi', + 'campaign', + 'campsite', + 'trail', + 'signpost', + 'note', + 'master', + ] + let ai = intentOrder.indexOf( + a.properties._.intent + ) + let bi = intentOrder.indexOf( + b.properties._.intent + ) + return ai - bi + }) + cb(data.body) + }, + function (data) { + console.warn( + 'ERROR! ' + + data.status + + ' in ' + + layerUrl + + ' /// ' + + data.message + ) + cb(null) + } + ) + break + case 'published': + calls.api( + 'files_getfile', + { + intent: urlSplit[2], + quick_published: true, + }, + function (data) { + cb(data.body) + }, + function (data) { + console.warn( + 'ERROR! ' + + data.status + + ' in ' + + layerUrl + + ' /// ' + + data.message + ) + cb(null) + } + ) + break + case 'tacticaltargets': + calls.api( + 'tactical_targets', + {}, + function (data) { + cb(data.body) + }, + function (data) { + if (data) { + console.warn( + 'ERROR! ' + + data.status + + ' in ' + + layerUrl + + ' /// ' + + data.message + ) + } + cb(null) + } + ) + break + default: + console.warn( + `Unknown layer URL ${layerUrl} in layer ${layerObj.name}` + ) + cb(null) + break + } + break + default: + done = false + } + + if (!done) { + // If there is no url to a JSON file but the "controlled" option is checked in the layer config, + // create the geoJSON layer with empty GeoJSON data + const layerData = L_.layersDataByName[layerObj.name] + if (L_.missionPath === layerUrl && layerData.controlled) { + // Empty GeoJSON data + const geojson = { type: 'FeatureCollection', features: [] } + cb(geojson) + } else { + $.getJSON(layerUrl, function (data) { + if (data.hasOwnProperty('Features')) { + data.features = data.Features + delete data.Features + } + cb(data) + }).fail(function (jqXHR, textStatus, errorThrown) { + //Tell the console council about what happened + console.warn( + 'ERROR! ' + + textStatus + + ' in ' + + layerUrl + + ' /// ' + + errorThrown + ) + cb(null) + }) + } + } +} diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 6efe8ac2..79668bb1 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -177,31 +177,23 @@ var L_ = { //Takes in config layer obj //Toggles a layer on and off and accounts for sublayers //Takes in a config layer object - toggleLayer: function (s) { + toggleLayer: async function (s) { if (s == null) return - var on //if on -> turn off //if off -> turn on - if (L_.toggledArray[s.name] == true) on = true + let on //if on -> turn off //if off -> turn on + if (L_.toggledArray[s.name] === true) on = true else on = false - if (s.type != 'header') { + if (s.type !== 'header') { if (on) { if (L_.Map_.map.hasLayer(L_.layersGroup[s.name])) { L_.Map_.map.removeLayer(L_.layersGroup[s.name]) } L_.Globe_.litho.removeLayer(s.name) } else { - if (L_.layersGroup[s.name]) { - L_.Map_.map.addLayer(L_.layersGroup[s.name]) - L_.layersGroup[s.name].setZIndex( - L_.layersOrdered.length + - 1 - - L_.layersOrdered.indexOf(s.name) - ) - } - if (s.type == 'tile') { - var layerUrl = s.url + if (s.type === 'tile') { + let layerUrl = s.url if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl - var demUrl = s.demtileurl + let demUrl = s.demtileurl if (!F_.isUrlAbsolute(demUrl)) demUrl = L_.missionPath + demUrl if (s.demtileurl == undefined || s.demtileurl.length == 0) @@ -227,35 +219,45 @@ var L_ = { //time: s.time == null ? '' : s.time.end, }) } else { - L_.Globe_.litho.addLayer( - s.type == 'vector' ? 'clamped' : s.type, - { - name: s.name, - order: 1000 - L_.layersIndex[s.name], // Since higher order in litho is on top - on: L_.opacityArray[s.name] ? true : false, - geojson: L_.layersGroup[s.name].toGeoJSON(), - onClick: (feature, lnglat, layer) => { - this.selectFeature(layer.name, feature) - }, - useKeyAsHoverName: s.useKeyAsName, - style: { - // Prefer feature[f].properties.style values - letPropertiesStyleOverride: true, // default false - default: { - fillColor: s.style.fillColor, //Use only rgb and hex. No css color names - fillOpacity: parseFloat( - s.style.fillOpacity - ), - color: s.style.color, - weight: s.style.weight, - radius: s.radius, + if (L_.layersGroup[s.name] === false) + await L_.Map_.makeLayer(s, true) + if (L_.layersGroup[s.name]) { + L_.Map_.map.addLayer(L_.layersGroup[s.name]) + L_.layersGroup[s.name].setZIndex( + L_.layersOrdered.length + + 1 - + L_.layersOrdered.indexOf(s.name) + ) + L_.Globe_.litho.addLayer( + s.type === 'vector' ? 'clamped' : s.type, + { + name: s.name, + order: 1000 - L_.layersIndex[s.name], // Since higher order in litho is on top + on: L_.opacityArray[s.name] ? true : false, + geojson: L_.layersGroup[s.name].toGeoJSON(), + onClick: (feature, lnglat, layer) => { + this.selectFeature(layer.name, feature) }, - }, - opacity: L_.opacityArray[s.name], - minZoom: 0, //s.minZoom, - maxZoom: 100, //s.maxNativeZoom, - } - ) + useKeyAsHoverName: s.useKeyAsName, + style: { + // Prefer feature[f].properties.style values + letPropertiesStyleOverride: true, // default false + default: { + fillColor: s.style.fillColor, //Use only rgb and hex. No css color names + fillOpacity: parseFloat( + s.style.fillOpacity + ), + color: s.style.color, + weight: s.style.weight, + radius: s.radius, + }, + }, + opacity: L_.opacityArray[s.name], + minZoom: 0, //s.minZoom, + maxZoom: 100, //s.maxNativeZoom, + } + ) + } } } } @@ -263,93 +265,7 @@ var L_ = { if (on) L_.toggledArray[s.name] = false if (!on) L_.toggledArray[s.name] = true - var sNext = getSublayers(s) - if (sNext != 0) toggleSubRecur(sNext, on) - - // Possibly deprecated because group layer toggling is no longer supported in the UI - function toggleSubRecur(r, on) { - for (var i = 0; i < r.length; i++) { - //( if it doesn't have it ) or ( if it has it and it's true ) - if ( - !r[i].hasOwnProperty('togglesWithHeader') || - (r[i].hasOwnProperty('togglesWithHeader') && - r[i].togglesWithHeader) - ) { - if (r[i].type != 'header') { - if (on) { - if ( - L_.Map_.map.hasLayer(L_.layersGroup[r[i].name]) - ) { - L_.Map_.map.removeLayer( - L_.layersGroup[r[i].name] - ) - } - if (r[i].type == 'tile') { - L_.Globe_.litho.removeLayer(r[i].name) - } else { - L_.Globe_.litho.toggleLayer(r[i].name, true) - } - L_.toggledArray[r[i].name] = false - } else { - if (L_.layersGroup[r[i].name]) { - L_.Map_.map.addLayer(L_.layersGroup[r[i].name]) - if (r[i].type == 'vector') { - L_.Map_.orderedBringToFront() - } - L_.layersGroup[r[i].name].setZIndex( - L_.layersOrdered.length + - 1 - - L_.layersOrdered.indexOf(r[i].name) - ) - } - if (r[i].type == 'tile') { - var layerUrl = r[i].url - if (!F_.isUrlAbsolute(layerUrl)) - layerUrl = L_.missionPath + layerUrl - var demUrl = s.demtileurl - if (!F_.isUrlAbsolute(demUrl)) - demUrl = L_.missionPath + demUrl - if (s.demtileurl == undefined) - demUrl = undefined - L_.Globe_.litho.addLayer('tile', { - name: r[i].name, - order: 99999 - L_.layersIndex[r[i].name], - on: L_.opacityArray[r[i].name], - format: s.tileformat || 'tms', - formatOptions: {}, - demFormat: s.tileformat || 'tms', - demFormatOptions: { - correctSeams: s.tileformat === 'wms', - wmsParams: {}, - }, - parser: s.demparser || null, - path: layerUrl, - demPath: demUrl, - opacity: L_.opacityArray[r[i].name], - minZoom: r[i].minZoom, - maxZoom: r[i].maxNativeZoom, - //boundingBox: r[i].boundingBox, - //time: r[i].time == null ? '' : r[i].time.end, - }) - } else { - L_.Globe_.litho.toggleLayer(r[i].name, false) - } - L_.toggledArray[r[i].name] = true - } - } else { - if (on) L_.toggledArray[r[i].name] = false - else L_.toggledArray[r[i].name] = true - } - var rNext = getSublayers(r[i]) - if (rNext != 0) toggleSubRecur(rNext, on) - } - } - } - function getSublayers(d) { - if (d.hasOwnProperty('sublayers')) return d.sublayers - else return 0 - } - if (!on && s.type == 'vector') { + if (!on && s.type === 'vector') { L_.Map_.orderedBringToFront() } }, @@ -389,7 +305,10 @@ var L_ = { map = map.map } for (var i = L_.layersData.length - 1; i >= 0; i--) { - if (L_.toggledArray[L_.layersData[i].name] === true) { + if ( + L_.toggledArray[L_.layersData[i].name] === true && + L_.layersGroup[L_.layersData[i].name] != null + ) { if (L_.layersData[i].type === 'tile') { // Make sure all tile layers follow z-index order at start instead of element order L_.layersGroup[L_.layersData[i].name].setZIndex( @@ -521,7 +440,249 @@ var L_ = { layer._icon.style.filter = `drop-shadow(${color} 2px 0px 0px) drop-shadow(${color} -2px 0px 0px) drop-shadow(${color} 0px 2px 0px) drop-shadow(${color} 0px -2px 0px)` } }, + addArrowToMap: function ( + layerId, + start, + end, + style, + feature, + index, + indexedCallback + ) { + var line + + var length + if (isNaN(style.length)) length = false + else length = parseInt(style.length) + + line = new L.Polyline([end, start], { + color: style.color, + weight: style.width + style.weight, + }) + var arrowBodyOutline + if (length === false) { + arrowBodyOutline = new L.Polyline([start, end], { + color: style.color, + weight: style.width + style.weight, + dashArray: style.dashArray, + lineCap: style.lineCap, + lineJoin: style.lineJoin, + }) + } else { + arrowBodyOutline = L.polylineDecorator(line, { + patterns: [ + { + offset: length / 2 + 'px', + repeat: 0, + symbol: L.Symbol.dash({ + pixelSize: style.length, + polygon: false, + pathOptions: { + stroke: true, + color: style.color, + weight: style.width + style.weight, + dashArray: style.dashArray, + lineCap: style.lineCap, + lineJoin: style.lineJoin, + }, + }), + }, + ], + }) + } + line = new L.Polyline([start, end], { + color: style.color, + weight: style.width + style.weight, + }) + var arrowHeadOutline = L.polylineDecorator(line, { + patterns: [ + { + offset: '100%', + repeat: 0, + symbol: L.Symbol.arrowHead({ + pixelSize: style.radius, + polygon: false, + pathOptions: { + stroke: true, + color: style.color, + weight: style.width + style.weight, + lineCap: style.lineCap, + lineJoin: style.lineJoin, + }, + }), + }, + ], + }) + line = new L.Polyline([end, start], { + color: style.fillColor, + weight: style.width, + }) + var arrowBody + if (length === false) { + arrowBody = new L.Polyline([start, end], { + color: style.fillColor, + weight: style.width, + dashArray: style.dashArray, + lineCap: style.lineCap, + lineJoin: style.lineJoin, + }) + } else { + arrowBody = L.polylineDecorator(line, { + patterns: [ + { + offset: length / 2 + 'px', + repeat: 0, + symbol: L.Symbol.dash({ + pixelSize: style.length, + polygon: false, + pathOptions: { + stroke: true, + color: style.fillColor, + weight: style.width, + dashArray: style.dashArray, + lineCap: style.lineCap, + lineJoin: style.lineJoin, + }, + }), + }, + ], + }) + } + line = new L.Polyline([start, end], { + color: style.fillColor, + weight: style.width, + }) + var arrowHead = L.polylineDecorator(line, { + patterns: [ + { + offset: '100%', + repeat: 0, + symbol: L.Symbol.arrowHead({ + pixelSize: style.radius, + polygon: false, + pathOptions: { + stroke: true, + color: style.fillColor, + weight: style.width, + lineCap: style.lineCap, + lineJoin: style.lineJoin, + }, + }), + }, + ], + }) + + if (layerId == null) { + const arrowLayer = L.layerGroup([ + arrowBodyOutline, + arrowHeadOutline, + arrowBody, + arrowHead, + ]) + arrowLayer.start = start + arrowLayer.end = end + arrowLayer.feature = feature + return arrowLayer + } + if (index != null) { + L_.Map_.rmNotNull(L_.layersGroup[layerId][index]) + L_.layersGroup[layerId][index] = L.layerGroup([ + arrowBodyOutline, + arrowHeadOutline, + arrowBody, + arrowHead, + ]).addTo(L_.Map_.map) + L_.layersGroup[layerId][index].start = start + L_.layersGroup[layerId][index].end = end + L_.layersGroup[layerId][index].feature = feature + if (typeof indexedCallback === 'function') indexedCallback() + } else { + L_.layersGroup[layerId].push( + L.layerGroup([ + arrowBodyOutline, + arrowHeadOutline, + arrowBody, + arrowHead, + ]).addTo(L_.Map_.map) + ) + L_.layersGroup[layerId][L_.layersGroup[layerId].length - 1].start = + start + L_.layersGroup[layerId][L_.layersGroup[layerId].length - 1].end = + end + L_.layersGroup[layerId][ + L_.layersGroup[layerId].length - 1 + ].feature = feature + } + }, + createAnnotation: function ( + feature, + className, + layerId, + id1, + id2, + andAddToMap + ) { + if (id2 == null) id2 = 0 + + console.log(feature, className, layerId, id1, id2) + className = className.replace(/ /g, '_') + //Remove previous annotation if any + $(`#${className}_${id1}_${id2}`) + .parent() + .parent() + .parent() + .parent() + .remove() + + const s = feature.properties.style + const styleString = + (s.color != null + ? 'text-shadow: ' + + F_.getTextShadowString(s.color, s.strokeOpacity, s.weight) + + '; ' + : '') + + (s.fillColor != null ? 'color: ' + s.fillColor + '; ' : '') + + (s.fontSize != null ? 'font-size: ' + s.fontSize + '; ' : '') + + (s.rotation != null + ? 'transform: rotateX)' + s.rotation + 'deg); ' + : '') + // prettier-ignore + const popup = L.popup({ + className: 'leaflet-popup-annotation', + closeButton: false, + autoClose: false, + closeOnEscapeKey: false, + closeOnClick: false, + autoPan: false, + offset: new L.point(0, 3), + }) + .setLatLng( + new L.LatLng( + feature.geometry.coordinates[1], + feature.geometry.coordinates[0] + ) + ) + .setContent( + '
    ' + + "
    " + + `${feature.properties.name.replace(/\W/g, '')}`, + '
    ' + + '
    ' + ) + if (andAddToMap) { + popup.addTo(L_.Map_.map) + L_.layersGroup[layerId].push(popup) + L_.layersGroup[layerId][ + L_.layersGroup[layerId].length - 1 + ].feature = feature + } + return popup + }, setLayerOpacity: function (name, newOpacity) { if (L_.Globe_) L_.Globe_.litho.setLayerOpacity(name, newOpacity) var l = L_.layersGroup[name] @@ -550,9 +711,9 @@ var L_ = { var opacity try { - opacity = l.options.style.opacity + opacity = l.options?.style.opacity } catch (error) { - opacity = l.options.opacity + opacity = l.options?.opacity } return opacity }, diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 5083fa22..ebd6ea03 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -2,6 +2,7 @@ import $ from 'jquery' import * as d3 from 'd3' import F_ from '../Formulae_/Formulae_' import L_ from '../Layers_/Layers_' +import { captureVector } from '../Layers_/LayerCapturer' import Viewer_ from '../Viewer_/Viewer_' import Globe_ from '../Globe_/Globe_' import ToolController_ from '../ToolController_/ToolController_' @@ -12,7 +13,6 @@ import Kinds from '../../Tools/Kinds/Kinds' import DataShaders from '../../Ancillary/DataShaders' import calls from '../../../pre/calls' import TimeControl from '../../Ancillary/TimeControl' -import { color } from 'd3' let L = window.L let essenceFina = function () {} @@ -458,6 +458,7 @@ let Map_ = { return xyzs }, + makeLayer: makeLayer, } //Specific internal functions likely only to be used once @@ -506,17 +507,17 @@ function makeLayers(layersObj) { } } //Takes the layer object and makes it a map layer -function makeLayer(layerObj) { +async function makeLayer(layerObj, evenIfOff) { //Decide what kind of layer it is //Headers do not need to be made if (layerObj.type != 'header') { //Simply call the appropriate function for each layer type switch (layerObj.type) { case 'vector': - makeVectorLayer() + await makeVectorLayer(evenIfOff) break case 'point': - makeVectorLayer() //makePointLayer(); //DEATH TO POINT + await makeVectorLayer(evenIfOff) //makePointLayer(); //DEATH TO POINT break case 'tile': makeTileLayer() @@ -759,435 +760,305 @@ function makeLayer(layerObj) { } //Pretty much like makePointLayer but without the pointToLayer stuff - function makeVectorLayer() { - var layerUrl = layerObj.url - // Give time enabled layers a default start and end time to avoid errors - var layerTimeFormat = - layerObj.time == null - ? d3.utcFormat('%Y-%m-%dT%H:%M:%SZ') - : d3.utcFormat(layerObj.time.format) - var startTime = layerTimeFormat(Date.parse(TimeControl.getStartTime())) - var endTime = layerTimeFormat(Date.parse(TimeControl.getEndTime())) - if (typeof layerObj.time != 'undefined') { - layerUrl = layerObj.url - .replace('{starttime}', startTime) - .replace('{endtime}', endTime) - .replace('{time}', endTime) - } - if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl - let urlSplit = layerObj.url.split(':') + async function makeVectorLayer(evenIfOff) { + return new Promise((resolve, reject) => { + captureVector(layerObj, { evenIfOff: evenIfOff }, add) - if ( - urlSplit[0].toLowerCase() === 'geodatasets' && - urlSplit[1] != null - ) { - calls.api( - 'geodatasets_get', - { - layer: urlSplit[1], - type: 'geojson', - }, - function (data) { - add(data.body) - }, - function (data) { - console.warn( - 'ERROR! ' + - data.status + - ' in ' + - layerObj.url + - ' /// ' + - data.message - ) - add(null) - } - ) - } else if (layerObj.url.substr(0, 16) == 'api:publishedall') { - calls.api( - 'files_getfile', - { - id: JSON.stringify([1, 2, 3, 4, 5]), - quick_published: true, - }, - function (data) { - data.body.features.sort((a, b) => { - let intentOrder = [ - 'all', - 'roi', - 'campaign', - 'campsite', - 'trail', - 'signpost', - 'note', - 'master', - ] - let ai = intentOrder.indexOf(a.properties._.intent) - let bi = intentOrder.indexOf(b.properties._.intent) - return ai - bi - }) - add(data.body) - }, - function (data) { - console.warn( - 'ERROR! ' + - data.status + - ' in ' + - layerObj.url + - ' /// ' + - data.message - ) - add(null) - } - ) - } else if (layerObj.url.substr(0, 13) == 'api:published') { - calls.api( - 'files_getfile', - { - intent: layerObj.url.split(':')[2], - quick_published: true, - }, - function (data) { - add(data.body) - }, - function (data) { - console.warn( - 'ERROR! ' + - data.status + - ' in ' + - layerObj.url + - ' /// ' + - data.message - ) - add(null) - } - ) - } else if (layerObj.url.substr(0, 19) == 'api:tacticaltargets') { - calls.api( - 'tactical_targets', - {}, - function (data) { - add(data.body) - }, - function (data) { - if (data) { - console.warn( - 'ERROR! ' + - data.status + - ' in ' + - layerObj.url + - ' /// ' + - data.message - ) - } - add(null) - } - ) - } else { - // If there is no url to a JSON file but the "controlled" option is checked in the layer config, - // create the geoJSON layer with empty GeoJSON data - var layerData = L_.layersDataByName[layerObj.name] - if (L_.missionPath === layerUrl && layerData.controlled) { - // Empty GeoJSON data - var geojson = { type: 'FeatureCollection', features: [] } - add(geojson) - } else { - $.getJSON(layerUrl, function (data) { - add(data) - }).fail(function (jqXHR, textStatus, errorThrown) { - //Tell the console council about what happened - console.warn( - 'ERROR! ' + - textStatus + - ' in ' + - layerObj.url + - ' /// ' + - errorThrown - ) - //Say that this layer was loaded, albeit erroneously + function add(data) { + if (data == null || data === 'off') { L_.layersLoaded[ L_.layersOrdered.indexOf(layerObj.name) ] = true - //Check again to see if all layers have loaded + L_.layersGroup[layerObj.name] = data == null ? null : false allLayersLoaded() - }) - if (typeof layerObj.time != 'undefined') { - layerUrl = layerObj.url + resolve() + return } - } - } - function add(data) { - if (data == null) { - L_.layersLoaded[L_.layersOrdered.indexOf(layerObj.name)] = true - allLayersLoaded() - return - } + layerObj.style.layerName = layerObj.name - layerObj.style.layerName = layerObj.name - - layerObj.style.opacity = L_.opacityArray[layerObj.name] - //layerObj.style.fillOpacity = L_.opacityArray[layerObj.name] - - var col = layerObj.style.color - var opa = String(layerObj.style.opacity) - var wei = String(layerObj.style.weight) - var fiC = layerObj.style.fillColor - var fiO = String(layerObj.style.fillOpacity) - var leafletLayerObject = { - style: function (feature) { - if (feature.properties.hasOwnProperty('style')) { - let className = layerObj.style.className - let layerName = layerObj.style.layerName - layerObj.style = JSON.parse( - JSON.stringify(feature.properties.style) - ) + layerObj.style.opacity = L_.opacityArray[layerObj.name] + //layerObj.style.fillOpacity = L_.opacityArray[layerObj.name] - layerObj.style.className = className - layerObj.style.layerName = layerName - } else { - // Priority to prop, prop.color, then style color. - var finalCol = - col.toLowerCase().substring(0, 4) == 'prop' - ? F_.parseColor( - feature.properties[col.substring(5)] - ) || '#FFF' - : feature.style && feature.style.stroke != null - ? feature.style.stroke - : col - var finalOpa = - opa.toLowerCase().substring(0, 4) == 'prop' - ? feature.properties[opa.substring(5)] || '1' - : feature.style && feature.style.opacity != null - ? feature.style.opacity - : opa - var finalWei = - wei.toLowerCase().substring(0, 4) == 'prop' - ? feature.properties[wei.substring(5)] || '1' - : feature.style && feature.style.weight != null - ? feature.style.weight - : wei - if (!isNaN(parseInt(wei))) finalWei = parseInt(wei) - var finalFiC = - fiC.toLowerCase().substring(0, 4) == 'prop' - ? F_.parseColor( - feature.properties[fiC.substring(5)] - ) || '#000' - : feature.style && feature.style.fill != null - ? feature.style.fill - : fiC - var finalFiO = - fiO.toLowerCase().substring(0, 4) == 'prop' - ? feature.properties[fiO.substring(5)] || '1' - : feature.style && - feature.style.fillopacity != null - ? feature.style.fillopacity - : fiO - - // Check for radius property if radius=1 (default/prop:radius) - layerObj.style.radius = - layerObj.radius == 1 - ? parseFloat(feature.properties['radius']) - : layerObj.radius - - var noPointerEventsClass = - feature.style && feature.style.nointeraction - ? ' noPointerEvents' - : '' - - layerObj.style.color = finalCol - layerObj.style.opacity = finalOpa - layerObj.style.weight = finalWei - layerObj.style.fillColor = finalFiC - layerObj.style.fillOpacity = finalFiO - } - layerObj.style.className = - layerObj.style.className + noPointerEventsClass - layerObj.style.metadata = data.metadata || {} - return layerObj.style - }, - onEachFeature: (function (layerObjName) { - return onEachFeatureDefault - })(layerObj.name), - } - if (layerObj.hasOwnProperty('radius')) { - let markerIcon = null - if ( - layerObj.hasOwnProperty('variables') && - layerObj.variables.hasOwnProperty('markerIcon') - ) { - let markerIconOptions = F_.clone( - layerObj.variables.markerIcon - ) - if ( - markerIconOptions.iconUrl && - !F_.isUrlAbsolute(markerIconOptions.iconUrl) - ) - markerIconOptions.iconUrl = - L_.missionPath + markerIconOptions.iconUrl - if ( - markerIconOptions.shadowUrl && - !F_.isUrlAbsolute(markerIconOptions.shadowUrl) - ) - markerIconOptions.shadowUrl = - L_.missionPath + markerIconOptions.shadowUrl + var col = layerObj.style.color + var opa = String(layerObj.style.opacity) + var wei = String(layerObj.style.weight) + var fiC = layerObj.style.fillColor + var fiO = String(layerObj.style.fillOpacity) + var leafletLayerObject = { + style: function (feature) { + if (feature.properties.hasOwnProperty('style')) { + let className = layerObj.style.className + let layerName = layerObj.style.layerName + layerObj.style = JSON.parse( + JSON.stringify(feature.properties.style) + ) - markerIcon = new L.icon(markerIconOptions) + layerObj.style.className = className + layerObj.style.layerName = layerName + } else { + // Priority to prop, prop.color, then style color. + var finalCol = + col.toLowerCase().substring(0, 4) == 'prop' + ? F_.parseColor( + feature.properties[col.substring(5)] + ) || '#FFF' + : feature.style && + feature.style.stroke != null + ? feature.style.stroke + : col + var finalOpa = + opa.toLowerCase().substring(0, 4) == 'prop' + ? feature.properties[opa.substring(5)] || + '1' + : feature.style && + feature.style.opacity != null + ? feature.style.opacity + : opa + var finalWei = + wei.toLowerCase().substring(0, 4) == 'prop' + ? feature.properties[wei.substring(5)] || + '1' + : feature.style && + feature.style.weight != null + ? feature.style.weight + : wei + if (!isNaN(parseInt(wei))) finalWei = parseInt(wei) + var finalFiC = + fiC.toLowerCase().substring(0, 4) == 'prop' + ? F_.parseColor( + feature.properties[fiC.substring(5)] + ) || '#000' + : feature.style && + feature.style.fill != null + ? feature.style.fill + : fiC + var finalFiO = + fiO.toLowerCase().substring(0, 4) == 'prop' + ? feature.properties[fiO.substring(5)] || + '1' + : feature.style && + feature.style.fillopacity != null + ? feature.style.fillopacity + : fiO + + // Check for radius property if radius=1 (default/prop:radius) + layerObj.style.radius = + layerObj.radius == 1 + ? parseFloat(feature.properties['radius']) + : layerObj.radius + + var noPointerEventsClass = + feature.style && feature.style.nointeraction + ? ' noPointerEvents' + : '' + + layerObj.style.color = finalCol + layerObj.style.opacity = finalOpa + layerObj.style.weight = finalWei + layerObj.style.fillColor = finalFiC + layerObj.style.fillOpacity = finalFiO + } + layerObj.style.className = + layerObj.style.className + noPointerEventsClass + layerObj.style.metadata = data.metadata || {} + return layerObj.style + }, + onEachFeature: (function (layerObjName) { + return onEachFeatureDefault + })(layerObj.name), } + if (layerObj.hasOwnProperty('radius')) { + let markerIcon = null + if ( + layerObj.hasOwnProperty('variables') && + layerObj.variables.hasOwnProperty('markerIcon') + ) { + let markerIconOptions = F_.clone( + layerObj.variables.markerIcon + ) + if ( + markerIconOptions.iconUrl && + !F_.isUrlAbsolute(markerIconOptions.iconUrl) + ) + markerIconOptions.iconUrl = + L_.missionPath + markerIconOptions.iconUrl + if ( + markerIconOptions.shadowUrl && + !F_.isUrlAbsolute(markerIconOptions.shadowUrl) + ) + markerIconOptions.shadowUrl = + L_.missionPath + markerIconOptions.shadowUrl - leafletLayerObject.pointToLayer = function (feature, latlong) { - const featureStyle = leafletLayerObject.style(feature) - let svg = '' - let layer = null - const pixelBuffer = featureStyle.weight || 0 - - switch (layerObj.shape) { - case 'circle': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'triangle': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'triangle-flipped': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'square': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'diamond': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'pentagon': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'hexagon': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'star': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'plus': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'pin': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'none': - default: - layer = L.circleMarker( - latlong, - leafletLayerObject.style - ).setRadius(layerObj.radius) - break + markerIcon = new L.icon(markerIconOptions) } - if (markerIcon) { - layer = L.marker(latlong, { icon: markerIcon }) - } else if (layer == null && svg != null) { - layer = L.marker(latlong, { - icon: L.divIcon({ - className: 'leafletMarkerShape', - iconSize: [ - (featureStyle.radius + pixelBuffer) * 2, - (featureStyle.radius + pixelBuffer) * 2, - ], - html: svg, - }), - }) - } + leafletLayerObject.pointToLayer = function ( + feature, + latlong + ) { + const featureStyle = leafletLayerObject.style(feature) + let svg = '' + let layer = null + const pixelBuffer = featureStyle.weight || 0 + + switch (layerObj.shape) { + case 'circle': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'triangle': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'triangle-flipped': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'square': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'diamond': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'pentagon': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'hexagon': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'star': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'plus': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'pin': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'none': + default: + layer = L.circleMarker( + latlong, + leafletLayerObject.style + ).setRadius(layerObj.radius) + break + } - if (layer == null) return + if (markerIcon) { + layer = L.marker(latlong, { icon: markerIcon }) + } else if (layer == null && svg != null) { + layer = L.marker(latlong, { + icon: L.divIcon({ + className: 'leafletMarkerShape', + iconSize: [ + (featureStyle.radius + pixelBuffer) * 2, + (featureStyle.radius + pixelBuffer) * 2, + ], + html: svg, + }), + }) + } + + if (layer == null) return - layer.options.layerName = layerObj.name + layer.options.layerName = layerObj.name - return layer + return layer + } } - } + L_.layersGroup[layerObj.name] = constructVectorLayer( + data, + leafletLayerObject + ) - //If it's a drawing layer - if (layerObj.name.toLowerCase().indexOf('draw') != -1) { - F_.sortGeoJSONFeatures(data) + d3.selectAll( + '.' + layerObj.name.replace(/\s/g, '').toLowerCase() + ).data(data.features) + L_.layersLoaded[L_.layersOrdered.indexOf(layerObj.name)] = true + allLayersLoaded() - leafletLayerObject = { - style: function (feature) { - return { - color: 'black', - radius: 6, - opacity: feature.properties.opacity, - fillColor: feature.properties.fill, - fillOpacity: feature.properties.fillOpacity, - color: feature.properties.stroke, - weight: feature.properties.weight, - className: 'spePolygonLayer', - } - }, - pointToLayer: function (feature, latlng) { - return L.circleMarker(latlng) - }, - onEachFeature: function (feature, layer) { - var desc = feature.properties.description - if (desc) desc = desc.replace(/\n/g, '
    ') - var list = - '
    ' + - feature.properties.name + - '
    ' + - desc + - '
    ' - layer.bindPopup(list) - }, - } + resolve() } - L_.layersGroup[layerObj.name] = L.geoJson(data, leafletLayerObject) + }) + } - d3.selectAll( - '.' + layerObj.name.replace(/\s/g, '').toLowerCase() - ).data(data.features) - L_.layersLoaded[L_.layersOrdered.indexOf(layerObj.name)] = true - allLayersLoaded() - } + /** + * Takes regular geojson and makes it fancy with annotations and arrows when applicable + * @return leaflet geojson + */ + function constructVectorLayer(geojson, leafletLayerObject) { + const layer = L.geoJson(geojson, leafletLayerObject) + + Object.keys(layer._layers).forEach((idx) => { + let l = layer._layers[idx] + if (l.feature?.properties?.arrow === true) { + const savedUseKeyAsName = l.useKeyAsName + const savedOptions = l.options + const c = l.feature.geometry.coordinates + const start = new L.LatLng(c[0][1], c[0][0]) + const end = new L.LatLng(c[1][1], c[1][0]) + layer._layers[idx] = L_.addArrowToMap( + null, + start, + end, + l.feature?.properties?.style, + l.feature + ) + layer._layers[idx].useKeyAsName = savedUseKeyAsName + layer._layers[idx].options = savedOptions + } else if (l.feature?.properties?.annotation === true) { + layer._layers[idx] = L_.createAnnotation( + l.feature, + 'LayerAnnotation', + layer._layers[idx].options.layerName, + idx + ) + layer._layers[idx].feature = l.feature + } + }) + return layer } function makeTileLayer() { diff --git a/src/essence/Tools/Draw/DrawTool_Drawing.js b/src/essence/Tools/Draw/DrawTool_Drawing.js index 093207bd..10808fa4 100644 --- a/src/essence/Tools/Draw/DrawTool_Drawing.js +++ b/src/essence/Tools/Draw/DrawTool_Drawing.js @@ -84,8 +84,10 @@ var Drawing = { let newGeometry let noChange = false try { - newGeometry = turf.difference(geojson, d.shape) - .geometry + newGeometry = turf.difference( + geojson, + d.shape + ).geometry if ( JSON.stringify(newGeometry) == JSON.stringify(geojson) @@ -469,12 +471,10 @@ var Drawing = { arrowHead, ]).addTo(Map_.map) ) - L_.layersGroup[layerId][ - L_.layersGroup[layerId].length - 1 - ].start = start - L_.layersGroup[layerId][ - L_.layersGroup[layerId].length - 1 - ].end = end + L_.layersGroup[layerId][L_.layersGroup[layerId].length - 1].start = + start + L_.layersGroup[layerId][L_.layersGroup[layerId].length - 1].end = + end L_.layersGroup[layerId][ L_.layersGroup[layerId].length - 1 ].feature = feature diff --git a/src/essence/Tools/Layers/LayersTool.css b/src/essence/Tools/Layers/LayersTool.css index c6343c61..d2112f2b 100644 --- a/src/essence/Tools/Layers/LayersTool.css +++ b/src/essence/Tools/Layers/LayersTool.css @@ -337,12 +337,20 @@ border: 2px solid #777; border-radius: 3px; transition: background 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), - border 0.2s cubic-bezier(0.39, 0.575, 0.565, 1); + border 0.1s cubic-bezier(0.39, 0.575, 0.565, 1), + border-radius 0.1s cubic-bezier(0.39, 0.575, 0.565, 1); } #layersTool .checkbox.on { background: white; border: 0px solid #777; } +#layersTool .checkbox.loading { + background: transparent; + border: 3px solid rgba(255, 255, 255, 0.3); + border-radius: 50%; + border-top-color: #fff; + animation: layerLoadingSpin 1s ease-in-out infinite; +} #layersTool .checkboxSmall { margin: 3px; @@ -442,3 +450,9 @@ background: transparent !important; border: 2px solid #777 !important; } + +@keyframes layerLoadingSpin { + to { + transform: rotate(360deg); + } +} diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index 23937a5b..c27c7385 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -449,11 +449,15 @@ function interfaceWithMMGIS() { //Add event functions and whatnot //Makes layers clickable on and off - $('#layersToolList > li > .title .checkbox').on('click', function () { + $('#layersToolList > li > .title .checkbox').on('click', async function () { let li = $(this).parent().parent().parent() - if (li.attr('type') != 'header') { - $(this).toggleClass('on') - L_.toggleLayer(L_.layersNamed[li.attr('name')]) + if (li.attr('type') !== 'header') { + $(this).addClass('loading') + await L_.toggleLayer(L_.layersNamed[li.attr('name')]) + $(this).removeClass('loading') + if (L_.layersGroup[li.attr('name')]) $(this).toggleClass('on') + else if (L_.layersGroup[li.attr('name')] == null) + li.addClass('layernotfound') } }) From c25b482750a65e0d28c5b8ef6bcb39d943859ab0 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 23 Sep 2021 10:03:51 -0700 Subject: [PATCH 19/85] Disable Globe highlighting --- package-lock.json | 14 +++++++------- package.json | 2 +- src/essence/Basics/Globe_/Globe_.js | 2 ++ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index b0d66093..1c8eeab0 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.4", + "lithosphere": "^1.0.5", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", @@ -11759,9 +11759,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/lithosphere": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.4.tgz", - "integrity": "sha512-mFouJ52FhXhJl0bE6ICiEXL0nOwpymOPiiptxjMyVaMGaTt+Hkm1PnARUrvSjpggep+lynxOAb4Tb0xAuQtXZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.5.tgz", + "integrity": "sha512-KUNGQx3AxmijI4cJDa3yWP/Q6GCHJbnpRkqa9HfBQVCH8lE2csCJ1IYfvFFwX2KBaSqdZvIdxxxvclqboTbuYA==", "dependencies": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", @@ -30382,9 +30382,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "lithosphere": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.4.tgz", - "integrity": "sha512-mFouJ52FhXhJl0bE6ICiEXL0nOwpymOPiiptxjMyVaMGaTt+Hkm1PnARUrvSjpggep+lynxOAb4Tb0xAuQtXZw==", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.5.tgz", + "integrity": "sha512-KUNGQx3AxmijI4cJDa3yWP/Q6GCHJbnpRkqa9HfBQVCH8lE2csCJ1IYfvFFwX2KBaSqdZvIdxxxvclqboTbuYA==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/package.json b/package.json index ed2e5a17..eab96ebd 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.4", + "lithosphere": "^1.0.5", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", diff --git a/src/essence/Basics/Globe_/Globe_.js b/src/essence/Basics/Globe_/Globe_.js index f2b6530e..6e7f2f3f 100644 --- a/src/essence/Basics/Globe_/Globe_.js +++ b/src/essence/Basics/Globe_/Globe_.js @@ -65,7 +65,9 @@ let Globe_ = { atmosphere: { color: '#0c0c0c', }, + canBecomeHighlighted: false, highlightColor: 'yellow', //css color for vector hover highlights | default 'yellow' + canBecomeActive: false, activeColor: 'red', //css color for active vector features | default 'red' } From 183e3ad1eac8eec1df2d28ee6b5ccb82f7f80255 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 27 Sep 2021 08:42:17 -0700 Subject: [PATCH 20/85] IdentiferTool - use asHTML CursorInfo --- src/essence/Ancillary/CursorInfo.js | 6 ++++-- src/essence/Tools/Identifier/IdentifierTool.js | 6 +++++- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/essence/Ancillary/CursorInfo.js b/src/essence/Ancillary/CursorInfo.js index f091aa79..ec36c22b 100644 --- a/src/essence/Ancillary/CursorInfo.js +++ b/src/essence/Ancillary/CursorInfo.js @@ -53,7 +53,8 @@ var CursorInfo = { isError, position, forceColor, - forceFontColor + forceFontColor, + asHTML ) { if (position) { CursorInfo.forcedPos = true @@ -76,7 +77,8 @@ var CursorInfo = { return isError ? '1px solid var(--color-a)' : 'none' }) .style('display', 'block') - .text(message) + if (asHTML) CursorInfo.cursorInfoDiv.html(message) + else CursorInfo.cursorInfoDiv.text(message) if (time != null) { setTimeout(function () { diff --git a/src/essence/Tools/Identifier/IdentifierTool.js b/src/essence/Tools/Identifier/IdentifierTool.js index 62a4172f..a6d3b9e1 100644 --- a/src/essence/Tools/Identifier/IdentifierTool.js +++ b/src/essence/Tools/Identifier/IdentifierTool.js @@ -297,7 +297,11 @@ var IdentifierTool = { CursorInfo.update( htmlInfoString + liEls.join('') + '', null, - false + false, + null, + null, + null, + true ) if (!trueValue) { From 17798cf6bdc76458114d361b90d5bd0cb6796930 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 27 Sep 2021 11:48:34 -0700 Subject: [PATCH 21/85] #107 1 --- src/essence/Basics/Layers_/Layers_.js | 5 ++++- src/essence/Basics/Map_/Map_.js | 1 + src/essence/Tools/Kinds/Kinds.js | 1 - 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 79668bb1..96284e38 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -189,6 +189,7 @@ var L_ = { } L_.Globe_.litho.removeLayer(s.name) } else { + console.log(s.type) if (s.type === 'tile') { let layerUrl = s.url if (!F_.isUrlAbsolute(layerUrl)) @@ -218,6 +219,7 @@ var L_ = { //boundingBox: s.boundingBox, //time: s.time == null ? '' : s.time.end, }) + } else if (s.type === 'data') { } else { if (L_.layersGroup[s.name] === false) await L_.Map_.makeLayer(s, true) @@ -734,7 +736,8 @@ var L_ = { var s = key.split('_') var onId = s[1] != 'master' ? parseInt(s[1]) : s[1] if ( - (this.layersNamed[key] && + (this.layersGroup[key] && + this.layersNamed[key] && (this.layersNamed[key].type == 'point' || (key.toLowerCase().indexOf('draw') == -1 && this.layersNamed[key].type == 'vector'))) || diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index ebd6ea03..ab76b8d6 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -1502,6 +1502,7 @@ function clearOnMapClick(event) { let found = false // For all MMGIS layers for (let key in L_.layersGroup) { + if (L_.layersGroup[key] === false) continue let layers // Layers can be a LayerGroup or an array of LayerGroup diff --git a/src/essence/Tools/Kinds/Kinds.js b/src/essence/Tools/Kinds/Kinds.js index a9470a93..78df296d 100644 --- a/src/essence/Tools/Kinds/Kinds.js +++ b/src/essence/Tools/Kinds/Kinds.js @@ -97,7 +97,6 @@ var Kinds = { true, layerName ) - useInfo(false) break default: From dd65fefc0df5a2e91a71b13f178972f029bcc84f Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 27 Sep 2021 11:50:12 -0700 Subject: [PATCH 22/85] Roll HTML2Canvas back to rc5 --- src/external/HTML2Canvas/html2canvas.min.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/external/HTML2Canvas/html2canvas.min.js b/src/external/HTML2Canvas/html2canvas.min.js index c9fa1362..9fb83879 100644 --- a/src/external/HTML2Canvas/html2canvas.min.js +++ b/src/external/HTML2Canvas/html2canvas.min.js @@ -1,6 +1,6 @@ /*! - * html2canvas 1.0.0-rc.7 - * Copyright (c) 2020 Niklas von Hertzen + * html2canvas 1.0.0-rc.5 + * Copyright (c) 2019 Niklas von Hertzen * Released under MIT License */ !function(A,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e():"function"==typeof define&&define.amd?define(e):(A=A||self).html2canvas=e()}(this,function(){"use strict"; @@ -17,4 +17,4 @@ See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. - ***************************************************************************** */var r=function(A,e){return(r=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(A,e){A.__proto__=e}||function(A,e){for(var t in e)e.hasOwnProperty(t)&&(A[t]=e[t])})(A,e)};function A(A,e){function t(){this.constructor=A}r(A,e),A.prototype=null===e?Object.create(e):(t.prototype=e.prototype,new t)}var K=function(){return(K=Object.assign||function(A){for(var e,t=1,r=arguments.length;ts[0]&&e[1]>10),s%1024+56320)),(n+1===t||16384>5])<<2)+(31&A),this.data[e];if(A<=65535)return e=((e=this.index[2048+(A-55296>>5)])<<2)+(31&A),this.data[e];if(A>11),e=this.index[e],e+=A>>5&63,e=((e=this.index[e])<<2)+(31&A),this.data[e];if(A<=1114111)return this.data[this.highValueIndex]}return this.errorValue},o);function o(A,e,t,r,n,B){this.initialValue=A,this.errorValue=e,this.highStart=t,this.highValueIndex=r,this.index=n,this.data=B}function C(A,e,t,r){var n=r[t];if(Array.isArray(A)?-1!==A.indexOf(n):A===n)for(var B=t;B<=r.length;){if((i=r[++B])===e)return!0;if(i!==H)break}if(n===H)for(B=t;0>4,c[i++]=(15&r)<<4|n>>2,c[i++]=(3&n)<<6|63&B;return a}("KwAAAAAAAAAACA4AIDoAAPAfAAACAAAAAAAIABAAGABAAEgAUABYAF4AZgBeAGYAYABoAHAAeABeAGYAfACEAIAAiACQAJgAoACoAK0AtQC9AMUAXgBmAF4AZgBeAGYAzQDVAF4AZgDRANkA3gDmAOwA9AD8AAQBDAEUARoBIgGAAIgAJwEvATcBPwFFAU0BTAFUAVwBZAFsAXMBewGDATAAiwGTAZsBogGkAawBtAG8AcIBygHSAdoB4AHoAfAB+AH+AQYCDgIWAv4BHgImAi4CNgI+AkUCTQJTAlsCYwJrAnECeQKBAk0CiQKRApkCoQKoArACuALAAsQCzAIwANQC3ALkAjAA7AL0AvwCAQMJAxADGAMwACADJgMuAzYDPgOAAEYDSgNSA1IDUgNaA1oDYANiA2IDgACAAGoDgAByA3YDfgOAAIQDgACKA5IDmgOAAIAAogOqA4AAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAK8DtwOAAIAAvwPHA88D1wPfAyAD5wPsA/QD/AOAAIAABAQMBBIEgAAWBB4EJgQuBDMEIAM7BEEEXgBJBCADUQRZBGEEaQQwADAAcQQ+AXkEgQSJBJEEgACYBIAAoASoBK8EtwQwAL8ExQSAAIAAgACAAIAAgACgAM0EXgBeAF4AXgBeAF4AXgBeANUEXgDZBOEEXgDpBPEE+QQBBQkFEQUZBSEFKQUxBTUFPQVFBUwFVAVcBV4AYwVeAGsFcwV7BYMFiwWSBV4AmgWgBacFXgBeAF4AXgBeAKsFXgCyBbEFugW7BcIFwgXIBcIFwgXQBdQF3AXkBesF8wX7BQMGCwYTBhsGIwYrBjMGOwZeAD8GRwZNBl4AVAZbBl4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAGMGXgBqBnEGXgBeAF4AXgBeAF4AXgBeAF4AXgB5BoAG4wSGBo4GkwaAAIADHgR5AF4AXgBeAJsGgABGA4AAowarBrMGswagALsGwwbLBjAA0wbaBtoG3QbaBtoG2gbaBtoG2gblBusG8wb7BgMHCwcTBxsHCwcjBysHMAc1BzUHOgdCB9oGSgdSB1oHYAfaBloHaAfaBlIH2gbaBtoG2gbaBtoG2gbaBjUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHbQdeAF4ANQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQd1B30HNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B4MH2gaKB68EgACAAIAAgACAAIAAgACAAI8HlwdeAJ8HpweAAIAArwe3B14AXgC/B8UHygcwANAH2AfgB4AA6AfwBz4B+AcACFwBCAgPCBcIogEYAR8IJwiAAC8INwg/CCADRwhPCFcIXwhnCEoDGgSAAIAAgABvCHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIhAiLCI4IMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlggwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAANQc1BzUHNQc1BzUHNQc1BzUHNQc1B54INQc1B6II2gaqCLIIugiAAIAAvgjGCIAAgACAAIAAgACAAIAAgACAAIAAywiHAYAA0wiAANkI3QjlCO0I9Aj8CIAAgACAAAIJCgkSCRoJIgknCTYHLwk3CZYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiAAIAAAAFAAXgBeAGAAcABeAHwAQACQAKAArQC9AJ4AXgBeAE0A3gBRAN4A7AD8AMwBGgEAAKcBNwEFAUwBXAF4QkhCmEKnArcCgAHHAsABz4LAAcABwAHAAd+C6ABoAG+C/4LAAcABwAHAAc+DF4MAAcAB54M3gweDV4Nng3eDaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAEeDqABVg6WDqABoQ6gAaABoAHXDvcONw/3DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DncPAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcAB7cPPwlGCU4JMACAAIAAgABWCV4JYQmAAGkJcAl4CXwJgAkwADAAMAAwAIgJgACLCZMJgACZCZ8JowmrCYAAswkwAF4AXgB8AIAAuwkABMMJyQmAAM4JgADVCTAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAqwYWBNkIMAAwADAAMADdCeAJ6AnuCR4E9gkwAP4JBQoNCjAAMACAABUK0wiAAB0KJAosCjQKgAAwADwKQwqAAEsKvQmdCVMKWwowADAAgACAALcEMACAAGMKgABrCjAAMAAwADAAMAAwADAAMAAwADAAMAAeBDAAMAAwADAAMAAwADAAMAAwADAAMAAwAIkEPQFzCnoKiQSCCooKkAqJBJgKoAqkCokEGAGsCrQKvArBCjAAMADJCtEKFQHZCuEK/gHpCvEKMAAwADAAMACAAIwE+QowAIAAPwEBCzAAMAAwADAAMACAAAkLEQswAIAAPwEZCyELgAAOCCkLMAAxCzkLMAAwADAAMAAwADAAXgBeAEELMAAwADAAMAAwADAAMAAwAEkLTQtVC4AAXAtkC4AAiQkwADAAMAAwADAAMAAwADAAbAtxC3kLgAuFC4sLMAAwAJMLlwufCzAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAApwswADAAMACAAIAAgACvC4AAgACAAIAAgACAALcLMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAvwuAAMcLgACAAIAAgACAAIAAyguAAIAAgACAAIAA0QswADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAANkLgACAAIAA4AswADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACJCR4E6AswADAAhwHwC4AA+AsADAgMEAwwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMACAAIAAGAwdDCUMMAAwAC0MNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQw1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHPQwwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADUHNQc1BzUHNQc1BzUHNQc2BzAAMAA5DDUHNQc1BzUHNQc1BzUHNQc1BzUHNQdFDDAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAATQxSDFoMMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAF4AXgBeAF4AXgBeAF4AYgxeAGoMXgBxDHkMfwxeAIUMXgBeAI0MMAAwADAAMAAwAF4AXgCVDJ0MMAAwADAAMABeAF4ApQxeAKsMswy7DF4Awgy9DMoMXgBeAF4AXgBeAF4AXgBeAF4AXgDRDNkMeQBqCeAM3Ax8AOYM7Az0DPgMXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgCgAAANoAAHDQ4NFg0wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAeDSYNMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAC4NMABeAF4ANg0wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAD4NRg1ODVYNXg1mDTAAbQ0wADAAMAAwADAAMAAwADAA2gbaBtoG2gbaBtoG2gbaBnUNeg3CBYANwgWFDdoGjA3aBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gaUDZwNpA2oDdoG2gawDbcNvw3HDdoG2gbPDdYN3A3fDeYN2gbsDfMN2gbaBvoN/g3aBgYODg7aBl4AXgBeABYOXgBeACUG2gYeDl4AJA5eACwO2w3aBtoGMQ45DtoG2gbaBtoGQQ7aBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gZJDjUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B1EO2gY1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQdZDjUHNQc1BzUHNQc1B2EONQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHaA41BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B3AO2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gY1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B2EO2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gZJDtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBkkOeA6gAKAAoAAwADAAMAAwAKAAoACgAKAAoACgAKAAgA4wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAD//wQABAAEAAQABAAEAAQABAAEAA0AAwABAAEAAgAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAKABMAFwAeABsAGgAeABcAFgASAB4AGwAYAA8AGAAcAEsASwBLAEsASwBLAEsASwBLAEsAGAAYAB4AHgAeABMAHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAFgAbABIAHgAeAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABYADQARAB4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAUABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAkAFgAaABsAGwAbAB4AHQAdAB4ATwAXAB4ADQAeAB4AGgAbAE8ATwAOAFAAHQAdAB0ATwBPABcATwBPAE8AFgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AHgAeAB4AUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAFAATwBAAE8ATwBPAEAATwBQAFAATwBQAB4AHgAeAB4AHgAeAB0AHQAdAB0AHgAdAB4ADgBQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgBQAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAJAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAkACQAJAAkACQAJAAkABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAeAB4AHgAeAFAAHgAeAB4AKwArAFAAUABQAFAAGABQACsAKwArACsAHgAeAFAAHgBQAFAAUAArAFAAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAAQABAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAUAAeAB4AHgAeAB4AHgArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwAYAA0AKwArAB4AHgAbACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQADQAEAB4ABAAEAB4ABAAEABMABAArACsAKwArACsAKwArACsAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAKwArACsAKwArAFYAVgBWAB4AHgArACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AGgAaABoAGAAYAB4AHgAEAAQABAAEAAQABAAEAAQABAAEAAQAEwAEACsAEwATAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABLAEsASwBLAEsASwBLAEsASwBLABoAGQAZAB4AUABQAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABMAUAAEAAQABAAEAAQABAAEAB4AHgAEAAQABAAEAAQABABQAFAABAAEAB4ABAAEAAQABABQAFAASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUAAeAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAFAABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQAUABQAB4AHgAYABMAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAFAABAAEAAQABAAEAFAABAAEAAQAUAAEAAQABAAEAAQAKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAArACsAHgArAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAeAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAFAABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAAQABAANAA0ASwBLAEsASwBLAEsASwBLAEsASwAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAKwArACsAUABQAFAAUAArACsABABQAAQABAAEAAQABAAEAAQAKwArAAQABAArACsABAAEAAQAUAArACsAKwArACsAKwArACsABAArACsAKwArAFAAUAArAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwBQAFAAGgAaAFAAUABQAFAAUABMAB4AGwBQAB4AKwArACsABAAEAAQAKwBQAFAAUABQAFAAUAArACsAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUAArAFAAUAArAFAAUAArACsABAArAAQABAAEAAQABAArACsAKwArAAQABAArACsABAAEAAQAKwArACsABAArACsAKwArACsAKwArAFAAUABQAFAAKwBQACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwAEAAQAUABQAFAABAArACsAKwArACsAKwArACsAKwArACsABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUAArAFAAUABQAFAAUAArACsABABQAAQABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQAKwArAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwAeABsAKwArACsAKwArACsAKwBQAAQABAAEAAQABAAEACsABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAKwArAAQABAArACsABAAEAAQAKwArACsAKwArACsAKwArAAQABAArACsAKwArAFAAUAArAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwAeAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwAEAFAAKwBQAFAAUABQAFAAUAArACsAKwBQAFAAUAArAFAAUABQAFAAKwArACsAUABQACsAUAArAFAAUAArACsAKwBQAFAAKwArACsAUABQAFAAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwAEAAQABAAEAAQAKwArACsABAAEAAQAKwAEAAQABAAEACsAKwBQACsAKwArACsAKwArAAQAKwArACsAKwArACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAB4AHgAeAB4AHgAeABsAHgArACsAKwArACsABAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABAArACsAKwArACsAKwArAAQABAArAFAAUABQACsAKwArACsAKwBQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAB4AUAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQACsAKwAEAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABAArACsAKwArACsAKwArAAQABAArACsAKwArACsAKwArAFAAKwBQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABABQAB4AKwArACsAKwBQAFAAUAAEAFAAUABQAFAAUABQAFAAUABQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAFAAUABQAFAAUABQABoAUABQAFAAUABQAFAAKwArAAQABAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQACsAUAArACsAUABQAFAAUABQAFAAUAArACsAKwAEACsAKwArACsABAAEAAQABAAEAAQAKwAEACsABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArAAQABAAeACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqAFwAXAAqACoAKgAqACoAKgAqACsAKwArACsAGwBcAFwAXABcAFwAXABcACoAKgAqACoAKgAqACoAKgAeAEsASwBLAEsASwBLAEsASwBLAEsADQANACsAKwArACsAKwBcAFwAKwBcACsAKwBcAFwAKwBcACsAKwBcACsAKwArACsAKwArAFwAXABcAFwAKwBcAFwAXABcAFwAXABcACsAXABcAFwAKwBcACsAXAArACsAXABcACsAXABcAFwAXAAqAFwAXAAqACoAKgAqACoAKgArACoAKgBcACsAKwBcAFwAXABcAFwAKwBcACsAKgAqACoAKgAqACoAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArAFwAXABcAFwAUAAOAA4ADgAOAB4ADgAOAAkADgAOAA0ACQATABMAEwATABMACQAeABMAHgAeAB4ABAAEAB4AHgAeAB4AHgAeAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAFAAUAANAAQAHgAEAB4ABAAWABEAFgARAAQABABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAANAAQABAAEAAQABAANAAQABABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsADQANAB4AHgAeAB4AHgAeAAQAHgAeAB4AHgAeAB4AKwAeAB4ADgAOAA0ADgAeAB4AHgAeAB4ACQAJACsAKwArACsAKwBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqAFwASwBLAEsASwBLAEsASwBLAEsASwANAA0AHgAeAB4AHgBcAFwAXABcAFwAXAAqACoAKgAqAFwAXABcAFwAKgAqACoAXAAqACoAKgBcAFwAKgAqACoAKgAqACoAKgBcAFwAXAAqACoAKgAqAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgAqACoAXAAqAEsASwBLAEsASwBLAEsASwBLAEsAKgAqACoAKgAqACoAUABQAFAAUABQAFAAKwBQACsAKwArACsAKwBQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAFAAUABQAFAAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQACsAKwBQAFAAUABQAFAAUABQACsAUAArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArACsAUABQAFAAUABQAFAAUAArAFAAKwBQAFAAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwAEAAQABAAeAA0AHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQACsAKwANAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABYAEQArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAADQANAA0AUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAABAAEAAQAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAA0ADQArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsABAAEACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoADQANABUAXAANAB4ADQAbAFwAKgArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArAB4AHgATABMADQANAA4AHgATABMAHgAEAAQABAAJACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAUABQAFAAUABQAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABABQACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwAeACsAKwArABMAEwBLAEsASwBLAEsASwBLAEsASwBLAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcACsAKwBcAFwAXABcAFwAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcACsAKwArACsAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwBcACsAKwArACoAKgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEACsAKwAeAB4AXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgArACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsABABLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAKgAqACoAKgAqACoAKgBcACoAKgAqACoAKgAqACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAUABQAFAAUABQAFAAUAArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsADQANAB4ADQANAA0ADQAeAB4AHgAeAB4AHgAeAB4AHgAeAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArAAQABAAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAUABQAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAHgAeAB4AHgBQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwANAA0ADQANAA0ASwBLAEsASwBLAEsASwBLAEsASwArACsAKwBQAFAAUABLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAANAA0AUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsABAAEAAQAHgAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAFAAUABQAFAABABQAFAAUABQAAQABAAEAFAAUAAEAAQABAArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwAEAAQABAAEAAQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUAArAFAAKwBQACsAUAArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAFAAHgAeAB4AUABQAFAAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAKwArAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAKwAeAB4AHgAeAB4AHgAeAA4AHgArAA0ADQANAA0ADQANAA0ACQANAA0ADQAIAAQACwAEAAQADQAJAA0ADQAMAB0AHQAeABcAFwAWABcAFwAXABYAFwAdAB0AHgAeABQAFAAUAA0AAQABAAQABAAEAAQABAAJABoAGgAaABoAGgAaABoAGgAeABcAFwAdABUAFQAeAB4AHgAeAB4AHgAYABYAEQAVABUAFQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgANAB4ADQANAA0ADQAeAA0ADQANAAcAHgAeAB4AHgArAAQABAAEAAQABAAEAAQABAAEAAQAUABQACsAKwBPAFAAUABQAFAAUAAeAB4AHgAWABEATwBQAE8ATwBPAE8AUABQAFAAUABQAB4AHgAeABYAEQArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAGwAbABsAGwAbABsAGwAaABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAaABsAGwAbABsAGgAbABsAGgAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgBQABoAHgAdAB4AUAAeABoAHgAeAB4AHgAeAB4AHgAeAB4ATwAeAFAAGwAeAB4AUABQAFAAUABQAB4AHgAeAB0AHQAeAFAAHgBQAB4AUAAeAFAATwBQAFAAHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AUABQAFAAUABPAE8AUABQAFAAUABQAE8AUABQAE8AUABPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAFAAUABQAE8ATwBPAE8ATwBPAE8ATwBPAE8AUABQAFAAUABQAFAAUABQAFAAHgAeAFAAUABQAFAATwAeAB4AKwArACsAKwAdAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAeAB0AHQAeAB4AHgAdAB0AHgAeAB0AHgAeAB4AHQAeAB0AGwAbAB4AHQAeAB4AHgAeAB0AHgAeAB0AHQAdAB0AHgAeAB0AHgAdAB4AHQAdAB0AHQAdAB0AHgAdAB4AHgAeAB4AHgAdAB0AHQAdAB4AHgAeAB4AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAeAB4AHgAdAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB4AHgAdAB0AHQAdAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHQAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAWABEAFgARAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAlACUAHgAeAB4AHgAeAB4AHgAeAB4AFgARAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB0AHQAeAB4AHgAeAB0AHQAdAB4AHgAdAB4AHgAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAeAB0AHQAeAB4AHQAeAB4AHgAeAB0AHQAeAB4AHgAeACUAJQAdAB0AJQAeACUAJQAlACAAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAHgAeAB4AHgAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB4AHQAdAB0AHgAdACUAHQAdAB4AHQAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAHQAdAB0AHQAlAB4AJQAlACUAHQAlACUAHQAdAB0AJQAlAB0AHQAlAB0AHQAlACUAJQAeAB0AHgAeAB4AHgAdAB0AJQAdAB0AHQAdAB0AHQAlACUAJQAlACUAHQAlACUAIAAlAB0AHQAlACUAJQAlACUAJQAlACUAHgAeAB4AJQAlACAAIAAgACAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeABcAFwAXABcAFwAXAB4AEwATACUAHgAeAB4AFgARABYAEQAWABEAFgARABYAEQAWABEAFgARAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAWABEAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFgARABYAEQAWABEAFgARABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABYAEQAWABEAFgARABYAEQAWABEAFgARABYAEQAWABEAFgARABYAEQAWABEAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFgARABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAEAAQABAAeAB4AKwArACsAKwArABMADQANAA0AUAATAA0AUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUAANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQACsAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAA0ADQANAA0ADQANAA0ADQAeAA0AFgANAB4AHgAXABcAHgAeABcAFwAWABEAFgARABYAEQAWABEADQANAA0ADQATAFAADQANAB4ADQANAB4AHgAeAB4AHgAMAAwADQANAA0AHgANAA0AFgANAA0ADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAKwArACsAKwArACsAKwArACsAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArAA0AEQARACUAJQBHAFcAVwAWABEAFgARABYAEQAWABEAFgARACUAJQAWABEAFgARABYAEQAWABEAFQAWABEAEQAlAFcAVwBXAFcAVwBXAFcAVwBXAAQABAAEAAQABAAEACUAVwBXAFcAVwA2ACUAJQBXAFcAVwBHAEcAJQAlACUAKwBRAFcAUQBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFEAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBRAFcAUQBXAFEAVwBXAFcAVwBXAFcAUQBXAFcAVwBXAFcAVwBRAFEAKwArAAQABAAVABUARwBHAFcAFQBRAFcAUQBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBRAFcAVwBXAFcAVwBXAFEAUQBXAFcAVwBXABUAUQBHAEcAVwArACsAKwArACsAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwArACUAJQBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAKwArACUAJQAlACUAKwArACsAKwArACsAKwArACsAKwArACsAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAVwBXAFcAVwBXAFcAVwBXAFcAVwAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAE8ATwBPAE8ATwBPAE8ATwAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAEcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAADQATAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABLAEsASwBLAEsASwBLAEsASwBLAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAABAAEAAQABAAeAAQABAAEAAQABAAEAAQABAAEAAQAHgBQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AUABQAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAeAA0ADQANAA0ADQArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AHgAeAB4AHgAeAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAAQAUABQAFAABABQAFAAUABQAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAeAB4AHgAeACsAKwArACsAUABQAFAAUABQAFAAHgAeABoAHgArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAADgAOABMAEwArACsAKwArACsAKwArACsABAAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwANAA0ASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUAAeAB4AHgBQAA4AUAArACsAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAA0ADQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwArACsAKwArACsAKwArAB4AWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYACsAKwArAAQAHgAeAB4AHgAeAB4ADQANAA0AHgAeAB4AHgArAFAASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArAB4AHgBcAFwAXABcAFwAKgBcAFwAXABcAFwAXABcAFwAXABcAEsASwBLAEsASwBLAEsASwBLAEsAXABcAFwAXABcACsAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArAFAAUABQAAQAUABQAFAAUABQAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAHgANAA0ADQBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAXAAqACoAKgBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqAFwAKgAqACoAXABcACoAKgBcAFwAXABcAFwAKgAqAFwAKgBcACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcACoAKgBQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAA0ADQBQAFAAUAAEAAQAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAArACsAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQADQAEAAQAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAVABVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBUAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVACsAKwArACsAKwArACsAKwArACsAKwArAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAKwArACsAKwBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAKwArACsAKwAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAKwArACsAKwArAFYABABWAFYAVgBWAFYAVgBWAFYAVgBWAB4AVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgArAFYAVgBWAFYAVgArAFYAKwBWAFYAKwBWAFYAKwBWAFYAVgBWAFYAVgBWAFYAVgBWAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAEQAWAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUAAaAB4AKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAGAARABEAGAAYABMAEwAWABEAFAArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACUAJQAlACUAJQAWABEAFgARABYAEQAWABEAFgARABYAEQAlACUAFgARACUAJQAlACUAJQAlACUAEQAlABEAKwAVABUAEwATACUAFgARABYAEQAWABEAJQAlACUAJQAlACUAJQAlACsAJQAbABoAJQArACsAKwArAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAcAKwATACUAJQAbABoAJQAlABYAEQAlACUAEQAlABEAJQBXAFcAVwBXAFcAVwBXAFcAVwBXABUAFQAlACUAJQATACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXABYAJQARACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwAWACUAEQAlABYAEQARABYAEQARABUAVwBRAFEAUQBRAFEAUQBRAFEAUQBRAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAEcARwArACsAVwBXAFcAVwBXAFcAKwArAFcAVwBXAFcAVwBXACsAKwBXAFcAVwBXAFcAVwArACsAVwBXAFcAKwArACsAGgAbACUAJQAlABsAGwArAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwAEAAQABAAQAB0AKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsADQANAA0AKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAFAAHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAKwArAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsADQBQAFAAUABQACsAKwArACsAUABQAFAAUABQAFAAUABQAA0AUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAArACsAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQACsAKwArAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AHgBQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsADQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwBQAFAAUABQAFAABAAEAAQAKwAEAAQAKwArACsAKwArAAQABAAEAAQAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsABAAEAAQAKwArACsAKwAEAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsADQANAA0ADQANAA0ADQANAB4AKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AUABQAFAAUABQAFAAUABQAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEACsAKwArACsAUABQAFAAUABQAA0ADQANAA0ADQANABQAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwANAA0ADQANAA0ADQANAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAA0ADQAeAB4AHgAeAB4AKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAeAB4AHgANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsASwBLAEsASwBLAEsASwBLAEsASwANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAeAA4AUAArACsAKwArACsAKwArACsAKwAEAFAAUABQAFAADQANAB4ADQAeAAQABAAEAB4AKwArAEsASwBLAEsASwBLAEsASwBLAEsAUAAOAFAADQANAA0AKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAANAA0AHgANAA0AHgAEACsAUABQAFAAUABQAFAAUAArAFAAKwBQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAA0AKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsABAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArACsAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAArACsABAAEACsAKwAEAAQABAArACsAUAArACsAKwArACsAKwAEACsAKwArACsAKwBQAFAAUABQAFAABAAEACsAKwAEAAQABAAEAAQABAAEACsAKwArAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABABQAFAAUABQAA0ADQANAA0AHgBLAEsASwBLAEsASwBLAEsASwBLACsADQArAB4AKwArAAQABAAEAAQAUABQAB4AUAArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEACsAKwAEAAQABAAEAAQABAAEAAQABAAOAA0ADQATABMAHgAeAB4ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0AUABQAFAAUAAEAAQAKwArAAQADQANAB4AUAArACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAArACsAKwAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAXABcAA0ADQANACoASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwBQAFAABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAFAABAAEAAQABAAOAB4ADQANAA0ADQAOAB4ABAArACsAKwArACsAKwArACsAUAAEAAQABAAEAAQABAAEAAQABAAEAAQAUABQAFAAUAArACsAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAA0ADQANACsADgAOAA4ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEACsABAAEAAQABAAEAAQABAAEAFAADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwAOABMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAArACsAKwAEACsABAAEACsABAAEAAQABAAEAAQABABQAAQAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAASABIAEgAQwBDAEMAUABQAFAAUABDAFAAUABQAEgAQwBIAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAASABDAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABIAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwANAA0AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAQABAAEAAQABAANACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAA0ADQANAB4AHgAeAB4AHgAeAFAAUABQAFAADQAeACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEcARwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwArACsAKwArACsAKwArACsAKwArACsAKwArAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQACsAKwAeAAQABAANAAQABAAEAAQAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAB4AHgAeAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAHgAeAAQABAAEAAQABAAEAAQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAEAAQABAAeACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUAArACsAUAArACsAUABQACsAKwBQAFAAUABQACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwBQACsAUABQAFAAUABQAFAAUAArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwAeAB4AUABQAFAAUABQACsAUAArACsAKwBQAFAAUABQAFAAUABQACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AKwArAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4ABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAEAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAeAB4ADQANAA0ADQAeACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsABAAEAAQABAAEAAQABAArAAQABAArAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAEAAQABAAEAAQABAAEACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAFgAWAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUAArAFAAKwArAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArAFAAKwBQACsAKwArACsAKwArAFAAKwArACsAKwBQACsAUAArAFAAKwBQAFAAUAArAFAAUAArAFAAKwArAFAAKwBQACsAUAArAFAAKwBQACsAUABQACsAUAArACsAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQACsAUABQAFAAUAArAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwBQAFAAUAArAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArACsATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwAlACUAJQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAeACUAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeACUAJQAlACUAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAHgAeACUAJQAlACUAJQAeACUAJQAlACUAJQAgACAAIAAlACUAIAAlACUAIAAgACAAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIQAhACEAIQAhACUAJQAgACAAJQAlACAAIAAgACAAIAAgACAAIAAgACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACAAIAAlACUAJQAlACAAJQAgACAAIAAgACAAIAAgACAAIAAlACUAJQAgACUAJQAlACUAIAAgACAAJQAgACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeACUAHgAlAB4AJQAlACUAJQAlACAAJQAlACUAJQAeACUAHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAHgAeAB4AHgAeAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAIAAgACAAJQAlACUAIAAgACAAIAAgAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFwAXABcAFQAVABUAHgAeAB4AHgAlACUAJQAgACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACAAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAlACAAIAAlACUAJQAlACUAJQAgACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAgACAAIAAgACAAJQAlACUAIAAgACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAKwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArAAQAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsA"),U=Array.isArray(i)?function(A){for(var e=A.length,t=[],r=0;r=this._value.length?-1:this._value[A]},yA.prototype.consumeUnicodeRangeToken=function(){for(var A=[],e=this.consumeCodePoint();aA(e)&&A.length<6;)A.push(e),e=this.consumeCodePoint();for(var t=!1;63===e&&A.length<6;)A.push(e),e=this.consumeCodePoint(),t=!0;if(t){var r=parseInt(l.apply(void 0,A.map(function(A){return 63===A?48:A})),16),n=parseInt(l.apply(void 0,A.map(function(A){return 63===A?70:A})),16);return{type:sA.UNICODE_RANGE_TOKEN,start:r,end:n}}var B=parseInt(l.apply(void 0,A),16);if(45===this.peekCodePoint(0)&&aA(this.peekCodePoint(1))){this.consumeCodePoint(),e=this.consumeCodePoint();for(var s=[];aA(e)&&s.length<6;)s.push(e),e=this.consumeCodePoint();return n=parseInt(l.apply(void 0,s),16),{type:sA.UNICODE_RANGE_TOKEN,start:B,end:n}}return{type:sA.UNICODE_RANGE_TOKEN,start:B,end:B}},yA.prototype.consumeIdentLikeToken=function(){var A=this.consumeName();return"url"===A.toLowerCase()&&40===this.peekCodePoint(0)?(this.consumeCodePoint(),this.consumeUrlToken()):40===this.peekCodePoint(0)?(this.consumeCodePoint(),{type:sA.FUNCTION_TOKEN,value:A}):{type:sA.IDENT_TOKEN,value:A}},yA.prototype.consumeUrlToken=function(){var A=[];if(this.consumeWhiteSpace(),-1===this.peekCodePoint(0))return{type:sA.URL_TOKEN,value:""};var e,t=this.peekCodePoint(0);if(39===t||34===t){var r=this.consumeStringToken(this.consumeCodePoint());return r.type===sA.STRING_TOKEN&&(this.consumeWhiteSpace(),-1===this.peekCodePoint(0)||41===this.peekCodePoint(0))?(this.consumeCodePoint(),{type:sA.URL_TOKEN,value:r.value}):(this.consumeBadUrlRemnants(),IA)}for(;;){var n=this.consumeCodePoint();if(-1===n||41===n)return{type:sA.URL_TOKEN,value:l.apply(void 0,A)};if(cA(n))return this.consumeWhiteSpace(),-1===this.peekCodePoint(0)||41===this.peekCodePoint(0)?(this.consumeCodePoint(),{type:sA.URL_TOKEN,value:l.apply(void 0,A)}):(this.consumeBadUrlRemnants(),IA);if(34===n||39===n||40===n||0<=(e=n)&&e<=8||11===e||14<=e&&e<=31||127===e)return this.consumeBadUrlRemnants(),IA;if(92===n){if(!uA(n,this.peekCodePoint(0)))return this.consumeBadUrlRemnants(),IA;A.push(this.consumeEscapedCodePoint())}else A.push(n)}},yA.prototype.consumeWhiteSpace=function(){for(;cA(this.peekCodePoint(0));)this.consumeCodePoint()},yA.prototype.consumeBadUrlRemnants=function(){for(;;){var A=this.consumeCodePoint();if(41===A||-1===A)return;uA(A,this.peekCodePoint(0))&&this.consumeEscapedCodePoint()}},yA.prototype.consumeStringSlice=function(A){for(var e="";0>8,r=255&A>>16,n=255&A>>24;return e<255?"rgba("+n+","+r+","+t+","+e/255+")":"rgb("+n+","+r+","+t+")"}function re(A,e){if(A.type===sA.NUMBER_TOKEN)return A.number;if(A.type!==sA.PERCENTAGE_TOKEN)return 0;var t=3===e?1:255;return 3===e?A.number/100*t:Math.round(A.number/100*t)}function ne(A){var e=A.filter(kA);if(3===e.length){var t=e.map(re),r=t[0],n=t[1],B=t[2];return ue(r,n,B,1)}if(4!==e.length)return 0;var s=e.map(re),o=(r=s[0],n=s[1],B=s[2],s[3]);return ue(r,n,B,o)}var Be=function(A,e){return e===sA.LEFT_CURLY_BRACKET_TOKEN&&A.type===sA.RIGHT_CURLY_BRACKET_TOKEN||(e===sA.LEFT_SQUARE_BRACKET_TOKEN&&A.type===sA.RIGHT_SQUARE_BRACKET_TOKEN||e===sA.LEFT_PARENTHESIS_TOKEN&&A.type===sA.RIGHT_PARENTHESIS_TOKEN)},se={type:sA.NUMBER_TOKEN,number:0,flags:4},oe={type:sA.PERCENTAGE_TOKEN,number:50,flags:4},ie={type:sA.PERCENTAGE_TOKEN,number:100,flags:4},ae=function(A,e){if(A.type===sA.PERCENTAGE_TOKEN)return A.number/100*e;if(xA(A))switch(A.unit){case"rem":case"em":return 16*A.number;case"px":default:return A.number}return A.number},ce=function(A){if(A.type===sA.DIMENSION_TOKEN)switch(A.unit){case"deg":return Math.PI*A.number/180;case"grad":return Math.PI/200*A.number;case"rad":return A.number;case"turn":return 2*Math.PI*A.number}throw new Error("Unsupported angle type")},Qe=function(A){return Math.PI*A/180},we=function(A){if(A.type===sA.FUNCTION){var e=he[A.name];if(void 0===e)throw new Error('Attempting to parse an unsupported color function "'+A.name+'"');return e(A.values)}if(A.type===sA.HASH_TOKEN){if(3===A.value.length){var t=A.value.substring(0,1),r=A.value.substring(1,2),n=A.value.substring(2,3);return ue(parseInt(t+t,16),parseInt(r+r,16),parseInt(n+n,16),1)}if(4===A.value.length){t=A.value.substring(0,1),r=A.value.substring(1,2),n=A.value.substring(2,3);var B=A.value.substring(3,4);return ue(parseInt(t+t,16),parseInt(r+r,16),parseInt(n+n,16),parseInt(B+B,16)/255)}if(6===A.value.length){t=A.value.substring(0,2),r=A.value.substring(2,4),n=A.value.substring(4,6);return ue(parseInt(t,16),parseInt(r,16),parseInt(n,16),1)}if(8===A.value.length){t=A.value.substring(0,2),r=A.value.substring(2,4),n=A.value.substring(4,6),B=A.value.substring(6,8);return ue(parseInt(t,16),parseInt(r,16),parseInt(n,16),parseInt(B,16)/255)}}if(A.type===sA.IDENT_TOKEN){var s=He[A.value.toUpperCase()];if(void 0!==s)return s}return He.TRANSPARENT},ue=function(A,e,t,r){return(A<<24|e<<16|t<<8|Math.round(255*r)<<0)>>>0};function Ue(A,e,t){return t<0&&(t+=1),1<=t&&(t-=1),t<1/6?(e-A)*t*6+A:t<.5?e:t<2/3?6*(e-A)*(2/3-t)+A:A}function le(A){var e=A.filter(kA),t=e[0],r=e[1],n=e[2],B=e[3],s=(t.type===sA.NUMBER_TOKEN?Qe(t.number):ce(t))/(2*Math.PI),o=qA(r)?r.number/100:0,i=qA(n)?n.number/100:0,a=void 0!==B&&qA(B)?ae(B,1):1;if(0==o)return ue(255*i,255*i,255*i,1);var c=i<=.5?i*(1+o):i+o-i*o,Q=2*i-c,w=Ue(Q,c,s+1/3),u=Ue(Q,c,s),U=Ue(Q,c,s-1/3);return ue(255*w,255*u,255*U,a)}var Ce,ge,Ee,Fe,he={hsl:le,hsla:le,rgb:ne,rgba:ne},He={ALICEBLUE:4042850303,ANTIQUEWHITE:4209760255,AQUA:16777215,AQUAMARINE:2147472639,AZURE:4043309055,BEIGE:4126530815,BISQUE:4293182719,BLACK:255,BLANCHEDALMOND:4293643775,BLUE:65535,BLUEVIOLET:2318131967,BROWN:2771004159,BURLYWOOD:3736635391,CADETBLUE:1604231423,CHARTREUSE:2147418367,CHOCOLATE:3530104575,CORAL:4286533887,CORNFLOWERBLUE:1687547391,CORNSILK:4294499583,CRIMSON:3692313855,CYAN:16777215,DARKBLUE:35839,DARKCYAN:9145343,DARKGOLDENROD:3095837695,DARKGRAY:2846468607,DARKGREEN:6553855,DARKGREY:2846468607,DARKKHAKI:3182914559,DARKMAGENTA:2332068863,DARKOLIVEGREEN:1433087999,DARKORANGE:4287365375,DARKORCHID:2570243327,DARKRED:2332033279,DARKSALMON:3918953215,DARKSEAGREEN:2411499519,DARKSLATEBLUE:1211993087,DARKSLATEGRAY:793726975,DARKSLATEGREY:793726975,DARKTURQUOISE:13554175,DARKVIOLET:2483082239,DEEPPINK:4279538687,DEEPSKYBLUE:12582911,DIMGRAY:1768516095,DIMGREY:1768516095,DODGERBLUE:512819199,FIREBRICK:2988581631,FLORALWHITE:4294635775,FORESTGREEN:579543807,FUCHSIA:4278255615,GAINSBORO:3705462015,GHOSTWHITE:4177068031,GOLD:4292280575,GOLDENROD:3668254975,GRAY:2155905279,GREEN:8388863,GREENYELLOW:2919182335,GREY:2155905279,HONEYDEW:4043305215,HOTPINK:4285117695,INDIANRED:3445382399,INDIGO:1258324735,IVORY:4294963455,KHAKI:4041641215,LAVENDER:3873897215,LAVENDERBLUSH:4293981695,LAWNGREEN:2096890111,LEMONCHIFFON:4294626815,LIGHTBLUE:2916673279,LIGHTCORAL:4034953471,LIGHTCYAN:3774873599,LIGHTGOLDENRODYELLOW:4210742015,LIGHTGRAY:3553874943,LIGHTGREEN:2431553791,LIGHTGREY:3553874943,LIGHTPINK:4290167295,LIGHTSALMON:4288707327,LIGHTSEAGREEN:548580095,LIGHTSKYBLUE:2278488831,LIGHTSLATEGRAY:2005441023,LIGHTSLATEGREY:2005441023,LIGHTSTEELBLUE:2965692159,LIGHTYELLOW:4294959359,LIME:16711935,LIMEGREEN:852308735,LINEN:4210091775,MAGENTA:4278255615,MAROON:2147483903,MEDIUMAQUAMARINE:1724754687,MEDIUMBLUE:52735,MEDIUMORCHID:3126187007,MEDIUMPURPLE:2473647103,MEDIUMSEAGREEN:1018393087,MEDIUMSLATEBLUE:2070474495,MEDIUMSPRINGGREEN:16423679,MEDIUMTURQUOISE:1221709055,MEDIUMVIOLETRED:3340076543,MIDNIGHTBLUE:421097727,MINTCREAM:4127193855,MISTYROSE:4293190143,MOCCASIN:4293178879,NAVAJOWHITE:4292783615,NAVY:33023,OLDLACE:4260751103,OLIVE:2155872511,OLIVEDRAB:1804477439,ORANGE:4289003775,ORANGERED:4282712319,ORCHID:3664828159,PALEGOLDENROD:4008225535,PALEGREEN:2566625535,PALETURQUOISE:2951671551,PALEVIOLETRED:3681588223,PAPAYAWHIP:4293907967,PEACHPUFF:4292524543,PERU:3448061951,PINK:4290825215,PLUM:3718307327,POWDERBLUE:2967529215,PURPLE:2147516671,REBECCAPURPLE:1714657791,RED:4278190335,ROSYBROWN:3163525119,ROYALBLUE:1097458175,SADDLEBROWN:2336560127,SALMON:4202722047,SANDYBROWN:4104413439,SEAGREEN:780883967,SEASHELL:4294307583,SIENNA:2689740287,SILVER:3233857791,SKYBLUE:2278484991,SLATEBLUE:1784335871,SLATEGRAY:1887473919,SLATEGREY:1887473919,SNOW:4294638335,SPRINGGREEN:16744447,STEELBLUE:1182971135,TAN:3535047935,TEAL:8421631,THISTLE:3636451583,TOMATO:4284696575,TRANSPARENT:0,TURQUOISE:1088475391,VIOLET:4001558271,WHEAT:4125012991,WHITE:4294967295,WHITESMOKE:4126537215,YELLOW:4294902015,YELLOWGREEN:2597139199};(ge=Ce||(Ce={}))[ge.VALUE=0]="VALUE",ge[ge.LIST=1]="LIST",ge[ge.IDENT_VALUE=2]="IDENT_VALUE",ge[ge.TYPE_VALUE=3]="TYPE_VALUE",ge[ge.TOKEN_VALUE=4]="TOKEN_VALUE",(Fe=Ee||(Ee={}))[Fe.BORDER_BOX=0]="BORDER_BOX",Fe[Fe.PADDING_BOX=1]="PADDING_BOX";function de(A){var e=we(A[0]),t=A[1];return t&&qA(t)?{color:e,stop:t}:{color:e,stop:null}}function fe(A,t){var e=A[0],r=A[A.length-1];null===e.stop&&(e.stop=se),null===r.stop&&(r.stop=ie);for(var n=[],B=0,s=0;sA.optimumDistance)?{optimumCorner:e,optimumDistance:n}:A},{optimumDistance:o?1/0:-1/0,optimumCorner:null}).optimumCorner}function Ie(A){var n=Qe(180),B=[];return WA(A).forEach(function(A,e){if(0===e){var t=A[0];if(t.type===sA.IDENT_TOKEN&&-1!==["top","left","right","bottom"].indexOf(t.value))return void(n=Ae(A));if($A(t))return void(n=(ce(t)+Qe(270))%Qe(360))}var r=de(A);B.push(r)}),{angle:n,stops:B,type:xe.LINEAR_GRADIENT}}function Te(A){return 0===A[0]&&255===A[1]&&0===A[2]&&255===A[3]}var me={name:"background-clip",initialValue:"border-box",prefix:!(Fe[Fe.CONTENT_BOX=2]="CONTENT_BOX"),type:Ce.LIST,parse:function(A){return A.map(function(A){if(zA(A))switch(A.value){case"padding-box":return Ee.PADDING_BOX;case"content-box":return Ee.CONTENT_BOX}return Ee.BORDER_BOX})}},Re={name:"background-color",initialValue:"transparent",prefix:!1,type:Ce.TYPE_VALUE,format:"color"},Le=function(A,e,t,r,n){var B="http://www.w3.org/2000/svg",s=document.createElementNS(B,"svg"),o=document.createElementNS(B,"foreignObject");return s.setAttributeNS(null,"width",A.toString()),s.setAttributeNS(null,"height",e.toString()),o.setAttributeNS(null,"width","100%"),o.setAttributeNS(null,"height","100%"),o.setAttributeNS(null,"x",t.toString()),o.setAttributeNS(null,"y",r.toString()),o.setAttributeNS(null,"externalResourcesRequired","true"),s.appendChild(o),o.appendChild(n),s},ve=function(r){return new Promise(function(A,e){var t=new Image;t.onload=function(){return A(t)},t.onerror=e,t.src="data:image/svg+xml;charset=utf-8,"+encodeURIComponent((new XMLSerializer).serializeToString(r))})},Oe={get SUPPORT_RANGE_BOUNDS(){var A=function(A){if(A.createRange){var e=A.createRange();if(e.getBoundingClientRect){var t=A.createElement("boundtest");t.style.height="123px",t.style.display="block",A.body.appendChild(t),e.selectNode(t);var r=e.getBoundingClientRect(),n=Math.round(r.height);if(A.body.removeChild(t),123===n)return!0}}return!1}(document);return Object.defineProperty(Oe,"SUPPORT_RANGE_BOUNDS",{value:A}),A},get SUPPORT_SVG_DRAWING(){var A=function(A){var e=new Image,t=A.createElement("canvas"),r=t.getContext("2d");if(!r)return!1;e.src="data:image/svg+xml,";try{r.drawImage(e,0,0),t.toDataURL()}catch(A){return!1}return!0}(document);return Object.defineProperty(Oe,"SUPPORT_SVG_DRAWING",{value:A}),A},get SUPPORT_FOREIGNOBJECT_DRAWING(){var A="function"==typeof Array.from&&"function"==typeof window.fetch?function(r){var A=r.createElement("canvas"),n=100;A.width=n,A.height=n;var B=A.getContext("2d");if(!B)return Promise.reject(!1);B.fillStyle="rgb(0, 255, 0)",B.fillRect(0,0,n,n);var e=new Image,s=A.toDataURL();e.src=s;var t=Le(n,n,0,0,e);return B.fillStyle="red",B.fillRect(0,0,n,n),ve(t).then(function(A){B.drawImage(A,0,0);var e=B.getImageData(0,0,n,n).data;B.fillStyle="red",B.fillRect(0,0,n,n);var t=r.createElement("div");return t.style.backgroundImage="url("+s+")",t.style.height="100px",Te(e)?ve(Le(n,n,0,0,t)):Promise.reject(!1)}).then(function(A){return B.drawImage(A,0,0),Te(B.getImageData(0,0,n,n).data)}).catch(function(){return!1})}(document):Promise.resolve(!1);return Object.defineProperty(Oe,"SUPPORT_FOREIGNOBJECT_DRAWING",{value:A}),A},get SUPPORT_CORS_IMAGES(){var A=void 0!==(new Image).crossOrigin;return Object.defineProperty(Oe,"SUPPORT_CORS_IMAGES",{value:A}),A},get SUPPORT_RESPONSE_TYPE(){var A="string"==typeof(new XMLHttpRequest).responseType;return Object.defineProperty(Oe,"SUPPORT_RESPONSE_TYPE",{value:A}),A},get SUPPORT_CORS_XHR(){var A="withCredentials"in new XMLHttpRequest;return Object.defineProperty(Oe,"SUPPORT_CORS_XHR",{value:A}),A}},De=(be.prototype.debug=function(){for(var A=[],e=0;eA.height?new I(A.left+(A.width-A.height)/2,A.top,A.height,A.height):A.width"),WB(this.referenceElement.ownerDocument,n,B),o.replaceChild(o.adoptNode(this.documentElement),o.documentElement),o.close(),i},xB.prototype.createElementClone=function(A){if(FB(A))return this.createCanvasClone(A);if(rB(A))return this.createStyleClone(A);var e=A.cloneNode(!1);return hB(e)&&"lazy"===e.loading&&(e.loading="eager"),e},xB.prototype.createStyleClone=function(A){try{var e=A.sheet;if(e&&e.cssRules){var t=[].slice.call(e.cssRules,0).reduce(function(A,e){return e&&"string"==typeof e.cssText?A+e.cssText:A},""),r=A.cloneNode(!1);return r.textContent=t,r}}catch(A){if(De.getInstance(this.options.id).error("Unable to access cssRules property",A),"SecurityError"!==A.name)throw A}return A.cloneNode(!1)},xB.prototype.createCanvasClone=function(A){if(this.options.inlineImages&&A.ownerDocument){var e=A.ownerDocument.createElement("img");try{return e.src=A.toDataURL(),e}catch(A){De.getInstance(this.options.id).info("Unable to clone canvas contents, canvas is tainted")}}var t=A.cloneNode(!1);try{t.width=A.width,t.height=A.height;var r=A.getContext("2d"),n=t.getContext("2d");return n&&(r?n.putImageData(r.getImageData(0,0,A.width,A.height),0,0):n.drawImage(A,0,0)),t}catch(A){}return t},xB.prototype.cloneNode=function(A){if(cB(A))return document.createTextNode(A.data);if(!A.ownerDocument)return A.cloneNode(!1);var e=A.ownerDocument.defaultView;if(e&&QB(A)&&(wB(A)||uB(A))){var t=this.createElementClone(A),r=e.getComputedStyle(A),n=e.getComputedStyle(A,":before"),B=e.getComputedStyle(A,":after");this.referenceElement===A&&wB(t)&&(this.clonedReferenceElement=t),EB(t)&&$B(t);for(var s=this.counters.parse(new wn(r)),o=this.resolvePseudoContent(A,t,n,LB.BEFORE),i=A.firstChild;i;i=i.nextSibling)QB(i)&&("SCRIPT"===i.tagName||i.hasAttribute(_B)||"function"==typeof this.options.ignoreElements&&this.options.ignoreElements(i))||this.options.copyStyles&&QB(i)&&rB(i)||t.appendChild(this.cloneNode(i));o&&t.insertBefore(o,t.firstChild);var a=this.resolvePseudoContent(A,t,B,LB.AFTER);return a&&t.appendChild(a),this.counters.pop(s),r&&(this.options.copyStyles||uB(A))&&!HB(A)&&GB(r,t),0===A.scrollTop&&0===A.scrollLeft||this.scrolledElements.push([t,A.scrollLeft,A.scrollTop]),(dB(A)||fB(A))&&(dB(t)||fB(t))&&(t.value=A.value),t}return A.cloneNode(!1)},xB.prototype.resolvePseudoContent=function(U,A,e,t){var l=this;if(e){var r=e.content,C=A.ownerDocument;if(C&&r&&"none"!==r&&"-moz-alt-content"!==r&&"none"!==e.display){this.counters.parse(new wn(e));var g=new Qn(e),E=C.createElement("html2canvaspseudoelement");GB(e,E),g.content.forEach(function(A){if(A.type===sA.STRING_TOKEN)E.appendChild(C.createTextNode(A.value));else if(A.type===sA.URL_TOKEN){var e=C.createElement("img");e.src=A.value,e.style.opacity="1",E.appendChild(e)}else if(A.type===sA.FUNCTION){if("attr"===A.name){var t=A.values.filter(zA);t.length&&E.appendChild(C.createTextNode(U.getAttribute(t[0].value)||""))}else if("counter"===A.name){var r=A.values.filter(kA),n=r[0],B=r[1];if(n&&zA(n)){var s=l.counters.getCounterValue(n.value),o=B&&zA(B)?ir.parse(B.value):tr.DECIMAL;E.appendChild(C.createTextNode(yB(s,o,!1)))}}else if("counters"===A.name){var i=A.values.filter(kA),a=(n=i[0],i[1]);if(B=i[2],n&&zA(n)){var c=l.counters.getCounterValues(n.value),Q=B&&zA(B)?ir.parse(B.value):tr.DECIMAL,w=a&&a.type===sA.STRING_TOKEN?a.value:"",u=c.map(function(A){return yB(A,Q,!1)}).join(w);E.appendChild(C.createTextNode(u))}}}else if(A.type===sA.IDENT_TOKEN)switch(A.value){case"open-quote":E.appendChild(C.createTextNode(An(g.quotes,l.quoteDepth++,!0)));break;case"close-quote":E.appendChild(C.createTextNode(An(g.quotes,--l.quoteDepth,!1)));break;default:E.appendChild(C.createTextNode(A.value))}}),E.className=qB+" "+ZB;var n=t===LB.BEFORE?" "+qB:" "+ZB;return uB(A)?A.className.baseValue+=n:A.className+=n,E}}},xB.destroy=function(A){return!!A.parentNode&&(A.parentNode.removeChild(A),!0)},xB);function xB(A,e){if(this.options=e,this.scrolledElements=[],this.referenceElement=A,this.counters=new pB,this.quoteDepth=0,!A.ownerDocument)throw new Error("Cloned element does not have an owner document");this.documentElement=this.cloneNode(A.ownerDocument.documentElement)}(vB=LB||(LB={}))[vB.BEFORE=0]="BEFORE",vB[vB.AFTER=1]="AFTER";var VB,zB,XB=function(A,e){var t=A.createElement("iframe");return t.className="html2canvas-container",t.style.visibility="hidden",t.style.position="fixed",t.style.left="-10000px",t.style.top="0px",t.style.border="0",t.width=e.width.toString(),t.height=e.height.toString(),t.scrolling="no",t.setAttribute(_B,"true"),A.body.appendChild(t),t},JB=function(n){return new Promise(function(e,A){var t=n.contentWindow;if(!t)return A("No window assigned for iframe");var r=t.document;t.onload=n.onload=r.onreadystatechange=function(){t.onload=n.onload=r.onreadystatechange=null;var A=setInterval(function(){0"),e},WB=function(A,e,t){A&&A.defaultView&&(e!==A.defaultView.pageXOffset||t!==A.defaultView.pageYOffset)&&A.defaultView.scrollTo(e,t)},YB=function(A){var e=A[0],t=A[1],r=A[2];e.scrollLeft=t,e.scrollTop=r},qB="___html2canvas___pseudoelement_before",ZB="___html2canvas___pseudoelement_after",jB='{\n content: "" !important;\n display: none !important;\n}',$B=function(A){As(A,"."+qB+":before"+jB+"\n ."+ZB+":after"+jB)},As=function(A,e){var t=A.ownerDocument;if(t){var r=t.createElement("style");r.textContent=e,A.appendChild(r)}};(zB=VB||(VB={}))[zB.VECTOR=0]="VECTOR",zB[zB.BEZIER_CURVE=1]="BEZIER_CURVE";function es(A,t){return A.length===t.length&&A.some(function(A,e){return A===t[e]})}var ts=(rs.prototype.add=function(A,e){return new rs(this.x+A,this.y+e)},rs);function rs(A,e){this.type=VB.VECTOR,this.x=A,this.y=e}function ns(A,e,t){return new ts(A.x+(e.x-A.x)*t,A.y+(e.y-A.y)*t)}var Bs=(ss.prototype.subdivide=function(A,e){var t=ns(this.start,this.startControl,A),r=ns(this.startControl,this.endControl,A),n=ns(this.endControl,this.end,A),B=ns(t,r,A),s=ns(r,n,A),o=ns(B,s,A);return e?new ss(this.start,t,B,o):new ss(o,s,n,this.end)},ss.prototype.add=function(A,e){return new ss(this.start.add(A,e),this.startControl.add(A,e),this.endControl.add(A,e),this.end.add(A,e))},ss.prototype.reverse=function(){return new ss(this.end,this.endControl,this.startControl,this.start)},ss);function ss(A,e,t,r){this.type=VB.BEZIER_CURVE,this.start=A,this.startControl=e,this.endControl=t,this.end=r}function os(A){return A.type===VB.BEZIER_CURVE}var is,as,cs=function(A){var e=A.styles,t=A.bounds,r=jA(e.borderTopLeftRadius,t.width,t.height),n=r[0],B=r[1],s=jA(e.borderTopRightRadius,t.width,t.height),o=s[0],i=s[1],a=jA(e.borderBottomRightRadius,t.width,t.height),c=a[0],Q=a[1],w=jA(e.borderBottomLeftRadius,t.width,t.height),u=w[0],U=w[1],l=[];l.push((n+o)/t.width),l.push((u+c)/t.width),l.push((B+U)/t.height),l.push((i+Q)/t.height);var C=Math.max.apply(Math,l);1t.width+p?0:o-p,i-H,is.TOP_RIGHT):new ts(t.left+t.width-d,t.top+H),this.bottomRightPaddingBox=0t.width+p+T?0:o-p+T,i-(H+N),is.TOP_RIGHT):new ts(t.left+t.width-(d+K),t.top+H+N),this.bottomRightContentBox=0A.element.container.styles.zIndex.order?(i=e,!1):0=A.element.container.styles.zIndex.order?(a=e+1,!1):0s[0]&&e[1]>10),s%1024+56320)),(n+1===t||16384>5])<<2)+(31&A),this.data[e];if(A<=65535)return e=((e=this.index[2048+(A-55296>>5)])<<2)+(31&A),this.data[e];if(A>11),e=this.index[e],e+=A>>5&63,e=((e=this.index[e])<<2)+(31&A),this.data[e];if(A<=1114111)return this.data[this.highValueIndex]}return this.errorValue},o);function o(A,e,t,r,n,B){this.initialValue=A,this.errorValue=e,this.highStart=t,this.highValueIndex=r,this.index=n,this.data=B}function C(A,e,t,r){var n=r[t];if(Array.isArray(A)?-1!==A.indexOf(n):A===n)for(var B=t;B<=r.length;){if((i=r[++B])===e)return!0;if(i!==H)break}if(n===H)for(B=t;0>4,c[i++]=(15&r)<<4|n>>2,c[i++]=(3&n)<<6|63&B;return a}("KwAAAAAAAAAACA4AIDoAAPAfAAACAAAAAAAIABAAGABAAEgAUABYAF4AZgBeAGYAYABoAHAAeABeAGYAfACEAIAAiACQAJgAoACoAK0AtQC9AMUAXgBmAF4AZgBeAGYAzQDVAF4AZgDRANkA3gDmAOwA9AD8AAQBDAEUARoBIgGAAIgAJwEvATcBPwFFAU0BTAFUAVwBZAFsAXMBewGDATAAiwGTAZsBogGkAawBtAG8AcIBygHSAdoB4AHoAfAB+AH+AQYCDgIWAv4BHgImAi4CNgI+AkUCTQJTAlsCYwJrAnECeQKBAk0CiQKRApkCoQKoArACuALAAsQCzAIwANQC3ALkAjAA7AL0AvwCAQMJAxADGAMwACADJgMuAzYDPgOAAEYDSgNSA1IDUgNaA1oDYANiA2IDgACAAGoDgAByA3YDfgOAAIQDgACKA5IDmgOAAIAAogOqA4AAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAK8DtwOAAIAAvwPHA88D1wPfAyAD5wPsA/QD/AOAAIAABAQMBBIEgAAWBB4EJgQuBDMEIAM7BEEEXgBJBCADUQRZBGEEaQQwADAAcQQ+AXkEgQSJBJEEgACYBIAAoASoBK8EtwQwAL8ExQSAAIAAgACAAIAAgACgAM0EXgBeAF4AXgBeAF4AXgBeANUEXgDZBOEEXgDpBPEE+QQBBQkFEQUZBSEFKQUxBTUFPQVFBUwFVAVcBV4AYwVeAGsFcwV7BYMFiwWSBV4AmgWgBacFXgBeAF4AXgBeAKsFXgCyBbEFugW7BcIFwgXIBcIFwgXQBdQF3AXkBesF8wX7BQMGCwYTBhsGIwYrBjMGOwZeAD8GRwZNBl4AVAZbBl4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAGMGXgBqBnEGXgBeAF4AXgBeAF4AXgBeAF4AXgB5BoAG4wSGBo4GkwaAAIADHgR5AF4AXgBeAJsGgABGA4AAowarBrMGswagALsGwwbLBjAA0wbaBtoG3QbaBtoG2gbaBtoG2gblBusG8wb7BgMHCwcTBxsHCwcjBysHMAc1BzUHOgdCB9oGSgdSB1oHYAfaBloHaAfaBlIH2gbaBtoG2gbaBtoG2gbaBjUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHbQdeAF4ANQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQd1B30HNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B4MH2gaKB68EgACAAIAAgACAAIAAgACAAI8HlwdeAJ8HpweAAIAArwe3B14AXgC/B8UHygcwANAH2AfgB4AA6AfwBz4B+AcACFwBCAgPCBcIogEYAR8IJwiAAC8INwg/CCADRwhPCFcIXwhnCEoDGgSAAIAAgABvCHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIfQh3CHgIeQh6CHsIfAh9CHcIeAh5CHoIewh8CH0Idwh4CHkIegh7CHwIhAiLCI4IMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlggwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAANQc1BzUHNQc1BzUHNQc1BzUHNQc1B54INQc1B6II2gaqCLIIugiAAIAAvgjGCIAAgACAAIAAgACAAIAAgACAAIAAywiHAYAA0wiAANkI3QjlCO0I9Aj8CIAAgACAAAIJCgkSCRoJIgknCTYHLwk3CZYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiWCJYIlgiAAIAAAAFAAXgBeAGAAcABeAHwAQACQAKAArQC9AJ4AXgBeAE0A3gBRAN4A7AD8AMwBGgEAAKcBNwEFAUwBXAF4QkhCmEKnArcCgAHHAsABz4LAAcABwAHAAd+C6ABoAG+C/4LAAcABwAHAAc+DF4MAAcAB54M3gweDV4Nng3eDaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAGgAaABoAEeDqABVg6WDqABoQ6gAaABoAHXDvcONw/3DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DvcO9w73DncPAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcABwAHAAcAB7cPPwlGCU4JMACAAIAAgABWCV4JYQmAAGkJcAl4CXwJgAkwADAAMAAwAIgJgACLCZMJgACZCZ8JowmrCYAAswkwAF4AXgB8AIAAuwkABMMJyQmAAM4JgADVCTAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAqwYWBNkIMAAwADAAMADdCeAJ6AnuCR4E9gkwAP4JBQoNCjAAMACAABUK0wiAAB0KJAosCjQKgAAwADwKQwqAAEsKvQmdCVMKWwowADAAgACAALcEMACAAGMKgABrCjAAMAAwADAAMAAwADAAMAAwADAAMAAeBDAAMAAwADAAMAAwADAAMAAwADAAMAAwAIkEPQFzCnoKiQSCCooKkAqJBJgKoAqkCokEGAGsCrQKvArBCjAAMADJCtEKFQHZCuEK/gHpCvEKMAAwADAAMACAAIwE+QowAIAAPwEBCzAAMAAwADAAMACAAAkLEQswAIAAPwEZCyELgAAOCCkLMAAxCzkLMAAwADAAMAAwADAAXgBeAEELMAAwADAAMAAwADAAMAAwAEkLTQtVC4AAXAtkC4AAiQkwADAAMAAwADAAMAAwADAAbAtxC3kLgAuFC4sLMAAwAJMLlwufCzAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAApwswADAAMACAAIAAgACvC4AAgACAAIAAgACAALcLMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAvwuAAMcLgACAAIAAgACAAIAAyguAAIAAgACAAIAA0QswADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAANkLgACAAIAA4AswADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAIAAgACJCR4E6AswADAAhwHwC4AA+AsADAgMEAwwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMACAAIAAGAwdDCUMMAAwAC0MNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQw1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHPQwwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADUHNQc1BzUHNQc1BzUHNQc2BzAAMAA5DDUHNQc1BzUHNQc1BzUHNQc1BzUHNQdFDDAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAgACAAIAATQxSDFoMMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAF4AXgBeAF4AXgBeAF4AYgxeAGoMXgBxDHkMfwxeAIUMXgBeAI0MMAAwADAAMAAwAF4AXgCVDJ0MMAAwADAAMABeAF4ApQxeAKsMswy7DF4Awgy9DMoMXgBeAF4AXgBeAF4AXgBeAF4AXgDRDNkMeQBqCeAM3Ax8AOYM7Az0DPgMXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgBeAF4AXgCgAAANoAAHDQ4NFg0wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAeDSYNMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAIAAgACAAIAAgACAAC4NMABeAF4ANg0wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwAD4NRg1ODVYNXg1mDTAAbQ0wADAAMAAwADAAMAAwADAA2gbaBtoG2gbaBtoG2gbaBnUNeg3CBYANwgWFDdoGjA3aBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gaUDZwNpA2oDdoG2gawDbcNvw3HDdoG2gbPDdYN3A3fDeYN2gbsDfMN2gbaBvoN/g3aBgYODg7aBl4AXgBeABYOXgBeACUG2gYeDl4AJA5eACwO2w3aBtoGMQ45DtoG2gbaBtoGQQ7aBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gZJDjUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B1EO2gY1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQdZDjUHNQc1BzUHNQc1B2EONQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHaA41BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B3AO2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gY1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1BzUHNQc1B2EO2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gZJDtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBtoG2gbaBkkOeA6gAKAAoAAwADAAMAAwAKAAoACgAKAAoACgAKAAgA4wADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAAwADAAMAD//wQABAAEAAQABAAEAAQABAAEAA0AAwABAAEAAgAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAKABMAFwAeABsAGgAeABcAFgASAB4AGwAYAA8AGAAcAEsASwBLAEsASwBLAEsASwBLAEsAGAAYAB4AHgAeABMAHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAFgAbABIAHgAeAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABYADQARAB4ABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAUABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAkAFgAaABsAGwAbAB4AHQAdAB4ATwAXAB4ADQAeAB4AGgAbAE8ATwAOAFAAHQAdAB0ATwBPABcATwBPAE8AFgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AHgAeAB4AUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAFAATwBAAE8ATwBPAEAATwBQAFAATwBQAB4AHgAeAB4AHgAeAB0AHQAdAB0AHgAdAB4ADgBQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgBQAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAJAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAkACQAJAAkACQAJAAkABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAeAB4AHgAeAFAAHgAeAB4AKwArAFAAUABQAFAAGABQACsAKwArACsAHgAeAFAAHgBQAFAAUAArAFAAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAAQABAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAUAAeAB4AHgAeAB4AHgArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwAYAA0AKwArAB4AHgAbACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQADQAEAB4ABAAEAB4ABAAEABMABAArACsAKwArACsAKwArACsAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAKwArACsAKwArAFYAVgBWAB4AHgArACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AGgAaABoAGAAYAB4AHgAEAAQABAAEAAQABAAEAAQABAAEAAQAEwAEACsAEwATAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABLAEsASwBLAEsASwBLAEsASwBLABoAGQAZAB4AUABQAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABMAUAAEAAQABAAEAAQABAAEAB4AHgAEAAQABAAEAAQABABQAFAABAAEAB4ABAAEAAQABABQAFAASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUAAeAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAFAABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQAUABQAB4AHgAYABMAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAFAABAAEAAQABAAEAFAABAAEAAQAUAAEAAQABAAEAAQAKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAArACsAHgArAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAeAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAFAABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAAQABAANAA0ASwBLAEsASwBLAEsASwBLAEsASwAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAKwArACsAUABQAFAAUAArACsABABQAAQABAAEAAQABAAEAAQAKwArAAQABAArACsABAAEAAQAUAArACsAKwArACsAKwArACsABAArACsAKwArAFAAUAArAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwBQAFAAGgAaAFAAUABQAFAAUABMAB4AGwBQAB4AKwArACsABAAEAAQAKwBQAFAAUABQAFAAUAArACsAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUAArAFAAUAArAFAAUAArACsABAArAAQABAAEAAQABAArACsAKwArAAQABAArACsABAAEAAQAKwArACsABAArACsAKwArACsAKwArAFAAUABQAFAAKwBQACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwAEAAQAUABQAFAABAArACsAKwArACsAKwArACsAKwArACsABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUAArAFAAUABQAFAAUAArACsABABQAAQABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQAKwArAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwAeABsAKwArACsAKwArACsAKwBQAAQABAAEAAQABAAEACsABAAEAAQAKwBQAFAAUABQAFAAUABQAFAAKwArAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAKwArAAQABAArACsABAAEAAQAKwArACsAKwArACsAKwArAAQABAArACsAKwArAFAAUAArAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwAeAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwAEAFAAKwBQAFAAUABQAFAAUAArACsAKwBQAFAAUAArAFAAUABQAFAAKwArACsAUABQACsAUAArAFAAUAArACsAKwBQAFAAKwArACsAUABQAFAAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwAEAAQABAAEAAQAKwArACsABAAEAAQAKwAEAAQABAAEACsAKwBQACsAKwArACsAKwArAAQAKwArACsAKwArACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAB4AHgAeAB4AHgAeABsAHgArACsAKwArACsABAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABAArACsAKwArACsAKwArAAQABAArAFAAUABQACsAKwArACsAKwBQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAB4AUAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQACsAKwAEAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABAArACsAKwArACsAKwArAAQABAArACsAKwArACsAKwArAFAAKwBQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAFAABAAEAAQABAAEAAQABAArAAQABAAEACsABAAEAAQABABQAB4AKwArACsAKwBQAFAAUAAEAFAAUABQAFAAUABQAFAAUABQAFAABAAEACsAKwBLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAFAAUABQAFAAUABQABoAUABQAFAAUABQAFAAKwArAAQABAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQACsAUAArACsAUABQAFAAUABQAFAAUAArACsAKwAEACsAKwArACsABAAEAAQABAAEAAQAKwAEACsABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArAAQABAAeACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqAFwAXAAqACoAKgAqACoAKgAqACsAKwArACsAGwBcAFwAXABcAFwAXABcACoAKgAqACoAKgAqACoAKgAeAEsASwBLAEsASwBLAEsASwBLAEsADQANACsAKwArACsAKwBcAFwAKwBcACsAKwBcAFwAKwBcACsAKwBcACsAKwArACsAKwArAFwAXABcAFwAKwBcAFwAXABcAFwAXABcACsAXABcAFwAKwBcACsAXAArACsAXABcACsAXABcAFwAXAAqAFwAXAAqACoAKgAqACoAKgArACoAKgBcACsAKwBcAFwAXABcAFwAKwBcACsAKgAqACoAKgAqACoAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArAFwAXABcAFwAUAAOAA4ADgAOAB4ADgAOAAkADgAOAA0ACQATABMAEwATABMACQAeABMAHgAeAB4ABAAEAB4AHgAeAB4AHgAeAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAFAAUAANAAQAHgAEAB4ABAAWABEAFgARAAQABABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAANAAQABAAEAAQABAANAAQABABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsADQANAB4AHgAeAB4AHgAeAAQAHgAeAB4AHgAeAB4AKwAeAB4ADgAOAA0ADgAeAB4AHgAeAB4ACQAJACsAKwArACsAKwBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqAFwASwBLAEsASwBLAEsASwBLAEsASwANAA0AHgAeAB4AHgBcAFwAXABcAFwAXAAqACoAKgAqAFwAXABcAFwAKgAqACoAXAAqACoAKgBcAFwAKgAqACoAKgAqACoAKgBcAFwAXAAqACoAKgAqAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgAqACoAXAAqAEsASwBLAEsASwBLAEsASwBLAEsAKgAqACoAKgAqACoAUABQAFAAUABQAFAAKwBQACsAKwArACsAKwBQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAFAAUABQAFAAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQACsAKwBQAFAAUABQAFAAUABQACsAUAArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArACsAUABQAFAAUABQAFAAUAArAFAAKwBQAFAAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwAEAAQABAAeAA0AHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQACsAKwANAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQABYAEQArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAADQANAA0AUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAABAAEAAQAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAA0ADQArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQACsABAAEACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoADQANABUAXAANAB4ADQAbAFwAKgArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArAB4AHgATABMADQANAA4AHgATABMAHgAEAAQABAAJACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAUABQAFAAUABQAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABABQACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwAeACsAKwArABMAEwBLAEsASwBLAEsASwBLAEsASwBLAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcACsAKwBcAFwAXABcAFwAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcACsAKwArACsAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwBcACsAKwArACoAKgBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEACsAKwAeAB4AXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAKgAqACoAKgAqACoAKgArACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsABABLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAKgAqACoAKgAqACoAKgBcACoAKgAqACoAKgAqACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAUABQAFAAUABQAFAAUAArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsADQANAB4ADQANAA0ADQAeAB4AHgAeAB4AHgAeAB4AHgAeAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArAAQABAAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAUABQAEsASwBLAEsASwBLAEsASwBLAEsAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAHgAeAB4AHgBQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwANAA0ADQANAA0ASwBLAEsASwBLAEsASwBLAEsASwArACsAKwBQAFAAUABLAEsASwBLAEsASwBLAEsASwBLAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAANAA0AUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsABAAEAAQAHgAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAFAAUABQAFAABABQAFAAUABQAAQABAAEAFAAUAAEAAQABAArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwAEAAQABAAEAAQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUAArAFAAKwBQACsAUAArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAFAAHgAeAB4AUABQAFAAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAKwArAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAKwAeAB4AHgAeAB4AHgAeAA4AHgArAA0ADQANAA0ADQANAA0ACQANAA0ADQAIAAQACwAEAAQADQAJAA0ADQAMAB0AHQAeABcAFwAWABcAFwAXABYAFwAdAB0AHgAeABQAFAAUAA0AAQABAAQABAAEAAQABAAJABoAGgAaABoAGgAaABoAGgAeABcAFwAdABUAFQAeAB4AHgAeAB4AHgAYABYAEQAVABUAFQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgANAB4ADQANAA0ADQAeAA0ADQANAAcAHgAeAB4AHgArAAQABAAEAAQABAAEAAQABAAEAAQAUABQACsAKwBPAFAAUABQAFAAUAAeAB4AHgAWABEATwBQAE8ATwBPAE8AUABQAFAAUABQAB4AHgAeABYAEQArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAGwAbABsAGwAbABsAGwAaABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAaABsAGwAbABsAGgAbABsAGgAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsAGwAbABsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgBQABoAHgAdAB4AUAAeABoAHgAeAB4AHgAeAB4AHgAeAB4ATwAeAFAAGwAeAB4AUABQAFAAUABQAB4AHgAeAB0AHQAeAFAAHgBQAB4AUAAeAFAATwBQAFAAHgAeAB4AHgAeAB4AHgBQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AUABQAFAAUABPAE8AUABQAFAAUABQAE8AUABQAE8AUABPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAFAAUABQAE8ATwBPAE8ATwBPAE8ATwBPAE8AUABQAFAAUABQAFAAUABQAFAAHgAeAFAAUABQAFAATwAeAB4AKwArACsAKwAdAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAeAB0AHQAeAB4AHgAdAB0AHgAeAB0AHgAeAB4AHQAeAB0AGwAbAB4AHQAeAB4AHgAeAB0AHgAeAB0AHQAdAB0AHgAeAB0AHgAdAB4AHQAdAB0AHQAdAB0AHgAdAB4AHgAeAB4AHgAdAB0AHQAdAB4AHgAeAB4AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAeAB4AHgAdAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB4AHgAdAB0AHQAdAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHQAeAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAWABEAFgARAB4AHgAeAB4AHgAeAB0AHgAeAB4AHgAeAB4AHgAlACUAHgAeAB4AHgAeAB4AHgAeAB4AFgARAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBQAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeAB0AHQAdAB0AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAdAB0AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAdAB0AHgAeAB0AHQAeAB4AHgAeAB0AHQAeAB4AHgAeAB0AHQAdAB4AHgAdAB4AHgAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAeAB0AHQAeAB4AHQAeAB4AHgAeAB0AHQAeAB4AHgAeACUAJQAdAB0AJQAeACUAJQAlACAAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAHgAeAB4AHgAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB4AHQAdAB0AHgAdACUAHQAdAB4AHQAdAB4AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB0AHQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAHQAdAB0AHQAlAB4AJQAlACUAHQAlACUAHQAdAB0AJQAlAB0AHQAlAB0AHQAlACUAJQAeAB0AHgAeAB4AHgAdAB0AJQAdAB0AHQAdAB0AHQAlACUAJQAlACUAHQAlACUAIAAlAB0AHQAlACUAJQAlACUAJQAlACUAHgAeAB4AJQAlACAAIAAgACAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAdAB4AHgAeABcAFwAXABcAFwAXAB4AEwATACUAHgAeAB4AFgARABYAEQAWABEAFgARABYAEQAWABEAFgARAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAWABEAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFgARABYAEQAWABEAFgARABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABYAEQAWABEAFgARABYAEQAWABEAFgARABYAEQAWABEAFgARABYAEQAWABEAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFgARABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeABYAEQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHQAdAB0AHQAdAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAEAAQABAAeAB4AKwArACsAKwArABMADQANAA0AUAATAA0AUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUAANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQACsAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAA0ADQANAA0ADQANAA0ADQAeAA0AFgANAB4AHgAXABcAHgAeABcAFwAWABEAFgARABYAEQAWABEADQANAA0ADQATAFAADQANAB4ADQANAB4AHgAeAB4AHgAMAAwADQANAA0AHgANAA0AFgANAA0ADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAKwArACsAKwArACsAKwArACsAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArAA0AEQARACUAJQBHAFcAVwAWABEAFgARABYAEQAWABEAFgARACUAJQAWABEAFgARABYAEQAWABEAFQAWABEAEQAlAFcAVwBXAFcAVwBXAFcAVwBXAAQABAAEAAQABAAEACUAVwBXAFcAVwA2ACUAJQBXAFcAVwBHAEcAJQAlACUAKwBRAFcAUQBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFEAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBRAFcAUQBXAFEAVwBXAFcAVwBXAFcAUQBXAFcAVwBXAFcAVwBRAFEAKwArAAQABAAVABUARwBHAFcAFQBRAFcAUQBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFEAVwBRAFcAUQBXAFcAVwBXAFcAVwBRAFcAVwBXAFcAVwBXAFEAUQBXAFcAVwBXABUAUQBHAEcAVwArACsAKwArACsAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwArACUAJQBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAKwArACUAJQAlACUAKwArACsAKwArACsAKwArACsAKwArACsAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQBRAFEAUQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAVwBXAFcAVwBXAFcAVwBXAFcAVwAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAE8ATwBPAE8ATwBPAE8ATwAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAEcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAADQATAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABLAEsASwBLAEsASwBLAEsASwBLAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAABAAEAAQABAAeAAQABAAEAAQABAAEAAQABAAEAAQAHgBQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AUABQAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAeAA0ADQANAA0ADQArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAB4AHgAeAB4AHgAeAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAB4AHgAeAB4AHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAAQAUABQAFAABABQAFAAUABQAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAeAB4AHgAeACsAKwArACsAUABQAFAAUABQAFAAHgAeABoAHgArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAADgAOABMAEwArACsAKwArACsAKwArACsABAAEAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwANAA0ASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUAAeAB4AHgBQAA4AUAArACsAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAA0ADQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwArACsAKwArACsAKwArAB4AWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYAFgAWABYACsAKwArAAQAHgAeAB4AHgAeAB4ADQANAA0AHgAeAB4AHgArAFAASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArAB4AHgBcAFwAXABcAFwAKgBcAFwAXABcAFwAXABcAFwAXABcAEsASwBLAEsASwBLAEsASwBLAEsAXABcAFwAXABcACsAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArAFAAUABQAAQAUABQAFAAUABQAFAAUABQAAQABAArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAHgANAA0ADQBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAKgAqACoAXAAqACoAKgBcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAAqAFwAKgAqACoAXABcACoAKgBcAFwAXABcAFwAKgAqAFwAKgBcACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcACoAKgBQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAA0ADQBQAFAAUAAEAAQAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAArACsAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQADQAEAAQAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAVABVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBUAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVAFUAVQBVACsAKwArACsAKwArACsAKwArACsAKwArAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAWQBZAFkAKwArACsAKwBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAWgBaAFoAKwArACsAKwAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYABgAGAAYAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAKwArACsAKwArAFYABABWAFYAVgBWAFYAVgBWAFYAVgBWAB4AVgBWAFYAVgBWAFYAVgBWAFYAVgBWAFYAVgArAFYAVgBWAFYAVgArAFYAKwBWAFYAKwBWAFYAKwBWAFYAVgBWAFYAVgBWAFYAVgBWAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAEQAWAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUAAaAB4AKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAGAARABEAGAAYABMAEwAWABEAFAArACsAKwArACsAKwAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACUAJQAlACUAJQAWABEAFgARABYAEQAWABEAFgARABYAEQAlACUAFgARACUAJQAlACUAJQAlACUAEQAlABEAKwAVABUAEwATACUAFgARABYAEQAWABEAJQAlACUAJQAlACUAJQAlACsAJQAbABoAJQArACsAKwArAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAcAKwATACUAJQAbABoAJQAlABYAEQAlACUAEQAlABEAJQBXAFcAVwBXAFcAVwBXAFcAVwBXABUAFQAlACUAJQATACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXABYAJQARACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwAWACUAEQAlABYAEQARABYAEQARABUAVwBRAFEAUQBRAFEAUQBRAFEAUQBRAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAEcARwArACsAVwBXAFcAVwBXAFcAKwArAFcAVwBXAFcAVwBXACsAKwBXAFcAVwBXAFcAVwArACsAVwBXAFcAKwArACsAGgAbACUAJQAlABsAGwArAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwAEAAQABAAQAB0AKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsADQANAA0AKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgBQAFAAHgAeAB4AKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAKwArAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsADQBQAFAAUABQACsAKwArACsAUABQAFAAUABQAFAAUABQAA0AUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAArACsAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQACsAKwArAFAAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAA0AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AHgBQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsADQBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwBQAFAAUABQAFAABAAEAAQAKwAEAAQAKwArACsAKwArAAQABAAEAAQAUABQAFAAUAArAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsABAAEAAQAKwArACsAKwAEAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsADQANAA0ADQANAA0ADQANAB4AKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAB4AUABQAFAAUABQAFAAUABQAB4AUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEACsAKwArACsAUABQAFAAUABQAA0ADQANAA0ADQANABQAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwANAA0ADQANAA0ADQANAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAHgAeAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAA0ADQAeAB4AHgAeAB4AKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQABAAEAAQABAAeAB4AHgANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAKwArAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsASwBLAEsASwBLAEsASwBLAEsASwANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAeAA4AUAArACsAKwArACsAKwArACsAKwAEAFAAUABQAFAADQANAB4ADQAeAAQABAAEAB4AKwArAEsASwBLAEsASwBLAEsASwBLAEsAUAAOAFAADQANAA0AKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAANAA0AHgANAA0AHgAEACsAUABQAFAAUABQAFAAUAArAFAAKwBQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAA0AKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsABAAEAAQABAArAFAAUABQAFAAUABQAFAAUAArACsAUABQACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAArACsABAAEACsAKwAEAAQABAArACsAUAArACsAKwArACsAKwAEACsAKwArACsAKwBQAFAAUABQAFAABAAEACsAKwAEAAQABAAEAAQABAAEACsAKwArAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABABQAFAAUABQAA0ADQANAA0AHgBLAEsASwBLAEsASwBLAEsASwBLACsADQArAB4AKwArAAQABAAEAAQAUABQAB4AUAArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEACsAKwAEAAQABAAEAAQABAAEAAQABAAOAA0ADQATABMAHgAeAB4ADQANAA0ADQANAA0ADQANAA0ADQANAA0ADQANAA0AUABQAFAAUAAEAAQAKwArAAQADQANAB4AUAArACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwAOAA4ADgAOAA4ADgAOAA4ADgAOAA4ADgAOACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXABcAFwAXAArACsAKwAqACoAKgAqACoAKgAqACoAKgAqACoAKgAqACoAKgArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAXABcAA0ADQANACoASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwBQAFAABAAEAAQABAAEAAQABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAFAABAAEAAQABAAOAB4ADQANAA0ADQAOAB4ABAArACsAKwArACsAKwArACsAUAAEAAQABAAEAAQABAAEAAQABAAEAAQAUABQAFAAUAArACsAUABQAFAAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAA0ADQANACsADgAOAA4ADQANACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAABAAEAAQABAAEAAQABAAEACsABAAEAAQABAAEAAQABAAEAFAADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwAOABMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQACsAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAArACsAKwAEACsABAAEACsABAAEAAQABAAEAAQABABQAAQAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsADQANAA0ADQANACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAASABIAEgAQwBDAEMAUABQAFAAUABDAFAAUABQAEgAQwBIAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAASABDAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABIAEMAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAEsASwBLAEsASwBLAEsASwBLAEsAKwArACsAKwANAA0AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArAAQABAAEAAQABAANACsAKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAEAAQABAAEAAQABAAEAA0ADQANAB4AHgAeAB4AHgAeAFAAUABQAFAADQAeACsAKwArACsAKwArACsAKwArACsASwBLAEsASwBLAEsASwBLAEsASwArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAUAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAEcARwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwArACsAKwArACsAKwArACsAKwArACsAKwArAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwBQAFAAUABQAFAAUABQAFAAUABQACsAKwAeAAQABAANAAQABAAEAAQAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAeAB4AHgArACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAEAAQABAAEAB4AHgAeAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQAHgAeAAQABAAEAAQABAAEAAQAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAEAAQABAAeACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwArACsAKwArACsAKwArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUAArACsAUAArACsAUABQACsAKwBQAFAAUABQACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AKwBQACsAUABQAFAAUABQAFAAUAArAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwAeAB4AUABQAFAAUABQACsAUAArACsAKwBQAFAAUABQAFAAUABQACsAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgArACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUAAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAHgAeAB4AHgAeAB4AHgAeAB4AKwArAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsASwBLAEsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4ABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAB4AHgAeAB4AHgAeAB4AHgAEAB4AHgAeAB4AHgAeAB4AHgAeAB4ABAAeAB4ADQANAA0ADQAeACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABAArAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsABAAEAAQABAAEAAQABAArAAQABAArAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwBQAFAAUABQAFAAKwArAFAAUABQAFAAUABQAFAAUABQAAQABAAEAAQABAAEAAQAKwArACsAKwArACsAKwArACsAHgAeAB4AHgAEAAQABAAEAAQABAAEACsAKwArACsAKwBLAEsASwBLAEsASwBLAEsASwBLACsAKwArACsAFgAWAFAAUABQAFAAKwBQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArAFAAUAArAFAAKwArAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUAArAFAAKwBQACsAKwArACsAKwArAFAAKwArACsAKwBQACsAUAArAFAAKwBQAFAAUAArAFAAUAArAFAAKwArAFAAKwBQACsAUAArAFAAKwBQACsAUABQACsAUAArACsAUABQAFAAUAArAFAAUABQAFAAUABQAFAAKwBQAFAAUABQACsAUABQAFAAUAArAFAAKwBQAFAAUABQAFAAUABQAFAAUABQACsAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQACsAKwArACsAKwBQAFAAUAArAFAAUABQAFAAUAArAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUABQAFAAUAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArAB4AHgArACsAKwArACsAKwArACsAKwArACsAKwArACsATwBPAE8ATwBPAE8ATwBPAE8ATwBPAE8ATwAlACUAJQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAeACUAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHgAeACUAJQAlACUAHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdAB0AHQAdACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQApACkAKQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAHgAeACUAJQAlACUAJQAeACUAJQAlACUAJQAgACAAIAAlACUAIAAlACUAIAAgACAAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIQAhACEAIQAhACUAJQAgACAAJQAlACAAIAAgACAAIAAgACAAIAAgACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACAAIAAlACUAJQAlACAAJQAgACAAIAAgACAAIAAgACAAIAAlACUAJQAgACUAJQAlACUAIAAgACAAJQAgACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeACUAHgAlAB4AJQAlACUAJQAlACAAJQAlACUAJQAeACUAHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAHgAeAB4AHgAeAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACAAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAIAAgACAAJQAlACUAIAAgACAAIAAgAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AFwAXABcAFQAVABUAHgAeAB4AHgAlACUAJQAgACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAIAAgACAAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAIAAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlACUAJQAlACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAJQAlAB4AHgAeAB4AHgAeAB4AHgAeAB4AJQAlACUAJQAlACUAHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeAB4AHgAeACUAJQAlACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAlACAAIAAlACUAJQAlACUAJQAgACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAgACAAIAAgACAAJQAlACUAIAAgACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACAAIAAgACAAIAAgACAAIAAgACAAIAAgACAAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACsAKwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAJQAlAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAVwBXAFcAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQAlACUAJQArAAQAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAAEAAQABAArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsAKwArACsA"),U=Array.isArray(i)?function(A){for(var e=A.length,t=[],r=0;r=this._value.length?-1:this._value[A]},yA.prototype.consumeUnicodeRangeToken=function(){for(var A=[],e=this.consumeCodePoint();aA(e)&&A.length<6;)A.push(e),e=this.consumeCodePoint();for(var t=!1;63===e&&A.length<6;)A.push(e),e=this.consumeCodePoint(),t=!0;if(t){var r=parseInt(l.apply(void 0,A.map(function(A){return 63===A?48:A})),16),n=parseInt(l.apply(void 0,A.map(function(A){return 63===A?70:A})),16);return{type:sA.UNICODE_RANGE_TOKEN,start:r,end:n}}var B=parseInt(l.apply(void 0,A),16);if(45===this.peekCodePoint(0)&&aA(this.peekCodePoint(1))){this.consumeCodePoint(),e=this.consumeCodePoint();for(var s=[];aA(e)&&s.length<6;)s.push(e),e=this.consumeCodePoint();return n=parseInt(l.apply(void 0,s),16),{type:sA.UNICODE_RANGE_TOKEN,start:B,end:n}}return{type:sA.UNICODE_RANGE_TOKEN,start:B,end:B}},yA.prototype.consumeIdentLikeToken=function(){var A=this.consumeName();return"url"===A.toLowerCase()&&40===this.peekCodePoint(0)?(this.consumeCodePoint(),this.consumeUrlToken()):40===this.peekCodePoint(0)?(this.consumeCodePoint(),{type:sA.FUNCTION_TOKEN,value:A}):{type:sA.IDENT_TOKEN,value:A}},yA.prototype.consumeUrlToken=function(){var A=[];if(this.consumeWhiteSpace(),-1===this.peekCodePoint(0))return{type:sA.URL_TOKEN,value:""};var e,t=this.peekCodePoint(0);if(39===t||34===t){var r=this.consumeStringToken(this.consumeCodePoint());return r.type===sA.STRING_TOKEN&&(this.consumeWhiteSpace(),-1===this.peekCodePoint(0)||41===this.peekCodePoint(0))?(this.consumeCodePoint(),{type:sA.URL_TOKEN,value:r.value}):(this.consumeBadUrlRemnants(),IA)}for(;;){var n=this.consumeCodePoint();if(-1===n||41===n)return{type:sA.URL_TOKEN,value:l.apply(void 0,A)};if(cA(n))return this.consumeWhiteSpace(),-1===this.peekCodePoint(0)||41===this.peekCodePoint(0)?(this.consumeCodePoint(),{type:sA.URL_TOKEN,value:l.apply(void 0,A)}):(this.consumeBadUrlRemnants(),IA);if(34===n||39===n||40===n||0<=(e=n)&&e<=8||11===e||14<=e&&e<=31||127===e)return this.consumeBadUrlRemnants(),IA;if(92===n){if(!uA(n,this.peekCodePoint(0)))return this.consumeBadUrlRemnants(),IA;A.push(this.consumeEscapedCodePoint())}else A.push(n)}},yA.prototype.consumeWhiteSpace=function(){for(;cA(this.peekCodePoint(0));)this.consumeCodePoint()},yA.prototype.consumeBadUrlRemnants=function(){for(;;){var A=this.consumeCodePoint();if(41===A||-1===A)return;uA(A,this.peekCodePoint(0))&&this.consumeEscapedCodePoint()}},yA.prototype.consumeStringSlice=function(A){for(var e="";0>8,r=255&A>>16,n=255&A>>24;return e<255?"rgba("+n+","+r+","+t+","+e/255+")":"rgb("+n+","+r+","+t+")"}function re(A,e){if(A.type===sA.NUMBER_TOKEN)return A.number;if(A.type!==sA.PERCENTAGE_TOKEN)return 0;var t=3===e?1:255;return 3===e?A.number/100*t:Math.round(A.number/100*t)}function ne(A){var e=A.filter(kA);if(3===e.length){var t=e.map(re),r=t[0],n=t[1],B=t[2];return ue(r,n,B,1)}if(4!==e.length)return 0;var s=e.map(re),o=(r=s[0],n=s[1],B=s[2],s[3]);return ue(r,n,B,o)}var Be=function(A,e){return e===sA.LEFT_CURLY_BRACKET_TOKEN&&A.type===sA.RIGHT_CURLY_BRACKET_TOKEN||(e===sA.LEFT_SQUARE_BRACKET_TOKEN&&A.type===sA.RIGHT_SQUARE_BRACKET_TOKEN||e===sA.LEFT_PARENTHESIS_TOKEN&&A.type===sA.RIGHT_PARENTHESIS_TOKEN)},se={type:sA.NUMBER_TOKEN,number:0,flags:4},oe={type:sA.PERCENTAGE_TOKEN,number:50,flags:4},ie={type:sA.PERCENTAGE_TOKEN,number:100,flags:4},ae=function(A,e){if(A.type===sA.PERCENTAGE_TOKEN)return A.number/100*e;if(xA(A))switch(A.unit){case"rem":case"em":return 16*A.number;case"px":default:return A.number}return A.number},ce=function(A){if(A.type===sA.DIMENSION_TOKEN)switch(A.unit){case"deg":return Math.PI*A.number/180;case"grad":return Math.PI/200*A.number;case"rad":return A.number;case"turn":return 2*Math.PI*A.number}throw new Error("Unsupported angle type")},Qe=function(A){return Math.PI*A/180},we=function(A){if(A.type===sA.FUNCTION){var e=he[A.name];if(void 0===e)throw new Error('Attempting to parse an unsupported color function "'+A.name+'"');return e(A.values)}if(A.type===sA.HASH_TOKEN){if(3===A.value.length){var t=A.value.substring(0,1),r=A.value.substring(1,2),n=A.value.substring(2,3);return ue(parseInt(t+t,16),parseInt(r+r,16),parseInt(n+n,16),1)}if(4===A.value.length){t=A.value.substring(0,1),r=A.value.substring(1,2),n=A.value.substring(2,3);var B=A.value.substring(3,4);return ue(parseInt(t+t,16),parseInt(r+r,16),parseInt(n+n,16),parseInt(B+B,16)/255)}if(6===A.value.length){t=A.value.substring(0,2),r=A.value.substring(2,4),n=A.value.substring(4,6);return ue(parseInt(t,16),parseInt(r,16),parseInt(n,16),1)}if(8===A.value.length){t=A.value.substring(0,2),r=A.value.substring(2,4),n=A.value.substring(4,6),B=A.value.substring(6,8);return ue(parseInt(t,16),parseInt(r,16),parseInt(n,16),parseInt(B,16)/255)}}if(A.type===sA.IDENT_TOKEN){var s=He[A.value.toUpperCase()];if(void 0!==s)return s}return He.TRANSPARENT},ue=function(A,e,t,r){return(A<<24|e<<16|t<<8|Math.round(255*r)<<0)>>>0};function Ue(A,e,t){return t<0&&(t+=1),1<=t&&(t-=1),t<1/6?(e-A)*t*6+A:t<.5?e:t<2/3?6*(e-A)*(2/3-t)+A:A}function le(A){var e=A.filter(kA),t=e[0],r=e[1],n=e[2],B=e[3],s=(t.type===sA.NUMBER_TOKEN?Qe(t.number):ce(t))/(2*Math.PI),o=qA(r)?r.number/100:0,i=qA(n)?n.number/100:0,a=void 0!==B&&qA(B)?ae(B,1):1;if(0==o)return ue(255*i,255*i,255*i,1);var c=i<=.5?i*(1+o):i+o-i*o,Q=2*i-c,w=Ue(Q,c,s+1/3),u=Ue(Q,c,s),U=Ue(Q,c,s-1/3);return ue(255*w,255*u,255*U,a)}var Ce,ge,Ee,Fe,he={hsl:le,hsla:le,rgb:ne,rgba:ne},He={ALICEBLUE:4042850303,ANTIQUEWHITE:4209760255,AQUA:16777215,AQUAMARINE:2147472639,AZURE:4043309055,BEIGE:4126530815,BISQUE:4293182719,BLACK:255,BLANCHEDALMOND:4293643775,BLUE:65535,BLUEVIOLET:2318131967,BROWN:2771004159,BURLYWOOD:3736635391,CADETBLUE:1604231423,CHARTREUSE:2147418367,CHOCOLATE:3530104575,CORAL:4286533887,CORNFLOWERBLUE:1687547391,CORNSILK:4294499583,CRIMSON:3692313855,CYAN:16777215,DARKBLUE:35839,DARKCYAN:9145343,DARKGOLDENROD:3095837695,DARKGRAY:2846468607,DARKGREEN:6553855,DARKGREY:2846468607,DARKKHAKI:3182914559,DARKMAGENTA:2332068863,DARKOLIVEGREEN:1433087999,DARKORANGE:4287365375,DARKORCHID:2570243327,DARKRED:2332033279,DARKSALMON:3918953215,DARKSEAGREEN:2411499519,DARKSLATEBLUE:1211993087,DARKSLATEGRAY:793726975,DARKSLATEGREY:793726975,DARKTURQUOISE:13554175,DARKVIOLET:2483082239,DEEPPINK:4279538687,DEEPSKYBLUE:12582911,DIMGRAY:1768516095,DIMGREY:1768516095,DODGERBLUE:512819199,FIREBRICK:2988581631,FLORALWHITE:4294635775,FORESTGREEN:579543807,FUCHSIA:4278255615,GAINSBORO:3705462015,GHOSTWHITE:4177068031,GOLD:4292280575,GOLDENROD:3668254975,GRAY:2155905279,GREEN:8388863,GREENYELLOW:2919182335,GREY:2155905279,HONEYDEW:4043305215,HOTPINK:4285117695,INDIANRED:3445382399,INDIGO:1258324735,IVORY:4294963455,KHAKI:4041641215,LAVENDER:3873897215,LAVENDERBLUSH:4293981695,LAWNGREEN:2096890111,LEMONCHIFFON:4294626815,LIGHTBLUE:2916673279,LIGHTCORAL:4034953471,LIGHTCYAN:3774873599,LIGHTGOLDENRODYELLOW:4210742015,LIGHTGRAY:3553874943,LIGHTGREEN:2431553791,LIGHTGREY:3553874943,LIGHTPINK:4290167295,LIGHTSALMON:4288707327,LIGHTSEAGREEN:548580095,LIGHTSKYBLUE:2278488831,LIGHTSLATEGRAY:2005441023,LIGHTSLATEGREY:2005441023,LIGHTSTEELBLUE:2965692159,LIGHTYELLOW:4294959359,LIME:16711935,LIMEGREEN:852308735,LINEN:4210091775,MAGENTA:4278255615,MAROON:2147483903,MEDIUMAQUAMARINE:1724754687,MEDIUMBLUE:52735,MEDIUMORCHID:3126187007,MEDIUMPURPLE:2473647103,MEDIUMSEAGREEN:1018393087,MEDIUMSLATEBLUE:2070474495,MEDIUMSPRINGGREEN:16423679,MEDIUMTURQUOISE:1221709055,MEDIUMVIOLETRED:3340076543,MIDNIGHTBLUE:421097727,MINTCREAM:4127193855,MISTYROSE:4293190143,MOCCASIN:4293178879,NAVAJOWHITE:4292783615,NAVY:33023,OLDLACE:4260751103,OLIVE:2155872511,OLIVEDRAB:1804477439,ORANGE:4289003775,ORANGERED:4282712319,ORCHID:3664828159,PALEGOLDENROD:4008225535,PALEGREEN:2566625535,PALETURQUOISE:2951671551,PALEVIOLETRED:3681588223,PAPAYAWHIP:4293907967,PEACHPUFF:4292524543,PERU:3448061951,PINK:4290825215,PLUM:3718307327,POWDERBLUE:2967529215,PURPLE:2147516671,REBECCAPURPLE:1714657791,RED:4278190335,ROSYBROWN:3163525119,ROYALBLUE:1097458175,SADDLEBROWN:2336560127,SALMON:4202722047,SANDYBROWN:4104413439,SEAGREEN:780883967,SEASHELL:4294307583,SIENNA:2689740287,SILVER:3233857791,SKYBLUE:2278484991,SLATEBLUE:1784335871,SLATEGRAY:1887473919,SLATEGREY:1887473919,SNOW:4294638335,SPRINGGREEN:16744447,STEELBLUE:1182971135,TAN:3535047935,TEAL:8421631,THISTLE:3636451583,TOMATO:4284696575,TRANSPARENT:0,TURQUOISE:1088475391,VIOLET:4001558271,WHEAT:4125012991,WHITE:4294967295,WHITESMOKE:4126537215,YELLOW:4294902015,YELLOWGREEN:2597139199};(ge=Ce||(Ce={}))[ge.VALUE=0]="VALUE",ge[ge.LIST=1]="LIST",ge[ge.IDENT_VALUE=2]="IDENT_VALUE",ge[ge.TYPE_VALUE=3]="TYPE_VALUE",ge[ge.TOKEN_VALUE=4]="TOKEN_VALUE",(Fe=Ee||(Ee={}))[Fe.BORDER_BOX=0]="BORDER_BOX",Fe[Fe.PADDING_BOX=1]="PADDING_BOX";function de(A){var e=we(A[0]),t=A[1];return t&&qA(t)?{color:e,stop:t}:{color:e,stop:null}}function fe(A,t){var e=A[0],r=A[A.length-1];null===e.stop&&(e.stop=se),null===r.stop&&(r.stop=ie);for(var n=[],B=0,s=0;sA.optimumDistance)?{optimumCorner:e,optimumDistance:n}:A},{optimumDistance:o?1/0:-1/0,optimumCorner:null}).optimumCorner}function Ie(A){var n=Qe(180),B=[];return WA(A).forEach(function(A,e){if(0===e){var t=A[0];if(t.type===sA.IDENT_TOKEN&&-1!==["top","left","right","bottom"].indexOf(t.value))return void(n=Ae(A));if($A(t))return void(n=(ce(t)+Qe(270))%Qe(360))}var r=de(A);B.push(r)}),{angle:n,stops:B,type:xe.LINEAR_GRADIENT}}function Te(A){return 0===A[0]&&255===A[1]&&0===A[2]&&255===A[3]}var me={name:"background-clip",initialValue:"border-box",prefix:!(Fe[Fe.CONTENT_BOX=2]="CONTENT_BOX"),type:Ce.LIST,parse:function(A){return A.map(function(A){if(zA(A))switch(A.value){case"padding-box":return Ee.PADDING_BOX;case"content-box":return Ee.CONTENT_BOX}return Ee.BORDER_BOX})}},Re={name:"background-color",initialValue:"transparent",prefix:!1,type:Ce.TYPE_VALUE,format:"color"},Le=function(A,e,t,r,n){var B="http://www.w3.org/2000/svg",s=document.createElementNS(B,"svg"),o=document.createElementNS(B,"foreignObject");return s.setAttributeNS(null,"width",A.toString()),s.setAttributeNS(null,"height",e.toString()),o.setAttributeNS(null,"width","100%"),o.setAttributeNS(null,"height","100%"),o.setAttributeNS(null,"x",t.toString()),o.setAttributeNS(null,"y",r.toString()),o.setAttributeNS(null,"externalResourcesRequired","true"),s.appendChild(o),o.appendChild(n),s},ve=function(r){return new Promise(function(A,e){var t=new Image;t.onload=function(){return A(t)},t.onerror=e,t.src="data:image/svg+xml;charset=utf-8,"+encodeURIComponent((new XMLSerializer).serializeToString(r))})},Oe={get SUPPORT_RANGE_BOUNDS(){var A=function(A){if(A.createRange){var e=A.createRange();if(e.getBoundingClientRect){var t=A.createElement("boundtest");t.style.height="123px",t.style.display="block",A.body.appendChild(t),e.selectNode(t);var r=e.getBoundingClientRect(),n=Math.round(r.height);if(A.body.removeChild(t),123===n)return!0}}return!1}(document);return Object.defineProperty(Oe,"SUPPORT_RANGE_BOUNDS",{value:A}),A},get SUPPORT_SVG_DRAWING(){var A=function(A){var e=new Image,t=A.createElement("canvas"),r=t.getContext("2d");if(!r)return!1;e.src="data:image/svg+xml,";try{r.drawImage(e,0,0),t.toDataURL()}catch(A){return!1}return!0}(document);return Object.defineProperty(Oe,"SUPPORT_SVG_DRAWING",{value:A}),A},get SUPPORT_FOREIGNOBJECT_DRAWING(){var A="function"==typeof Array.from&&"function"==typeof window.fetch?function(r){var A=r.createElement("canvas"),n=100;A.width=n,A.height=n;var B=A.getContext("2d");if(!B)return Promise.reject(!1);B.fillStyle="rgb(0, 255, 0)",B.fillRect(0,0,n,n);var e=new Image,s=A.toDataURL();e.src=s;var t=Le(n,n,0,0,e);return B.fillStyle="red",B.fillRect(0,0,n,n),ve(t).then(function(A){B.drawImage(A,0,0);var e=B.getImageData(0,0,n,n).data;B.fillStyle="red",B.fillRect(0,0,n,n);var t=r.createElement("div");return t.style.backgroundImage="url("+s+")",t.style.height="100px",Te(e)?ve(Le(n,n,0,0,t)):Promise.reject(!1)}).then(function(A){return B.drawImage(A,0,0),Te(B.getImageData(0,0,n,n).data)}).catch(function(){return!1})}(document):Promise.resolve(!1);return Object.defineProperty(Oe,"SUPPORT_FOREIGNOBJECT_DRAWING",{value:A}),A},get SUPPORT_CORS_IMAGES(){var A=void 0!==(new Image).crossOrigin;return Object.defineProperty(Oe,"SUPPORT_CORS_IMAGES",{value:A}),A},get SUPPORT_RESPONSE_TYPE(){var A="string"==typeof(new XMLHttpRequest).responseType;return Object.defineProperty(Oe,"SUPPORT_RESPONSE_TYPE",{value:A}),A},get SUPPORT_CORS_XHR(){var A="withCredentials"in new XMLHttpRequest;return Object.defineProperty(Oe,"SUPPORT_CORS_XHR",{value:A}),A}},De=(be.prototype.debug=function(){for(var A=[],e=0;eA.height?new I(A.left+(A.width-A.height)/2,A.top,A.height,A.height):A.width"),WB(this.referenceElement.ownerDocument,n,B),o.replaceChild(o.adoptNode(this.documentElement),o.documentElement),o.close(),i},xB.prototype.createElementClone=function(A){return FB(A)?this.createCanvasClone(A):nB(A)?this.createStyleClone(A):A.cloneNode(!1)},xB.prototype.createStyleClone=function(A){try{var e=A.sheet;if(e&&e.cssRules){var t=[].slice.call(e.cssRules,0).reduce(function(A,e){return e&&"string"==typeof e.cssText?A+e.cssText:A},""),r=A.cloneNode(!1);return r.textContent=t,r}}catch(A){if(De.getInstance(this.options.id).error("Unable to access cssRules property",A),"SecurityError"!==A.name)throw A}return A.cloneNode(!1)},xB.prototype.createCanvasClone=function(A){if(this.options.inlineImages&&A.ownerDocument){var e=A.ownerDocument.createElement("img");try{return e.src=A.toDataURL(),e}catch(A){De.getInstance(this.options.id).info("Unable to clone canvas contents, canvas is tainted")}}var t=A.cloneNode(!1);try{t.width=A.width,t.height=A.height;var r=A.getContext("2d"),n=t.getContext("2d");return n&&(r?n.putImageData(r.getImageData(0,0,A.width,A.height),0,0):n.drawImage(A,0,0)),t}catch(A){}return t},xB.prototype.cloneNode=function(A){if(QB(A))return document.createTextNode(A.data);if(!A.ownerDocument)return A.cloneNode(!1);var e=A.ownerDocument.defaultView;if(uB(A)&&e){var t=this.createElementClone(A),r=e.getComputedStyle(A),n=e.getComputedStyle(A,":before"),B=e.getComputedStyle(A,":after");this.referenceElement===A&&(this.clonedReferenceElement=t),EB(t)&&$B(t);for(var s=this.counters.parse(new un(r)),o=this.resolvePseudoContent(A,t,n,LB.BEFORE),i=A.firstChild;i;i=i.nextSibling)wB(i)&&("SCRIPT"===i.tagName||i.hasAttribute(_B)||"function"==typeof this.options.ignoreElements&&this.options.ignoreElements(i))||this.options.copyStyles&&wB(i)&&nB(i)||t.appendChild(this.cloneNode(i));o&&t.insertBefore(o,t.firstChild);var a=this.resolvePseudoContent(A,t,B,LB.AFTER);return a&&t.appendChild(a),this.counters.pop(s),r&&this.options.copyStyles&&!HB(A)&&GB(r,t),0===A.scrollTop&&0===A.scrollLeft||this.scrolledElements.push([t,A.scrollLeft,A.scrollTop]),(dB(A)||fB(A))&&(dB(t)||fB(t))&&(t.value=A.value),t}return A.cloneNode(!1)},xB.prototype.resolvePseudoContent=function(U,A,e,t){var l=this;if(e){var r=e.content,C=A.ownerDocument;if(C&&r&&"none"!==r&&"-moz-alt-content"!==r&&"none"!==e.display){this.counters.parse(new un(e));var g=new wn(e),E=C.createElement("html2canvaspseudoelement");GB(e,E),g.content.forEach(function(A){if(A.type===sA.STRING_TOKEN)E.appendChild(C.createTextNode(A.value));else if(A.type===sA.URL_TOKEN){var e=C.createElement("img");e.src=A.value,e.style.opacity="1",E.appendChild(e)}else if(A.type===sA.FUNCTION){if("attr"===A.name){var t=A.values.filter(zA);t.length&&E.appendChild(C.createTextNode(U.getAttribute(t[0].value)||""))}else if("counter"===A.name){var r=A.values.filter(kA),n=r[0],B=r[1];if(n&&zA(n)){var s=l.counters.getCounterValue(n.value),o=B&&zA(B)?ir.parse(B.value):tr.DECIMAL;E.appendChild(C.createTextNode(yB(s,o,!1)))}}else if("counters"===A.name){var i=A.values.filter(kA),a=(n=i[0],i[1]);if(B=i[2],n&&zA(n)){var c=l.counters.getCounterValues(n.value),Q=B&&zA(B)?ir.parse(B.value):tr.DECIMAL,w=a&&a.type===sA.STRING_TOKEN?a.value:"",u=c.map(function(A){return yB(A,Q,!1)}).join(w);E.appendChild(C.createTextNode(u))}}}else if(A.type===sA.IDENT_TOKEN)switch(A.value){case"open-quote":E.appendChild(C.createTextNode(en(g.quotes,l.quoteDepth++,!0)));break;case"close-quote":E.appendChild(C.createTextNode(en(g.quotes,--l.quoteDepth,!1)));break;default:E.appendChild(C.createTextNode(A.value))}}),E.className=qB+" "+ZB;var n=t===LB.BEFORE?" "+qB:" "+ZB;return function(A){return"object"==typeof A.className}(A)?A.className.baseValue+=n:A.className+=n,E}}},xB.destroy=function(A){return!!A.parentNode&&(A.parentNode.removeChild(A),!0)},xB);function xB(A,e){if(this.options=e,this.scrolledElements=[],this.referenceElement=A,this.counters=new pB,this.quoteDepth=0,!A.ownerDocument)throw new Error("Cloned element does not have an owner document");this.documentElement=this.cloneNode(A.ownerDocument.documentElement)}(vB=LB||(LB={}))[vB.BEFORE=0]="BEFORE",vB[vB.AFTER=1]="AFTER";var VB,zB,XB=function(A,e){var t=A.createElement("iframe");return t.className="html2canvas-container",t.style.visibility="hidden",t.style.position="fixed",t.style.left="-10000px",t.style.top="0px",t.style.border="0",t.width=e.width.toString(),t.height=e.height.toString(),t.scrolling="no",t.setAttribute(_B,"true"),A.body.appendChild(t),t},JB=function(n){return new Promise(function(e,A){var t=n.contentWindow;if(!t)return A("No window assigned for iframe");var r=t.document;t.onload=n.onload=r.onreadystatechange=function(){t.onload=n.onload=r.onreadystatechange=null;var A=setInterval(function(){0"),e},WB=function(A,e,t){A&&A.defaultView&&(e!==A.defaultView.pageXOffset||t!==A.defaultView.pageYOffset)&&A.defaultView.scrollTo(e,t)},YB=function(A){var e=A[0],t=A[1],r=A[2];e.scrollLeft=t,e.scrollTop=r},qB="___html2canvas___pseudoelement_before",ZB="___html2canvas___pseudoelement_after",jB='{\n content: "" !important;\n display: none !important;\n}',$B=function(A){As(A,"."+qB+":before"+jB+"\n ."+ZB+":after"+jB)},As=function(A,e){var t=A.ownerDocument;if(t){var r=t.createElement("style");r.textContent=e,A.appendChild(r)}};(zB=VB||(VB={}))[zB.VECTOR=0]="VECTOR",zB[zB.BEZIER_CURVE=1]="BEZIER_CURVE";function es(A,t){return A.length===t.length&&A.some(function(A,e){return A===t[e]})}var ts=(rs.prototype.add=function(A,e){return new rs(this.x+A,this.y+e)},rs);function rs(A,e){this.type=VB.VECTOR,this.x=A,this.y=e}function ns(A,e,t){return new ts(A.x+(e.x-A.x)*t,A.y+(e.y-A.y)*t)}var Bs=(ss.prototype.subdivide=function(A,e){var t=ns(this.start,this.startControl,A),r=ns(this.startControl,this.endControl,A),n=ns(this.endControl,this.end,A),B=ns(t,r,A),s=ns(r,n,A),o=ns(B,s,A);return e?new ss(this.start,t,B,o):new ss(o,s,n,this.end)},ss.prototype.add=function(A,e){return new ss(this.start.add(A,e),this.startControl.add(A,e),this.endControl.add(A,e),this.end.add(A,e))},ss.prototype.reverse=function(){return new ss(this.end,this.endControl,this.startControl,this.start)},ss);function ss(A,e,t,r){this.type=VB.BEZIER_CURVE,this.start=A,this.startControl=e,this.endControl=t,this.end=r}function os(A){return A.type===VB.BEZIER_CURVE}var is,as,cs=function(A){var e=A.styles,t=A.bounds,r=jA(e.borderTopLeftRadius,t.width,t.height),n=r[0],B=r[1],s=jA(e.borderTopRightRadius,t.width,t.height),o=s[0],i=s[1],a=jA(e.borderBottomRightRadius,t.width,t.height),c=a[0],Q=a[1],w=jA(e.borderBottomLeftRadius,t.width,t.height),u=w[0],U=w[1],l=[];l.push((n+o)/t.width),l.push((u+c)/t.width),l.push((B+U)/t.height),l.push((i+Q)/t.height);var C=Math.max.apply(Math,l);1t.width+p?0:o-p,i-H,is.TOP_RIGHT):new ts(t.left+t.width-d,t.top+H),this.bottomRightPaddingBox=0t.width+p+T?0:o-p+T,i-(H+N),is.TOP_RIGHT):new ts(t.left+t.width-(d+K),t.top+H+N),this.bottomRightContentBox=0A.element.container.styles.zIndex.order?(i=e,!1):0A.element.container.styles.zIndex.order?(a=e+1,!1):0 Date: Mon, 27 Sep 2021 13:01:10 -0700 Subject: [PATCH 23/85] Fix globeLon deeplink --- src/essence/Ancillary/QueryURL.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/essence/Ancillary/QueryURL.js b/src/essence/Ancillary/QueryURL.js index 88a57d11..a9d67f54 100644 --- a/src/essence/Ancillary/QueryURL.js +++ b/src/essence/Ancillary/QueryURL.js @@ -249,14 +249,14 @@ var QueryURL = { } //Defaults - if (mapLon === undefined) mapLon = L_.Map_.map.getCenter().lng - if (mapLat === undefined) mapLat = L_.Map_.map.getCenter().lat - if (mapZoom === undefined) mapZoom = L_.Map_.map.getZoom() + if (mapLon == undefined) mapLon = L_.Map_.map.getCenter().lng + if (mapLat == undefined) mapLat = L_.Map_.map.getCenter().lat + if (mapZoom == undefined) mapZoom = L_.Map_.map.getZoom() var globeCenter = L_.Globe_.litho.getCenter() - if (globeLon === undefined) globeLon = globeCenter.lon - if (globeLat === undefined) globeLat = globeCenter.lat - if (globeZoom === undefined) globeZoom = L_.Globe_.litho.zoom + if (globeLon == undefined) globeLon = globeCenter.lng + if (globeLat == undefined) globeLat = globeCenter.lat + if (globeZoom == undefined) globeZoom = L_.Globe_.litho.zoom var viewerImg = L_.Viewer_.getLastImageId() var viewerLoc = L_.Viewer_.getLocation() From e717214ff7d71b16e7c7159e83af1854d84ecef1 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 28 Sep 2021 18:29:27 -0700 Subject: [PATCH 24/85] DrawTool Annotations 2 --- API/Backend/Draw/models/published.js | 3 + API/Backend/Draw/routes/files.js | 101 +-- src/essence/Ancillary/Description.js | 10 +- src/essence/Basics/Formulae_/Formulae_.js | 3 + src/essence/Basics/Layers_/Layers_.js | 43 +- src/essence/Basics/Map_/Map_.js | 20 +- src/essence/Tools/Draw/DrawTool.js | 2 +- ...let-src_DEBUG.js => leaflet1.5.1_DEBUG.js} | 612 +++++++++--------- 8 files changed, 413 insertions(+), 381 deletions(-) rename src/external/Leaflet/{leaflet-src_DEBUG.js => leaflet1.5.1_DEBUG.js} (94%) diff --git a/API/Backend/Draw/models/published.js b/API/Backend/Draw/models/published.js index c55507c2..064ebc34 100644 --- a/API/Backend/Draw/models/published.js +++ b/API/Backend/Draw/models/published.js @@ -31,6 +31,9 @@ const attributes = { "campsite", "trail", "signpost", + "polygon", + "line", + "point", "text", "arrow", ], diff --git a/API/Backend/Draw/routes/files.js b/API/Backend/Draw/routes/files.js index 8df8cf7d..a0a90190 100644 --- a/API/Backend/Draw/routes/files.js +++ b/API/Backend/Draw/routes/files.js @@ -817,6 +817,7 @@ const compile = function (req, res, callback) { .spread((results) => { let hierarchy = []; let intentOrder = ["roi", "campaign", "campsite", "signpost"]; + let excludeIntents = ["polygon", "line", "point", "text", "arrow"]; let flatHierarchy = []; let issues = []; let changes = []; @@ -826,32 +827,36 @@ const compile = function (req, res, callback) { let intersects = []; let contains = []; let children = []; - for (let r = 0; r < results.length; r++) { - if (results[r].id == features[f].id) { - let childProps = JSON.parse(results[r].associated_properties); - if (results[r].association === "intersects") { - intersects.push({ - name: childProps.name, - uuid: childProps.uuid, - id: results[r].associated_id, - intent: results[r].associated_intent, - }); - } else if (results[r].association === "contains") { - contains.push({ - name: childProps.name, - uuid: childProps.uuid, - id: results[r].associated_id, - intent: results[r].associated_intent, - }); - children.push({ - name: childProps.name, - uuid: childProps.uuid, - id: results[r].associated_id, - intent: results[r].associated_intent, - }); + + if (!excludeIntents.includes(features[f].intent)) { + for (let r = 0; r < results.length; r++) { + if (results[r].id == features[f].id) { + let childProps = JSON.parse(results[r].associated_properties); + if (results[r].association === "intersects") { + intersects.push({ + name: childProps.name, + uuid: childProps.uuid, + id: results[r].associated_id, + intent: results[r].associated_intent, + }); + } else if (results[r].association === "contains") { + contains.push({ + name: childProps.name, + uuid: childProps.uuid, + id: results[r].associated_id, + intent: results[r].associated_intent, + }); + children.push({ + name: childProps.name, + uuid: childProps.uuid, + id: results[r].associated_id, + intent: results[r].associated_intent, + }); + } } } } + let featureProps = JSON.parse(features[f].properties); flatHierarchy.push({ feature: features[f], @@ -983,28 +988,32 @@ const compile = function (req, res, callback) { //Build the root of the trees for (let f = 0; f < features.length; f++) { let isCovered = false; - for (let r = 0; r < results.length; r++) { - if ( - results[r].association === "contains" && - results[r].associated_id == features[f].id - ) { - isCovered = true; - break; + if (!excludeIntents.includes(features[f].intent)) { + for (let r = 0; r < results.length; r++) { + if ( + !excludeIntents.includes(results[r].intent) && + results[r].association === "contains" && + results[r].associated_id == features[f].id + ) { + isCovered = true; + break; + } + } + + if (!isCovered) { + let featureProps = JSON.parse(features[f].properties); + hierarchy.push({ + intent: features[f].intent, + id: features[f].id, + name: featureProps.name, + uuid: featureProps.uuid, + children: { + intersects: [], + contains: [], + }, + }); + continue; } - } - if (!isCovered) { - let featureProps = JSON.parse(features[f].properties); - hierarchy.push({ - intent: features[f].intent, - id: features[f].id, - name: featureProps.name, - uuid: featureProps.uuid, - children: { - intersects: [], - contains: [], - }, - }); - continue; } } @@ -1106,7 +1115,7 @@ const compile = function (req, res, callback) { } } - //The Saviorng + //The Savioring depthTraversalB(hierarchy, 0); function depthTraversalB(node, depth) { for (let i = 0; i < node.length; i++) { @@ -1163,6 +1172,8 @@ const compile = function (req, res, callback) { let intent = node.intent; let props = JSON.parse(node.feature.properties); + if (excludeIntents.includes(intent)) continue; + //Check for duplicate uuids if (props.uuid == null) { issues.push({ diff --git a/src/essence/Ancillary/Description.js b/src/essence/Ancillary/Description.js index bee3188c..cf7ead5c 100644 --- a/src/essence/Ancillary/Description.js +++ b/src/essence/Ancillary/Description.js @@ -168,7 +168,11 @@ var Description = { }, 80 ) - if (activeLayer != null && activeLayer.hasOwnProperty('options')) { + if ( + activeLayer != null && + activeLayer.feature && + activeLayer.hasOwnProperty('options') + ) { var keyAsName var links = "" @@ -176,8 +180,8 @@ var Description = { this.L_.layersNamed[activeLayer.options.layerName] && this.L_.layersNamed[activeLayer.options.layerName].variables ) { - let v = this.L_.layersNamed[activeLayer.options.layerName] - .variables + let v = + this.L_.layersNamed[activeLayer.options.layerName].variables if (v.links) { links = '' for (let i = 0; i < v.links.length; i++) { diff --git a/src/essence/Basics/Formulae_/Formulae_.js b/src/essence/Basics/Formulae_/Formulae_.js index 6e6e34a6..975c0c61 100644 --- a/src/essence/Basics/Formulae_/Formulae_.js +++ b/src/essence/Basics/Formulae_/Formulae_.js @@ -1374,6 +1374,9 @@ var Formulae_ = { } return uniqueArray }, + sanitize(str) { + return str.replace(/[<>;{}]/g, '') + }, doBoundingBoxesIntersect(a, b) { return a[1] <= b[3] && a[3] >= b[1] && a[0] <= b[2] && a[2] >= b[0] }, diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 96284e38..ef7e7991 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -185,11 +185,13 @@ var L_ = { if (s.type !== 'header') { if (on) { if (L_.Map_.map.hasLayer(L_.layersGroup[s.name])) { + try { + $('.drawToolContextMenuHeaderClose').click() + } catch (err) {} L_.Map_.map.removeLayer(L_.layersGroup[s.name]) } L_.Globe_.litho.removeLayer(s.name) } else { - console.log(s.type) if (s.type === 'tile') { let layerUrl = s.url if (!F_.isUrlAbsolute(layerUrl)) @@ -221,9 +223,30 @@ var L_ = { }) } else if (s.type === 'data') { } else { - if (L_.layersGroup[s.name] === false) + let hadToMake = false + if (L_.layersGroup[s.name] === false) { await L_.Map_.makeLayer(s, true) + hadToMake = true + } if (L_.layersGroup[s.name]) { + if (!hadToMake) { + // Refresh annotation popups + Object.keys(L_.layersGroup[s.name]._layers).forEach( + (key) => { + const l = + L_.layersGroup[s.name]._layers[key] + if (l._isAnnotation) { + L_.layersGroup[s.name]._layers[key] = + L_.createAnnotation( + l._annotationParams.feature, + l._annotationParams.className, + l._annotationParams.layerId, + l._annotationParams.id1 + ) + } + } + ) + } L_.Map_.map.addLayer(L_.layersGroup[s.name]) L_.layersGroup[s.name].setZIndex( L_.layersOrdered.length + @@ -626,7 +649,6 @@ var L_ = { ) { if (id2 == null) id2 = 0 - console.log(feature, className, layerId, id1, id2) className = className.replace(/ /g, '_') //Remove previous annotation if any $(`#${className}_${id1}_${id2}`) @@ -672,16 +694,23 @@ var L_ = { " layer='" + id1 + "' index='" + L_.layersGroup[layerId].length + "' style='" + styleString + "'>" + - `${feature.properties.name.replace(/\W/g, '')}`, + `${feature.properties.name.replace(/[<>;{}]/g, '')}`, '' + '' ) + popup._isAnnotation = true + popup._annotationParams = { + feature, + className, + layerId, + id1, + id2, + andAddToMap, + } + popup.feature = feature if (andAddToMap) { popup.addTo(L_.Map_.map) L_.layersGroup[layerId].push(popup) - L_.layersGroup[layerId][ - L_.layersGroup[layerId].length - 1 - ].feature = feature } return popup }, diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index ab76b8d6..55b47161 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -9,7 +9,7 @@ import ToolController_ from '../ToolController_/ToolController_' import CursorInfo from '../../Ancillary/CursorInfo' import Description from '../../Ancillary/Description' import QueryURL from '../../Ancillary/QueryURL' -import Kinds from '../../Tools/Kinds/Kinds' +import { Kinds } from '../../../pre/tools' import DataShaders from '../../Ancillary/DataShaders' import calls from '../../../pre/calls' import TimeControl from '../../Ancillary/TimeControl' @@ -343,6 +343,8 @@ let Map_ = { for (var i = 0; i < hasIndex.length; i++) { Map_.map.addLayer(L_.layersGroup[L_.layersOrdered[hasIndex[i]]]) } + + enforceVisibilityCutoffs() }, refreshLayer: function (layerObj) { // We need to find and remove all points on the map that belong to the layer @@ -1034,11 +1036,12 @@ async function makeLayer(layerObj, evenIfOff) { Object.keys(layer._layers).forEach((idx) => { let l = layer._layers[idx] if (l.feature?.properties?.arrow === true) { + const c = l.feature.geometry.coordinates const savedUseKeyAsName = l.useKeyAsName const savedOptions = l.options - const c = l.feature.geometry.coordinates const start = new L.LatLng(c[0][1], c[0][0]) const end = new L.LatLng(c[1][1], c[1][0]) + layer._layers[idx] = L_.addArrowToMap( null, start, @@ -1048,6 +1051,17 @@ async function makeLayer(layerObj, evenIfOff) { ) layer._layers[idx].useKeyAsName = savedUseKeyAsName layer._layers[idx].options = savedOptions + Object.keys(layer._layers[idx]._layers).forEach((idx2) => { + layer._layers[idx]._layers[idx2].options.layerName = + savedOptions.layerName + layer._layers[idx]._layers[idx2].feature = l.feature + layer._layers[idx]._layers[idx2].useKeyAsName = + savedUseKeyAsName + Map_.onEachFeatureDefault( + l.feature, + layer._layers[idx]._layers[idx2] + ) + }) } else if (l.feature?.properties?.annotation === true) { layer._layers[idx] = L_.createAnnotation( l.feature, @@ -1055,9 +1069,9 @@ async function makeLayer(layerObj, evenIfOff) { layer._layers[idx].options.layerName, idx ) - layer._layers[idx].feature = l.feature } }) + return layer } diff --git a/src/essence/Tools/Draw/DrawTool.js b/src/essence/Tools/Draw/DrawTool.js index 72025ade..4d98f159 100644 --- a/src/essence/Tools/Draw/DrawTool.js +++ b/src/essence/Tools/Draw/DrawTool.js @@ -16,7 +16,7 @@ import Viewer_ from '../../Basics/Viewer_/Viewer_' import ToolController_ from '../../Basics/ToolController_/ToolController_' import CursorInfo from '../../Ancillary/CursorInfo' import Description from '../../Ancillary/Description' -import Kinds from '../../Tools/Kinds/Kinds' +import { Kinds } from '../../../pre/tools' import turf from 'turf' import shp from '../../../external/shpjs/shapefile' import shpwrite from '../../../external/SHPWrite/shpwrite' diff --git a/src/external/Leaflet/leaflet-src_DEBUG.js b/src/external/Leaflet/leaflet1.5.1_DEBUG.js similarity index 94% rename from src/external/Leaflet/leaflet-src_DEBUG.js rename to src/external/Leaflet/leaflet1.5.1_DEBUG.js index 4b1f348f..7f540d39 100644 --- a/src/external/Leaflet/leaflet-src_DEBUG.js +++ b/src/external/Leaflet/leaflet1.5.1_DEBUG.js @@ -1,6 +1,6 @@ /* @preserve - * Leaflet 1.6.0+Detached: bd88f73e8ddb90eb945a28bc1de9eb07f7386118.bd88f73, a JS library for interactive maps. http://leafletjs.com - * (c) 2010-2019 Vladimir Agafonkin, (c) 2010-2011 CloudMade + * Leaflet 1.5.1, a JS library for interactive maps. http://leafletjs.com + * (c) 2010-2018 Vladimir Agafonkin, (c) 2010-2011 CloudMade */ ;(function (global, factory) { @@ -12,7 +12,7 @@ })(this, function (exports) { 'use strict' - var version = '1.6.0' + var version = '1.5.1' /* * @namespace Util @@ -20,6 +20,11 @@ * Various utility functions, used by Leaflet internally. */ + var freeze = Object.freeze + Object.freeze = function (obj) { + return obj + } + // @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) { @@ -133,8 +138,8 @@ // @function formatNum(num: Number, digits?: Number): Number // Returns the number `num` rounded to `digits` decimals, or to 6 decimals by default. function formatNum(num, digits) { - var pow = Math.pow(10, digits === undefined ? 6 : digits) - return Math.round(num * pow) / pow + digits = digits === undefined ? 6 : digits + return +(Math.round(num + ('e+' + digits)) + ('e-' + digits)) } // @function trim(str: String): String @@ -152,7 +157,7 @@ // @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')) { + if (!obj.hasOwnProperty('options')) { obj.options = obj.options ? create(obj.options) : {} } for (var i in options) { @@ -282,7 +287,8 @@ } } - var Util = { + var Util = (Object.freeze || Object)({ + freeze: freeze, extend: extend, create: create, bind: bind, @@ -304,7 +310,7 @@ cancelFn: cancelFn, requestAnimFrame: requestAnimFrame, cancelAnimFrame: cancelAnimFrame, - } + }) // @class Class // @aka L.Class @@ -340,7 +346,7 @@ // inherit parent's statics for (var i in this) { if ( - Object.prototype.hasOwnProperty.call(this, i) && + this.hasOwnProperty(i) && i !== 'prototype' && i !== '__super__' ) { @@ -757,7 +763,7 @@ * map.panBy(L.point(200, 300)); * ``` * - * Note that `Point` does not inherit from Leaflet's `Class` object, + * Note that `Point` does not inherit from Leafet'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. */ @@ -979,7 +985,7 @@ * otherBounds.intersects([[10, 10], [40, 60]]); * ``` * - * Note that `Bounds` does not inherit from Leaflet's `Class` object, + * Note that `Bounds` does not inherit from Leafet'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. */ @@ -1165,7 +1171,7 @@ * * 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, + * Note that `LatLngBounds` does not inherit from Leafet'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. */ @@ -1351,7 +1357,7 @@ return latIntersects && lngIntersects }, - // @method overlaps(otherBounds: LatLngBounds): Boolean + // @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 = toLatLngBounds(bounds) @@ -1566,7 +1572,7 @@ * 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, + * Note that the CRS instances do not inherit from Leafet'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. */ @@ -1585,18 +1591,11 @@ // The inverse of `latLngToPoint`. Projects pixel coordinates on a given // zoom into geographical coordinates. pointToLatLng: function (point, zoom) { - console.log('pointToLatLng:', point, zoom) var scale = this.scale(zoom), untransformedPoint = this.transformation.untransform( point, scale ) - console.log( - 'scale:', - scale, - 'untransformedPoint:', - untransformedPoint - ) return this.projection.unproject(untransformedPoint) }, @@ -1836,15 +1835,6 @@ // by the given scale. Only accepts actual `L.Point` instances, not arrays. untransform: function (point, scale) { scale = scale || 1 - console.log( - 'UNTRANSFORM', - point, - scale, - this._a, - this._b, - this._c, - this._d - ) return new Point( (point.x / scale - this._b) / this._a, (point.y / scale - this._d) / this._c @@ -1982,7 +1972,7 @@ var opera = !!window.opera // @property chrome: Boolean; `true` for the Chrome browser. - var chrome = !edge && userAgentContains('chrome') + var chrome = userAgentContains('chrome') // @property gecko: Boolean; `true` for gecko-based browsers like Firefox. var gecko = userAgentContains('gecko') && !webkit && !opera && !ie @@ -2062,25 +2052,6 @@ (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 = (function () { @@ -2113,7 +2084,7 @@ return navigator.userAgent.toLowerCase().indexOf(str) >= 0 } - var Browser = { + var Browser = (Object.freeze || Object)({ ie: ie, ielt9: ielt9, edge: edge, @@ -2141,11 +2112,10 @@ mobileOpera: mobileOpera, mobileGecko: mobileGecko, retina: retina, - passiveEvents: passiveEvents, canvas: canvas, svg: svg, vml: vml, - } + }) /* * Extends L.DomEvent to provide touch support for Internet Explorer and Windows-based devices. @@ -2155,10 +2125,14 @@ var POINTER_MOVE = msPointer ? 'MSPointerMove' : 'pointermove' var POINTER_UP = msPointer ? 'MSPointerUp' : 'pointerup' var POINTER_CANCEL = msPointer ? 'MSPointerCancel' : 'pointercancel' + var TAG_WHITE_LIST = ['INPUT', 'SELECT', 'OPTION'] var _pointers = {} var _pointerDocListener = false + // DomEvent.DoubleTap needs to know about this + var _pointersCount = 0 + // Provides a touch events wrapper for (ms)pointer events. // ref http://www.w3.org/TR/pointerevents/ https://www.w3.org/Bugs/Public/show_bug.cgi?id=22890 @@ -2191,12 +2165,19 @@ function _addPointerStart(obj, handler, id) { var onDown = bind(function (e) { - // IE10 specific: MsTouch needs preventDefault. See #2000 if ( - e.MSPOINTER_TYPE_TOUCH && - e.pointerType === e.MSPOINTER_TYPE_TOUCH + e.pointerType !== 'mouse' && + e.MSPOINTER_TYPE_MOUSE && + e.pointerType !== e.MSPOINTER_TYPE_MOUSE ) { - preventDefault(e) + // In IE11, some touch events needs to fire for form controls, or + // the controls will stop working. We keep a whitelist of tag names that + // need these events. For other target tags, we prevent default on the event. + if (TAG_WHITE_LIST.indexOf(e.target.tagName) < 0) { + preventDefault(e) + } else { + return + } } _handlePointer(e, handler) @@ -2207,11 +2188,27 @@ // 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) + // we listen documentElement as any drags that end by moving the touch off the screen get fired there + document.documentElement.addEventListener( + POINTER_DOWN, + _globalPointerDown, + true + ) + document.documentElement.addEventListener( + POINTER_MOVE, + _globalPointerMove, + true + ) + document.documentElement.addEventListener( + POINTER_UP, + _globalPointerUp, + true + ) + document.documentElement.addEventListener( + POINTER_CANCEL, + _globalPointerUp, + true + ) _pointerDocListener = true } @@ -2219,6 +2216,7 @@ function _globalPointerDown(e) { _pointers[e.pointerId] = e + _pointersCount++ } function _globalPointerMove(e) { @@ -2229,6 +2227,7 @@ function _globalPointerUp(e) { delete _pointers[e.pointerId] + _pointersCount-- } function _handlePointer(e, handler) { @@ -2245,7 +2244,8 @@ var onMove = function (e) { // don't fire touch moves when mouse isn't down if ( - e.pointerType === (e.MSPOINTER_TYPE_MOUSE || 'mouse') && + (e.pointerType === e.MSPOINTER_TYPE_MOUSE || + e.pointerType === 'mouse') && e.buttons === 0 ) { return @@ -2292,14 +2292,18 @@ delay = 250 function onTouchStart(e) { + var count + if (pointer) { - if (!e.isPrimary) { + if (!edge || e.pointerType === 'mouse') { return } - if (e.pointerType === 'mouse') { - return - } // mouse fires native dblclick - } else if (e.touches.length > 1) { + count = _pointersCount + } else { + count = e.touches.length + } + + if (count > 1) { return } @@ -2314,7 +2318,7 @@ function onTouchEnd(e) { if (doubleTap && !touch$$1.cancelBubble) { if (pointer) { - if (e.pointerType === 'mouse') { + if (!edge || e.pointerType === 'mouse') { return } // work around .type being readonly with MSPointer* events @@ -2340,16 +2344,8 @@ obj[_pre + _touchend + id] = onTouchEnd obj[_pre + 'dblclick' + id] = handler - obj.addEventListener( - _touchstart, - onTouchStart, - passiveEvents ? { passive: false } : false - ) - obj.addEventListener( - _touchend, - onTouchEnd, - passiveEvents ? { passive: false } : false - ) + obj.addEventListener(_touchstart, onTouchStart, false) + obj.addEventListener(_touchend, onTouchEnd, false) // On some platforms (notably, chrome<55 on win10 + touchscreen + mouse), // the browser doesn't fire touchend/pointerup events but does fire @@ -2365,17 +2361,11 @@ touchend = obj[_pre + _touchend + id], dblclick = obj[_pre + 'dblclick' + id] - obj.removeEventListener( - _touchstart, - touchstart, - passiveEvents ? { passive: false } : false - ) - obj.removeEventListener( - _touchend, - touchend, - passiveEvents ? { passive: false } : false - ) - obj.removeEventListener('dblclick', dblclick, false) + obj.removeEventListener(_touchstart, touchstart, false) + obj.removeEventListener(_touchend, touchend, false) + if (!edge) { + obj.removeEventListener('dblclick', dblclick, false) + } return this } @@ -2700,7 +2690,8 @@ off(window, 'dragstart', preventDefault) } - var _outlineElement, _outlineStyle + var _outlineElement + var _outlineStyle // @function preventOutline(el: HTMLElement) // Makes the [outline](https://developer.mozilla.org/docs/Web/CSS/outline) // of the element `el` invisible. Used internally by Leaflet to prevent @@ -2755,7 +2746,7 @@ } } - var DomUtil = { + var DomUtil = (Object.freeze || Object)({ TRANSFORM: TRANSFORM, TRANSITION: TRANSITION, TRANSITION_END: TRANSITION_END, @@ -2784,7 +2775,7 @@ restoreOutline: restoreOutline, getSizedParentNode: getSizedParentNode, getScale: getScale, - } + }) /* * @namespace DomEvent @@ -2849,19 +2840,6 @@ return this } - function browserFiresNativeDblClick() { - // See https://github.com/w3c/pointerevents/issues/171 - if (pointer) { - return !(edge || safari) - } - } - - var mouseSubst = { - mouseenter: 'mouseover', - mouseleave: 'mouseout', - wheel: !('onwheel' in window) && 'mousewheel', - } - function addOne(obj, type, fn, context) { var id = type + stamp(fn) + (context ? '_' + stamp(context) : '') @@ -2881,20 +2859,18 @@ } else if ( touch && type === 'dblclick' && - !browserFiresNativeDblClick() + addDoubleTapListener && + !(pointer && chrome) ) { + // Chrome >55 does not need the synthetic dblclicks from addDoubleTapListener + // See #5180 addDoubleTapListener(obj, handler, id) } else if ('addEventListener' in obj) { - if ( - type === 'touchstart' || - type === 'touchmove' || - type === 'wheel' || - type === 'mousewheel' - ) { + if (type === 'mousewheel') { obj.addEventListener( - mouseSubst[type] || type, + 'onwheel' in obj ? 'wheel' : 'mousewheel', handler, - passiveEvents ? { passive: false } : false + false ) } else if (type === 'mouseenter' || type === 'mouseleave') { handler = function (e) { @@ -2903,9 +2879,18 @@ originalHandler(e) } } - obj.addEventListener(mouseSubst[type], handler, false) + obj.addEventListener( + type === 'mouseenter' ? 'mouseover' : 'mouseout', + handler, + false + ) } else { - obj.addEventListener(type, originalHandler, false) + if (type === 'click' && android) { + handler = function (e) { + filterClick(e, originalHandler) + } + } + obj.addEventListener(type, handler, false) } } else if ('attachEvent' in obj) { obj.attachEvent('on' + type, handler) @@ -2928,11 +2913,28 @@ } else if ( touch && type === 'dblclick' && - !browserFiresNativeDblClick() + removeDoubleTapListener && + !(pointer && chrome) ) { removeDoubleTapListener(obj, id) } else if ('removeEventListener' in obj) { - obj.removeEventListener(mouseSubst[type] || type, handler, false) + if (type === 'mousewheel') { + obj.removeEventListener( + 'onwheel' in obj ? 'wheel' : 'mousewheel', + handler, + false + ) + } else { + obj.removeEventListener( + type === 'mouseenter' + ? 'mouseover' + : type === 'mouseleave' + ? 'mouseout' + : type, + handler, + false + ) + } } else if ('detachEvent' in obj) { obj.detachEvent('on' + type, handler) } @@ -2962,9 +2964,9 @@ } // @function disableScrollPropagation(el: HTMLElement): this - // Adds `stopPropagation` to the element's `'wheel'` events (plus browser variants). + // Adds `stopPropagation` to the element's `'mousewheel'` events (plus browser variants). function disableScrollPropagation(el) { - addOne(el, 'wheel', stopPropagation) + addOne(el, 'mousewheel', stopPropagation) return this } @@ -3028,7 +3030,7 @@ : 1 // @function getWheelDelta(ev: DOMEvent): Number - // Gets normalized wheel delta from a wheel DOM event, in vertical + // Gets normalized wheel delta from a mousewheel DOM event, in vertical // pixels scrolled (negative if scrolling down). // Events from pointing devices without precise scrolling are mapped to // a best guess of 60 pixels. @@ -3084,7 +3086,32 @@ return related !== el } - var DomEvent = { + var lastClick + + // this is a horrible workaround for a bug in Android where a single touch triggers two click events + function filterClick(e, handler) { + var timeStamp = + e.timeStamp || (e.originalEvent && e.originalEvent.timeStamp), + elapsed = lastClick && timeStamp - lastClick + + // are they closer together than 500ms yet more than 100ms? + // Android typically triggers them ~300ms apart while multiple listeners + // on the same event should be triggered far faster; + // or check if click is simulated on the element, and if it is, reject any non-simulated events + + if ( + (elapsed && elapsed > 100 && elapsed < 500) || + (e.target._simulatedClick && !e._simulated) + ) { + stop(e) + return + } + lastClick = timeStamp + + handler(e) + } + + var DomEvent = (Object.freeze || Object)({ on: on, off: off, stopPropagation: stopPropagation, @@ -3099,7 +3126,7 @@ isExternalTarget: isExternalTarget, addListener: on, removeListener: off, - } + }) /* * @class PosAnimation @@ -3695,7 +3722,7 @@ return this.flyTo(target.center, target.zoom, options) }, - // @method setMaxBounds(bounds: LatLngBounds): this + // @method setMaxBounds(bounds: Bounds): this // Restricts the map view to the given bounds (see the [maxBounds](#map-maxbounds) option). setMaxBounds: function (bounds) { bounds = toLatLngBounds(bounds) @@ -4052,7 +4079,6 @@ // Destroys the map and clears all related event listeners. remove: function () { this._initEvents(true) - this.off('moveend', this._panInsideMaxBounds) if (this._containerId !== this._container._leaflet_id) { throw new Error( @@ -4310,14 +4336,12 @@ // the CRS origin. project: function (latlng, zoom) { zoom = zoom === undefined ? this._zoom : zoom - console.log('project:pointToLatLng') return this.options.crs.latLngToPoint(toLatLng(latlng), zoom) }, // @method unproject(point: Point, zoom: Number): LatLng // Inverse of [`project`](#map-project). unproject: function (point, zoom) { - console.log('unproject:pointToLatLng', point) zoom = zoom === undefined ? this._zoom : zoom return this.options.crs.pointToLatLng(toPoint(point), zoom) }, @@ -4326,7 +4350,6 @@ // Given a pixel coordinate relative to the [origin pixel](#map-getpixelorigin), // returns the corresponding geographical coordinate (for the current zoom level). layerPointToLatLng: function (point) { - console.log('layerPointToLatLng', point, this.getPixelOrigin()) var projectedPoint = toPoint(point).add(this.getPixelOrigin()) return this.unproject(projectedPoint) }, @@ -4496,10 +4519,10 @@ // Pane for `GridLayer`s and `TileLayer`s this.createPane('tilePane') // @pane overlayPane: HTMLElement = 400 - // Pane for overlay shadows (e.g. `Marker` shadows) + // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s this.createPane('shadowPane') // @pane shadowPane: HTMLElement = 500 - // Pane for vectors (`Path`s, like `Polyline`s and `Polygon`s), `ImageOverlay`s and `VideoOverlay`s + // Pane for overlay shadows (e.g. `Marker` shadows) this.createPane('overlayPane') // @pane markerPane: HTMLElement = 600 // Pane for `Icon`s of `Marker`s @@ -5058,27 +5081,28 @@ this ) - this.on('load moveend', this._animMoveEnd, this) + this.on( + 'load moveend', + function () { + var c = this.getCenter(), + z = this.getZoom() + setTransform( + this._proxy, + this.project(c, z), + this.getZoomScale(z, 1) + ) + }, + this + ) this._on('unload', this._destroyAnimProxy, this) }, _destroyAnimProxy: function () { remove(this._proxy) - this.off('load moveend', this._animMoveEnd, this) delete this._proxy }, - _animMoveEnd: function () { - var c = this.getCenter(), - z = this.getZoom() - setTransform( - this._proxy, - this.project(c, z), - this.getZoomScale(z, 1) - ) - }, - _catchTransitionEnd: function (e) { if ( this._animatingZoom && @@ -5143,7 +5167,6 @@ addClass(this._mapPane, 'leaflet-zoom-anim') } - // @section Other Events // @event zoomanim: ZoomAnimEvent // Fired at least once per zoom animation. For continuous zoom, like pinch zooming, fired once per frame during zoom. this.fire('zoomanim', { @@ -5685,11 +5708,11 @@ // @namespace Map // @section Layer events // @event baselayerchange: LayersControlEvent - // Fired when the base layer is changed through the [layers control](#control-layers). + // Fired when the base layer is changed through the [layer control](#control-layers). // @event overlayadd: LayersControlEvent - // Fired when an overlay is selected through the [layers control](#control-layers). + // Fired when an overlay is selected through the [layer control](#control-layers). // @event overlayremove: LayersControlEvent - // Fired when an overlay is deselected through the [layers control](#control-layers). + // Fired when an overlay is deselected through the [layer control](#control-layers). // @namespace Control.Layers var type = obj.overlay ? e.type === 'add' @@ -5834,7 +5857,7 @@ }) // @factory L.control.layers(baselayers?: Object, overlays?: Object, options?: Control.Layers options) - // Creates a layers control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation. + // Creates an attribution control with the given layers. Base layers will be switched with radio buttons, while overlays will be switched with checkboxes. Note that all base layers should be passed in the base layers object, but only one should be added to the map during map instantiation. var layers = function (baseLayers, overlays, options) { return new Layers(baseLayers, overlays, options) } @@ -6265,9 +6288,9 @@ control.attribution = attribution /* - L.Handler is a base class for handler classes that are used internally to inject - interaction features like dragging to classes like Map and Marker. - */ + L.Handler is a base class for handler classes that are used internally to inject + interaction features like dragging to classes like Map and Marker. +*/ // @class Handler // @aka L.Handler @@ -6517,7 +6540,7 @@ // if necessary if ( window.SVGElementInstance && - this._lastTarget instanceof window.SVGElementInstance + this._lastTarget instanceof SVGElementInstance ) { this._lastTarget = this._lastTarget.correspondingUseElement } @@ -6851,7 +6874,7 @@ return isFlat(latlngs) } - var LineUtil = { + var LineUtil = (Object.freeze || Object)({ simplify: simplify, pointToSegmentDistance: pointToSegmentDistance, closestPointOnSegment: closestPointOnSegment, @@ -6861,7 +6884,7 @@ _sqClosestPointOnSegment: _sqClosestPointOnSegment, isFlat: isFlat, _flat: _flat, - } + }) /* * @namespace PolyUtil @@ -6922,9 +6945,9 @@ return points } - var PolyUtil = { + var PolyUtil = (Object.freeze || Object)({ clipPolygon: clipPolygon, - } + }) /* * @namespace Projection @@ -7007,33 +7030,33 @@ } /* - * @class Projection + * @class Projection - * An object with methods for projecting geographical coordinates of the world onto - * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection). + * An object with methods for projecting geographical coordinates of the world onto + * a flat surface (and back). See [Map projection](http://en.wikipedia.org/wiki/Map_projection). - * @property bounds: Bounds - * The bounds (specified in CRS units) where the projection is valid + * @property bounds: Bounds + * The bounds (specified in CRS units) where the projection is valid - * @method project(latlng: LatLng): Point - * Projects geographical coordinates into a 2D point. - * Only accepts actual `L.LatLng` instances, not arrays. + * @method project(latlng: LatLng): Point + * Projects geographical coordinates into a 2D point. + * Only accepts actual `L.LatLng` instances, not arrays. - * @method unproject(point: Point): LatLng - * The inverse of `project`. Projects a 2D point into a geographical location. - * Only accepts actual `L.Point` instances, not arrays. + * @method unproject(point: Point): LatLng + * The inverse of `project`. Projects a 2D point into a geographical location. + * Only accepts actual `L.Point` instances, not arrays. - * Note that the projection 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. + * Note that the projection instances do not inherit from Leafet'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 index = { + var index = (Object.freeze || Object)({ LonLat: LonLat, Mercator: Mercator, SphericalMercator: SphericalMercator, - } + }) /* * @namespace CRS @@ -7166,10 +7189,6 @@ // @method removeFrom(map: Map): this // Removes the layer from the given map - // - // @alternative - // @method removeFrom(group: LayerGroup): this - // Removes the layer from the given `LayerGroup` removeFrom: function (obj) { if (obj) { obj.removeLayer(this) @@ -7484,12 +7503,11 @@ // @method hasLayer(id: Number): Boolean // Returns `true` if the given internal ID is currently added to the group. hasLayer: function (layer) { - if (!layer) { - return false - } - var layerId = - typeof layer === 'number' ? layer : this.getLayerId(layer) - return layerId in this._layers + return ( + !!layer && + (layer in this._layers || + this.getLayerId(layer) in this._layers) + ) }, // @method clearLayers(): this @@ -7660,10 +7678,10 @@ }, }) - // @factory L.featureGroup(layers?: Layer[], options?: Object) - // Create a feature group, optionally given an initial set of layers and an `options` object. - var featureGroup = function (layers, options) { - return new FeatureGroup(layers, options) + // @factory L.featureGroup(layers: Layer[]) + // Create a feature group, optionally given an initial set of layers. + var featureGroup = function (layers) { + return new FeatureGroup(layers) } /* @@ -8010,11 +8028,7 @@ // Fired when the marker starts moving (because of dragging). this._oldLatLng = this._marker.getLatLng() - - // When using ES6 imports it could not be set when `Popup` was not imported as well - this._marker.closePopup && this._marker.closePopup() - - this._marker.fire('movestart').fire('dragstart') + this._marker.closePopup().fire('movestart').fire('dragstart') }, _onPreDrag: function (e) { @@ -8117,7 +8131,7 @@ // `Map pane` where the markers icon will be added. pane: 'markerPane', - // @option shadowPane: String = 'shadowPane' + // @option pane: String = 'shadowPane' // `Map pane` where the markers shadow will be added. shadowPane: 'shadowPane', @@ -8341,9 +8355,7 @@ }, _setPos: function (pos) { - if (this._icon) { - setPosition(this._icon, pos) - } + setPosition(this._icon, pos) if (this._shadow) { setPosition(this._shadow, pos) @@ -8355,9 +8367,7 @@ }, _updateZIndex: function (offset) { - if (this._icon) { - this._icon.style.zIndex = this._zIndex + offset - } + this._icon.style.zIndex = this._zIndex + offset }, _animateZoom: function (opt) { @@ -8543,11 +8553,7 @@ setOptions(this, style) if (this._renderer) { this._renderer._updateStyle(this) - if ( - this.options.stroke && - style && - Object.prototype.hasOwnProperty.call(style, 'weight') - ) { + if (this.options.stroke && style.hasOwnProperty('weight')) { this._updateBounds() } } @@ -8619,16 +8625,9 @@ // @method setLatLng(latLng: LatLng): this // Sets the position of a circle marker to a new location. setLatLng: function (latlng) { - var oldLatLng = this._latlng this._latlng = toLatLng(latlng) this.redraw() - - // @event move: Event - // Fired when the marker is moved via [`setLatLng`](#circlemarker-setlatlng). Old and new coordinates are included in event arguments as `oldLatLng`, `latlng`. - return this.fire('move', { - oldLatLng: oldLatLng, - latlng: this._latlng, - }) + return this.fire('move', { latlng: this._latlng }) }, // @method getLatLng(): LatLng @@ -8982,7 +8981,7 @@ return this._bounds }, - // @method addLatLng(latlng: LatLng, latlngs?: LatLng[]): this + // @method addLatLng(latlng: LatLng, latlngs? LatLng[]): this // Adds a given point to the polyline. By default, adds to the first ring of // the polyline in case of a multi-polyline, but can be overridden by passing // a specific ring as a LatLng array (that you can earlier access with [`getLatLngs`](#polyline-getlatlngs)). @@ -9464,9 +9463,6 @@ * @option coordsToLatLng: Function = * * A `Function` that will be used for converting GeoJSON coordinates to `LatLng`s. * The default is the `coordsToLatLng` static method. - * - * @option markersInheritOptions: Boolean = false - * Whether default Markers for "Point" type Features inherit from group options. */ initialize: function (geojson, options) { @@ -9525,13 +9521,9 @@ return this.addLayer(layer) }, - // @method resetStyle( layer? ): this + // @method resetStyle( layer ): this // Resets the given vector layer's style to the original GeoJSON style, useful for resetting style after hover events. - // If `layer` is omitted, the style of all features in the current layer is reset. resetStyle: function (layer) { - if (layer === undefined) { - return this.eachLayer(this.resetStyle, this) - } // reset any custom styles layer.options = extend({}, layer.defaultOptions) this._setLayerStyle(layer, this.options.style) @@ -9582,13 +9574,17 @@ switch (geometry.type) { case 'Point': latlng = _coordsToLatLng(coords) - return _pointToLayer(pointToLayer, geojson, latlng, options) + return pointToLayer + ? pointToLayer(geojson, latlng) + : new Marker(latlng) case 'MultiPoint': for (i = 0, len = coords.length; i < len; i++) { latlng = _coordsToLatLng(coords[i]) layers.push( - _pointToLayer(pointToLayer, geojson, latlng, options) + pointToLayer + ? pointToLayer(geojson, latlng) + : new Marker(latlng) ) } return new FeatureGroup(layers) @@ -9633,15 +9629,6 @@ } } - function _pointToLayer(pointToLayerFn, geojson, latlng, options) { - return pointToLayerFn - ? pointToLayerFn(geojson, latlng) - : new Marker( - latlng, - options && options.markersInheritOptions && options - ) - } - // @function coordsToLatLng(coords: Array): LatLng // Creates a `LatLng` object from an array of 2 numbers (longitude, latitude) // or 3 numbers (longitude, latitude, altitude) used in GeoJSON for points. @@ -9742,7 +9729,6 @@ } // @namespace Marker - // @section Other methods // @method toGeoJSON(precision?: Number): Object // `precision` is the number of decimal places for coordinates. // The default value is 6 places. @@ -10195,10 +10181,6 @@ // Whether the video will save aspect ratio after the projection. // Relevant for supported browsers. Browser compatibility- https://developer.mozilla.org/en-US/docs/Web/CSS/object-fit keepAspectRatio: true, - - // @option muted: Boolean = false - // Whether the video starts on mute when loaded. - muted: false, }, _initImage: function () { @@ -10211,9 +10193,6 @@ if (this._zoomAnimated) { addClass(vid, 'leaflet-zoom-animated') } - if (this.options.className) { - addClass(vid, this.options.className) - } vid.onselectstart = falseFn vid.onmousemove = falseFn @@ -10239,13 +10218,12 @@ if ( !this.options.keepAspectRatio && - Object.prototype.hasOwnProperty.call(vid.style, 'objectFit') + vid.style.hasOwnProperty('objectFit') ) { vid.style['objectFit'] = 'fill' } vid.autoplay = !!this.options.autoplay vid.loop = !!this.options.loop - vid.muted = !!this.options.muted for (var i = 0; i < this._url.length; i++) { var source = create$1('source') source.src = this._url[i] @@ -10278,12 +10256,9 @@ * @example * * ```js - * var svgElement = document.createElementNS("http://www.w3.org/2000/svg", "svg"); - * svgElement.setAttribute('xmlns', "http://www.w3.org/2000/svg"); - * svgElement.setAttribute('viewBox', "0 0 200 200"); - * svgElement.innerHTML = ''; - * var svgElementBounds = [ [ 32, -130 ], [ 13, -100 ] ]; - * L.svgOverlay(svgElement, svgElementBounds).addTo(map); + * var element = '', + * elementBounds = [ [ 32, -130 ], [ 13, -100 ] ]; + * L.svgOverlay(element, elementBounds).addTo(map); * ``` */ @@ -10295,9 +10270,6 @@ if (this._zoomAnimated) { addClass(el, 'leaflet-zoom-animated') } - if (this.options.className) { - addClass(el, this.options.className) - } el.onselectstart = falseFn el.onmousemove = falseFn @@ -10415,7 +10387,7 @@ }, // @method getElement: String|HTMLElement - // Returns the HTML container of the popup. + // Alias for [getContent()](#popup-getcontent) getElement: function () { return this._container }, @@ -10741,9 +10713,9 @@ )) this._contentNode = create$1('div', prefix + '-content', wrapper) - disableClickPropagation(container) + disableClickPropagation(wrapper) disableScrollPropagation(this._contentNode) - on(container, 'contextmenu', stopPropagation) + on(wrapper, 'contextmenu', stopPropagation) this._tipContainer = create$1( 'div', @@ -11227,9 +11199,7 @@ _adjustPan: function () {}, _setPosition: function (pos) { - var subX, - subY, - map = this._map, + var map = this._map, container = this._container, centerPoint = map.latLngToContainerPoint(map.getCenter()), tooltipPoint = map.layerPointToContainerPoint(pos), @@ -11240,35 +11210,48 @@ anchor = this._getAnchor() if (direction === 'top') { - subX = tooltipWidth / 2 - subY = tooltipHeight + pos = pos.add( + toPoint( + -tooltipWidth / 2 + offset.x, + -tooltipHeight + offset.y + anchor.y, + true + ) + ) } else if (direction === 'bottom') { - subX = tooltipWidth / 2 - subY = 0 + pos = pos.subtract( + toPoint(tooltipWidth / 2 - offset.x, -offset.y, true) + ) } else if (direction === 'center') { - subX = tooltipWidth / 2 - subY = tooltipHeight / 2 - } else if (direction === 'right') { - subX = 0 - subY = tooltipHeight / 2 - } else if (direction === 'left') { - subX = tooltipWidth - subY = tooltipHeight / 2 - } else if (tooltipPoint.x < centerPoint.x) { + pos = pos.subtract( + toPoint( + tooltipWidth / 2 + offset.x, + tooltipHeight / 2 - anchor.y + offset.y, + true + ) + ) + } else if ( + direction === 'right' || + (direction === 'auto' && tooltipPoint.x < centerPoint.x) + ) { direction = 'right' - subX = 0 - subY = tooltipHeight / 2 + pos = pos.add( + toPoint( + offset.x + anchor.x, + anchor.y - tooltipHeight / 2 + offset.y, + true + ) + ) } else { direction = 'left' - subX = tooltipWidth + (offset.x + anchor.x) * 2 - subY = tooltipHeight / 2 + pos = pos.subtract( + toPoint( + tooltipWidth + anchor.x - offset.x, + tooltipHeight / 2 - anchor.y - offset.y, + true + ) + ) } - pos = pos - .subtract(toPoint(subX, subY, true)) - .add(offset) - .add(anchor) - removeClass(container, 'leaflet-tooltip-right') removeClass(container, 'leaflet-tooltip-left') removeClass(container, 'leaflet-tooltip-top') @@ -11988,7 +11971,6 @@ } for (var z in this._levels) { - z = Number(z) if (this._levels[z].el.children.length || z === zoom) { this._levels[z].el.style.zIndex = maxZoom - Math.abs(zoom - z) @@ -12103,7 +12085,7 @@ _invalidateAll: function () { for (var z in this._levels) { remove(this._levels[z].el) - this._onRemoveLevel(Number(z)) + this._onRemoveLevel(z) delete this._levels[z] } this._removeAllTiles() @@ -12193,7 +12175,7 @@ }, _setView: function (center, zoom, noPrune, noUpdate) { - var tileZoom = Math.round(zoom) + var tileZoom = this._clampZoom(Math.round(zoom)) if ( (this.options.maxZoom !== undefined && tileZoom > this.options.maxZoom) || @@ -12201,8 +12183,6 @@ tileZoom < this.options.minZoom) ) { tileZoom = undefined - } else { - tileZoom = this._clampZoom(tileZoom) } var tileZoomChanged = @@ -12446,8 +12426,6 @@ sePoint = nwPoint.add(tileSize), nw = map.unproject(nwPoint, coords.z), se = map.unproject(sePoint, coords.z) - console.log(coords, 'tc2Nw:', nwPoint, nw) - console.log(coords, 'tc2Se:', sePoint, se) return [nw, se] }, @@ -12784,15 +12762,15 @@ } /* - Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons - http://www.w3.org/TR/WCAG20-TECHS/H67 - */ + Alt tag is set to empty string to keep screen readers from reading URL and for compliance reasons + http://www.w3.org/TR/WCAG20-TECHS/H67 + */ tile.alt = '' /* - Set role="presentation" to force screen readers to ignore this - https://www.w3.org/TR/wai-aria/roles#textalternativecomputation - */ + Set role="presentation" to force screen readers to ignore this + https://www.w3.org/TR/wai-aria/roles#textalternativecomputation + */ tile.setAttribute('role', 'presentation') tile.src = this.getTileUrl(coords) @@ -13254,7 +13232,12 @@ _initContainer: function () { var container = (this._container = document.createElement('canvas')) - on(container, 'mousemove', this._onMouseMove, this) + on( + container, + 'mousemove', + throttle(this._onMouseMove, 32, this), + this + ) on( container, 'click dblclick mousedown mouseup contextmenu', @@ -13450,15 +13433,12 @@ var size = bounds.getSize() this._ctx.clearRect(bounds.min.x, bounds.min.y, size.x, size.y) } else { - this._ctx.save() - this._ctx.setTransform(1, 0, 0, 1, 0, 0) this._ctx.clearRect( 0, 0, this._container.width, this._container.height ) - this._ctx.restore() } }, @@ -13583,13 +13563,12 @@ for (var order = this._drawFirst; order; order = order.next) { layer = order.layer - if (layer.options.interactive && layer._containsPoint(point)) { - if ( - !(e.type === 'click' || e.type !== 'preclick') || - !this._map._draggableMoved(layer) - ) { - clickedLayer = layer - } + if ( + layer.options.interactive && + layer._containsPoint(point) && + !this._map._draggableMoved(layer) + ) { + clickedLayer = layer } } if (clickedLayer) { @@ -13618,15 +13597,10 @@ removeClass(this._container, 'leaflet-interactive') this._fireEvent([layer], e, 'mouseout') this._hoveredLayer = null - this._mouseHoverThrottled = false } }, _handleMouseHover: function (e, point) { - if (this._mouseHoverThrottled) { - return - } - var layer, candidateHoveredLayer for (var order = this._drawFirst; order; order = order.next) { @@ -13649,14 +13623,6 @@ if (this._hoveredLayer) { this._fireEvent([this._hoveredLayer], e) } - - this._mouseHoverThrottled = true - setTimeout( - bind(function () { - this._mouseHoverThrottled = false - }, this), - 32 - ) }, _fireEvent: function (layers, e, type) { @@ -14909,7 +14875,7 @@ // @namespace Map // @section Interaction Options Map.mergeOptions({ - // @section Mouse wheel options + // @section Mousewheel options // @option scrollWheelZoom: Boolean|String = true // Whether the map can be zoomed by using the mouse wheel. If passed `'center'`, // it will zoom to the center of the view regardless of where the mouse was. @@ -14929,13 +14895,13 @@ var ScrollWheelZoom = Handler.extend({ addHooks: function () { - on(this._map._container, 'wheel', this._onWheelScroll, this) + on(this._map._container, 'mousewheel', this._onWheelScroll, this) this._delta = 0 }, removeHooks: function () { - off(this._map._container, 'wheel', this._onWheelScroll, this) + off(this._map._container, 'mousewheel', this._onWheelScroll, this) }, _onWheelScroll: function (e) { @@ -15148,7 +15114,7 @@ // @section Handlers // @property tap: Handler // Mobile touch hacks (quick tap and touch hold) handler. - if (touch && (!pointer || safari)) { + if (touch && !pointer) { Map.addInitHook('addHandler', 'tap', Tap) } @@ -15287,8 +15253,8 @@ this._zooming = false cancelAnimFrame(this._animRequest) - off(document, 'touchmove', this._onTouchMove, this) - off(document, 'touchend', this._onTouchEnd, this) + off(document, 'touchmove', this._onTouchMove) + off(document, 'touchend', this._onTouchEnd) // Pinch updates GridLayers' levels only when zoomSnap is off, so zoomSnap becomes noUpdate. if (this._map.options.zoomAnimation) { @@ -15320,6 +15286,8 @@ Map.Tap = Tap Map.TouchZoom = TouchZoom + Object.freeze = freeze + exports.version = version exports.Control = Control exports.control = control From 9120a95a46b8c7c1eebdbe20902f8d3cd384c371 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 29 Sep 2021 10:54:08 -0700 Subject: [PATCH 25/85] DrawTool Annotations 3 --- API/Backend/Draw/routes/files.js | 14 ++++++-------- package.json | 2 +- src/essence/Ancillary/Coordinates.js | 14 ++++++++++++++ src/essence/Basics/Layers_/LayerCapturer.js | 7 ++++++- src/essence/Basics/Layers_/Layers_.js | 16 +++++++++++++--- src/essence/Basics/Map_/Map_.js | 6 ++++-- 6 files changed, 44 insertions(+), 15 deletions(-) diff --git a/API/Backend/Draw/routes/files.js b/API/Backend/Draw/routes/files.js index a0a90190..7d2b5682 100644 --- a/API/Backend/Draw/routes/files.js +++ b/API/Backend/Draw/routes/files.js @@ -1511,19 +1511,17 @@ router.post("/publish", function (req, res, next) { failureCallback ) { Table.findAll({ + limit: 1, where: { file_id: file_id, }, + order: [["history_id", "DESC"]], }) - .then((histories) => { - let maxHistoryId = -Infinity; - if (histories && histories.length > 0) { - for (let i = 0; i < histories.length; i++) { - maxHistoryId = Math.max(histories[i].history_id, maxHistoryId); - } + .then((lastHistory) => { + if (lastHistory && lastHistory.length > 0) { return { - historyIndex: maxHistoryId + 1, - history: histories[maxHistoryId].history, + historyIndex: lastHistory[0].history_id + 1, + history: lastHistory[0].history, }; } else return { historyIndex: 0, history: [] }; }) diff --git a/package.json b/package.json index ed2e5a17..e28354b5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mmgis", - "version": "2.4.0", + "version": "2.4.1", "description": "A web-based mapping and localization solution for science operation on planetary missions.", "homepage": "build", "repository": { diff --git a/src/essence/Ancillary/Coordinates.js b/src/essence/Ancillary/Coordinates.js index a7f53e26..5b2f9900 100644 --- a/src/essence/Ancillary/Coordinates.js +++ b/src/essence/Ancillary/Coordinates.js @@ -305,6 +305,15 @@ var Coordinates = { Coordinates.elevation != null ? ',Z' : '' })` ) + d3.select('#mouseDescPicking').html( + 'Site Frame - ' + + Map_.activeLayer.options.layerName + + ': ' + + keyAsName + + ` (X,Y${ + Coordinates.elevation != null ? ',Z' : '' + })` + ) if (!isPartial) { Coordinates.mouseLngLat[0] -= Map_.activeLayer.feature.geometry.coordinates[0] @@ -320,6 +329,11 @@ var Coordinates = { Coordinates.elevation != null ? ',Z' : '' })` ) + d3.select('#mouseDescPicking').html( + `Site Frame - Map Origin (X,Y${ + Coordinates.elevation != null ? ',Z' : '' + })` + ) } d3.select('#mouseLngLat').html( ( diff --git a/src/essence/Basics/Layers_/LayerCapturer.js b/src/essence/Basics/Layers_/LayerCapturer.js index 1aa138a8..802280fb 100644 --- a/src/essence/Basics/Layers_/LayerCapturer.js +++ b/src/essence/Basics/Layers_/LayerCapturer.js @@ -72,12 +72,17 @@ export const captureVector = (layerObj, options, cb) => { function (data) { data.body.features.sort((a, b) => { let intentOrder = [ - 'all', + 'polygon', 'roi', 'campaign', 'campsite', + 'all', + 'line', 'trail', + 'point', 'signpost', + 'arrow', + 'text', 'note', 'master', ] diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index ef7e7991..5745cb2f 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -192,6 +192,14 @@ var L_ = { } L_.Globe_.litho.removeLayer(s.name) } else { + if (L_.layersGroup[s.name]) { + L_.Map_.map.addLayer(L_.layersGroup[s.name]) + L_.layersGroup[s.name].setZIndex( + L_.layersOrdered.length + + 1 - + L_.layersOrdered.indexOf(s.name) + ) + } if (s.type === 'tile') { let layerUrl = s.url if (!F_.isUrlAbsolute(layerUrl)) @@ -712,6 +720,7 @@ var L_ = { popup.addTo(L_.Map_.map) L_.layersGroup[layerId].push(popup) } + return popup }, setLayerOpacity: function (name, newOpacity) { @@ -779,12 +788,13 @@ var L_ = { this.layersStyles[key] != undefined && this.layersStyles[key].hasOwnProperty('fillColor') ) { - var fillColor = this.layersStyles[key].fillColor - this.layersGroup[key].eachLayer(function (layer) { + this.layersGroup[key].eachLayer((layer) => { + var fillColor = this.layersStyles[key].fillColor var opacity = layer.options.opacity var fillOpacity = layer.options.fillOpacity var weight = layer.options.weight - L_.layersGroup[key].resetStyle(layer) + if (!layer._isAnnotation) + L_.layersGroup[key].resetStyle(layer) try { layer.setStyle({ opacity: opacity, diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 55b47161..c42eff59 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -1035,10 +1035,10 @@ async function makeLayer(layerObj, evenIfOff) { Object.keys(layer._layers).forEach((idx) => { let l = layer._layers[idx] + const savedUseKeyAsName = l.useKeyAsName + const savedOptions = l.options if (l.feature?.properties?.arrow === true) { const c = l.feature.geometry.coordinates - const savedUseKeyAsName = l.useKeyAsName - const savedOptions = l.options const start = new L.LatLng(c[0][1], c[0][0]) const end = new L.LatLng(c[1][1], c[1][0]) @@ -1057,6 +1057,8 @@ async function makeLayer(layerObj, evenIfOff) { layer._layers[idx]._layers[idx2].feature = l.feature layer._layers[idx]._layers[idx2].useKeyAsName = savedUseKeyAsName + l.feature.style = l.feature.style || {} + l.feature.style.noclick = true Map_.onEachFeatureDefault( l.feature, layer._layers[idx]._layers[idx2] From 2bcecd8d8d54e6ba1ea7b6cafa454be91c2af79b Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 29 Sep 2021 11:46:08 -0700 Subject: [PATCH 26/85] DrawTool Annotations 4 --- src/essence/Tools/Draw/DrawTool.js | 11 +- src/essence/Tools/Draw/DrawTool_Drawing.js | 155 ------------------ src/essence/Tools/Draw/DrawTool_Editing.js | 92 +++++++---- src/essence/Tools/Draw/DrawTool_Files.js | 83 +--------- .../Tools/Draw/DrawTool_SetOperations.js | 2 +- src/essence/Tools/Draw/config.json | 3 +- 6 files changed, 81 insertions(+), 265 deletions(-) diff --git a/src/essence/Tools/Draw/DrawTool.js b/src/essence/Tools/Draw/DrawTool.js index 4d98f159..868b8f86 100644 --- a/src/essence/Tools/Draw/DrawTool.js +++ b/src/essence/Tools/Draw/DrawTool.js @@ -307,10 +307,10 @@ var DrawTool = { 'all', ], intentOrder: [ - 'all', 'roi', 'campaign', 'campsite', + 'all', 'trail', 'signpost', 'note', @@ -377,7 +377,6 @@ var DrawTool = { opacity: 1, fontSize: '18px', }, - all: { color: 'rgb(255, 255, 255)', radius: 2, @@ -419,11 +418,11 @@ var DrawTool = { }, arrow: { color: 'rgb(0, 0, 0)', - radius: 30, //used as arrowhead limb pixel length + radius: 20, //used as arrowhead limb pixel length fillColor: 'rgb(255, 255, 255)', - width: 8, //width of line + width: 4, //width of line length: 'Full', //length of line body - weight: 2, //outline + weight: 4, //outline opacity: 1, fillOpacity: 1, dashArray: '', @@ -450,6 +449,8 @@ var DrawTool = { this.intentNameMapping.trail = this.vars.intents[3] if (this.vars.intents[4]) this.intentNameMapping.signpost = this.vars.intents[4] + if (this.vars.intents[5]) + this.intentNameMapping.all = this.vars.intents[5] } //Bring in other scripts diff --git a/src/essence/Tools/Draw/DrawTool_Drawing.js b/src/essence/Tools/Draw/DrawTool_Drawing.js index 10808fa4..b7223a1c 100644 --- a/src/essence/Tools/Draw/DrawTool_Drawing.js +++ b/src/essence/Tools/Draw/DrawTool_Drawing.js @@ -20,7 +20,6 @@ var Drawing = { DrawTool.setDrawingType = Drawing.setDrawingType DrawTool.switchDrawingType = Drawing.switchDrawingType DrawTool.setDrawing = Drawing.setDrawing - DrawTool.addArrowToMap = Drawing.addArrowToMap }, drawOver: function (d, clip, callback) { var file_id = @@ -326,160 +325,6 @@ var Drawing = { DrawTool.intentType ) }, - addArrowToMap: function (layerId, start, end, style, feature, index) { - var line - - var length - if (isNaN(style.length)) length = false - else length = parseInt(style.length) - - line = new L.Polyline([end, start], { - color: style.color, - weight: style.width + style.weight, - }) - var arrowBodyOutline - if (length === false) { - arrowBodyOutline = new L.Polyline([start, end], { - color: style.color, - weight: style.width + style.weight, - dashArray: style.dashArray, - lineCap: style.lineCap, - lineJoin: style.lineJoin, - }) - } else { - arrowBodyOutline = L.polylineDecorator(line, { - patterns: [ - { - offset: length / 2 + 'px', - repeat: 0, - symbol: L.Symbol.dash({ - pixelSize: style.length, - polygon: false, - pathOptions: { - stroke: true, - color: style.color, - weight: style.width + style.weight, - dashArray: style.dashArray, - lineCap: style.lineCap, - lineJoin: style.lineJoin, - }, - }), - }, - ], - }) - } - line = new L.Polyline([start, end], { - color: style.color, - weight: style.width + style.weight, - }) - var arrowHeadOutline = L.polylineDecorator(line, { - patterns: [ - { - offset: '100%', - repeat: 0, - symbol: L.Symbol.arrowHead({ - pixelSize: style.radius, - polygon: false, - pathOptions: { - stroke: true, - color: style.color, - weight: style.width + style.weight, - lineCap: style.lineCap, - lineJoin: style.lineJoin, - }, - }), - }, - ], - }) - line = new L.Polyline([end, start], { - color: style.fillColor, - weight: style.width, - }) - var arrowBody - if (length === false) { - arrowBody = new L.Polyline([start, end], { - color: style.fillColor, - weight: style.width, - dashArray: style.dashArray, - lineCap: style.lineCap, - lineJoin: style.lineJoin, - }) - } else { - arrowBody = L.polylineDecorator(line, { - patterns: [ - { - offset: length / 2 + 'px', - repeat: 0, - symbol: L.Symbol.dash({ - pixelSize: style.length, - polygon: false, - pathOptions: { - stroke: true, - color: style.fillColor, - weight: style.width, - dashArray: style.dashArray, - lineCap: style.lineCap, - lineJoin: style.lineJoin, - }, - }), - }, - ], - }) - } - line = new L.Polyline([start, end], { - color: style.fillColor, - weight: style.width, - }) - var arrowHead = L.polylineDecorator(line, { - patterns: [ - { - offset: '100%', - repeat: 0, - symbol: L.Symbol.arrowHead({ - pixelSize: style.radius, - polygon: false, - pathOptions: { - stroke: true, - color: style.fillColor, - weight: style.width, - lineCap: style.lineCap, - lineJoin: style.lineJoin, - }, - }), - }, - ], - }) - - if (index != null) { - Map_.rmNotNull(L_.layersGroup[layerId][index]) - L_.layersGroup[layerId][index] = L.layerGroup([ - arrowBodyOutline, - arrowHeadOutline, - arrowBody, - arrowHead, - ]).addTo(Map_.map) - L_.layersGroup[layerId][index].start = start - L_.layersGroup[layerId][index].end = end - L_.layersGroup[layerId][index].feature = feature - DrawTool.populateShapes() - } else { - L_.layersGroup[layerId].push( - L.layerGroup([ - arrowBodyOutline, - arrowHeadOutline, - arrowBody, - arrowHead, - ]).addTo(Map_.map) - ) - L_.layersGroup[layerId][L_.layersGroup[layerId].length - 1].start = - start - L_.layersGroup[layerId][L_.layersGroup[layerId].length - 1].end = - end - L_.layersGroup[layerId][ - L_.layersGroup[layerId].length - 1 - ].feature = feature - } - }, } var drawing = { diff --git a/src/essence/Tools/Draw/DrawTool_Editing.js b/src/essence/Tools/Draw/DrawTool_Editing.js index 8a893f1e..ad2d5d2e 100644 --- a/src/essence/Tools/Draw/DrawTool_Editing.js +++ b/src/essence/Tools/Draw/DrawTool_Editing.js @@ -516,7 +516,7 @@ var Editing = { "
    ", "
    ", "
    ", - "
    " + title + "
    ", + "
    " + F_.sanitize(title) + "
    ", "
    ", "x" + DrawTool.contextMenuLayers.length + "", "
    ", @@ -526,8 +526,8 @@ var Editing = { "
    ", "
    ", "
    ", - "
    by " + file.file_owner + "
    ", - "
    from" + file.file_name + "
    ", + "
    by " + F_.sanitize(file.file_owner) + "
    ", + "
    from" + F_.sanitize(file.file_name) + "
    ", "
    ", "
    ", @@ -548,7 +548,7 @@ var Editing = { "
    ", "
    ", "
    Name
    ", - "", + "", "
    ", "
    ", "
    Description
    ", @@ -928,13 +928,16 @@ var Editing = { L_.layersGroup[l.l_i_f.layer][l.l_i_f.index] != null && l.properties.arrow == true ) { - DrawTool.addArrowToMap( + L_.addArrowToMap( l.l_i_f.layer, l.shape.start, l.shape.end, l.properties.style, l.shape.feature, - l.l_i_f.index + l.l_i_f.index, + () => { + DrawTool.populateShapes() + } ) } else { DrawTool.contextMenuLayer.resetGeoJSON() @@ -1094,13 +1097,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1183,13 +1189,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1241,13 +1250,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1320,13 +1332,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1414,13 +1429,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1503,13 +1521,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1589,13 +1610,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1649,13 +1673,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1705,13 +1732,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1763,13 +1793,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } @@ -1821,13 +1854,16 @@ var Editing = { s.feature.properties.style ) style = setProperties({ style: style }).style - DrawTool.addArrowToMap( + L_.addArrowToMap( lif.layer, s.start, s.end, style, s.feature, - lif.index + lif.index, + () => { + DrawTool.populateShapes() + } ) } } diff --git a/src/essence/Tools/Draw/DrawTool_Files.js b/src/essence/Tools/Draw/DrawTool_Files.js index c075ab3d..f966b43b 100644 --- a/src/essence/Tools/Draw/DrawTool_Files.js +++ b/src/essence/Tools/Draw/DrawTool_Files.js @@ -1187,7 +1187,7 @@ var Files = { var start = new L.LatLng(c[0][1], c[0][0]) var end = new L.LatLng(c[1][1], c[1][0]) - DrawTool.addArrowToMap( + L_.addArrowToMap( layerId, start, end, @@ -1195,81 +1195,14 @@ var Files = { features[i] ) } else if (features[i].properties.annotation === true) { - //Remove previous annotation if any - $( - '#DrawToolAnnotation_' + - id + - '_' + - features[i].properties._.id - ) - .parent() - .parent() - .parent() - .parent() - .remove() - - var s = features[i].properties.style - var styleString = - (s.color != null - ? 'text-shadow: ' + - F_.getTextShadowString( - s.color, - s.strokeOpacity, - s.weight - ) + - '; ' - : '') + - (s.fillColor != null - ? 'color: ' + s.fillColor + '; ' - : '') + - (s.fontSize != null - ? 'font-size: ' + s.fontSize + '; ' - : '') - L_.layersGroup[layerId].push( - L.popup({ - className: 'leaflet-popup-annotation', - closeButton: false, - autoClose: false, - closeOnEscapeKey: false, - closeOnClick: false, - autoPan: false, - offset: new L.point(0, 3), - }) - .setLatLng( - new L.LatLng( - features[i].geometry.coordinates[1], - features[i].geometry.coordinates[0] - ) - ) - .setContent( - '
    ' + - "
    " + - '
    ' + - '
    ' - ) - .addTo(Map_.map) + L_.createAnnotation( + features[i], + 'DrawToolAnnotation', + layerId, + id, + features[i].properties._.id, + true ) - L_.layersGroup[layerId][ - L_.layersGroup[layerId].length - 1 - ].feature = features[i] - $( - '#DrawToolAnnotation_' + - id + - '_' + - features[i].properties._.id - ).text(features[i].properties.name) DrawTool.refreshNoteEvents() } else if (features[i].geometry.type === 'Point') { diff --git a/src/essence/Tools/Draw/DrawTool_SetOperations.js b/src/essence/Tools/Draw/DrawTool_SetOperations.js index bea1490d..4f98b4d0 100644 --- a/src/essence/Tools/Draw/DrawTool_SetOperations.js +++ b/src/essence/Tools/Draw/DrawTool_SetOperations.js @@ -70,7 +70,7 @@ var SetOperations = { lis.push( [ "
  • ", - "
    " + DrawTool.contextMenuLayers[i].properties.name + "
    ", + "
    " + F_.sanitize(DrawTool.contextMenuLayers[i].properties.name) + "
    ", "
    ", "
  • " ].join('\n') diff --git a/src/essence/Tools/Draw/config.json b/src/essence/Tools/Draw/config.json index 06deca1a..eb4c9e4d 100644 --- a/src/essence/Tools/Draw/config.json +++ b/src/essence/Tools/Draw/config.json @@ -9,7 +9,8 @@ "Polygon_2_Alias", "Polygon_3_Alias", "Line_Alias", - "Point_Alias" + "Point_Alias", + "All_Alias" ], "preferredTags": ["preferredTagA", "example1"], "hoverLengthOnLines": false From 633fcc3d946642b3b44454e16ead0a01a8e76485 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 29 Sep 2021 13:34:25 -0700 Subject: [PATCH 27/85] Bugfix - Description info for intially off layers --- src/essence/Ancillary/Description.js | 1 + src/essence/Basics/Layers_/Layers_.js | 1 + 2 files changed, 2 insertions(+) diff --git a/src/essence/Ancillary/Description.js b/src/essence/Ancillary/Description.js index cf7ead5c..9b397c53 100644 --- a/src/essence/Ancillary/Description.js +++ b/src/essence/Ancillary/Description.js @@ -89,6 +89,7 @@ var Description = { for (let layer in this.L_.layersNamed) { let l = this.L_.layersNamed[layer] if ( + this.L_.layersGroup[layer] && l.hasOwnProperty('variables') && l.variables.hasOwnProperty('info') && l.variables.info.hasOwnProperty('length') diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 5745cb2f..c1e27e5b 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -234,6 +234,7 @@ var L_ = { let hadToMake = false if (L_.layersGroup[s.name] === false) { await L_.Map_.makeLayer(s, true) + Description.updateInfo() hadToMake = true } if (L_.layersGroup[s.name]) { From c81d642655bd955d1522f839ed17180cc55b20d8 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 29 Sep 2021 13:41:38 -0700 Subject: [PATCH 28/85] Bugfix - Reload Vector tile layers --- src/essence/Basics/Layers_/Layers_.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index c1e27e5b..6bc6b2db 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -240,8 +240,10 @@ var L_ = { if (L_.layersGroup[s.name]) { if (!hadToMake) { // Refresh annotation popups - Object.keys(L_.layersGroup[s.name]._layers).forEach( - (key) => { + if (L_.layersGroup[s.name]._layers) + Object.keys( + L_.layersGroup[s.name]._layers + ).forEach((key) => { const l = L_.layersGroup[s.name]._layers[key] if (l._isAnnotation) { @@ -253,8 +255,7 @@ var L_ = { l._annotationParams.id1 ) } - } - ) + }) } L_.Map_.map.addLayer(L_.layersGroup[s.name]) L_.layersGroup[s.name].setZIndex( From 343584c9ea8eb7f07e074a8e7096c903392e97c5 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 29 Sep 2021 13:56:48 -0700 Subject: [PATCH 29/85] Bugfix - Reload Vector tile layers 2 --- src/essence/Basics/Layers_/Layers_.js | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 6bc6b2db..b35f0093 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -263,9 +263,8 @@ var L_ = { 1 - L_.layersOrdered.indexOf(s.name) ) - L_.Globe_.litho.addLayer( - s.type === 'vector' ? 'clamped' : s.type, - { + if (s.type === 'vector') + L_.Globe_.litho.addLayer('clamped', { name: s.name, order: 1000 - L_.layersIndex[s.name], // Since higher order in litho is on top on: L_.opacityArray[s.name] ? true : false, @@ -290,8 +289,7 @@ var L_ = { opacity: L_.opacityArray[s.name], minZoom: 0, //s.minZoom, maxZoom: 100, //s.maxNativeZoom, - } - ) + }) } } } From b5f821b0bbdce157b64675b43bda30f337065bf5 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 29 Sep 2021 16:44:54 -0700 Subject: [PATCH 30/85] Touch ups and Layer Url docs --- API/Backend/Draw/routes/files.js | 4 +- API/Backend/Geodatasets/routes/geodatasets.js | 108 +++++++++--------- docs/docs.js | 1 + docs/pages/markdowns/Layer_URLs.md | 28 +++++ src/essence/Ancillary/Search.js | 83 ++++++-------- src/essence/Basics/Layers_/LayerCapturer.js | 3 +- src/essence/Tools/Kinds/Kinds.js | 17 +-- 7 files changed, 138 insertions(+), 106 deletions(-) create mode 100644 docs/pages/markdowns/Layer_URLs.md diff --git a/API/Backend/Draw/routes/files.js b/API/Backend/Draw/routes/files.js index 7d2b5682..c8779b7c 100644 --- a/API/Backend/Draw/routes/files.js +++ b/API/Backend/Draw/routes/files.js @@ -113,7 +113,9 @@ router.post("/getfile", function (req, res, next) { (req.body.test === "true" ? "publisheds_test" : "publisheds") + "" + (req.body.intent && req.body.intent.length > 0 - ? " WHERE intent=:intent" + ? req.body.intent === "all" + ? " WHERE intent IN ('polygon', 'line', 'point', 'text', 'arrow')" + : " WHERE intent=:intent" : ""), { replacements: { diff --git a/API/Backend/Geodatasets/routes/geodatasets.js b/API/Backend/Geodatasets/routes/geodatasets.js index 318f3661..be645aa2 100644 --- a/API/Backend/Geodatasets/routes/geodatasets.js +++ b/API/Backend/Geodatasets/routes/geodatasets.js @@ -13,10 +13,10 @@ const Geodatasets = geodatasets.Geodatasets; const makeNewGeodatasetTable = geodatasets.makeNewGeodatasetTable; //Returns a geodataset table as a geojson -router.post("/get", function(req, res, next) { +router.post("/get", function (req, res, next) { get("post", req, res, next); }); -router.get("/get", function(req, res, next) { +router.get("/get", function (req, res, next) { get("get", req, res, next); }); @@ -31,7 +31,7 @@ function get(reqtype, req, res, next) { xyz = { x: parseInt(req.body.x), y: parseInt(req.body.y), - z: parseInt(req.body.z) + z: parseInt(req.body.z), }; } } else if (reqtype == "get") { @@ -41,13 +41,13 @@ function get(reqtype, req, res, next) { xyz = { x: parseInt(req.query.x), y: parseInt(req.query.y), - z: parseInt(req.query.z) + z: parseInt(req.query.z), }; } } //First Find the table name Geodatasets.findOne({ where: { name: layer } }) - .then(result => { + .then((result) => { if (result) { let table = result.dataValues.table; if (type == "geojson") { @@ -55,7 +55,7 @@ function get(reqtype, req, res, next) { .query( "SELECT properties, ST_AsGeoJSON(geom)" + " " + "FROM " + table ) - .spread(results => { + .spread((results) => { let geojson = { type: "FeatureCollection", features: [] }; for (let i = 0; i < results.length; i++) { let properties = results[i].properties; @@ -71,14 +71,14 @@ function get(reqtype, req, res, next) { if (reqtype == "post") { res.send({ status: "success", - body: geojson + body: geojson, }); } else { res.send(geojson); } return null; }) - .catch(error => { + .catch((error) => { res.send({ status: "failure", message: "a" }); }); } else if ( @@ -89,11 +89,11 @@ function get(reqtype, req, res, next) { ) { let ne = { lat: tile2Lat(xyz.y, xyz.z), - lng: tile2Lng(xyz.x + 1, xyz.z) + lng: tile2Lng(xyz.x + 1, xyz.z), }; let sw = { lat: tile2Lat(xyz.y + 1, xyz.z), - lng: tile2Lng(xyz.x, xyz.z) + lng: tile2Lng(xyz.x, xyz.z), }; //We make these slightly large bounds for our initial bounds of data, @@ -151,25 +151,25 @@ function get(reqtype, req, res, next) { ") AS q;", { replacements: { - table: table - } + table: table, + }, } ) - .spread(results => { + .spread((results) => { res.setHeader("Content-Type", "application/x-protobuf"); res.setHeader("Access-Control-Allow-Origin", "*"); if (reqtype == "post") { res.send({ status: "success", - body: results + body: results, }); } else { res.send(Buffer.from(results[0].st_asmvt, "binary")); } return null; }) - .catch(err => { + .catch((err) => { logger( "error", "Geodataset SQL error.", @@ -182,25 +182,25 @@ function get(reqtype, req, res, next) { } else { res.send({ status: "failure", - message: "Unknown type or missing xyz." + message: "Unknown type or missing xyz.", }); } } else { - res.send({ status: "failure", message: "c" }); + res.send({ status: "failure", message: "Not Found" }); } return null; }) - .catch(err => { + .catch((err) => { logger("error", "Failure finding geodataset.", req.originalUrl, req, err); res.send({ status: "failure", message: "d" }); }); } //Returns a list of entries in the geodatasets table -router.post("/entries", function(req, res, next) { +router.post("/entries", function (req, res, next) { Geodatasets.findAll() - .then(sets => { + .then((sets) => { if (sets && sets.length > 0) { let entries = []; for (let i = 0; i < sets.length; i++) { @@ -208,15 +208,15 @@ router.post("/entries", function(req, res, next) { } res.send({ status: "success", - body: { entries: entries } + body: { entries: entries }, }); } else { res.send({ - status: "failure" + status: "failure", }); } }) - .catch(err => { + .catch((err) => { logger( "error", "Failure finding geodatasets.", @@ -225,7 +225,7 @@ router.post("/entries", function(req, res, next) { err ); res.send({ - status: "failure" + status: "failure", }); }); }); @@ -235,10 +235,10 @@ router.post("/entries", function(req, res, next) { * req.body.key * req.body.value */ -router.post("/search", function(req, res, next) { +router.post("/search", function (req, res, next) { //First Find the table name Geodatasets.findOne({ where: { name: req.body.layer } }) - .then(result => { + .then((result) => { if (result) { let table = result.dataValues.table; @@ -250,11 +250,11 @@ router.post("/search", function(req, res, next) { { replacements: { key: req.body.key, - value: req.body.value.replace(/[`;'"]/gi, "") - } + value: req.body.value.replace(/[`;'"]/gi, ""), + }, } ) - .spread(results => { + .spread((results) => { let r = []; for (let i = 0; i < results.length; i++) { let feature = JSON.parse(results[i].st_asgeojson); @@ -264,12 +264,12 @@ router.post("/search", function(req, res, next) { res.send({ status: "success", - body: r + body: r, }); return null; }) - .catch(err => { + .catch((err) => { logger( "error", "SQL error search through geodataset.", @@ -279,27 +279,27 @@ router.post("/search", function(req, res, next) { ); res.send({ status: "failure", - message: "SQL error." + message: "SQL error.", }); }); } else { res.send({ status: "failure", - message: "Layer not found." + message: "Layer not found.", }); } return null; }) - .catch(err => { + .catch((err) => { logger("error", "Failure finding geodataset.", req.originalUrl, req, err); res.send({ - status: "failure" + status: "failure", }); }); }); -router.post("/recreate", function(req, res, next) { +router.post("/recreate", function (req, res, next) { let features = null; try { features = JSON.parse(req.body.geojson).features; @@ -308,19 +308,19 @@ router.post("/recreate", function(req, res, next) { res.send({ status: "failure", message: "Failure: Malformed file.", - body: {} + body: {}, }); } makeNewGeodatasetTable( req.body.name, - function(result) { + function (result) { let checkEnding = result.table.split("_"); if (checkEnding[checkEnding.length - 1] !== "geodatasets") { logger("error", "Malformed table name.", req.originalUrl, req); res.send({ status: "failed", - message: "Malformed table name" + message: "Malformed table name", }); return; } @@ -328,22 +328,26 @@ router.post("/recreate", function(req, res, next) { sequelize .query("TRUNCATE TABLE " + result.table + " RESTART IDENTITY") .then(() => { - populateGeodatasetTable(result.tableObj, features, function(success) { - res.send({ - status: success == true ? "success" : "failure", - message: "", - body: {} - }); - }); + populateGeodatasetTable( + result.tableObj, + features, + function (success) { + res.send({ + status: success == true ? "success" : "failure", + message: "", + body: {}, + }); + } + ); return null; }) - .catch(err => { + .catch((err) => { logger("error", "Recreation error.", req.originalUrl, req, err); res.send(result); }); }, - function(result) { + function (result) { res.send(result); } ); @@ -358,17 +362,17 @@ router.post("/recreate", function(req, res, next) { geom: { crs: { type: "name", properties: { name: "EPSG:4326" } }, type: features[i].geometry.type, - coordinates: features[i].geometry.coordinates - } + coordinates: features[i].geometry.coordinates, + }, }); } Table.bulkCreate(rows, { returning: true }) - .then(function(response) { + .then(function (response) { cb(true); return null; }) - .catch(function(err) { + .catch(function (err) { logger( "error", "Geodatasets: Failed to populate a geodataset table!", diff --git a/docs/docs.js b/docs/docs.js index 4ee5ea4e..419cea10 100644 --- a/docs/docs.js +++ b/docs/docs.js @@ -19,6 +19,7 @@ let configure = [ "Time_Tab", "Kinds", "Vector_Styling", + "Layer_URLs", "Keys", "Manage_Datasets", "Manage_Geodatasets", diff --git a/docs/pages/markdowns/Layer_URLs.md b/docs/pages/markdowns/Layer_URLs.md new file mode 100644 index 00000000..7e93ab2a --- /dev/null +++ b/docs/pages/markdowns/Layer_URLs.md @@ -0,0 +1,28 @@ +# Layer URLs + +Layers in the Configure CMS can take in a variety of URLs aside from standard absolute and relative ones. Visit the Layers Tab page for more information about constructing standard URLs. + +## API + +### `api:publishedall` + +_For a vector layer._ +Grabs all features published via the DrawTool + +### `api:published:` + +_For a vector layer._ +Grabs all features published via the DrawTool of a certain intent. +Possible values are: `roi, campaign, campsite, signpost, trail, all` + +### `api:tacticaltargets` + +_For a vector layer._ +If applicable, grabs all ingested tactical targets. + +## GeoDatasets + +### `geodatasets:` + +_For a vector or vectortile layer._ +Grab features uploaded to the CMS as a geodataset (a geojson dataset). _Case Sensitive_ diff --git a/src/essence/Ancillary/Search.js b/src/essence/Ancillary/Search.js index dacdf347..f89cc9e8 100644 --- a/src/essence/Ancillary/Search.js +++ b/src/essence/Ancillary/Search.js @@ -1,4 +1,5 @@ import $ from 'jquery' +import F_ from '../Basics/Formulae_/Formulae_' //jqueryUI import * as d3 from 'd3' @@ -149,7 +150,7 @@ function initializeSearch() { }) } -function changeSearchField(val, selectedPlaceholder) { +async function changeSearchField(val, selectedPlaceholder) { if (selectedPlaceholder || val == null) { // We're on the placeholder Search.arrayToSearch = [] @@ -161,51 +162,43 @@ function changeSearchField(val, selectedPlaceholder) { if (Map_ != null) { Search.lname = val - let urlSplit = L_.layersNamed[Search.lname].url.split(':') - Search.layerType = L_.layersNamed[Search.lname].type - if (urlSplit[0] == 'geodatasets' && urlSplit[1] != null) { - Search.type = 'geodatasets' - Search.lastGeodatasetLayerName = urlSplit[1] - $('#SearchSelect').css({ display: 'inherit' }) - $('#SearchBoth').css({ display: 'inherit' }) - if (document.getElementById('auto_search') != null) { - document.getElementById('auto_search').placeholder = - getSearchFieldKeys(Search.lname) - } + if (L_.toggledArray[Search.lname] !== true) { + await L_.toggleLayer(L_.layersNamed[Search.lname]) + } - initializeSearch() - } else { - Search.type = 'geojson' - $('#SearchSelect').css({ display: 'inherit' }) - $('#SearchBoth').css({ display: 'inherit' }) - - var searchFile = L_.layersNamed[Search.lname].url - - $.getJSON(L_.missionPath + searchFile, function (data) { - Search.arrayToSearch = [] - var props - for (var i = 0; i < data.features.length; i++) { - props = data.features[i].properties - Search.arrayToSearch.push( - getSearchFieldStringForFeature(Search.lname, props) - ) - } - if (Search.arrayToSearch[0]) { - if (!isNaN(Search.arrayToSearch[0])) - Search.arrayToSearch.sort(function (a, b) { - return a - b - }) - else Search.arrayToSearch.sort() - } - if (document.getElementById('auto_search') != null) { - document.getElementById('auto_search').placeholder = - getSearchFieldKeys(Search.lname) - } + Search.type = 'geojson' + $('#SearchSelect').css({ display: 'inherit' }) + $('#SearchBoth').css({ display: 'inherit' }) - initializeSearch() - }) + Search.arrayToSearch = [] + let data + try { + data = L_.layersGroup[Search.lname].toGeoJSON() + } catch (err) { + data = { features: [] } + } + var props + for (var i = 0; i < data.features.length; i++) { + props = data.features[i].properties + Search.arrayToSearch.push( + getSearchFieldStringForFeature(Search.lname, props) + ) + } + if (Search.arrayToSearch[0]) { + if (!isNaN(Search.arrayToSearch[0])) + Search.arrayToSearch.sort(function (a, b) { + return a - b + }) + else Search.arrayToSearch.sort() } + if (document.getElementById('auto_search') != null) { + document.getElementById('auto_search').placeholder = + getSearchFieldKeys(Search.lname) + } + + initializeSearch() + //} } } @@ -409,13 +402,13 @@ function getSearchFieldStringForFeature(name, props) { for (var i = 0; i < sf.length; i++) { switch (sf[i][0].toLowerCase()) { case '': //no function - str += props[sf[i][1]] + str += F_.getIn(props, sf[i][1]) break case 'round': - str += Math.round(props[sf[i][1]]) + str += Math.round(F_.getIn(props, sf[i][1])) break case 'rmunder': - str += props[sf[i][1]].replace('_', ' ') + str += F_.getIn(props, sf[i][1]).replace('_', ' ') break } if (i != sf.length - 1) str += ' ' diff --git a/src/essence/Basics/Layers_/LayerCapturer.js b/src/essence/Basics/Layers_/LayerCapturer.js index 802280fb..d0672e27 100644 --- a/src/essence/Basics/Layers_/LayerCapturer.js +++ b/src/essence/Basics/Layers_/LayerCapturer.js @@ -35,6 +35,7 @@ export const captureVector = (layerObj, options, cb) => { if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl let done = true + let urlSplitRaw = layerObj.url.split(':') let urlSplit = layerObj.url.toLowerCase().split(':') switch (urlSplit[0]) { @@ -42,7 +43,7 @@ export const captureVector = (layerObj, options, cb) => { calls.api( 'geodatasets_get', { - layer: urlSplit[1], + layer: urlSplitRaw[1], type: 'geojson', }, function (data) { diff --git a/src/essence/Tools/Kinds/Kinds.js b/src/essence/Tools/Kinds/Kinds.js index 78df296d..da53cf8a 100644 --- a/src/essence/Tools/Kinds/Kinds.js +++ b/src/essence/Tools/Kinds/Kinds.js @@ -31,7 +31,7 @@ var Kinds = { var lngM = F_.metersToDegrees(wm) / 2 var latM = lngM * (h / w) var center = [layer._latlng.lng, layer._latlng.lat] - var angle = -layer.feature.properties.yaw_rad + var angle = -layer.feature.properties.yaw_rad || 0 var topLeft = F_.rotatePoint( { y: layer._latlng.lat + latM, @@ -71,12 +71,15 @@ var Kinds = { [bottomRight.y, bottomRight.x], [bottomLeft.y, bottomLeft.x], ] - Map_.tempOverlayImage = L.imageTransform( - 'public/images/rovers/PerseveranceTopDown.png', - anchors, - { opacity: 1, clip: anchors } - ) - Map_.tempOverlayImage.addTo(Map_.map).bringToBack() + + try { + Map_.tempOverlayImage = L.imageTransform( + 'public/images/rovers/PerseveranceTopDown.png', + anchors, + { opacity: 1, clip: anchors } + ) + Map_.tempOverlayImage.addTo(Map_.map).bringToBack() + } catch (err) {} useInfo(false) break From e19477a576209a96e621db82ea640078250a9d4a Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 30 Sep 2021 14:17:14 -0700 Subject: [PATCH 31/85] Coordinates and Search touch ups --- src/essence/Ancillary/Coordinates.js | 8 +++--- src/essence/Ancillary/Search.js | 32 ++++++++++++++++++++-- src/external/JQuery/jquery.autocomplete.js | 2 ++ 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/essence/Ancillary/Coordinates.js b/src/essence/Ancillary/Coordinates.js index 5b2f9900..becf701c 100644 --- a/src/essence/Ancillary/Coordinates.js +++ b/src/essence/Ancillary/Coordinates.js @@ -297,7 +297,7 @@ var Coordinates = { keyAsName = Map_.activeLayer.feature.properties[0] } d3.select('#mouseDesc').html( - 'Site Frame - ' + + 'Local Level - ' + Map_.activeLayer.options.layerName + ': ' + keyAsName + @@ -306,7 +306,7 @@ var Coordinates = { })` ) d3.select('#mouseDescPicking').html( - 'Site Frame - ' + + 'Local Level - ' + Map_.activeLayer.options.layerName + ': ' + keyAsName + @@ -325,12 +325,12 @@ var Coordinates = { 0 } else { d3.select('#mouseDesc').html( - `Site Frame - Map Origin (X,Y${ + `Local Level - Map Origin (X,Y${ Coordinates.elevation != null ? ',Z' : '' })` ) d3.select('#mouseDescPicking').html( - `Site Frame - Map Origin (X,Y${ + `Local Level - Map Origin (X,Y${ Coordinates.elevation != null ? ',Z' : '' })` ) diff --git a/src/essence/Ancillary/Search.js b/src/essence/Ancillary/Search.js index f89cc9e8..b64509ee 100644 --- a/src/essence/Ancillary/Search.js +++ b/src/essence/Ancillary/Search.js @@ -1,6 +1,7 @@ import $ from 'jquery' import F_ from '../Basics/Formulae_/Formulae_' //jqueryUI +import turf from 'turf' import * as d3 from 'd3' import Dropy from '../../external/Dropy/dropy' @@ -130,7 +131,30 @@ function initializeSearch() { $('#auto_search').autocomplete({ lookup: Search.arrayToSearch, lookupLimit: 100, - minChars: 2, + minChars: 1, + transformResult: function (response, originalQuery) { + let resultSuggestions = [] + $.map(response, function (jsonItem) { + if (typeof jsonItem != 'string') { + $.map(jsonItem, function (suggestionItem) { + resultSuggestions.push(suggestionItem) + }) + } + }) + resultSuggestions.sort(function (a, b) { + const aStart = String(a.value).match( + new RegExp(originalQuery, 'i') + ) || { index: -1 }, + bStart = String(b.value).match( + new RegExp(originalQuery, 'i') + ) || { index: -1 } + if (aStart.index != bStart.index) + return aStart.index - bStart.index + else return a > b ? 1 : -1 + }) + response.suggestions = resultSuggestions + return response + }, onSelect: function (event) { searchBoth(event.value) }, @@ -448,8 +472,10 @@ function getMapZoomCoordinate(layers) { var longitudeValidRange = [-180, 180] for (var i = 0; i < layers.length; i++) { - var latitude = layers[i].feature.geometry.coordinates[1] - var longitude = layers[i].feature.geometry.coordinates[0] + const center = turf.center(layers[0].feature)?.geometry + ?.coordinates || [0, 0] + var latitude = center[1] + var longitude = center[0] //make sure latitude and longitude are in [-90, 90] and [-180, 180] if ( diff --git a/src/external/JQuery/jquery.autocomplete.js b/src/external/JQuery/jquery.autocomplete.js index 7cba6f6d..6ec646fb 100644 --- a/src/external/JQuery/jquery.autocomplete.js +++ b/src/external/JQuery/jquery.autocomplete.js @@ -614,6 +614,8 @@ if (that.isLocal) { response = that.getSuggestionsLocal(q) + if (typeof options.transformResult === 'function') + response = options.transformResult(response, q) } else { if ($.isFunction(serviceUrl)) { serviceUrl = serviceUrl.call(that.element, q) From ad298806aa40d9d7cde555b57502ef27a5b669ca Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 30 Sep 2021 14:27:46 -0700 Subject: [PATCH 32/85] Search touch ups 2 --- src/essence/Ancillary/Search.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/essence/Ancillary/Search.js b/src/essence/Ancillary/Search.js index b64509ee..69622d38 100644 --- a/src/essence/Ancillary/Search.js +++ b/src/essence/Ancillary/Search.js @@ -195,6 +195,8 @@ async function changeSearchField(val, selectedPlaceholder) { $('#SearchSelect').css({ display: 'inherit' }) $('#SearchBoth').css({ display: 'inherit' }) + $('#auto_search').val('') + Search.arrayToSearch = [] let data try { @@ -472,8 +474,8 @@ function getMapZoomCoordinate(layers) { var longitudeValidRange = [-180, 180] for (var i = 0; i < layers.length; i++) { - const center = turf.center(layers[0].feature)?.geometry - ?.coordinates || [0, 0] + const center = turf.center(layers[i].feature)?.geometry + ?.coordinates || [-1001, -1001] var latitude = center[1] var longitude = center[0] From 04f85a473404d6cf37621e08d7987b4c86ec5fb5 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 6 Oct 2021 10:05:35 -0700 Subject: [PATCH 33/85] DrawTool - Text Rotation --- .../great_circle_calculator.pyc | Bin 6194 -> 7924 bytes src/css/mmgis.css | 4 ++ src/css/mmgisUI.css | 36 ++++++++++ src/essence/Basics/Layers_/Layers_.js | 8 ++- src/essence/Tools/Draw/DrawTool.css | 9 +-- src/essence/Tools/Draw/DrawTool_Editing.js | 65 +++++++++++++++++- src/essence/Tools/Draw/DrawTool_Files.js | 8 +-- src/essence/Tools/Measure/MeasureTool.js | 42 +++++++---- 8 files changed, 148 insertions(+), 24 deletions(-) diff --git a/private/api/great_circle_calculator/great_circle_calculator.pyc b/private/api/great_circle_calculator/great_circle_calculator.pyc index 3fc89c714175e5789f6149ffb477e47fd121ee65..f269800a263684005ae2cbb42a8d32062b906e9b 100644 GIT binary patch delta 3097 zcmaJ@O>7%g5T3V=9sk>j*Y-AP6E`ib)BlD86a<6<%BiXbOAaDWSf3nwJ5T#z_$;YVCh_-5AmQ9;<=*_nCsX6DVC_dS1h z>i0Xw6TcO*Kfip|S){>d2=7@u{XedcpAFq4t)!`wp;m^JJ49|u6>nxa;XFw?CFUnke3`DXR{2XBVnCO%Dt#rV7`$9KB1lpIJiv6z6kxZ00} zVF*3P^_=cN!J~a|Fq8fCFZcYNiE!$tpzXB%cCWw4u212~5vA!Kww@e{9#_>cNkNKy zq@qYGx+=e?3<`!RNRw}npCE0J3w?ru4Cx{2-IZ`*kR^AVf*fHh0xUB{?l4t@0&}`R zmd=wI6iFvZr^pCO6qHF1lTJezp>#x=KNfe8i}*VNfSOy~SIiH$}fk^f5mclAESroSvUkeujCSrK<+r`}FN9*h_kx zbG!xP?5ZZy_lc{RpCCU=dTd8yx*4iyi}W5cb)APyy^l*=^aN69khb%J_7CeX-eY>QhuNtO{Dqu{vo!7+AM#a?qKZVM(iP>LIfnKUyd8-&NV z%thRh>U^j&+!owod6|hLhh57{+0iCuaDp`U=LEQuq)*bkUy!JA9C#nZ`H#?0N#^5x zcua0hc-nH)+{*wFZfN6Ab^n^vb2^PHUU#wG^&2baOjetiDPyFCWP<<~m?JNrKB z&3X{XGnkZ_Fu-{Xc>5ep*;0wXhz>yr^e()HCAW-o6UNc&@_3H9ot9O z>pJ>8H=@=yzRM+zTW@eLZ74B>`=1!;;-~7R=!@bRbuM~L)uL?aP>9nc`B%P0xtN7cdmyz*GbL4}gHte~kcqFbE(S+6FZE1)u;-SS>&#z?Kws9se41 zI=(LlQ{Z{ml<0cNY~tpML&hfT3s$i&hDAnD&`h*h8f$=uy7hTXf7u6$vr zLiBa@aLCOpc}j;nIBz%RDvcpHCTX6-1W9uXob4*R*ltJhbFtT5wi);B$C->Xkv8Sl zZQ_YZ-;3U_ccLF^`_+fhU$qHkMfLg4(zI5kX?;-Ijf#(;=t5Uc#YI=9nN%X0VrE3B6AHFF zL9`bU#GS5NG&@&rb?HU~{Ri&!2l$;kZN(~v+;7gg=XuZhex7+dQ;q$|m`BcixY4HV zUku+Sj{op!_58(7io67^YqVgHr_(yof=OOd2^M)NC8WuN)ueSn3mNj_77o{>HFNH4FpivN`P$N&!T8suM3S-p& zN@0@11eHUb!Z?++fk6Y4f;fe!uaUDR{#5KB!Tx*=A<2Tx-grXfy+^qNNYAWb3qNkhs|n4$R~rK(1CkbS$(KT6{&>YN)X0gz}XOM{2v&k9Yh zWa>j-|19M5R5Q;b>S_!E&@kk(F?}4ffp52`zU^fnuOn&&t==qN2g}`lpoA7|jja4) zOv#)%BVSr&(UM!%t9>c<+7BSJEXtxFhFj??+MJ0C*I=+1xNJkIyev1zP+%Bguo)bA zEcaR*9Dd4u6!~%7G&snO{N=Y=DBtJu+U(r$R3V|A*polauBwPC_n#v7?Kk4AoN`Wz zrffT>FJljQ`>i-ROqK-G1Y{{=^fsotyKD!KpY^%T;_)JKG&BN)s*h zTkW8`-1}>lu%TZfuX8(SxfND9$D%t5bn83%ihGFl!)m*oN-=*Gs$T?9ipf+QKB~Oa zgf1`DCRdZ}%2gvig0m67RPVn@rkJ4G9AjS&@VY(--R`(~PO(cnm1nWvyXkU8cZ$Jb zP;}(yHgF>FyYhSOu~?E1M(ZLcUyNQKyVk$gi6%7;FZTe$B*RgL8QH9F*j#Wz%L_A> Ms~UO3GDgzQFLu+^SpWb4 diff --git a/src/css/mmgis.css b/src/css/mmgis.css index 144dfa23..f34b1ee0 100644 --- a/src/css/mmgis.css +++ b/src/css/mmgis.css @@ -693,6 +693,10 @@ body { transition: bottom 0.2s ease-in; } +.leaflet-popup-annotation > .leaflet-popup-content-wrapper { + overflow: visible; +} + .highlightAnim1 { animation-name: highlightAnim1; animation-duration: 1.2s; diff --git a/src/css/mmgisUI.css b/src/css/mmgisUI.css index eec27a87..6b5fd9da 100644 --- a/src/css/mmgisUI.css +++ b/src/css/mmgisUI.css @@ -918,6 +918,42 @@ blink { cursor: pointer; } +/*Slider3*/ + +.slider3 { + -webkit-appearance: none; + width: 100%; + height: 17px; + background: #ccc; + border: 1px solid #aaa; + border-radius: 8px; + outline: none; + opacity: 0.8; + transition: opacity 0.4s; +} + +.slider3:hover { + opacity: 1; +} + +.slider3::-webkit-slider-thumb { + -webkit-appearance: none; + appearance: none; + width: 17px; + height: 17px; + border-radius: 50%; + background: #111; + cursor: pointer; +} + +.slider3::-moz-range-thumb { + width: 25px; + height: 25px; + border-radius: 50%; + background: #111; + cursor: pointer; +} + /*=====+==*/ /*Other*/ diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index b35f0093..9bc6bb7f 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -676,12 +676,14 @@ var L_ = { (s.fillColor != null ? 'color: ' + s.fillColor + '; ' : '') + (s.fontSize != null ? 'font-size: ' + s.fontSize + '; ' : '') + (s.rotation != null - ? 'transform: rotateX)' + s.rotation + 'deg); ' + ? 'transform: rotateZ(' + + parseInt(!isNaN(s.rotation) ? s.rotation : 0) * -1 + + 'deg) translateY(-20%); ' : '') // prettier-ignore const popup = L.popup({ - className: 'leaflet-popup-annotation', + className: `leaflet-popup-annotation${!andAddToMap ? ' noPointerEvents' : ''}`, closeButton: false, autoClose: false, closeOnEscapeKey: false, @@ -696,7 +698,7 @@ var L_ = { ) ) .setContent( - '
    ' + + "
    " + "
    ", "
    None
    ", "
    ", - "
    ", + "
    ", "
    ", "
    ", "
    ", @@ -744,6 +746,15 @@ var Editing = { "
    42px
    ", "
    54px
    ", "
    ", + + + "
    ", + "
    Rotation
    ", + "
    " + (style.rotation || '0') + "deg
    ", + "
    ", + "
    ", + "", + "
    ", "
    ", "
    ", @@ -916,6 +927,7 @@ var Editing = { updateWidth(l.properties.style.width, l.shape) updateFontSize(l.properties.style.fontSize, l.shape) + updateRotation(l.properties.style.rotation, l.shape) if (justThis != null) break } @@ -1930,6 +1942,49 @@ var Editing = { else $('.fontsize').prev().css('background', 'inherit') } + //ROTATION + $('.rotationpick > input').on('input', function () { + const v = $(this).val() + updateRotation(v) + }) + function updateRotation(v, layer) { + if (v == null) return + + DrawTool.contextMenuChanges.style.rotation = true + + $('.rotation.stylevalue').text(v + 'deg') + $('.rotation.stylevalue').attr('v', v) + + for (var c in DrawTool.contextMenuLayers) { + var s = DrawTool.contextMenuLayers[c].shape + var p = s.feature.properties._ + $('#DrawToolAnnotation_' + p.file_id + '_' + p.id).css( + 'transform', + `rotateZ(${ + parseInt(!isNaN(v) ? v : 0) * -1 + }deg) translateY(-20%)` + ) + } + + if (properties && v != properties.style.rotation) + $('.rotation') + .parent() + .find('.drawToolStyleHighlight') + .css('background', DrawTool.highlightColor) + else + $('.rotation') + .parent() + .find('.drawToolStyleHighlight') + .css('background', 'inherit') + + //Group change + if (!layer && DrawTool.contextMenuChanges.use) + $('.rotation') + .prev() + .css('background', DrawTool.highlightGradient) + else $('.rotation').prev().css('background', 'inherit') + } + //CLOSE $('.drawToolContextMenuHeaderClose').on('click', function () { if (DrawTool.contextMenuLayer && !displayOnly) { @@ -2381,6 +2436,14 @@ var Editing = { ) .attr('v') .toLowerCase() + if ( + hasRotation && + (force || DrawTool.contextMenuChanges.style.rotation) + ) + newProperties.style.rotation = $( + '.drawToolContextMenu .rotationPicker > input' + ).val() + return newProperties } }, diff --git a/src/essence/Tools/Draw/DrawTool_Files.js b/src/essence/Tools/Draw/DrawTool_Files.js index f966b43b..8e7ebccc 100644 --- a/src/essence/Tools/Draw/DrawTool_Files.js +++ b/src/essence/Tools/Draw/DrawTool_Files.js @@ -379,12 +379,12 @@ var Files = { } function addFileToList(file) { - var checkState = '-blank-outline' + var checkState = '' var onState = ' on' var shieldState = '' var ownedByUser = false - if (DrawTool.currentFileId == file.id) checkState = '-intermediate' + if (DrawTool.currentFileId == file.id) checkState = ' checked' if (DrawTool.filesOn.indexOf(file.id) == -1) onState = '' @@ -420,7 +420,7 @@ var Files = { if (file.is_master) { d3.select('#drawToolDrawFilesListMaster') .append('li') - .attr('class', 'drawToolDrawFilesListElem') + .attr('class', `drawToolDrawFilesListElem${checkState}`) .attr('file_id', file.id) .attr('file_name', file.file_name) .attr('file_owner', file.file_owner) @@ -441,7 +441,7 @@ var Files = { } else { d3.select('#drawToolDrawFilesList') .append('li') - .attr('class', 'drawToolDrawFilesListElem') + .attr('class', `drawToolDrawFilesListElem${checkState}`) .attr('file_id', file.id) .attr('file_name', file.file_name) .attr('file_owner', file.file_owner) diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index dc58beaf..af8e9671 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -25,7 +25,7 @@ let measureToolLayer = null let clickedLatLngs = [] let distLineToMouse = null let distMousePoint = null -let distDisplayUnit = "meters" +let distDisplayUnit = 'meters' let mode = 'segment' let steps = 100 let profileData = [] @@ -126,7 +126,9 @@ const Measure = () => { data={{ labels: MeasureTool.lastData.map((d) => { const xAxes = parseInt(d[2], 10) - return distDisplayUnit == 'kilometers' ? (xAxes/1000).toFixed(2) : xAxes + return distDisplayUnit == 'kilometers' + ? (xAxes / 1000).toFixed(2) + : xAxes }), datasets: [ { @@ -187,7 +189,9 @@ const Measure = () => { callbacks: { label: (item) => `${item.yLabel}m`, title: (item) => - distDisplayUnit == 'meters' ? `${item[0].xLabel}m from start` : `${item[0].xLabel}km from start,` + distDisplayUnit == 'meters' + ? `${item[0].xLabel}m from start` + : `${item[0].xLabel}km from start,`, }, }, onHover: (e, el, el2) => { @@ -540,7 +544,7 @@ function makeMeasureToolLayer() { ) / rAm if (distAzimuth < 0) distAzimuth = 360 + distAzimuth //Map to 0 to 360 degrees if (i == clickedLatLngs.length - 1) { - if(distDisplayUnit == 'meters'){ + if (distDisplayUnit == 'meters') { temp.bindTooltip( '' + roundedTotalDist + 'm ' + distAzimuth + '°', { @@ -550,9 +554,13 @@ function makeMeasureToolLayer() { offset: [4, 0], } ) - }else if(distDisplayUnit == "kilometers"){ + } else if (distDisplayUnit == 'kilometers') { temp.bindTooltip( - '' + (roundedTotalDist/1000).toFixed(2) + 'km ' + distAzimuth + '°', + '' + + (roundedTotalDist / 1000).toFixed(2) + + 'km ' + + distAzimuth + + '°', { permanent: true, direction: 'right', @@ -809,21 +817,31 @@ function makeGhostLine(lng, lat) { //distMousePoint.bindTooltip("" + roundedTotalDist + "m\n (+" + roundedDist + "m) " + distAzimuth + "°", // {permanent: true, direction: 'right', className: "distLabel", className: "noPointerEvents", offset: [15,-15]}) //distMousePoint.addTo(Map_.map); - if(distDisplayUnit == 'meters'){ + if (distDisplayUnit == 'meters') { CursorInfo.update( `${roundedTotalDist}m ${ mode === 'continuous' ? `(+${roundedDist}m)` : '' } ${distAzimuth}°`, null, - false + false, + null, + null, + null, + true ) - }else if (distDisplayUnit == "kilometers"){ + } else if (distDisplayUnit == 'kilometers') { CursorInfo.update( - `${(roundedTotalDist/1000).toFixed(2)}km ${ - mode === 'continuous' ? `(+${(roundedDist/1000).toFixed(2)}km)` : '' + `${(roundedTotalDist / 1000).toFixed(2)}km ${ + mode === 'continuous' + ? `(+${(roundedDist / 1000).toFixed(2)}km)` + : '' } ${distAzimuth}°`, null, - false + false, + null, + null, + null, + true ) } } From c3c17a287a7bcdb110cc0c8a506f6a1a72244e9c Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 11 Oct 2021 08:41:04 -0700 Subject: [PATCH 34/85] Fix for annotation features that are on initially --- src/essence/Basics/Layers_/Layers_.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 9bc6bb7f..dd263613 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -702,7 +702,7 @@ var L_ = { "
    " + `${feature.properties.name.replace(/[<>;{}]/g, '')}`, '
    ' + From e347f94590150df3143545afd5617919145cd1b9 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 19 Oct 2021 08:59:30 -0700 Subject: [PATCH 35/85] Fix text rotation anchor and Search layer toggle bug --- src/css/mmgis.css | 8 +++-- src/essence/Ancillary/Search.js | 35 ++++++++++++++++++++-- src/essence/Basics/Layers_/Layers_.js | 2 +- src/essence/Tools/Draw/DrawTool.css | 1 - src/essence/Tools/Draw/DrawTool_Editing.js | 4 +-- 5 files changed, 41 insertions(+), 9 deletions(-) diff --git a/src/css/mmgis.css b/src/css/mmgis.css index f34b1ee0..8e91552e 100644 --- a/src/css/mmgis.css +++ b/src/css/mmgis.css @@ -445,8 +445,8 @@ body { } .leaflet-popup-annotation { - left: 0 !important; - top: -10px !important; + left: 0px !important; + top: -15px !important; } .leaflet-popup-annotation > .leaflet-popup-content-wrapper { background: transparent; @@ -457,6 +457,10 @@ body { margin: 0; width: auto !important; } +.leaflet-popup-annotation .leaflet-popup-content > div { + position: relative; + left: -50%; +} .leaflet-popup-annotation textarea { background: rgba(0, 0, 0, 0.4); color: white; diff --git a/src/essence/Ancillary/Search.js b/src/essence/Ancillary/Search.js index 69622d38..dc1abccb 100644 --- a/src/essence/Ancillary/Search.js +++ b/src/essence/Ancillary/Search.js @@ -189,6 +189,17 @@ async function changeSearchField(val, selectedPlaceholder) { Search.layerType = L_.layersNamed[Search.lname].type if (L_.toggledArray[Search.lname] !== true) { await L_.toggleLayer(L_.layersNamed[Search.lname]) + + const layerCheck = $( + `#LayersTool${Search.lname.replace( + /\s/g, + '' + )} .title .checkboxcont .checkbox` + ) + if (layerCheck.length > 0) { + $(layerCheck[0]).removeClass('off') + $(layerCheck[0]).addClass('on') + } } Search.type = 'geojson' @@ -290,6 +301,16 @@ function searchGeodatasets() { if (!L_.toggledArray[Search.lname]) { wasOff = true L_.toggleLayer(L_.layersNamed[Search.lname]) + const layerCheck = $( + `#LayersTool${Search.lname.replace( + /\s/g, + '' + )} .title .checkboxcont .checkbox` + ) + if (layerCheck.length > 0) { + $(layerCheck[0]).removeClass('off') + $(layerCheck[0]).addClass('on') + } } function selectFeature() { @@ -337,11 +358,21 @@ function doWithSearch(doX, forceX, forceSTS, isURLSearch, value) { var markers = L_.layersGroup[Search.lname] var selectLayers = [] var gotoLayers = [] - var targetsID // Turn the layer on if it's off - if (!L_.toggledArray[Search.lname]) + if (!L_.toggledArray[Search.lname]) { L_.toggleLayer(L_.layersNamed[Search.lname]) + const layerCheck = $( + `#LayersTool${Search.lname.replace( + /\s/g, + '' + )} .title .checkboxcont .checkbox` + ) + if (layerCheck.length > 0) { + $(layerCheck[0]).removeClass('off') + $(layerCheck[0]).addClass('on') + } + } if (doX == 'both' || doX == 'select') { L_.resetLayerFills() diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index dd263613..aabdd22d 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -678,7 +678,7 @@ var L_ = { (s.rotation != null ? 'transform: rotateZ(' + parseInt(!isNaN(s.rotation) ? s.rotation : 0) * -1 + - 'deg) translateY(-20%); ' + 'deg); ' : '') // prettier-ignore diff --git a/src/essence/Tools/Draw/DrawTool.css b/src/essence/Tools/Draw/DrawTool.css index f1028f42..7e2da3cc 100644 --- a/src/essence/Tools/Draw/DrawTool.css +++ b/src/essence/Tools/Draw/DrawTool.css @@ -1754,7 +1754,6 @@ padding: 2px; white-space: nowrap; cursor: pointer; - transform: translateY(-20%); transition: all 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95), transform 0s ease-in-out; } diff --git a/src/essence/Tools/Draw/DrawTool_Editing.js b/src/essence/Tools/Draw/DrawTool_Editing.js index 9b56972f..e436f2e7 100644 --- a/src/essence/Tools/Draw/DrawTool_Editing.js +++ b/src/essence/Tools/Draw/DrawTool_Editing.js @@ -1960,9 +1960,7 @@ var Editing = { var p = s.feature.properties._ $('#DrawToolAnnotation_' + p.file_id + '_' + p.id).css( 'transform', - `rotateZ(${ - parseInt(!isNaN(v) ? v : 0) * -1 - }deg) translateY(-20%)` + `rotateZ(${parseInt(!isNaN(v) ? v : 0) * -1}deg)` ) } From 286985ef0b798323e639b1f25c020f98a84bec9a Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 19 Oct 2021 10:21:56 -0700 Subject: [PATCH 36/85] Fix MeasureTool for Globe --- src/essence/Tools/Measure/MeasureTool.js | 76 +++++++++++++++++++++--- 1 file changed, 67 insertions(+), 9 deletions(-) diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index af8e9671..5b51ec1a 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -280,10 +280,9 @@ let MeasureTool = { .off('mousemove', MeasureTool.moveMap) .off('mouseout', MeasureTool.mouseOutMap) - // Globe_.litho - // .getContainer() - // .removeEventListener('click', MeasureTool.clickGlobe) - // .removeEventListener('mousemove', MeasureTool.moveGlobe) + const globeCont = Globe_.litho.getContainer() + globeCont.removeEventListener('click', MeasureTool.clickGlobe, false) + globeCont.removeEventListener('mousemove', MeasureTool.moveGlobe, false) Viewer_.imageViewerMap.removeHandler( 'canvas-click', @@ -394,15 +393,20 @@ let MeasureTool = { Globe_.litho.addLayer( 'vector', { - name: '_MeasureToolGlobeFocusMarker', - id: '_MeasureToolGlobeFocusMarker', + name: '_measurePoint', + id: '_measurePoint', on: true, opacity: 1, + order: 2, minZoom: 0, maxZoom: 30, style: { - fillColor: 'yellow', - color: '#000', + default: { + fillColor: 'yellow', + color: '#000', + weight: 2, + radius: 8, + }, }, geojson: { type: 'FeatureCollection', @@ -411,7 +415,7 @@ let MeasureTool = { type: 'Feature', geometry: { type: 'Point', - coordinates: [[lat, lng, z]], + coordinates: [[lng, lat, 3 + z]], }, }, ], @@ -422,6 +426,7 @@ let MeasureTool = { }, clearFocusPoint() { Map_.rmNotNull(MeasureTool.mapFocusMarker) + Globe_.litho.removeLayer('_measurePoint') }, undo: function (e) { clickedLatLngs.pop() @@ -814,6 +819,59 @@ function makeGhostLine(lng, lat) { { lat: lat, lng: lng }, { className: 'noPointerEvents', color: 'red' } ).setRadius(3) + + Globe_.litho.removeLayer('_measure') + + Globe_.litho.addLayer( + 'vector', + { + name: '_measure', + id: '_measure', + on: true, + order: 2, + opacity: 1, + minZoom: 0, + maxZoom: 30, + style: { + default: { + fillColor: 'white', + weight: 5, + }, + }, + geojson: { + type: 'FeatureCollection', + features: [ + { + type: 'Feature', + geometry: { + type: 'LineString', + coordinates: [ + [ + endDC['y'], + endDC['x'], + 3 + + Globe_.litho.getElevationAtLngLat( + endDC['y'], + endDC['x'] + ), + ], + [ + lng, + lat, + 3 + + Globe_.litho.getElevationAtLngLat( + lng, + lat + ), + ], + ], + }, + }, + ], + }, + }, + 1 + ) //distMousePoint.bindTooltip("" + roundedTotalDist + "m\n (+" + roundedDist + "m) " + distAzimuth + "°", // {permanent: true, direction: 'right', className: "distLabel", className: "noPointerEvents", offset: [15,-15]}) //distMousePoint.addTo(Map_.map); From 0a5a93333704d46eaa0b7329f722b08c063a9fc1 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 19 Oct 2021 10:23:22 -0700 Subject: [PATCH 37/85] Fix MeasureTool for Globe 2 --- src/essence/Tools/Measure/MeasureTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index 5b51ec1a..4db51b2e 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -296,7 +296,7 @@ let MeasureTool = { Map_.rmNotNull(measureToolLayer) Globe_.litho.removeLayer('_measure') - Globe_.litho.removeLayer('_MeasureToolGlobeFocusMarker') + Globe_.litho.removeLayer('_measurePoint') CursorInfo.hide() From 655cc63d4a8237f508bb8922d859115bc49ab91d Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 25 Oct 2021 09:10:00 -0700 Subject: [PATCH 38/85] Support ENMultipier for rxy and site coords --- src/essence/Ancillary/Coordinates.js | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/essence/Ancillary/Coordinates.js b/src/essence/Ancillary/Coordinates.js index becf701c..6a0eb317 100644 --- a/src/essence/Ancillary/Coordinates.js +++ b/src/essence/Ancillary/Coordinates.js @@ -267,13 +267,15 @@ var Coordinates = { ( Coordinates.mouseLngLat[0] * (Math.PI / 180) * - F_.radiusOfPlanetMajor + F_.radiusOfPlanetMajor * + Coordinates.coordENMultiplier[0] ).toFixed(3) + 'm, ' + ( Coordinates.mouseLngLat[1] * (Math.PI / 180) * - F_.radiusOfPlanetMajor + F_.radiusOfPlanetMajor * + Coordinates.coordENMultiplier[1] ).toFixed(3) + 'm' ) @@ -339,13 +341,15 @@ var Coordinates = { ( Coordinates.mouseLngLat[1] * (Math.PI / 180) * - F_.radiusOfPlanetMajor + F_.radiusOfPlanetMajor * + Coordinates.coordENMultiplier[1] ).toFixed(3) + 'm, ' + ( Coordinates.mouseLngLat[0] * (Math.PI / 180) * - F_.radiusOfPlanetMajor + F_.radiusOfPlanetMajor * + Coordinates.coordENMultiplier[0] ).toFixed(3) + 'm' ) @@ -534,6 +538,8 @@ function pickLngLatGo() { relativeA = Map_.activeLayer.feature.geometry.coordinates[0] relativeB = Map_.activeLayer.feature.geometry.coordinates[1] } + valA /= Coordinates.coordENMultiplier[0] + valB /= Coordinates.coordENMultiplier[1] const valALngRel = (valA * (180 / Math.PI)) / F_.radiusOfPlanetMajor + relativeA const valBLatRel = @@ -552,6 +558,8 @@ function pickLngLatGo() { siteRelativeA = Map_.activeLayer.feature.geometry.coordinates[0] siteRelativeB = Map_.activeLayer.feature.geometry.coordinates[1] } + valA /= Coordinates.coordENMultiplier[0] + valB /= Coordinates.coordENMultiplier[1] const valSiteALngRel = (valA * (180 / Math.PI)) / F_.radiusOfPlanetMajor + siteRelativeA From 48067a9fa13c11412a073c692894bccff751ee9d Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 8 Nov 2021 10:57:41 -0800 Subject: [PATCH 39/85] Prevent legend items from getting squished --- src/essence/Tools/Legend/LegendTool.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/essence/Tools/Legend/LegendTool.js b/src/essence/Tools/Legend/LegendTool.js index c15e3c16..eea5dc87 100644 --- a/src/essence/Tools/Legend/LegendTool.js +++ b/src/essence/Tools/Legend/LegendTool.js @@ -181,7 +181,7 @@ function interfaceWithMMWebGIS() { ) r.append('div') .style('margin-left', '5px') - .style('height', '20px') + .style('height', '100%') .style('line-height', '21px') .style('font-size', '14px') .html(L_.layersLegendsData[l][d].value) From 801a4eac65fe6c97074c03215c65db6195c8ec41 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 11 Nov 2021 18:06:56 -0800 Subject: [PATCH 40/85] #144 Marker bearings 1 --- config/js/config.js | 5 ++ src/essence/Basics/Map_/Map_.js | 87 ++++++++++++++++++++++++++++++--- 2 files changed, 86 insertions(+), 6 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 207b0e3d..4af0cf6f 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2751,6 +2751,11 @@ function layerPopulateVariable(modalId, layerType) { }; } else { currentLayerVars.useKeyAsName = currentLayerVars.useKeyAsName || "prop"; + currentLayerVars.markerBearing = + currentLayerVars.markerBearing || + "unit:prop (unit is either deg or rad)"; + currentLayerVars.markerBearingColor = + currentLayerVars.markerBearingColor || "#FFFFFF"; currentLayerVars.datasetLinks = currentLayerVars.datasetLinks || [ { prop: "{prop}", diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index c42eff59..7f911ac2 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -801,7 +801,7 @@ async function makeLayer(layerObj, evenIfOff) { } else { // Priority to prop, prop.color, then style color. var finalCol = - col.toLowerCase().substring(0, 4) == 'prop' + col.toLowerCase().substring(0, 4) === 'prop' ? F_.parseColor( feature.properties[col.substring(5)] ) || '#FFF' @@ -810,7 +810,7 @@ async function makeLayer(layerObj, evenIfOff) { ? feature.style.stroke : col var finalOpa = - opa.toLowerCase().substring(0, 4) == 'prop' + opa.toLowerCase().substring(0, 4) === 'prop' ? feature.properties[opa.substring(5)] || '1' : feature.style && @@ -818,7 +818,7 @@ async function makeLayer(layerObj, evenIfOff) { ? feature.style.opacity : opa var finalWei = - wei.toLowerCase().substring(0, 4) == 'prop' + wei.toLowerCase().substring(0, 4) === 'prop' ? feature.properties[wei.substring(5)] || '1' : feature.style && @@ -827,7 +827,7 @@ async function makeLayer(layerObj, evenIfOff) { : wei if (!isNaN(parseInt(wei))) finalWei = parseInt(wei) var finalFiC = - fiC.toLowerCase().substring(0, 4) == 'prop' + fiC.toLowerCase().substring(0, 4) === 'prop' ? F_.parseColor( feature.properties[fiC.substring(5)] ) || '#000' @@ -836,7 +836,7 @@ async function makeLayer(layerObj, evenIfOff) { ? feature.style.fill : fiC var finalFiO = - fiO.toLowerCase().substring(0, 4) == 'prop' + fiO.toLowerCase().substring(0, 4) === 'prop' ? feature.properties[fiO.substring(5)] || '1' : feature.style && @@ -904,6 +904,26 @@ async function makeLayer(layerObj, evenIfOff) { let layer = null const pixelBuffer = featureStyle.weight || 0 + //check for a bearing + let yaw = 0 + if ( + layerObj.hasOwnProperty('variables') && + layerObj.variables.hasOwnProperty('markerBearing') + ) { + const markerBearing = + layerObj.variables.markerBearing.split(':') + const unit = markerBearing[0] + const bearingProp = markerBearing[1] + + yaw = parseFloat( + F_.getIn(feature.properties, bearingProp) + ) + if (unit === 'rad') { + yaw = yaw * (180 / Math.PI) + } + layerObj.shape = 'directional_circle' + } + switch (layerObj.shape) { case 'circle': svg = [ @@ -914,6 +934,26 @@ async function makeLayer(layerObj, evenIfOff) { ``, ].join('\n') break + case 'directional_circle': + svg = [ + `
    `, + ``, + ``, + ``, + ``, + `
    `, + ].join('\n') + break case 'triangle': svg = [ ``, @@ -1005,8 +1045,43 @@ async function makeLayer(layerObj, evenIfOff) { if (layer == null) return + // Support marker bearings + if ( + layerObj.hasOwnProperty('variables') && + layerObj.variables.hasOwnProperty('markerBearing') + ) { + const markerBearing = + layerObj.variables.markerBearing.split(':') + const unit = markerBearing[0] + const bearingProp = markerBearing[1] + let yaw = parseFloat( + F_.getIn(feature.properties, bearingProp) + ) + if (unit === 'rad') yaw = yaw * (180 / Math.PI) + const size = + (featureStyle.radius + featureStyle.weight) * 2 + const bearing = L.marker(latlong, { + icon: L.divIcon({ + className: 'leafletMarkerBearing', + iconSize: [size, size], + html: [ + `
    `, + ``, + ``, + ``, + `
    `, + ].join('\n'), + }), + }) + layer = L.featureGroup([bearing, layer]) + } layer.options.layerName = layerObj.name - return layer } } From 8b8ba61f496303701b75ee3f6dc73e3098a59341 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 15 Nov 2021 10:38:41 -0800 Subject: [PATCH 41/85] #114 Improved marker bearings, support rotated markerIcons, docs --- docs/pages/markdowns/Layers_Tab.md | 7 +- src/essence/Basics/Map_/Map_.js | 47 +++--------- src/external/Leaflet/leaflet.rotatedMarker.js | 72 +++++++++++++++++++ src/index.js | 1 + 4 files changed, 88 insertions(+), 39 deletions(-) create mode 100644 src/external/Leaflet/leaflet.rotatedMarker.js diff --git a/docs/pages/markdowns/Layers_Tab.md b/docs/pages/markdowns/Layers_Tab.md index aae1aced..c85e9bd1 100644 --- a/docs/pages/markdowns/Layers_Tab.md +++ b/docs/pages/markdowns/Layers_Tab.md @@ -478,6 +478,8 @@ Example: "value": "Prop: {prop}" } ], + "markerBearing": "unit:prop", + "markerBearingColor": "css color", "markerIcon": { //See: https://leafletjs.com/reference-1.7.1.html#icon-l-icon iconUrl: "pathToMainIconImage.png", shadowUrl: "(opt)pathToShadowImage.png", @@ -503,6 +505,9 @@ Example: - `which`: This only supports the value `last` at this point. - `icon`: Any [Material Design Icon](http://materialdesignicons.com/) name - `value`: A name to display. All `{prop}`s will be replaced by their corresponding `features[which].properties[prop]` value. +- `markerBearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). `{unit}` is either `deg` or `rad` and `{prop}` is the dot notated path to the feature properties that contains the desired rotation angle. Ex. `deg:headings.yaw`. +- `markerBearingColor`: A css color for the directional arrow for non-markerIcon bearings. +- `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. - `search`: This requires the "Minimalist" option in the Look Tab to be unchecked. When set, this layer will become searchable through the search bar at the top. The search will look for and autocomplete on the properties specified. All properties are enclosed by parentheses and space-separated. `round` can be used like a function to round the property beforehand. `rmunder` works similarly but removes all underscores instead. # Model @@ -579,4 +584,4 @@ The string format to be used in the URL for `{starttime}` and `{endtime}`. Defau --- -_Note:_ Additional vector layer stylings can be found on the [Meaningful GeoJSON Styles](Meaningful-GeoJSON-Styles) page. +_Note:_ Additional vector layer stylings can be found on the [Vector Styling](Vector_Styling) page. diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 7f911ac2..8d275b05 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -938,7 +938,7 @@ async function makeLayer(layerObj, evenIfOff) { svg = [ `
    `, ``, - ``, - ``, - ``, - ``, - `
    `, - ].join('\n'), - }), - }) - layer = L.featureGroup([bearing, layer]) - } layer.options.layerName = layerObj.name return layer } diff --git a/src/external/Leaflet/leaflet.rotatedMarker.js b/src/external/Leaflet/leaflet.rotatedMarker.js new file mode 100644 index 00000000..31c42065 --- /dev/null +++ b/src/external/Leaflet/leaflet.rotatedMarker.js @@ -0,0 +1,72 @@ +;(function () { + // save these original methods before they are overwritten + var proto_initIcon = L.Marker.prototype._initIcon + var proto_setPos = L.Marker.prototype._setPos + + var oldIE = L.DomUtil.TRANSFORM === 'msTransform' + + L.Marker.addInitHook(function () { + var iconOptions = this.options.icon && this.options.icon.options + var iconAnchor = iconOptions && this.options.icon.options.iconAnchor + if (iconAnchor) { + iconAnchor = iconAnchor[0] + 'px ' + iconAnchor[1] + 'px' + } + this.options.rotationOrigin = + this.options.rotationOrigin || iconAnchor || 'center bottom' + this.options.rotationAngle = this.options.rotationAngle || 0 + + // Ensure marker keeps rotated during dragging + this.on('drag', function (e) { + e.target._applyRotation() + }) + }) + + L.Marker.include({ + _initIcon: function () { + proto_initIcon.call(this) + }, + + _setPos: function (pos) { + proto_setPos.call(this, pos) + this._applyRotation() + }, + + _applyRotation: function () { + if (this.options.rotationAngle) { + this._icon.style[L.DomUtil.TRANSFORM + 'Origin'] = + this.options.rotationOrigin + + if (oldIE) { + // for IE 9, use the 2D rotation + this._icon.style[L.DomUtil.TRANSFORM] = + 'rotate(' + this.options.rotationAngle + 'deg)' + } else if ( + !this._icon.style[L.DomUtil.TRANSFORM].includes('rotateZ') + ) { + // for modern browsers, prefer the 3D accelerated version + this._icon.style[L.DomUtil.TRANSFORM] += + ' rotateZ(' + this.options.rotationAngle + 'deg)' + } else { + this._icon.style[L.DomUtil.TRANSFORM] = this._icon.style[ + L.DomUtil.TRANSFORM + ].replace( + /rotateZ\(.*\)/g, + 'rotateZ(' + this.options.rotationAngle + 'deg)' + ) + } + } + }, + + setRotationAngle: function (angle) { + this.options.rotationAngle = angle + this.update() + return this + }, + + setRotationOrigin: function (origin) { + this.options.rotationOrigin = origin + this.update() + return this + }, + }) +})() diff --git a/src/index.js b/src/index.js index b00014c2..ab1adcb5 100644 --- a/src/index.js +++ b/src/index.js @@ -22,6 +22,7 @@ import lsf from './external/Leaflet/leaflet.scalefactor.min' import ltm from './essence/Basics/Layers_/leaflet-tilelayer-middleware' import ltl from './external/Leaflet/leaflet.tilelayer.gl' import lvg from './external/Leaflet/leaflet.vectorGrid.bundled' +import lrm from './external/Leaflet/leaflet.rotatedMarker' import THREE from './external/THREE/three118.js' import OrbitControls from './external/THREE/OrbitControls' From 1d58a4e538aef88b421e8c3b2b6a930f24163b87 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 15 Nov 2021 11:10:27 -0800 Subject: [PATCH 42/85] #114 docs - markerIcon should point north if used as a bearing --- docs/pages/markdowns/Layers_Tab.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/pages/markdowns/Layers_Tab.md b/docs/pages/markdowns/Layers_Tab.md index c85e9bd1..3361c76b 100644 --- a/docs/pages/markdowns/Layers_Tab.md +++ b/docs/pages/markdowns/Layers_Tab.md @@ -507,7 +507,7 @@ Example: - `value`: A name to display. All `{prop}`s will be replaced by their corresponding `features[which].properties[prop]` value. - `markerBearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). `{unit}` is either `deg` or `rad` and `{prop}` is the dot notated path to the feature properties that contains the desired rotation angle. Ex. `deg:headings.yaw`. - `markerBearingColor`: A css color for the directional arrow for non-markerIcon bearings. -- `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. +- `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. If you're using this as a bearing marker, make sure the base icon is pointing north. - `search`: This requires the "Minimalist" option in the Look Tab to be unchecked. When set, this layer will become searchable through the search bar at the top. The search will look for and autocomplete on the properties specified. All properties are enclosed by parentheses and space-separated. `round` can be used like a function to round the property beforehand. `rmunder` works similarly but removes all underscores instead. # Model From 2a2326516d26b77a64f6f6882feaf39e0744303c Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 23 Nov 2021 17:59:38 -0800 Subject: [PATCH 43/85] #115 MeasureTool - Continous profile --- src/essence/Tools/Measure/MeasureTool.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index 4db51b2e..84a8ea21 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -659,7 +659,7 @@ function makeProfile() { MeasureTool.data = MeasureTool.data.concat(F_.clone(data)) } - MeasureTool.lastData = F_.clone(data) + MeasureTool.lastData = F_.clone(MeasureTool.data) for (let i = 0; i < MeasureTool.lastData.length; i++) { let distance = 0 @@ -676,8 +676,8 @@ function makeProfile() { } profileData = [] - for (var i = 0; i < data.length; i++) { - profileData.push(data[i][2]) + for (var i = 0; i < MeasureTool.data.length; i++) { + profileData.push(MeasureTool.data[i][2]) } //profileData = profileData.concat(data); //var latestDistPerStep = latLongDistBetween(elevPoints[0].y, elevPoints[0].x, elevPoints[1].y, elevPoints[1].x) / steps; From 16bdc81a7d55d7483872ed266edd399a789ac69e Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 24 Nov 2021 13:42:58 -0800 Subject: [PATCH 44/85] #115 MeasureTool - Continuous profile, colored segments, accurate chart length --- package-lock.json | 102 +++++++---------------- package.json | 6 +- src/essence/Tools/Measure/MeasureTool.js | 94 +++++++++++++-------- 3 files changed, 94 insertions(+), 108 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1c8eeab0..21a936b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mmgis", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mmgis", - "version": "2.4.0", + "version": "2.4.1", "dependencies": { "@babel/core": "7.9.0", "@svgr/webpack": "4.3.3", @@ -25,8 +25,8 @@ "busboy": "^0.3.1", "camelcase": "^5.3.1", "case-sensitive-paths-webpack-plugin": "2.3.0", - "chart.js": "^2.9.4", - "chartjs-plugin-zoom": "^0.7.7", + "chart.js": "^3.6.0", + "chartjs-plugin-zoom": "^1.2.0", "compression": "^1.7.4", "cookie-parser": "^1.4.5", "cors": "^2.8.5", @@ -80,7 +80,7 @@ "pug": "^3.0.1", "react": "^16.13.1", "react-app-polyfill": "^1.0.6", - "react-chartjs-2": "^2.10.0", + "react-chartjs-2": "^3.3.0", "react-dev-utils": "^11.0.4", "react-dom": "^16.13.1", "resolve": "1.15.0", @@ -5369,37 +5369,19 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "node_modules/chart.js": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", - "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", - "dependencies": { - "chartjs-color": "^2.1.0", - "moment": "^2.10.2" - } - }, - "node_modules/chartjs-color": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", - "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", - "dependencies": { - "chartjs-color-string": "^0.6.0", - "color-convert": "^1.9.3" - } - }, - "node_modules/chartjs-color-string": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", - "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", - "dependencies": { - "color-name": "^1.0.0" - } + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.0.tgz", + "integrity": "sha512-iOzzDKePL+bj+ccIsVAgWQehCXv8xOKGbaU2fO/myivH736zcx535PGJzQGanvcSGVOqX6yuLZsN3ygcQ35UgQ==" }, "node_modules/chartjs-plugin-zoom": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-0.7.7.tgz", - "integrity": "sha512-8fOHPPiZTT2+K0w278TQWYs/DtPg06s1OpTqdXxPpdfH7QQbl6Io/WuE1FjPehDWVCxpe3tSTts+dPbxgq2Z5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.2.0.tgz", + "integrity": "sha512-cLYKUHHx4bevuZQDpEKdjpvZ6HGu6NF8laTThgA0I9af+PV1N4qVTRZmyDNh0SAzsHZPtDOhuO3I7B4CF1lstw==", "dependencies": { "hammerjs": "^2.0.8" + }, + "peerDependencies": { + "chart.js": "^3.2.0" } }, "node_modules/chokidar": { @@ -15308,12 +15290,12 @@ } }, "node_modules/react-chartjs-2": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.11.1.tgz", - "integrity": "sha512-G7cNq/n2Bkh/v4vcI+GKx7Q1xwZexKYhOSj2HmrFXlvNeaURWXun6KlOUpEQwi1cv9Tgs4H3kGywDWMrX2kxfA==", - "dependencies": { - "lodash": "^4.17.19", - "prop-types": "^15.7.2" + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-3.3.0.tgz", + "integrity": "sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ==", + "peerDependencies": { + "chart.js": "^3.5.0", + "react": "^16.8.0 || ^17.0.0" } }, "node_modules/react-dev-utils": { @@ -25082,35 +25064,14 @@ "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" }, "chart.js": { - "version": "2.9.4", - "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.9.4.tgz", - "integrity": "sha512-B07aAzxcrikjAPyV+01j7BmOpxtQETxTSlQ26BEYJ+3iUkbNKaOJ/nDbT6JjyqYxseM0ON12COHYdU2cTIjC7A==", - "requires": { - "chartjs-color": "^2.1.0", - "moment": "^2.10.2" - } - }, - "chartjs-color": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.4.1.tgz", - "integrity": "sha512-haqOg1+Yebys/Ts/9bLo/BqUcONQOdr/hoEr2LLTRl6C5LXctUdHxsCYfvQVg5JIxITrfCNUDr4ntqmQk9+/0w==", - "requires": { - "chartjs-color-string": "^0.6.0", - "color-convert": "^1.9.3" - } - }, - "chartjs-color-string": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz", - "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==", - "requires": { - "color-name": "^1.0.0" - } + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-3.6.0.tgz", + "integrity": "sha512-iOzzDKePL+bj+ccIsVAgWQehCXv8xOKGbaU2fO/myivH736zcx535PGJzQGanvcSGVOqX6yuLZsN3ygcQ35UgQ==" }, "chartjs-plugin-zoom": { - "version": "0.7.7", - "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-0.7.7.tgz", - "integrity": "sha512-8fOHPPiZTT2+K0w278TQWYs/DtPg06s1OpTqdXxPpdfH7QQbl6Io/WuE1FjPehDWVCxpe3tSTts+dPbxgq2Z5g==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/chartjs-plugin-zoom/-/chartjs-plugin-zoom-1.2.0.tgz", + "integrity": "sha512-cLYKUHHx4bevuZQDpEKdjpvZ6HGu6NF8laTThgA0I9af+PV1N4qVTRZmyDNh0SAzsHZPtDOhuO3I7B4CF1lstw==", "requires": { "hammerjs": "^2.0.8" } @@ -33362,13 +33323,10 @@ } }, "react-chartjs-2": { - "version": "2.11.1", - "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-2.11.1.tgz", - "integrity": "sha512-G7cNq/n2Bkh/v4vcI+GKx7Q1xwZexKYhOSj2HmrFXlvNeaURWXun6KlOUpEQwi1cv9Tgs4H3kGywDWMrX2kxfA==", - "requires": { - "lodash": "^4.17.19", - "prop-types": "^15.7.2" - } + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/react-chartjs-2/-/react-chartjs-2-3.3.0.tgz", + "integrity": "sha512-4Mt0SR2aiUbWi/4762odRBYSnbNKSs4HWc0o3IW43py5bMfmfpeZU95w6mbvtuLZH/M3GsPJMU8DvDc+5U9blQ==", + "requires": {} }, "react-dev-utils": { "version": "11.0.4", diff --git a/package.json b/package.json index c11f9f73..34117be4 100644 --- a/package.json +++ b/package.json @@ -59,8 +59,8 @@ "busboy": "^0.3.1", "camelcase": "^5.3.1", "case-sensitive-paths-webpack-plugin": "2.3.0", - "chart.js": "^2.9.4", - "chartjs-plugin-zoom": "^0.7.7", + "chart.js": "^3.6.0", + "chartjs-plugin-zoom": "^1.2.0", "compression": "^1.7.4", "cookie-parser": "^1.4.5", "cors": "^2.8.5", @@ -114,7 +114,7 @@ "pug": "^3.0.1", "react": "^16.13.1", "react-app-polyfill": "^1.0.6", - "react-chartjs-2": "^2.10.0", + "react-chartjs-2": "^3.3.0", "react-dev-utils": "^11.0.4", "react-dom": "^16.13.1", "resolve": "1.15.0", diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index 84a8ea21..68eeaf06 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -134,8 +134,19 @@ const Measure = () => { { label: 'Profile', data: profileData, - backgroundColor: ['rgba(255, 90, 119, 0.2)'], - borderColor: ['rgba(255, 90, 119, 1)'], + borderColor: ['rgba(255, 0, 47, 1)'], + segment: { + backgroundColor: (ctx) => { + const i = + MeasureTool.datasetMapping[ + ctx.p0DataIndex + ] + return i % 2 === 0 + ? 'rgba(255, 0, 47, 0.2)' + : 'rgba(255, 0, 47, 0.1)' + }, + }, + spanGaps: true, borderWidth: 1, fill: 'start', pointRadius: 6, @@ -149,9 +160,12 @@ const Measure = () => { }} height={150} options={{ + responsive: true, maintainAspectRatio: false, - legend: { - display: false, + plugins: { + legend: { + display: false, + }, }, layout: { padding: { @@ -162,23 +176,17 @@ const Measure = () => { }, }, scales: { - yAxes: [ - { - gridLines: { - color: 'rgba(255,255,255,0.05)', - }, - ticks: { - callback: function ( - value, - index, - values - ) { - return `${value}m` - }, - lineHeight: 1.5, + y: { + grid: { + color: 'rgba(255,255,255,0.05)', + }, + ticks: { + callback: function (value, index, values) { + return `${value}m` }, + lineHeight: 1.5, }, - ], + }, }, tooltips: { intersect: false, @@ -189,23 +197,22 @@ const Measure = () => { callbacks: { label: (item) => `${item.yLabel}m`, title: (item) => - distDisplayUnit == 'meters' + distDisplayUnit === 'meters' ? `${item[0].xLabel}m from start` : `${item[0].xLabel}km from start,`, }, }, onHover: (e, el, el2) => { if (el[0]) { - const d = MeasureTool.lastData[el[0]._index] + const d = MeasureTool.lastData[el[0].index] MeasureTool.makeFocusPoint(d[1], d[0], d[3]) - } else if (refLine && e.layerX != null) { - const chartArea = - refLine.current.chartInstance.chartArea + } else if (refLine && e.x != null) { + const chartArea = refLine.current.chartArea const bestIndex = Math.round( F_.linearScale( [chartArea.left, chartArea.right], [0, profileData.length], - e.layerX + e.x ) ) if ( @@ -266,6 +273,7 @@ let MeasureTool = { Map_.rmNotNull(measureToolLayer) MeasureTool.data = [] MeasureTool.lastData = [] + MeasureTool.datasetMapping = [] //Get tool variables this.vars = L_.getToolVars('measure') @@ -309,6 +317,7 @@ let MeasureTool = { updateProfileData(profileData) MeasureTool.data = [] MeasureTool.lastData = [] + MeasureTool.datasetMapping = [] MeasureTool.clearFocusPoint() Map_.rmNotNull(distLineToMouse) Map_.rmNotNull(distMousePoint) @@ -458,6 +467,7 @@ let MeasureTool = { profileData = [] MeasureTool.data = [] MeasureTool.lastData = [] + MeasureTool.datasetMapping = [] Map_.rmNotNull(distLineToMouse) Map_.rmNotNull(distMousePoint) @@ -660,18 +670,36 @@ function makeProfile() { } MeasureTool.lastData = F_.clone(MeasureTool.data) - + MeasureTool.datasetMapping = MeasureTool.datasetMapping || [] + MeasureTool.datasetMapping = MeasureTool.datasetMapping.concat( + new Array(steps).fill(numOfPts - 1) + ) + + let currentDataset = 0 + let currentDatasetStart = 0 + let lastDistance = 0 + let currentDatasetDistanceStart = 0 for (let i = 0; i < MeasureTool.lastData.length; i++) { let distance = 0 + if (MeasureTool.datasetMapping[i] - 1 !== currentDataset) { + currentDataset = MeasureTool.datasetMapping[i] - 1 + currentDatasetStart = i + currentDatasetDistanceStart = lastDistance + } if (i > 0 && i < MeasureTool.lastData.length) { - distance = F_.lngLatDistBetween( - MeasureTool.lastData[i][0], - MeasureTool.lastData[i][1], - MeasureTool.lastData[0][0], - MeasureTool.lastData[0][1] - ) - if (F_.dam) distance = F_.metersToDegrees(distance) + distance = + F_.lngLatDistBetween( + MeasureTool.lastData[i][0], + MeasureTool.lastData[i][1], + MeasureTool.lastData[currentDatasetStart][0], + MeasureTool.lastData[currentDatasetStart][1] + ) + currentDatasetDistanceStart + if (F_.dam) + distance = + F_.metersToDegrees(distance) + + currentDatasetDistanceStart } + lastDistance = distance MeasureTool.lastData[i].splice(2, 0, distance) } From 07a0735c074243d6a198aa1fc62893c1efe12743 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 24 Nov 2021 13:55:12 -0800 Subject: [PATCH 45/85] #115 MeasureTool - Reset state when tool retoggled --- src/essence/Tools/Measure/MeasureTool.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index 68eeaf06..4475616a 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -274,6 +274,9 @@ let MeasureTool = { MeasureTool.data = [] MeasureTool.lastData = [] MeasureTool.datasetMapping = [] + distDisplayUnit = 'meters' + mode = 'segment' + steps = 100 //Get tool variables this.vars = L_.getToolVars('measure') @@ -468,6 +471,7 @@ let MeasureTool = { MeasureTool.data = [] MeasureTool.lastData = [] MeasureTool.datasetMapping = [] + distDisplayUnit = 'meters' Map_.rmNotNull(distLineToMouse) Map_.rmNotNull(distMousePoint) From 4b63a4197b7f1bd44c2083453903558c86e57f98 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 29 Nov 2021 17:53:16 -0800 Subject: [PATCH 46/85] #144 Rework marker vars and include uncertainty ellipse --- config/js/config.js | 30 +- package-lock.json | 4080 ++++++++++++------------- package.json | 2 +- src/essence/Basics/Layers_/Layers_.js | 20 +- src/essence/Basics/Map_/Map_.js | 113 +- 5 files changed, 2141 insertions(+), 2104 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 4af0cf6f..94fb2d4f 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2751,11 +2751,31 @@ function layerPopulateVariable(modalId, layerType) { }; } else { currentLayerVars.useKeyAsName = currentLayerVars.useKeyAsName || "prop"; - currentLayerVars.markerBearing = - currentLayerVars.markerBearing || - "unit:prop (unit is either deg or rad)"; - currentLayerVars.markerBearingColor = - currentLayerVars.markerBearingColor || "#FFFFFF"; + currentLayerVars.markerAttachments = + currentLayerVars.markerAttachments || { + bearing: { + angleProp: "path.to.angle.prop", + angleUnit: "deg || rad", + color: "#FFFFFF", + }, + uncertainty: { + xAxisProp: "path.to.x.prop", + yAxisProp: "path.to.y.prop", + axisUnit: "meters || kilometers", + angleProp: "path.to.angle.prop", + angleUnit: "deg || rad", + color: "#888888", + }, + rover: { + image: + "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", + widthMeters: 2.6924, + widthPixels: 420, + heightPixels: 600, + angleProp: "path.to.angle.prop", + angleUnit: "deg || rad", + }, + }; currentLayerVars.datasetLinks = currentLayerVars.datasetLinks || [ { prop: "{prop}", diff --git a/package-lock.json b/package-lock.json index 1c8eeab0..30cae884 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,19 +1,19 @@ { "name": "mmgis", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mmgis", - "version": "2.4.0", + "version": "2.4.1", "dependencies": { "@babel/core": "7.9.0", "@svgr/webpack": "4.3.3", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", - "@turf/turf": "^5.1.6", + "@turf/turf": "^6.5.0", "@typescript-eslint/eslint-plugin": "^2.10.0", "@typescript-eslint/parser": "^2.10.0", "babel-eslint": "10.1.0", @@ -1879,140 +1879,148 @@ "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" }, "node_modules/@turf/along": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/along/-/along-5.1.5.tgz", - "integrity": "sha1-YdbmplhKzdq1asVYTge/jL5fi+s=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/along/-/along-6.5.0.tgz", + "integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==", "dependencies": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/angle": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/angle/-/angle-6.5.0.tgz", + "integrity": "sha512-4pXMbWhFofJJAOvTMCns6N4C8CMd5Ih4O2jSAG9b3dDHakj3O4yN1+Zbm+NUei+eVEZ9gFeVp9svE3aMDenIkw==", + "dependencies": { + "@turf/bearing": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/area": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/area/-/area-5.1.5.tgz", - "integrity": "sha1-79iZv9Jgzb0VQbKjwVX4pdLu+h0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.5.0.tgz", + "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/bbox": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-5.1.5.tgz", - "integrity": "sha1-MFHfUUrUxQ9KT5uKLRX9i2hA7aM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz", + "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/bbox-clip": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-5.1.5.tgz", - "integrity": "sha1-M2S1Mo3/nzz0HZ4C7a/zdNFQzIQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-6.5.0.tgz", + "integrity": "sha512-F6PaIRF8WMp8EmgU/Ke5B1Y6/pia14UAYB5TiBC668w5rVVjy5L8rTm/m2lEkkDMHlzoP9vNY4pxpNthE7rLcQ==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "lineclip": "^1.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/bbox-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-5.1.5.tgz", - "integrity": "sha1-auuk7VHYXSluD3w4uIwznwHu4CQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz", + "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/bearing": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-5.1.5.tgz", - "integrity": "sha1-egt5ATbE70eX8CRjBdRcvi0ns/c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.5.0.tgz", + "integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/bezier-spline": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-5.1.5.tgz", - "integrity": "sha1-WaJ7ul17l+8Vqz/VpA+9I4cEm8o=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-6.5.0.tgz", + "integrity": "sha512-vokPaurTd4PF96rRgGVm6zYYC5r1u98ZsG+wZEv9y3kJTuJRX/O3xIY2QnTGTdbVmAJN1ouOsD0RoZYaVoXORQ==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/boolean-clockwise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", - "integrity": "sha1-MwK32sYsXikaB4nimvcoM4f6nes=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz", + "integrity": "sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/boolean-contains": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-5.1.5.tgz", - "integrity": "sha1-WW1jruY2961T7pn5/yTJaZSg7xQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz", + "integrity": "sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/boolean-point-on-line": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/boolean-crosses": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-5.1.5.tgz", - "integrity": "sha1-Ab+uollvFk3kpNMlCU3HwlXHFdY=", - "dependencies": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/polygon-to-line": "^5.1.5" - } - }, - "node_modules/@turf/boolean-disjoint": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-5.1.6.tgz", - "integrity": "sha512-KHvUS6SBNYHBCLIJEJrg04pF5Oy+Fqn8V5G9U+9pti5vI9tyX7Ln2g7RSB7iJ1Cxsz8QAi6OukhXjEF2/8ZpGg==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/polygon-to-line": "^5.1.5" - } - }, - "node_modules/@turf/boolean-equal": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-5.1.5.tgz", - "integrity": "sha1-Kfj21gu4RQff12WzIlTbjnLJOKQ=", - "dependencies": { - "@turf/clean-coords": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "geojson-equality": "0.1.6" - } - }, - "node_modules/@turf/boolean-intersects": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-intersects/-/boolean-intersects-6.5.0.tgz", - "integrity": "sha512-nIxkizjRdjKCYFQMnml6cjPsDOBCThrt+nkqtSEcxkKMhAQj5OO7o2CecioNTaX8EayqwMGVKcsz27oP4mKPTw==", + "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-6.5.0.tgz", + "integrity": "sha512-gvshbTPhAHporTlQwBJqyfW+2yV8q/mOTxG6PzRVl6ARsqNoqYQWkd4MLug7OmAqVyBzLK3201uAeBjxbGw0Ng==", "dependencies": { - "@turf/boolean-disjoint": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0" }, "funding": { "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/boolean-disjoint": { + "node_modules/@turf/boolean-disjoint": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz", "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==", @@ -2027,80 +2035,79 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/boolean-point-in-polygon": { + "node_modules/@turf/boolean-equal": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", - "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", + "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-6.5.0.tgz", + "integrity": "sha512-cY0M3yoLC26mhAnjv1gyYNQjn7wxIXmL2hBmI/qs8g5uKuC2hRWi13ydufE3k4x0aNRjFGlg41fjoYLwaVF+9Q==", "dependencies": { + "@turf/clean-coords": "^6.5.0", "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" + "@turf/invariant": "^6.5.0", + "geojson-equality": "0.1.6" }, "funding": { "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/helpers": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", - "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/invariant": { + "node_modules/@turf/boolean-intersects": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", - "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", + "resolved": "https://registry.npmjs.org/@turf/boolean-intersects/-/boolean-intersects-6.5.0.tgz", + "integrity": "sha512-nIxkizjRdjKCYFQMnml6cjPsDOBCThrt+nkqtSEcxkKMhAQj5OO7o2CecioNTaX8EayqwMGVKcsz27oP4mKPTw==", "dependencies": { - "@turf/helpers": "^6.5.0" + "@turf/boolean-disjoint": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" }, "funding": { "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/line-intersect": { + "node_modules/@turf/boolean-overlap": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz", - "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==", + "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-6.5.0.tgz", + "integrity": "sha512-8btMIdnbXVWUa1M7D4shyaSGxLRw6NjMcqKBcsTXcZdnaixl22k7ar7BvIzkaRYN3SFECk9VGXfLncNS3ckQUw==", "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0", - "@turf/line-segment": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-overlap": "^6.5.0", "@turf/meta": "^6.5.0", - "geojson-rbush": "3.x" + "geojson-equality": "0.1.6" }, "funding": { "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/line-segment": { + "node_modules/@turf/boolean-parallel": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz", - "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==", + "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-6.5.0.tgz", + "integrity": "sha512-aSHJsr1nq9e5TthZGZ9CZYeXklJyRgR5kCLm5X4urz7+MotMOp/LsGOsvKvK9NeUl9+8OUmfMn8EFTT8LkcvIQ==", "dependencies": { + "@turf/clean-coords": "^6.5.0", "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" + "@turf/line-segment": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0" }, "funding": { "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/meta": { + "node_modules/@turf/boolean-point-in-polygon": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", - "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", + "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", "dependencies": { - "@turf/helpers": "^6.5.0" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" }, "funding": { "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/@turf/polygon-to-line": { + "node_modules/@turf/boolean-point-on-line": { "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz", - "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz", + "integrity": "sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==", "dependencies": { "@turf/helpers": "^6.5.0", "@turf/invariant": "^6.5.0" @@ -2109,207 +2116,194 @@ "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/boolean-intersects/node_modules/geojson-rbush": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", - "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", - "dependencies": { - "@turf/bbox": "*", - "@turf/helpers": "6.x", - "@turf/meta": "6.x", - "@types/geojson": "7946.0.8", - "rbush": "^3.0.1" - } - }, - "node_modules/@turf/boolean-overlap": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-5.1.5.tgz", - "integrity": "sha1-DU5kxSx3CijpPZ7834qLg3OsznU=", - "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/line-overlap": "^5.1.5", - "@turf/meta": "^5.1.5", - "geojson-equality": "0.1.6" - } - }, - "node_modules/@turf/boolean-parallel": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-5.1.5.tgz", - "integrity": "sha1-c5NYR16ltlx+GCejw+DopofTqF0=", - "dependencies": { - "@turf/clean-coords": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/rhumb-bearing": "^5.1.5" - } - }, - "node_modules/@turf/boolean-point-in-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-5.1.5.tgz", - "integrity": "sha1-8BzBlNHgMKVIv9qYHLpDz9YpQbc=", - "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" - } - }, - "node_modules/@turf/boolean-point-on-line": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-5.1.5.tgz", - "integrity": "sha1-9jPF/4Aq0ku48Vja269v9KAj3Xs=", - "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" - } - }, "node_modules/@turf/boolean-within": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-5.1.5.tgz", - "integrity": "sha1-RxBdVtB1Kp0Pv81Dw2pfkUnchpc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-6.5.0.tgz", + "integrity": "sha512-YQB3oU18Inx35C/LU930D36RAVe7LDXk1kWsQ8mLmuqYn9YdPsDQTMTkLJMhoQ8EbN7QTdy333xRQ4MYgToteQ==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/boolean-point-on-line": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/buffer": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-5.1.5.tgz", - "integrity": "sha1-hByWJ8+5dLEirE4alW8EZrwCMcQ=", - "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/center": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/projection": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-6.5.0.tgz", + "integrity": "sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/projection": "^6.5.0", "d3-geo": "1.7.1", "turf-jsts": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/center": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center/-/center-5.1.5.tgz", - "integrity": "sha1-RKss2VT2PA03dX9xWKmcPvURS4A=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center/-/center-6.5.0.tgz", + "integrity": "sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/center-mean": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-5.1.5.tgz", - "integrity": "sha1-jI6YdTkeXwnw5uePXWYbiLIQigo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-6.5.0.tgz", + "integrity": "sha512-AAX6f4bVn12pTVrMUiB9KrnV94BgeBKpyg3YpfnEbBpkN/znfVhL8dG8IxMAxAoSZ61Zt9WLY34HfENveuOZ7Q==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/center-median": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-5.1.5.tgz", - "integrity": "sha1-u0Yb/noqSGAdikcnaFcYcjoUqHI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-6.5.0.tgz", + "integrity": "sha512-dT8Ndu5CiZkPrj15PBvslpuf01ky41DEYEPxS01LOxp5HOUHXp1oJxsPxvc+i/wK4BwccPNzU1vzJ0S4emd1KQ==", "dependencies": { - "@turf/center-mean": "^5.1.5", - "@turf/centroid": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/center-mean": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/center-of-mass": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-5.1.5.tgz", - "integrity": "sha1-TTvXnYhJjbq4Mk1PafAyL2Uguco=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-6.5.0.tgz", + "integrity": "sha512-EWrriU6LraOfPN7m1jZi+1NLTKNkuIsGLZc2+Y8zbGruvUW+QV7K0nhf7iZWutlxHXTBqEXHbKue/o79IumAsQ==", "dependencies": { - "@turf/centroid": "^5.1.5", - "@turf/convex": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/centroid": "^6.5.0", + "@turf/convex": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/centroid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-5.1.5.tgz", - "integrity": "sha1-d4radCFjNQIa2P0OemWoNJ1Tx2k=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz", + "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/circle": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-5.1.5.tgz", - "integrity": "sha1-mxV3g1UIq1L7HBCypQZcuiuHtqU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz", + "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==", "dependencies": { - "@turf/destination": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/destination": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clean-coords": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-5.1.5.tgz", - "integrity": "sha1-EoAKmKeMmkUqcuxChJPEOs8q2h8=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-6.5.0.tgz", + "integrity": "sha512-EMX7gyZz0WTH/ET7xV8MyrExywfm9qUi0/MY89yNffzGIEHuFfqwhcCqZ8O00rZIPZHUTxpmsxQSTfzJJA1CPw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clone": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", - "integrity": "sha1-JT6NNUdxgZduM636tQoPAqfw42c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.5.0.tgz", + "integrity": "sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clusters": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-5.1.5.tgz", - "integrity": "sha1-ZzpeXxsZycq6vFfJCO6t1oIiTdQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-6.5.0.tgz", + "integrity": "sha512-Y6gfnTJzQ1hdLfCsyd5zApNbfLIxYEpmDibHUqR5z03Lpe02pa78JtgrgUNt1seeO/aJ4TG1NLN8V5gOrHk04g==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clusters-dbscan": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-5.1.5.tgz", - "integrity": "sha1-V4H7TmVsdHoLjpk333MYHAMJ4m8=", - "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-6.5.0.tgz", + "integrity": "sha512-SxZEE4kADU9DqLRiT53QZBBhu8EP9skviSyl+FGj08Y01xfICM/RR9ACUdM0aEQimhpu+ZpRVcUK+2jtiCGrYQ==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", "density-clustering": "1.3.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/clusters-kmeans": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-5.1.5.tgz", - "integrity": "sha1-/W3+qLEzuovcI3CsPKzuFYejAvE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-6.5.0.tgz", + "integrity": "sha512-DwacD5+YO8kwDPKaXwT9DV46tMBVNsbi1IzdajZu1JDSWoN7yc7N9Qt88oi+p30583O0UPVkAK+A10WAQv4mUw==", "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", "skmeans": "0.9.7" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/collect": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-5.1.5.tgz", - "integrity": "sha1-/pjJqMIY7PJP/DPXApUXt8GbKj4=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-6.5.0.tgz", + "integrity": "sha512-4dN/T6LNnRg099m97BJeOcTA5fSI8cu87Ydgfibewd2KQwBexO69AnjEFqfPX3Wj+Zvisj1uAVIZbPmSSrZkjg==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "rbush": "^2.0.1" + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "rbush": "2.x" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/collect/node_modules/quickselect": { @@ -2326,976 +2320,1126 @@ } }, "node_modules/@turf/combine": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-5.1.5.tgz", - "integrity": "sha1-uxS976VVBDVxlfwaEkzX1TqMiQU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-6.5.0.tgz", + "integrity": "sha512-Q8EIC4OtAcHiJB3C4R+FpB4LANiT90t17uOd851qkM2/o6m39bfN5Mv0PWqMZIHWrrosZqRqoY9dJnzz/rJxYQ==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/concave": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-5.1.5.tgz", - "integrity": "sha1-I7uqw4fQNLlldKG9cNBZI3qdIRA=", - "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/tin": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-6.5.0.tgz", + "integrity": "sha512-I/sUmUC8TC5h/E2vPwxVht+nRt+TnXIPRoztDFvS8/Y0+cBDple9inLSo9nnPXMXidrBlGXZ9vQx/BjZUJgsRQ==", + "dependencies": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/tin": "^6.5.0", "topojson-client": "3.x", "topojson-server": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/convex": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-5.1.5.tgz", - "integrity": "sha1-Dfk3fdACIWzpghsH9wXgN9rj4B0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-6.5.0.tgz", + "integrity": "sha512-x7ZwC5z7PJB0SBwNh7JCeCNx7Iu+QSrH7fYgK0RhhNop13TqUlvHMirMLRgf2db1DqUetrAO2qHJeIuasquUWg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", "concaveman": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/destination": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-5.1.5.tgz", - "integrity": "sha1-7TU4G9zoO73cvQei4rzivd/7zCY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz", + "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/difference": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-5.1.5.tgz", - "integrity": "sha1-ok1pCnvKgD8QkKnuO52Qb8Q3H0I=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.5.0.tgz", + "integrity": "sha512-l8iR5uJqvI+5Fs6leNbhPY5t/a3vipUF/3AeVLpwPQcgmedNXyheYuy07PcMGH5Jdpi5gItOiTqwiU/bUH4b3A==", "dependencies": { - "@turf/area": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "turf-jsts": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/dissolve": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-5.1.5.tgz", - "integrity": "sha1-LPEzqQIdIWODHD16lY1lB/nYGTg=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-6.5.0.tgz", + "integrity": "sha512-WBVbpm9zLTp0Bl9CE35NomTaOL1c4TQCtEoO43YaAhNEWJOOIhZMFJyr8mbvYruKl817KinT3x7aYjjCMjTAsQ==", "dependencies": { - "@turf/boolean-overlap": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/union": "^5.1.5", - "geojson-rbush": "2.1.0", - "get-closest": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/distance": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-5.1.5.tgz", - "integrity": "sha1-Oc8YIEu/h1h9cH5gmmARiQkVZAk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.5.0.tgz", + "integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==", + "dependencies": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/distance-weight": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/distance-weight/-/distance-weight-6.5.0.tgz", + "integrity": "sha512-a8qBKkgVNvPKBfZfEJZnC3DV7dfIsC3UIdpRci/iap/wZLH41EmS90nM+BokAJflUHYy8PqE44wySGWHN1FXrQ==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/centroid": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/ellipse": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-5.1.5.tgz", - "integrity": "sha1-1XyrhTmFkgzeYCKKeNgEWAJcVL4=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-6.5.0.tgz", + "integrity": "sha512-kuXtwFviw/JqnyJXF1mrR/cb496zDTSbGKtSiolWMNImYzGGkbsAsFTjwJYgD7+4FixHjp0uQPzo70KDf3AIBw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5", - "@turf/transform-rotate": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/transform-rotate": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/envelope": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-5.1.5.tgz", - "integrity": "sha1-UBMwnFP91D369LWIplw/7X28EIo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-6.5.0.tgz", + "integrity": "sha512-9Z+FnBWvOGOU4X+fMZxYFs1HjFlkKqsddLuMknRaqcJd6t+NIv5DWvPtDL8ATD2GEExYDiFLwMdckfr1yqJgHA==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/bbox-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/explode": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-5.1.5.tgz", - "integrity": "sha1-sSsvd0AEobSPYrqVsgocZVo94Rg=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-6.5.0.tgz", + "integrity": "sha512-6cSvMrnHm2qAsace6pw9cDmK2buAlw8+tjeJVXMfMyY+w7ZUi1rprWMsY92J7s2Dar63Bv09n56/1V7+tcj52Q==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/flatten": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-5.1.5.tgz", - "integrity": "sha1-2iknBnEz7WFpsLnWB7khVoiqE1g=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-6.5.0.tgz", + "integrity": "sha512-IBZVwoNLVNT6U/bcUUllubgElzpMsNoCw8tLqBw6dfYg9ObGmpEjf9BIYLr7a2Yn5ZR4l7YIj2T7kD5uJjZADQ==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/flip": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-5.1.5.tgz", - "integrity": "sha1-Q29kOnIvDKU7n85jjkaT2zYIpoo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-6.5.0.tgz", + "integrity": "sha512-oyikJFNjt2LmIXQqgOGLvt70RgE2lyzPMloYWM7OR5oIFGRiBvqVD2hA6MNw6JewIm30fWZ8DQJw1NHXJTJPbg==", "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/great-circle": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-5.1.5.tgz", - "integrity": "sha1-3r+2cc5HVQnLY3MBwV/PzPo1mpM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-6.5.0.tgz", + "integrity": "sha512-7ovyi3HaKOXdFyN7yy1yOMa8IyOvV46RC1QOQTT+RYUN8ke10eyqExwBpL9RFUPvlpoTzoYbM/+lWPogQlFncg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/helpers": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", - "integrity": "sha1-FTQFInq5M9AEpbuWQantmZ/L4M8=" + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", + "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", + "funding": { + "url": "https://opencollective.com/turf" + } }, "node_modules/@turf/hex-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-5.1.5.tgz", - "integrity": "sha1-m3ul/s9QUfHoWJL3E/zlxVBQKmo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-6.5.0.tgz", + "integrity": "sha512-Ln3tc2tgZT8etDOldgc6e741Smg1CsMKAz1/Mlel+MEL5Ynv2mhx3m0q4J9IB1F3a4MNjDeVvm8drAaf9SF33g==", "dependencies": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/intersect": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/intersect": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/interpolate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-5.1.5.tgz", - "integrity": "sha1-DxLwq3VtbdEK+ykMpuh3ve8BPqo=", - "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/centroid": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/hex-grid": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/point-grid": "^5.1.5", - "@turf/square-grid": "^5.1.5", - "@turf/triangle-grid": "^5.1.5" + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-6.5.0.tgz", + "integrity": "sha512-LSH5fMeiGyuDZ4WrDJNgh81d2DnNDUVJtuFryJFup8PV8jbs46lQGfI3r1DJ2p1IlEJIz3pmAZYeTfMMoeeohw==", + "dependencies": { + "@turf/bbox": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/hex-grid": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/point-grid": "^6.5.0", + "@turf/square-grid": "^6.5.0", + "@turf/triangle-grid": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/intersect": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-5.1.6.tgz", - "integrity": "sha512-KXyNv/GXdoGAOy03qZF53rgtXC2tNhF/4jLwTKiVRrBQH6kcEpipGStdJ+QkYIlarQPa8f7I9UlVAB19et4MfQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.5.0.tgz", + "integrity": "sha512-2legGJeKrfFkzntcd4GouPugoqPUjexPZnOvfez+3SfIMrHvulw8qV8u7pfVyn2Yqs53yoVCEjS5sEpvQ5YRQg==", "dependencies": { - "@turf/clean-coords": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/truncate": "^5.1.5", - "turf-jsts": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/invariant": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.1.5.tgz", - "integrity": "sha1-9Z9P76CSJLFdzhZR+QPIaNV6JOE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", + "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/isobands": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-5.1.5.tgz", - "integrity": "sha1-a0TO9YTVUaMTBBh68jtKFYLj8I0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-6.5.0.tgz", + "integrity": "sha512-4h6sjBPhRwMVuFaVBv70YB7eGz+iw0bhPRnp+8JBdX1UPJSXhoi/ZF2rACemRUr0HkdVB/a1r9gC32vn5IAEkw==", "dependencies": { - "@turf/area": "^5.1.5", - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/explode": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/area": "^6.5.0", + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "object-assign": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/isolines": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-5.1.5.tgz", - "integrity": "sha1-irTn9Cuz38VGFOW/FVln9+VdLeE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-6.5.0.tgz", + "integrity": "sha512-6ElhiLCopxWlv4tPoxiCzASWt/jMRvmp6mRYrpzOm3EUl75OhHKa/Pu6Y9nWtCMmVC/RcWtiiweUocbPLZLm0A==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "object-assign": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/kinks": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-5.1.5.tgz", - "integrity": "sha1-irtpYdm7AQchO63fLCwmQNAlaYA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.5.0.tgz", + "integrity": "sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/length": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/length/-/length-5.1.5.tgz", - "integrity": "sha1-86X4ZMK5lqi7RxeUU1ofrxLuvvs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/length/-/length-6.5.0.tgz", + "integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==", "dependencies": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-arc": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-5.1.5.tgz", - "integrity": "sha1-AHinRHg1oSrkFKIR+aZNEYYVDhU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-6.5.0.tgz", + "integrity": "sha512-I6c+V6mIyEwbtg9P9zSFF89T7QPe1DPTG3MJJ6Cm1MrAY0MdejwQKOpsvNl8LDU2ekHOlz2kHpPVR7VJsoMllA==", "dependencies": { - "@turf/circle": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/circle": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-chunk": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-5.1.5.tgz", - "integrity": "sha1-kQqFwFwG2dD5w4l3oF4IGNUIXEI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-6.5.0.tgz", + "integrity": "sha512-i1FGE6YJaaYa+IJesTfyRRQZP31QouS+wh/pa6O3CC0q4T7LtHigyBSYjrbjSLfn2EVPYGlPCMFEqNWCOkC6zg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/length": "^5.1.5", - "@turf/line-slice-along": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/length": "^6.5.0", + "@turf/line-slice-along": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-intersect": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-5.1.5.tgz", - "integrity": "sha1-DikHGuQDKV5JFyO8SfXPrI0R3fM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz", + "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/meta": "^5.1.5", - "geojson-rbush": "2.1.0" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "geojson-rbush": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-offset": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-5.1.5.tgz", - "integrity": "sha1-KrWy8In4yRPiMdmUN4553KkLWh4=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-6.5.0.tgz", + "integrity": "sha512-CEXZbKgyz8r72qRvPchK0dxqsq8IQBdH275FE6o4MrBkzMcoZsfSjghtXzKaz9vvro+HfIXal0sTk2mqV1lQTw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-overlap": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-5.1.5.tgz", - "integrity": "sha1-lDxvh6A4bcQ9+sEdKz/5wRLNP2A=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-6.5.0.tgz", + "integrity": "sha512-xHOaWLd0hkaC/1OLcStCpfq55lPHpPNadZySDXYiYjEz5HXr1oKmtMYpn0wGizsLwrOixRdEp+j7bL8dPt4ojQ==", "dependencies": { - "@turf/boolean-point-on-line": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/nearest-point-on-line": "^5.1.5", - "geojson-rbush": "2.1.0" + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "deep-equal": "1.x", + "geojson-rbush": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-segment": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-5.1.5.tgz", - "integrity": "sha1-Mgeq7lRqskw9jcPMY/kcdwuAE+U=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz", + "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-slice": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-5.1.5.tgz", - "integrity": "sha1-Hs/OFGKjeFeXVM7fRGTN4mgp8rU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-6.5.0.tgz", + "integrity": "sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/nearest-point-on-line": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-slice-along": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-5.1.5.tgz", - "integrity": "sha1-7drQoh70efKWihG9LdcomiEy6aU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-6.5.0.tgz", + "integrity": "sha512-KHJRU6KpHrAj+BTgTNqby6VCTnDzG6a1sJx/I3hNvqMBLvWVA2IrkR9L9DtsQsVY63IBwVdQDqiwCuZLDQh4Ng==", "dependencies": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-split": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-5.1.5.tgz", - "integrity": "sha1-Wy30w3YZty73JbUWPPmSbVVArLc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-6.5.0.tgz", + "integrity": "sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/nearest-point-on-line": "^5.1.5", - "@turf/square": "^5.1.5", - "@turf/truncate": "^5.1.5", - "geojson-rbush": "2.1.0" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "@turf/square": "^6.5.0", + "@turf/truncate": "^6.5.0", + "geojson-rbush": "3.x" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/line-to-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-5.1.5.tgz", - "integrity": "sha1-ITz0Gmj4Ikd4ujnTGH3sPouBhlo=", - "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" - } - }, - "node_modules/@turf/mask": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-5.1.5.tgz", - "integrity": "sha1-mrD+8aJyyY/j70kvn/thggayQtU=", - "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/union": "^5.1.5", - "rbush": "^2.0.1" - } - }, - "node_modules/@turf/mask/node_modules/quickselect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", - "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" - }, - "node_modules/@turf/mask/node_modules/rbush": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz", - "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", - "dependencies": { - "quickselect": "^1.0.1" - } - }, - "node_modules/@turf/meta": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.1.6.tgz", - "integrity": "sha1-wgqGPt7Qhp+yhUje6Ik0G8y0akY=", - "dependencies": { - "@turf/helpers": "^5.1.5" - } - }, - "node_modules/@turf/midpoint": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-5.1.5.tgz", - "integrity": "sha1-4mH2srDqgSTM7/VSomLdRlydBfA=", - "dependencies": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" - } - }, - "node_modules/@turf/nearest-point": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-5.1.5.tgz", - "integrity": "sha1-EgUN5Bw5hEMiTHl43g9iE5ANNPs=", - "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" - } - }, - "node_modules/@turf/nearest-point-on-line": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-5.1.5.tgz", - "integrity": "sha1-VgauKX8VlHUkvqUaKp71HsG/nDY=", - "dependencies": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/meta": "^5.1.5" - } - }, - "node_modules/@turf/nearest-point-to-line": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-5.1.6.tgz", - "integrity": "sha512-ZSvDIEiHhifn/vNwLXZI/E8xmEz5yBPqfUR7BVHRZrB1cP7jLhKZvkbidjG//uW8Fr1Ulc+PFOXczLspIcx/lw==", - "dependencies": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x", - "@turf/meta": "6.x", - "@turf/point-to-line-distance": "^5.1.5", - "object-assign": "*" - } - }, - "node_modules/@turf/nearest-point-to-line/node_modules/@turf/helpers": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.4.tgz", - "integrity": "sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==" - }, - "node_modules/@turf/nearest-point-to-line/node_modules/@turf/invariant": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.1.2.tgz", - "integrity": "sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==", - "dependencies": { - "@turf/helpers": "6.x" - } - }, - "node_modules/@turf/nearest-point-to-line/node_modules/@turf/meta": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.0.2.tgz", - "integrity": "sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-6.5.0.tgz", + "integrity": "sha512-qYBuRCJJL8Gx27OwCD1TMijM/9XjRgXH/m/TyuND4OXedBpIWlK5VbTIO2gJ8OCfznBBddpjiObLBrkuxTpN4Q==", "dependencies": { - "@turf/helpers": "6.x" + "@turf/bbox": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/planepoint": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-5.1.5.tgz", - "integrity": "sha1-GLvfAG91ne9eQsagBsn53oGyt/8=", + "node_modules/@turf/mask": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-6.5.0.tgz", + "integrity": "sha512-RQha4aU8LpBrmrkH8CPaaoAfk0Egj5OuXtv6HuCQnHeGNOQt3TQVibTA3Sh4iduq4EPxnZfDjgsOeKtrCA19lg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-5.1.5.tgz", - "integrity": "sha1-MFFBJI9Quv42zn5mukuX56sjaIc=", + "node_modules/@turf/meta": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", + "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", "dependencies": { - "@turf/boolean-within": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-on-feature": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-5.1.5.tgz", - "integrity": "sha1-MMfwMkMCd8ZBjZbSieRba/shP+c=", + "node_modules/@turf/midpoint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-6.5.0.tgz", + "integrity": "sha512-MyTzV44IwmVI6ec9fB2OgZ53JGNlgOpaYl9ArKoF49rXpL84F9rNATndbe0+MQIhdkw8IlzA6xVP4lZzfMNVCw==", "dependencies": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/center": "^5.1.5", - "@turf/explode": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/nearest-point": "^5.1.5" + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-5.1.6.tgz", - "integrity": "sha512-PE3hiTeeDEi4ZLPtI8XAzFYW9nHo1EVsZGm/4ZVV8jo39d3X1oLVHxY3e1PkCmWwRapXy4QLqvnTQ7nU4wspNw==", + "node_modules/@turf/moran-index": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/moran-index/-/moran-index-6.5.0.tgz", + "integrity": "sha512-ItsnhrU2XYtTtTudrM8so4afBCYWNaB0Mfy28NZwLjB5jWuAsvyV+YW+J88+neK/ougKMTawkmjQqodNJaBeLQ==", "dependencies": { - "@turf/bearing": "6.x", - "@turf/distance": "6.x", - "@turf/helpers": "6.x", - "@turf/invariant": "6.x", - "@turf/meta": "6.x", - "@turf/projection": "6.x", - "@turf/rhumb-bearing": "6.x", - "@turf/rhumb-distance": "6.x" + "@turf/distance-weight": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/bearing": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.0.1.tgz", - "integrity": "sha512-mXY1NozqV9EFfBTbUItujwfqfQF0G/Xe2fzvnZle90ekPEUfhi4Dgf5JswJTd96J9LiT8kcd6Jonp5khnx0wIg==", + "node_modules/@turf/nearest-point": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-6.5.0.tgz", + "integrity": "sha512-fguV09QxilZv/p94s8SMsXILIAMiaXI5PATq9d7YWijLxWUj6Q/r43kxyoi78Zmwwh1Zfqz9w+bCYUAxZ5+euA==", "dependencies": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/clone": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.0.2.tgz", - "integrity": "sha512-UVpYPnW3wRj3bPncR6Z2PRbowBk+nEdVWgGewPxrKKLfvswtVtG9n/OIyvbU3E3ZOadBVxTH2uAMEMOz4800FA==", + "node_modules/@turf/nearest-point-on-line": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz", + "integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==", "dependencies": { - "@turf/helpers": "6.x" + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/distance": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.0.1.tgz", - "integrity": "sha512-q7t7rWIWfkg7MP1Vt4uLjSEhe5rPfCO2JjpKmk7JC+QZKEQkuvHEqy3ejW1iC7Kw5ZcZNR3qdMGGz+6HnVwqvg==", + "node_modules/@turf/nearest-point-to-line": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-6.5.0.tgz", + "integrity": "sha512-PXV7cN0BVzUZdjj6oeb/ESnzXSfWmEMrsfZSDRgqyZ9ytdiIj/eRsnOXLR13LkTdXVOJYDBuf7xt1mLhM4p6+Q==", "dependencies": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/point-to-line-distance": "^6.5.0", + "object-assign": "*" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/helpers": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.4.tgz", - "integrity": "sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==" - }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/invariant": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.1.2.tgz", - "integrity": "sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==", + "node_modules/@turf/planepoint": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-6.5.0.tgz", + "integrity": "sha512-R3AahA6DUvtFbka1kcJHqZ7DMHmPXDEQpbU5WaglNn7NaCQg9HB0XM0ZfqWcd5u92YXV+Gg8QhC8x5XojfcM4Q==", "dependencies": { - "@turf/helpers": "6.x" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/meta": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.0.2.tgz", - "integrity": "sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==", + "node_modules/@turf/point-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-6.5.0.tgz", + "integrity": "sha512-Iq38lFokNNtQJnOj/RBKmyt6dlof0yhaHEDELaWHuECm1lIZLY3ZbVMwbs+nXkwTAHjKfS/OtMheUBkw+ee49w==", "dependencies": { - "@turf/helpers": "6.x" + "@turf/boolean-within": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/projection": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.0.1.tgz", - "integrity": "sha512-Y3RvGT6I53MjYKLG69e9sMk45wJXcLbrEO1t6P3WQQQGqA2gYhhMJyV41vE2Z2llrJpvs2dDx/tIeQzGd0HHMQ==", + "node_modules/@turf/point-on-feature": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-6.5.0.tgz", + "integrity": "sha512-bDpuIlvugJhfcF/0awAQ+QI6Om1Y1FFYE8Y/YdxGRongivix850dTeXCo0mDylFdWFPGDo7Mmh9Vo4VxNwW/TA==", "dependencies": { - "@turf/clone": "6.x", - "@turf/helpers": "6.x", - "@turf/meta": "6.x" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/nearest-point": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/rhumb-bearing": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.0.1.tgz", - "integrity": "sha512-MVBra8OVfjM4+/N0B3o6cBIYg9p/uRKzA9uk05RfrzasEbUL1vdD23LkTooVL74Yw4UxL8BQD9hS5Re2COJFDA==", + "node_modules/@turf/point-to-line-distance": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-6.5.0.tgz", + "integrity": "sha512-opHVQ4vjUhNBly1bob6RWy+F+hsZDH9SA0UW36pIRzfpu27qipU18xup0XXEePfY6+wvhF6yL/WgCO2IbrLqEA==", "dependencies": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" + "@turf/bearing": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/projection": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/point-to-line-distance/node_modules/@turf/rhumb-distance": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.0.1.tgz", - "integrity": "sha512-3G45DQtQByzzfHFPcCyJdUZFwsd45zfZ7sAb1ddF7mhEj4G70+T2G3GKjInymqDNrbyh2gbG6wQiZSToC8Uf9g==", + "node_modules/@turf/points-within-polygon": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-6.5.0.tgz", + "integrity": "sha512-YyuheKqjliDsBDt3Ho73QVZk1VXX1+zIA2gwWvuz8bR1HXOkcuwk/1J76HuFMOQI3WK78wyAi+xbkx268PkQzQ==", "dependencies": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, - "node_modules/@turf/points-within-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-5.1.5.tgz", - "integrity": "sha1-K4VaXfOq2lfC7oIKB1SrlJKKIzc=", + "node_modules/@turf/polygon-smooth": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-smooth/-/polygon-smooth-6.5.0.tgz", + "integrity": "sha512-LO/X/5hfh/Rk4EfkDBpLlVwt3i6IXdtQccDT9rMjXEP32tRgy0VMFmdkNaXoGlSSKf/1mGqLl4y4wHd86DqKbg==", "dependencies": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/polygon-tangents": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-5.1.5.tgz", - "integrity": "sha1-K/AJkUcwJbF44lDcfLmuVAm71lI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-6.5.0.tgz", + "integrity": "sha512-sB4/IUqJMYRQH9jVBwqS/XDitkEfbyqRy+EH/cMRJURTg78eHunvJ708x5r6umXsbiUyQU4eqgPzEylWEQiunw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/boolean-within": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/nearest-point": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/polygon-to-line": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-5.1.5.tgz", - "integrity": "sha1-I7tEjYTcTGUZmaxhGjbZHFklA2o=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz", + "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/polygonize": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-5.1.5.tgz", - "integrity": "sha1-BJP6EYefOdELmtAs5qI+lC0IqjI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-6.5.0.tgz", + "integrity": "sha512-a/3GzHRaCyzg7tVYHo43QUChCspa99oK4yPqooVIwTC61npFzdrmnywMv0S+WZjHZwK37BrFJGFrZGf6ocmY5w==", "dependencies": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/envelope": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/envelope": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/projection": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-5.1.5.tgz", - "integrity": "sha1-JFF+7rLzaBa6n3EueubWo2jt91c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.5.0.tgz", + "integrity": "sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg==", "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/random": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/random/-/random-5.1.5.tgz", - "integrity": "sha1-sy78k0Vgroulfo67UfJBw5+6Lns=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/random/-/random-6.5.0.tgz", + "integrity": "sha512-8Q25gQ/XbA7HJAe+eXp4UhcXM9aOOJFaxZ02+XSNwMvY8gtWSCBLVqRcW4OhqilgZ8PeuQDWgBxeo+BIqqFWFQ==", + "dependencies": { + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" + } + }, + "node_modules/@turf/rectangle-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rectangle-grid/-/rectangle-grid-6.5.0.tgz", + "integrity": "sha512-yQZ/1vbW68O2KsSB3OZYK+72aWz/Adnf7m2CMKcC+aq6TwjxZjAvlbCOsNUnMAuldRUVN1ph6RXMG4e9KEvKvg==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/boolean-intersects": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/rewind": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", - "integrity": "sha1-nqPbSmi3PB/R3RH1djGxQ8/vock=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-6.5.0.tgz", + "integrity": "sha512-IoUAMcHWotBWYwSYuYypw/LlqZmO+wcBpn8ysrBNbazkFNkLf3btSDZMkKJO/bvOzl55imr/Xj4fi3DdsLsbzQ==", "dependencies": { - "@turf/boolean-clockwise": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/boolean-clockwise": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/rhumb-bearing": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-5.1.5.tgz", - "integrity": "sha1-rPalAkJ+uMSeGM2mrg7/qwxd3NI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.5.0.tgz", + "integrity": "sha512-jMyqiMRK4hzREjQmnLXmkJ+VTNTx1ii8vuqRwJPcTlKbNWfjDz/5JqJlb5NaFDcdMpftWovkW5GevfnuzHnOYA==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/rhumb-destination": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-5.1.5.tgz", - "integrity": "sha1-sbKuuSFUfyrAwamUtqEw+SRjx0I=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-6.5.0.tgz", + "integrity": "sha512-RHNP1Oy+7xTTdRrTt375jOZeHceFbjwohPHlr9Hf68VdHHPMAWgAKqiX2YgSWDcvECVmiGaBKWus1Df+N7eE4Q==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/rhumb-distance": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-5.1.5.tgz", - "integrity": "sha1-GAaFdiX0IlOE2tQT5p85U4/192U=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.5.0.tgz", + "integrity": "sha512-oKp8KFE8E4huC2Z1a1KNcFwjVOqa99isxNOwfo4g3SUABQ6NezjKDDrnvC4yI5YZ3/huDjULLBvhed45xdCrzg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/sample": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-5.1.5.tgz", - "integrity": "sha1-6ctEikeJzFbuPeLdZ4HiNDQ1tBE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-6.5.0.tgz", + "integrity": "sha512-kSdCwY7el15xQjnXYW520heKUrHwRvnzx8ka4eYxX9NFeOxaFITLW2G7UtXb6LJK8mmPXI8Aexv23F2ERqzGFg==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/sector": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-5.1.5.tgz", - "integrity": "sha1-rCu5TBPt1gNPb9wrZwCBNdIPXgc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-6.5.0.tgz", + "integrity": "sha512-cYUOkgCTWqa23SOJBqxoFAc/yGCUsPRdn/ovbRTn1zNTm/Spmk6hVB84LCKOgHqvSF25i0d2kWqpZDzLDdAPbw==", "dependencies": { - "@turf/circle": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-arc": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/circle": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-arc": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/shortest-path": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-5.1.5.tgz", - "integrity": "sha1-hUroCW9rw+EwD6ynfz6PZ9j5Nas=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-6.5.0.tgz", + "integrity": "sha512-4de5+G7+P4hgSoPwn+SO9QSi9HY5NEV/xRJ+cmoFVRwv2CDsuOPDheHKeuIAhKyeKDvPvPt04XYWbac4insJMg==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/bbox-polygon": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/clean-coords": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/transform-scale": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/clean-coords": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/transform-scale": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/simplify": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-5.1.5.tgz", - "integrity": "sha1-Csjyei60IYGD7dmZjDJ1q+QIuSY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-6.5.0.tgz", + "integrity": "sha512-USas3QqffPHUY184dwQdP8qsvcVH/PWBYdXY5am7YTBACaQOMAlf6AKJs9FT8jiO6fQpxfgxuEtwmox+pBtlOg==", "dependencies": { - "@turf/clean-coords": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clean-coords": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/square": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/square/-/square-5.1.5.tgz", - "integrity": "sha1-qnsh5gM8ySUsOlvW89iNq9b+0YA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/square/-/square-6.5.0.tgz", + "integrity": "sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==", "dependencies": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/square-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-5.1.5.tgz", - "integrity": "sha1-G9X3uesU8LYLwjH+/nNR0aMvGlE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-6.5.0.tgz", + "integrity": "sha512-mlR0ayUdA+L4c9h7p4k3pX6gPWHNGuZkt2c5II1TJRmhLkW2557d6b/Vjfd1z9OVaajb1HinIs1FMSAPXuuUrA==", "dependencies": { - "@turf/boolean-contains": "^5.1.5", - "@turf/boolean-overlap": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/intersect": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/rectangle-grid": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/standard-deviational-ellipse": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-5.1.5.tgz", - "integrity": "sha1-hc0oO14ayljyG9ZkEuQUtW2FIyQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-6.5.0.tgz", + "integrity": "sha512-02CAlz8POvGPFK2BKK8uHGUk/LXb0MK459JVjKxLC2yJYieOBTqEbjP0qaWhiBhGzIxSMaqe8WxZ0KvqdnstHA==", "dependencies": { - "@turf/center-mean": "^5.1.5", - "@turf/ellipse": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/points-within-polygon": "^5.1.5" + "@turf/center-mean": "^6.5.0", + "@turf/ellipse": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/points-within-polygon": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/tag": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-5.1.5.tgz", - "integrity": "sha1-0e4aUIjs/UoUEQGcmCOczypJfSA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-6.5.0.tgz", + "integrity": "sha512-XwlBvrOV38CQsrNfrxvBaAPBQgXMljeU0DV8ExOyGM7/hvuGHJw3y8kKnQ4lmEQcmcrycjDQhP7JqoRv8vFssg==", "dependencies": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/tesselate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-5.1.5.tgz", - "integrity": "sha1-MqWU6cIaAEIKn5DSxD3z4RZgYc0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-6.5.0.tgz", + "integrity": "sha512-M1HXuyZFCfEIIKkglh/r5L9H3c5QTEsnMBoZOFQiRnGPGmJWcaBissGb7mTFX2+DKE7FNWXh4TDnZlaLABB0dQ==", "dependencies": { - "@turf/helpers": "^5.1.5", + "@turf/helpers": "^6.5.0", "earcut": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/tin": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-5.1.5.tgz", - "integrity": "sha1-KCI+r8X76a6azKgc3P6l0UJMkX0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-6.5.0.tgz", + "integrity": "sha512-YLYikRzKisfwj7+F+Tmyy/LE3d2H7D4kajajIfc9mlik2+esG7IolsX/+oUz1biguDYsG0DUA8kVYXDkobukfg==", "dependencies": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/transform-rotate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-5.1.5.tgz", - "integrity": "sha1-0Jbt2eMA/jFQadVNjkWMQJIh7fs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-6.5.0.tgz", + "integrity": "sha512-A2Ip1v4246ZmpssxpcL0hhiVBEf4L8lGnSPWTgSv5bWBEoya2fa/0SnFX9xJgP40rMP+ZzRaCN37vLHbv1Guag==", "dependencies": { - "@turf/centroid": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/rhumb-bearing": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5", - "@turf/rhumb-distance": "^5.1.5" + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/transform-scale": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-5.1.5.tgz", - "integrity": "sha1-cP064BhWz3uunxWtVhzf6PiQAbk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-6.5.0.tgz", + "integrity": "sha512-VsATGXC9rYM8qTjbQJ/P7BswKWXHdnSJ35JlV4OsZyHBMxJQHftvmZJsFbOqVtQnIQIzf2OAly6rfzVV9QLr7g==", "dependencies": { - "@turf/bbox": "^5.1.5", - "@turf/center": "^5.1.5", - "@turf/centroid": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/rhumb-bearing": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5", - "@turf/rhumb-distance": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/transform-translate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-5.1.5.tgz", - "integrity": "sha1-Uwolf7Hccmja3Ks05nkB6yo97GM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-6.5.0.tgz", + "integrity": "sha512-NABLw5VdtJt/9vSstChp93pc6oel4qXEos56RBMsPlYB8hzNTEKYtC146XJvyF4twJeeYS8RVe1u7KhoFwEM5w==", "dependencies": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/triangle-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-5.1.5.tgz", - "integrity": "sha1-ezZ2IQhVTBTyjK/zxIsc/ILI3IE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-6.5.0.tgz", + "integrity": "sha512-2jToUSAS1R1htq4TyLQYPTIsoy6wg3e3BQXjm2rANzw4wPQCXGOxrur1Fy9RtzwqwljlC7DF4tg0OnWr8RjmfA==", "dependencies": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/intersect": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/intersect": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/truncate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-5.1.5.tgz", - "integrity": "sha1-nu37Oxi6gfLJjT6tCUMcyhiErYk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-6.5.0.tgz", + "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/turf": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-5.1.6.tgz", - "integrity": "sha1-wxIlkoh+0jS3VGi4qMRb+Ib7+PY=", - "dependencies": { - "@turf/along": "5.1.x", - "@turf/area": "5.1.x", - "@turf/bbox": "5.1.x", - "@turf/bbox-clip": "5.1.x", - "@turf/bbox-polygon": "5.1.x", - "@turf/bearing": "5.1.x", - "@turf/bezier-spline": "5.1.x", - "@turf/boolean-clockwise": "5.1.x", - "@turf/boolean-contains": "5.1.x", - "@turf/boolean-crosses": "5.1.x", - "@turf/boolean-disjoint": "5.1.x", - "@turf/boolean-equal": "5.1.x", - "@turf/boolean-overlap": "5.1.x", - "@turf/boolean-parallel": "5.1.x", - "@turf/boolean-point-in-polygon": "5.1.x", - "@turf/boolean-point-on-line": "5.1.x", - "@turf/boolean-within": "5.1.x", - "@turf/buffer": "5.1.x", - "@turf/center": "5.1.x", - "@turf/center-mean": "5.1.x", - "@turf/center-median": "5.1.x", - "@turf/center-of-mass": "5.1.x", - "@turf/centroid": "5.1.x", - "@turf/circle": "5.1.x", - "@turf/clean-coords": "5.1.x", - "@turf/clone": "5.1.x", - "@turf/clusters": "5.1.x", - "@turf/clusters-dbscan": "5.1.x", - "@turf/clusters-kmeans": "5.1.x", - "@turf/collect": "5.1.x", - "@turf/combine": "5.1.x", - "@turf/concave": "5.1.x", - "@turf/convex": "5.1.x", - "@turf/destination": "5.1.x", - "@turf/difference": "5.1.x", - "@turf/dissolve": "5.1.x", - "@turf/distance": "5.1.x", - "@turf/ellipse": "5.1.x", - "@turf/envelope": "5.1.x", - "@turf/explode": "5.1.x", - "@turf/flatten": "5.1.x", - "@turf/flip": "5.1.x", - "@turf/great-circle": "5.1.x", - "@turf/helpers": "5.1.x", - "@turf/hex-grid": "5.1.x", - "@turf/interpolate": "5.1.x", - "@turf/intersect": "5.1.x", - "@turf/invariant": "5.1.x", - "@turf/isobands": "5.1.x", - "@turf/isolines": "5.1.x", - "@turf/kinks": "5.1.x", - "@turf/length": "5.1.x", - "@turf/line-arc": "5.1.x", - "@turf/line-chunk": "5.1.x", - "@turf/line-intersect": "5.1.x", - "@turf/line-offset": "5.1.x", - "@turf/line-overlap": "5.1.x", - "@turf/line-segment": "5.1.x", - "@turf/line-slice": "5.1.x", - "@turf/line-slice-along": "5.1.x", - "@turf/line-split": "5.1.x", - "@turf/line-to-polygon": "5.1.x", - "@turf/mask": "5.1.x", - "@turf/meta": "5.1.x", - "@turf/midpoint": "5.1.x", - "@turf/nearest-point": "5.1.x", - "@turf/nearest-point-on-line": "5.1.x", - "@turf/nearest-point-to-line": "5.1.x", - "@turf/planepoint": "5.1.x", - "@turf/point-grid": "5.1.x", - "@turf/point-on-feature": "5.1.x", - "@turf/point-to-line-distance": "5.1.x", - "@turf/points-within-polygon": "5.1.x", - "@turf/polygon-tangents": "5.1.x", - "@turf/polygon-to-line": "5.1.x", - "@turf/polygonize": "5.1.x", - "@turf/projection": "5.1.x", - "@turf/random": "5.1.x", - "@turf/rewind": "5.1.x", - "@turf/rhumb-bearing": "5.1.x", - "@turf/rhumb-destination": "5.1.x", - "@turf/rhumb-distance": "5.1.x", - "@turf/sample": "5.1.x", - "@turf/sector": "5.1.x", - "@turf/shortest-path": "5.1.x", - "@turf/simplify": "5.1.x", - "@turf/square": "5.1.x", - "@turf/square-grid": "5.1.x", - "@turf/standard-deviational-ellipse": "5.1.x", - "@turf/tag": "5.1.x", - "@turf/tesselate": "5.1.x", - "@turf/tin": "5.1.x", - "@turf/transform-rotate": "5.1.x", - "@turf/transform-scale": "5.1.x", - "@turf/transform-translate": "5.1.x", - "@turf/triangle-grid": "5.1.x", - "@turf/truncate": "5.1.x", - "@turf/union": "5.1.x", - "@turf/unkink-polygon": "5.1.x", - "@turf/voronoi": "5.1.x" + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-6.5.0.tgz", + "integrity": "sha512-ipMCPnhu59bh92MNt8+pr1VZQhHVuTMHklciQURo54heoxRzt1neNYZOBR6jdL+hNsbDGAECMuIpAutX+a3Y+w==", + "dependencies": { + "@turf/along": "^6.5.0", + "@turf/angle": "^6.5.0", + "@turf/area": "^6.5.0", + "@turf/bbox": "^6.5.0", + "@turf/bbox-clip": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/bearing": "^6.5.0", + "@turf/bezier-spline": "^6.5.0", + "@turf/boolean-clockwise": "^6.5.0", + "@turf/boolean-contains": "^6.5.0", + "@turf/boolean-crosses": "^6.5.0", + "@turf/boolean-disjoint": "^6.5.0", + "@turf/boolean-equal": "^6.5.0", + "@turf/boolean-intersects": "^6.5.0", + "@turf/boolean-overlap": "^6.5.0", + "@turf/boolean-parallel": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/boolean-within": "^6.5.0", + "@turf/buffer": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/center-mean": "^6.5.0", + "@turf/center-median": "^6.5.0", + "@turf/center-of-mass": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/circle": "^6.5.0", + "@turf/clean-coords": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/clusters": "^6.5.0", + "@turf/clusters-dbscan": "^6.5.0", + "@turf/clusters-kmeans": "^6.5.0", + "@turf/collect": "^6.5.0", + "@turf/combine": "^6.5.0", + "@turf/concave": "^6.5.0", + "@turf/convex": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/difference": "^6.5.0", + "@turf/dissolve": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/distance-weight": "^6.5.0", + "@turf/ellipse": "^6.5.0", + "@turf/envelope": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/flatten": "^6.5.0", + "@turf/flip": "^6.5.0", + "@turf/great-circle": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/hex-grid": "^6.5.0", + "@turf/interpolate": "^6.5.0", + "@turf/intersect": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/isobands": "^6.5.0", + "@turf/isolines": "^6.5.0", + "@turf/kinks": "^6.5.0", + "@turf/length": "^6.5.0", + "@turf/line-arc": "^6.5.0", + "@turf/line-chunk": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-offset": "^6.5.0", + "@turf/line-overlap": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/line-slice": "^6.5.0", + "@turf/line-slice-along": "^6.5.0", + "@turf/line-split": "^6.5.0", + "@turf/line-to-polygon": "^6.5.0", + "@turf/mask": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/midpoint": "^6.5.0", + "@turf/moran-index": "^6.5.0", + "@turf/nearest-point": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "@turf/nearest-point-to-line": "^6.5.0", + "@turf/planepoint": "^6.5.0", + "@turf/point-grid": "^6.5.0", + "@turf/point-on-feature": "^6.5.0", + "@turf/point-to-line-distance": "^6.5.0", + "@turf/points-within-polygon": "^6.5.0", + "@turf/polygon-smooth": "^6.5.0", + "@turf/polygon-tangents": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0", + "@turf/polygonize": "^6.5.0", + "@turf/projection": "^6.5.0", + "@turf/random": "^6.5.0", + "@turf/rewind": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0", + "@turf/sample": "^6.5.0", + "@turf/sector": "^6.5.0", + "@turf/shortest-path": "^6.5.0", + "@turf/simplify": "^6.5.0", + "@turf/square": "^6.5.0", + "@turf/square-grid": "^6.5.0", + "@turf/standard-deviational-ellipse": "^6.5.0", + "@turf/tag": "^6.5.0", + "@turf/tesselate": "^6.5.0", + "@turf/tin": "^6.5.0", + "@turf/transform-rotate": "^6.5.0", + "@turf/transform-scale": "^6.5.0", + "@turf/transform-translate": "^6.5.0", + "@turf/triangle-grid": "^6.5.0", + "@turf/truncate": "^6.5.0", + "@turf/union": "^6.5.0", + "@turf/unkink-polygon": "^6.5.0", + "@turf/voronoi": "^6.5.0" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/union": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/union/-/union-5.1.5.tgz", - "integrity": "sha1-UyhbYJQEf8WNlqrA6pCGXsNNRUs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/union/-/union-6.5.0.tgz", + "integrity": "sha512-igYWCwP/f0RFHIlC2c0SKDuM/ObBaqSljI3IdV/x71805QbIvY/BYGcJdyNcgEA6cylIGl/0VSlIbpJHZ9ldhw==", "dependencies": { - "@turf/helpers": "^5.1.5", - "turf-jsts": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/unkink-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-5.1.5.tgz", - "integrity": "sha1-ewGEfFD7V0riV54Z5Ey6hSbSE8M=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-6.5.0.tgz", + "integrity": "sha512-8QswkzC0UqKmN1DT6HpA9upfa1HdAA5n6bbuzHy8NJOX8oVizVAqfEPY0wqqTgboDjmBR4yyImsdPGUl3gZ8JQ==", "dependencies": { - "@turf/area": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", + "@turf/area": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", "rbush": "^2.0.1" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@turf/unkink-polygon/node_modules/quickselect": { @@ -3312,13 +3456,16 @@ } }, "node_modules/@turf/voronoi": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-5.1.5.tgz", - "integrity": "sha1-6FbpQG3MLyXWbdyJhYTifC6/ymY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-6.5.0.tgz", + "integrity": "sha512-C/xUsywYX+7h1UyNqnydHXiun4UPjK88VDghtoRypR9cLlb7qozkiLRphQxxsCM0KxyxpVPHBVQXdAL3+Yurow==", "dependencies": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", "d3-voronoi": "1.1.2" + }, + "funding": { + "url": "https://opencollective.com/turf" } }, "node_modules/@types/babel__core": { @@ -5880,12 +6027,12 @@ } }, "node_modules/concaveman": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.0.tgz", - "integrity": "sha512-OcqechF2/kubbffomKqjGEkb0ndlYhEbmyg/fxIGqdfYp5AZjD2Kl5hc97Hh3ngEuHU2314Z4KDbxL7qXGWrQQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz", + "integrity": "sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==", "dependencies": { - "point-in-polygon": "^1.0.1", - "rbush": "^3.0.0", + "point-in-polygon": "^1.1.0", + "rbush": "^3.0.1", "robust-predicates": "^2.0.4", "tinyqueue": "^2.0.3" } @@ -9281,13 +9428,15 @@ } }, "node_modules/geojson-rbush": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-2.1.0.tgz", - "integrity": "sha1-O9c745H8ELCuaT2bis6iquC4Oo0=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", + "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", "dependencies": { - "@turf/helpers": "*", - "@turf/meta": "*", - "rbush": "*" + "@turf/bbox": "*", + "@turf/helpers": "6.x", + "@turf/meta": "6.x", + "@types/geojson": "7946.0.8", + "rbush": "^3.0.1" } }, "node_modules/get-caller-file": { @@ -9298,11 +9447,6 @@ "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/get-closest": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/get-closest/-/get-closest-0.0.4.tgz", - "integrity": "sha1-JprHdtHmAiqg/Vht1wjop9Miaa8=" - }, "node_modules/get-intrinsic": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", @@ -11748,11 +11892,6 @@ "node": ">= 0.8.0" } }, - "node_modules/lineclip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/lineclip/-/lineclip-1.1.5.tgz", - "integrity": "sha1-K/JgZ9lDVP6r+R5CdoI221YW/RM=" - }, "node_modules/lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -11773,49 +11912,6 @@ "three": ">=0.122.0" } }, - "node_modules/lithosphere/node_modules/@turf/circle": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz", - "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==", - "dependencies": { - "@turf/destination": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/lithosphere/node_modules/@turf/destination": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz", - "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/lithosphere/node_modules/@turf/helpers": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", - "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/lithosphere/node_modules/@turf/invariant": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", - "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, "node_modules/load-json-file": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", @@ -13638,9 +13734,17 @@ } }, "node_modules/point-in-polygon": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.0.1.tgz", - "integrity": "sha1-1Ztk6P7kHElFiqyCtWcYxZV7Kvc=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", + "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==" + }, + "node_modules/polygon-clipping": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz", + "integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==", + "dependencies": { + "splaytree": "^3.1.0" + } }, "node_modules/portfinder": { "version": "1.0.28", @@ -17033,6 +17137,11 @@ "node": ">=4.5" } }, + "node_modules/splaytree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.0.tgz", + "integrity": "sha512-gvUGR7xnOy0fLKTCxDeUZYgU/I1Tdf8M/lM1Qrf8L2TIOR5ipZjGk02uYcdv0o2x7WjVRgpm3iS2clLyuVAt0Q==" + }, "node_modules/split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", @@ -21861,123 +21970,134 @@ "integrity": "sha512-oZ0Ib5I4Z2pUEcoo95cT1cr6slco9WY7yiPpG+RGNkj8YcYgJnM7pXmYmorNOReh8MIGcKSqXyeGjxnr8YiZbA==" }, "@turf/along": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/along/-/along-5.1.5.tgz", - "integrity": "sha1-YdbmplhKzdq1asVYTge/jL5fi+s=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/along/-/along-6.5.0.tgz", + "integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==", + "requires": { + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + } + }, + "@turf/angle": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/angle/-/angle-6.5.0.tgz", + "integrity": "sha512-4pXMbWhFofJJAOvTMCns6N4C8CMd5Ih4O2jSAG9b3dDHakj3O4yN1+Zbm+NUei+eVEZ9gFeVp9svE3aMDenIkw==", "requires": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bearing": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0" } }, "@turf/area": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/area/-/area-5.1.5.tgz", - "integrity": "sha1-79iZv9Jgzb0VQbKjwVX4pdLu+h0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/area/-/area-6.5.0.tgz", + "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/bbox": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-5.1.5.tgz", - "integrity": "sha1-MFHfUUrUxQ9KT5uKLRX9i2hA7aM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox/-/bbox-6.5.0.tgz", + "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/bbox-clip": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-5.1.5.tgz", - "integrity": "sha1-M2S1Mo3/nzz0HZ4C7a/zdNFQzIQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-clip/-/bbox-clip-6.5.0.tgz", + "integrity": "sha512-F6PaIRF8WMp8EmgU/Ke5B1Y6/pia14UAYB5TiBC668w5rVVjy5L8rTm/m2lEkkDMHlzoP9vNY4pxpNthE7rLcQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "lineclip": "^1.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/bbox-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-5.1.5.tgz", - "integrity": "sha1-auuk7VHYXSluD3w4uIwznwHu4CQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz", + "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/bearing": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-5.1.5.tgz", - "integrity": "sha1-egt5ATbE70eX8CRjBdRcvi0ns/c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.5.0.tgz", + "integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/bezier-spline": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-5.1.5.tgz", - "integrity": "sha1-WaJ7ul17l+8Vqz/VpA+9I4cEm8o=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/bezier-spline/-/bezier-spline-6.5.0.tgz", + "integrity": "sha512-vokPaurTd4PF96rRgGVm6zYYC5r1u98ZsG+wZEv9y3kJTuJRX/O3xIY2QnTGTdbVmAJN1ouOsD0RoZYaVoXORQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/boolean-clockwise": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-5.1.5.tgz", - "integrity": "sha1-MwK32sYsXikaB4nimvcoM4f6nes=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz", + "integrity": "sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/boolean-contains": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-5.1.5.tgz", - "integrity": "sha1-WW1jruY2961T7pn5/yTJaZSg7xQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz", + "integrity": "sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/boolean-point-on-line": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/boolean-crosses": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-5.1.5.tgz", - "integrity": "sha1-Ab+uollvFk3kpNMlCU3HwlXHFdY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-crosses/-/boolean-crosses-6.5.0.tgz", + "integrity": "sha512-gvshbTPhAHporTlQwBJqyfW+2yV8q/mOTxG6PzRVl6ARsqNoqYQWkd4MLug7OmAqVyBzLK3201uAeBjxbGw0Ng==", "requires": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/polygon-to-line": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0" } }, "@turf/boolean-disjoint": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-5.1.6.tgz", - "integrity": "sha512-KHvUS6SBNYHBCLIJEJrg04pF5Oy+Fqn8V5G9U+9pti5vI9tyX7Ln2g7RSB7iJ1Cxsz8QAi6OukhXjEF2/8ZpGg==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz", + "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==", "requires": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/polygon-to-line": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0" } }, "@turf/boolean-equal": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-5.1.5.tgz", - "integrity": "sha1-Kfj21gu4RQff12WzIlTbjnLJOKQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-equal/-/boolean-equal-6.5.0.tgz", + "integrity": "sha512-cY0M3yoLC26mhAnjv1gyYNQjn7wxIXmL2hBmI/qs8g5uKuC2hRWi13ydufE3k4x0aNRjFGlg41fjoYLwaVF+9Q==", "requires": { - "@turf/clean-coords": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", + "@turf/clean-coords": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", "geojson-equality": "0.1.6" } }, @@ -21989,284 +22109,196 @@ "@turf/boolean-disjoint": "^6.5.0", "@turf/helpers": "^6.5.0", "@turf/meta": "^6.5.0" - }, - "dependencies": { - "@turf/boolean-disjoint": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz", - "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==", - "requires": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/polygon-to-line": "^6.5.0" - } - }, - "@turf/boolean-point-in-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", - "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", - "requires": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - } - }, - "@turf/helpers": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", - "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==" - }, - "@turf/invariant": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", - "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", - "requires": { - "@turf/helpers": "^6.5.0" - } - }, - "@turf/line-intersect": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz", - "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==", - "requires": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-segment": "^6.5.0", - "@turf/meta": "^6.5.0", - "geojson-rbush": "3.x" - } - }, - "@turf/line-segment": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz", - "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==", - "requires": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - } - }, - "@turf/meta": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", - "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", - "requires": { - "@turf/helpers": "^6.5.0" - } - }, - "@turf/polygon-to-line": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz", - "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==", - "requires": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - } - }, - "geojson-rbush": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", - "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", - "requires": { - "@turf/bbox": "*", - "@turf/helpers": "6.x", - "@turf/meta": "6.x", - "@types/geojson": "7946.0.8", - "rbush": "^3.0.1" - } - } } }, "@turf/boolean-overlap": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-5.1.5.tgz", - "integrity": "sha1-DU5kxSx3CijpPZ7834qLg3OsznU=", - "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/line-overlap": "^5.1.5", - "@turf/meta": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-overlap/-/boolean-overlap-6.5.0.tgz", + "integrity": "sha512-8btMIdnbXVWUa1M7D4shyaSGxLRw6NjMcqKBcsTXcZdnaixl22k7ar7BvIzkaRYN3SFECk9VGXfLncNS3ckQUw==", + "requires": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-overlap": "^6.5.0", + "@turf/meta": "^6.5.0", "geojson-equality": "0.1.6" } }, "@turf/boolean-parallel": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-5.1.5.tgz", - "integrity": "sha1-c5NYR16ltlx+GCejw+DopofTqF0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-parallel/-/boolean-parallel-6.5.0.tgz", + "integrity": "sha512-aSHJsr1nq9e5TthZGZ9CZYeXklJyRgR5kCLm5X4urz7+MotMOp/LsGOsvKvK9NeUl9+8OUmfMn8EFTT8LkcvIQ==", "requires": { - "@turf/clean-coords": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/rhumb-bearing": "^5.1.5" + "@turf/clean-coords": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0" } }, "@turf/boolean-point-in-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-5.1.5.tgz", - "integrity": "sha1-8BzBlNHgMKVIv9qYHLpDz9YpQbc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", + "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/boolean-point-on-line": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-5.1.5.tgz", - "integrity": "sha1-9jPF/4Aq0ku48Vja269v9KAj3Xs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz", + "integrity": "sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/boolean-within": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-5.1.5.tgz", - "integrity": "sha1-RxBdVtB1Kp0Pv81Dw2pfkUnchpc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/boolean-within/-/boolean-within-6.5.0.tgz", + "integrity": "sha512-YQB3oU18Inx35C/LU930D36RAVe7LDXk1kWsQ8mLmuqYn9YdPsDQTMTkLJMhoQ8EbN7QTdy333xRQ4MYgToteQ==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/boolean-point-on-line": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/buffer": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-5.1.5.tgz", - "integrity": "sha1-hByWJ8+5dLEirE4alW8EZrwCMcQ=", - "requires": { - "@turf/bbox": "^5.1.5", - "@turf/center": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/projection": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/buffer/-/buffer-6.5.0.tgz", + "integrity": "sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg==", + "requires": { + "@turf/bbox": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/projection": "^6.5.0", "d3-geo": "1.7.1", "turf-jsts": "*" } }, "@turf/center": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center/-/center-5.1.5.tgz", - "integrity": "sha1-RKss2VT2PA03dX9xWKmcPvURS4A=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center/-/center-6.5.0.tgz", + "integrity": "sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/center-mean": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-5.1.5.tgz", - "integrity": "sha1-jI6YdTkeXwnw5uePXWYbiLIQigo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-mean/-/center-mean-6.5.0.tgz", + "integrity": "sha512-AAX6f4bVn12pTVrMUiB9KrnV94BgeBKpyg3YpfnEbBpkN/znfVhL8dG8IxMAxAoSZ61Zt9WLY34HfENveuOZ7Q==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/center-median": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-5.1.5.tgz", - "integrity": "sha1-u0Yb/noqSGAdikcnaFcYcjoUqHI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-median/-/center-median-6.5.0.tgz", + "integrity": "sha512-dT8Ndu5CiZkPrj15PBvslpuf01ky41DEYEPxS01LOxp5HOUHXp1oJxsPxvc+i/wK4BwccPNzU1vzJ0S4emd1KQ==", "requires": { - "@turf/center-mean": "^5.1.5", - "@turf/centroid": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/center-mean": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/center-of-mass": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-5.1.5.tgz", - "integrity": "sha1-TTvXnYhJjbq4Mk1PafAyL2Uguco=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/center-of-mass/-/center-of-mass-6.5.0.tgz", + "integrity": "sha512-EWrriU6LraOfPN7m1jZi+1NLTKNkuIsGLZc2+Y8zbGruvUW+QV7K0nhf7iZWutlxHXTBqEXHbKue/o79IumAsQ==", "requires": { - "@turf/centroid": "^5.1.5", - "@turf/convex": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/centroid": "^6.5.0", + "@turf/convex": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/centroid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-5.1.5.tgz", - "integrity": "sha1-d4radCFjNQIa2P0OemWoNJ1Tx2k=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/centroid/-/centroid-6.5.0.tgz", + "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/circle": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-5.1.5.tgz", - "integrity": "sha1-mxV3g1UIq1L7HBCypQZcuiuHtqU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz", + "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==", "requires": { - "@turf/destination": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/destination": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/clean-coords": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-5.1.5.tgz", - "integrity": "sha1-EoAKmKeMmkUqcuxChJPEOs8q2h8=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clean-coords/-/clean-coords-6.5.0.tgz", + "integrity": "sha512-EMX7gyZz0WTH/ET7xV8MyrExywfm9qUi0/MY89yNffzGIEHuFfqwhcCqZ8O00rZIPZHUTxpmsxQSTfzJJA1CPw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/clone": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-5.1.5.tgz", - "integrity": "sha1-JT6NNUdxgZduM636tQoPAqfw42c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.5.0.tgz", + "integrity": "sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/clusters": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-5.1.5.tgz", - "integrity": "sha1-ZzpeXxsZycq6vFfJCO6t1oIiTdQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters/-/clusters-6.5.0.tgz", + "integrity": "sha512-Y6gfnTJzQ1hdLfCsyd5zApNbfLIxYEpmDibHUqR5z03Lpe02pa78JtgrgUNt1seeO/aJ4TG1NLN8V5gOrHk04g==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/clusters-dbscan": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-5.1.5.tgz", - "integrity": "sha1-V4H7TmVsdHoLjpk333MYHAMJ4m8=", - "requires": { - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters-dbscan/-/clusters-dbscan-6.5.0.tgz", + "integrity": "sha512-SxZEE4kADU9DqLRiT53QZBBhu8EP9skviSyl+FGj08Y01xfICM/RR9ACUdM0aEQimhpu+ZpRVcUK+2jtiCGrYQ==", + "requires": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", "density-clustering": "1.3.0" } }, "@turf/clusters-kmeans": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-5.1.5.tgz", - "integrity": "sha1-/W3+qLEzuovcI3CsPKzuFYejAvE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/clusters-kmeans/-/clusters-kmeans-6.5.0.tgz", + "integrity": "sha512-DwacD5+YO8kwDPKaXwT9DV46tMBVNsbi1IzdajZu1JDSWoN7yc7N9Qt88oi+p30583O0UPVkAK+A10WAQv4mUw==", "requires": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", "skmeans": "0.9.7" } }, "@turf/collect": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-5.1.5.tgz", - "integrity": "sha1-/pjJqMIY7PJP/DPXApUXt8GbKj4=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/collect/-/collect-6.5.0.tgz", + "integrity": "sha512-4dN/T6LNnRg099m97BJeOcTA5fSI8cu87Ydgfibewd2KQwBexO69AnjEFqfPX3Wj+Zvisj1uAVIZbPmSSrZkjg==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "rbush": "^2.0.1" + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "rbush": "2.x" }, "dependencies": { "quickselect": { @@ -22285,981 +22317,903 @@ } }, "@turf/combine": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-5.1.5.tgz", - "integrity": "sha1-uxS976VVBDVxlfwaEkzX1TqMiQU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/combine/-/combine-6.5.0.tgz", + "integrity": "sha512-Q8EIC4OtAcHiJB3C4R+FpB4LANiT90t17uOd851qkM2/o6m39bfN5Mv0PWqMZIHWrrosZqRqoY9dJnzz/rJxYQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/concave": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-5.1.5.tgz", - "integrity": "sha1-I7uqw4fQNLlldKG9cNBZI3qdIRA=", - "requires": { - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/tin": "^5.1.5", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/concave/-/concave-6.5.0.tgz", + "integrity": "sha512-I/sUmUC8TC5h/E2vPwxVht+nRt+TnXIPRoztDFvS8/Y0+cBDple9inLSo9nnPXMXidrBlGXZ9vQx/BjZUJgsRQ==", + "requires": { + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/tin": "^6.5.0", "topojson-client": "3.x", "topojson-server": "3.x" } }, "@turf/convex": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-5.1.5.tgz", - "integrity": "sha1-Dfk3fdACIWzpghsH9wXgN9rj4B0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/convex/-/convex-6.5.0.tgz", + "integrity": "sha512-x7ZwC5z7PJB0SBwNh7JCeCNx7Iu+QSrH7fYgK0RhhNop13TqUlvHMirMLRgf2db1DqUetrAO2qHJeIuasquUWg==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", "concaveman": "*" } }, "@turf/destination": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-5.1.5.tgz", - "integrity": "sha1-7TU4G9zoO73cvQei4rzivd/7zCY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz", + "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/difference": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-5.1.5.tgz", - "integrity": "sha1-ok1pCnvKgD8QkKnuO52Qb8Q3H0I=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/difference/-/difference-6.5.0.tgz", + "integrity": "sha512-l8iR5uJqvI+5Fs6leNbhPY5t/a3vipUF/3AeVLpwPQcgmedNXyheYuy07PcMGH5Jdpi5gItOiTqwiU/bUH4b3A==", "requires": { - "@turf/area": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "turf-jsts": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" } }, "@turf/dissolve": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-5.1.5.tgz", - "integrity": "sha1-LPEzqQIdIWODHD16lY1lB/nYGTg=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/dissolve/-/dissolve-6.5.0.tgz", + "integrity": "sha512-WBVbpm9zLTp0Bl9CE35NomTaOL1c4TQCtEoO43YaAhNEWJOOIhZMFJyr8mbvYruKl817KinT3x7aYjjCMjTAsQ==", "requires": { - "@turf/boolean-overlap": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/union": "^5.1.5", - "geojson-rbush": "2.1.0", - "get-closest": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "polygon-clipping": "^0.15.3" } }, "@turf/distance": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-5.1.5.tgz", - "integrity": "sha1-Oc8YIEu/h1h9cH5gmmARiQkVZAk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.5.0.tgz", + "integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==", + "requires": { + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" + } + }, + "@turf/distance-weight": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/distance-weight/-/distance-weight-6.5.0.tgz", + "integrity": "sha512-a8qBKkgVNvPKBfZfEJZnC3DV7dfIsC3UIdpRci/iap/wZLH41EmS90nM+BokAJflUHYy8PqE44wySGWHN1FXrQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/centroid": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/ellipse": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-5.1.5.tgz", - "integrity": "sha1-1XyrhTmFkgzeYCKKeNgEWAJcVL4=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/ellipse/-/ellipse-6.5.0.tgz", + "integrity": "sha512-kuXtwFviw/JqnyJXF1mrR/cb496zDTSbGKtSiolWMNImYzGGkbsAsFTjwJYgD7+4FixHjp0uQPzo70KDf3AIBw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5", - "@turf/transform-rotate": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/transform-rotate": "^6.5.0" } }, "@turf/envelope": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-5.1.5.tgz", - "integrity": "sha1-UBMwnFP91D369LWIplw/7X28EIo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/envelope/-/envelope-6.5.0.tgz", + "integrity": "sha512-9Z+FnBWvOGOU4X+fMZxYFs1HjFlkKqsddLuMknRaqcJd6t+NIv5DWvPtDL8ATD2GEExYDiFLwMdckfr1yqJgHA==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/bbox-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/explode": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-5.1.5.tgz", - "integrity": "sha1-sSsvd0AEobSPYrqVsgocZVo94Rg=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/explode/-/explode-6.5.0.tgz", + "integrity": "sha512-6cSvMrnHm2qAsace6pw9cDmK2buAlw8+tjeJVXMfMyY+w7ZUi1rprWMsY92J7s2Dar63Bv09n56/1V7+tcj52Q==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/flatten": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-5.1.5.tgz", - "integrity": "sha1-2iknBnEz7WFpsLnWB7khVoiqE1g=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/flatten/-/flatten-6.5.0.tgz", + "integrity": "sha512-IBZVwoNLVNT6U/bcUUllubgElzpMsNoCw8tLqBw6dfYg9ObGmpEjf9BIYLr7a2Yn5ZR4l7YIj2T7kD5uJjZADQ==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/flip": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-5.1.5.tgz", - "integrity": "sha1-Q29kOnIvDKU7n85jjkaT2zYIpoo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/flip/-/flip-6.5.0.tgz", + "integrity": "sha512-oyikJFNjt2LmIXQqgOGLvt70RgE2lyzPMloYWM7OR5oIFGRiBvqVD2hA6MNw6JewIm30fWZ8DQJw1NHXJTJPbg==", "requires": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/great-circle": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-5.1.5.tgz", - "integrity": "sha1-3r+2cc5HVQnLY3MBwV/PzPo1mpM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/great-circle/-/great-circle-6.5.0.tgz", + "integrity": "sha512-7ovyi3HaKOXdFyN7yy1yOMa8IyOvV46RC1QOQTT+RYUN8ke10eyqExwBpL9RFUPvlpoTzoYbM/+lWPogQlFncg==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/helpers": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-5.1.5.tgz", - "integrity": "sha1-FTQFInq5M9AEpbuWQantmZ/L4M8=" + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", + "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==" }, "@turf/hex-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-5.1.5.tgz", - "integrity": "sha1-m3ul/s9QUfHoWJL3E/zlxVBQKmo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/hex-grid/-/hex-grid-6.5.0.tgz", + "integrity": "sha512-Ln3tc2tgZT8etDOldgc6e741Smg1CsMKAz1/Mlel+MEL5Ynv2mhx3m0q4J9IB1F3a4MNjDeVvm8drAaf9SF33g==", "requires": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/intersect": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/intersect": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/interpolate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-5.1.5.tgz", - "integrity": "sha1-DxLwq3VtbdEK+ykMpuh3ve8BPqo=", - "requires": { - "@turf/bbox": "^5.1.5", - "@turf/centroid": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/hex-grid": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/point-grid": "^5.1.5", - "@turf/square-grid": "^5.1.5", - "@turf/triangle-grid": "^5.1.5" + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/interpolate/-/interpolate-6.5.0.tgz", + "integrity": "sha512-LSH5fMeiGyuDZ4WrDJNgh81d2DnNDUVJtuFryJFup8PV8jbs46lQGfI3r1DJ2p1IlEJIz3pmAZYeTfMMoeeohw==", + "requires": { + "@turf/bbox": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/hex-grid": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/point-grid": "^6.5.0", + "@turf/square-grid": "^6.5.0", + "@turf/triangle-grid": "^6.5.0" } }, "@turf/intersect": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-5.1.6.tgz", - "integrity": "sha512-KXyNv/GXdoGAOy03qZF53rgtXC2tNhF/4jLwTKiVRrBQH6kcEpipGStdJ+QkYIlarQPa8f7I9UlVAB19et4MfQ==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/intersect/-/intersect-6.5.0.tgz", + "integrity": "sha512-2legGJeKrfFkzntcd4GouPugoqPUjexPZnOvfez+3SfIMrHvulw8qV8u7pfVyn2Yqs53yoVCEjS5sEpvQ5YRQg==", "requires": { - "@turf/clean-coords": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/truncate": "^5.1.5", - "turf-jsts": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" } }, "@turf/invariant": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-5.1.5.tgz", - "integrity": "sha1-9Z9P76CSJLFdzhZR+QPIaNV6JOE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", + "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/isobands": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-5.1.5.tgz", - "integrity": "sha1-a0TO9YTVUaMTBBh68jtKFYLj8I0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/isobands/-/isobands-6.5.0.tgz", + "integrity": "sha512-4h6sjBPhRwMVuFaVBv70YB7eGz+iw0bhPRnp+8JBdX1UPJSXhoi/ZF2rACemRUr0HkdVB/a1r9gC32vn5IAEkw==", "requires": { - "@turf/area": "^5.1.5", - "@turf/bbox": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/explode": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/area": "^6.5.0", + "@turf/bbox": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "object-assign": "*" } }, "@turf/isolines": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-5.1.5.tgz", - "integrity": "sha1-irTn9Cuz38VGFOW/FVln9+VdLeE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/isolines/-/isolines-6.5.0.tgz", + "integrity": "sha512-6ElhiLCopxWlv4tPoxiCzASWt/jMRvmp6mRYrpzOm3EUl75OhHKa/Pu6Y9nWtCMmVC/RcWtiiweUocbPLZLm0A==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "object-assign": "*" } }, "@turf/kinks": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-5.1.5.tgz", - "integrity": "sha1-irtpYdm7AQchO63fLCwmQNAlaYA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/kinks/-/kinks-6.5.0.tgz", + "integrity": "sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/length": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/length/-/length-5.1.5.tgz", - "integrity": "sha1-86X4ZMK5lqi7RxeUU1ofrxLuvvs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/length/-/length-6.5.0.tgz", + "integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==", "requires": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/line-arc": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-5.1.5.tgz", - "integrity": "sha1-AHinRHg1oSrkFKIR+aZNEYYVDhU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-arc/-/line-arc-6.5.0.tgz", + "integrity": "sha512-I6c+V6mIyEwbtg9P9zSFF89T7QPe1DPTG3MJJ6Cm1MrAY0MdejwQKOpsvNl8LDU2ekHOlz2kHpPVR7VJsoMllA==", "requires": { - "@turf/circle": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/circle": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/line-chunk": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-5.1.5.tgz", - "integrity": "sha1-kQqFwFwG2dD5w4l3oF4IGNUIXEI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-chunk/-/line-chunk-6.5.0.tgz", + "integrity": "sha512-i1FGE6YJaaYa+IJesTfyRRQZP31QouS+wh/pa6O3CC0q4T7LtHigyBSYjrbjSLfn2EVPYGlPCMFEqNWCOkC6zg==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/length": "^5.1.5", - "@turf/line-slice-along": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/length": "^6.5.0", + "@turf/line-slice-along": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/line-intersect": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-5.1.5.tgz", - "integrity": "sha1-DikHGuQDKV5JFyO8SfXPrI0R3fM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-intersect/-/line-intersect-6.5.0.tgz", + "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/meta": "^5.1.5", - "geojson-rbush": "2.1.0" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "geojson-rbush": "3.x" } }, "@turf/line-offset": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-5.1.5.tgz", - "integrity": "sha1-KrWy8In4yRPiMdmUN4553KkLWh4=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-offset/-/line-offset-6.5.0.tgz", + "integrity": "sha512-CEXZbKgyz8r72qRvPchK0dxqsq8IQBdH275FE6o4MrBkzMcoZsfSjghtXzKaz9vvro+HfIXal0sTk2mqV1lQTw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/line-overlap": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-5.1.5.tgz", - "integrity": "sha1-lDxvh6A4bcQ9+sEdKz/5wRLNP2A=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-overlap/-/line-overlap-6.5.0.tgz", + "integrity": "sha512-xHOaWLd0hkaC/1OLcStCpfq55lPHpPNadZySDXYiYjEz5HXr1oKmtMYpn0wGizsLwrOixRdEp+j7bL8dPt4ojQ==", "requires": { - "@turf/boolean-point-on-line": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/nearest-point-on-line": "^5.1.5", - "geojson-rbush": "2.1.0" + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "deep-equal": "1.x", + "geojson-rbush": "3.x" } }, "@turf/line-segment": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-5.1.5.tgz", - "integrity": "sha1-Mgeq7lRqskw9jcPMY/kcdwuAE+U=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-segment/-/line-segment-6.5.0.tgz", + "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/line-slice": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-5.1.5.tgz", - "integrity": "sha1-Hs/OFGKjeFeXVM7fRGTN4mgp8rU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-slice/-/line-slice-6.5.0.tgz", + "integrity": "sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/nearest-point-on-line": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0" } }, "@turf/line-slice-along": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-5.1.5.tgz", - "integrity": "sha1-7drQoh70efKWihG9LdcomiEy6aU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-slice-along/-/line-slice-along-6.5.0.tgz", + "integrity": "sha512-KHJRU6KpHrAj+BTgTNqby6VCTnDzG6a1sJx/I3hNvqMBLvWVA2IrkR9L9DtsQsVY63IBwVdQDqiwCuZLDQh4Ng==", "requires": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/line-split": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-5.1.5.tgz", - "integrity": "sha1-Wy30w3YZty73JbUWPPmSbVVArLc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-split/-/line-split-6.5.0.tgz", + "integrity": "sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/line-segment": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/nearest-point-on-line": "^5.1.5", - "@turf/square": "^5.1.5", - "@turf/truncate": "^5.1.5", - "geojson-rbush": "2.1.0" + "@turf/bbox": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "@turf/square": "^6.5.0", + "@turf/truncate": "^6.5.0", + "geojson-rbush": "3.x" } }, "@turf/line-to-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-5.1.5.tgz", - "integrity": "sha1-ITz0Gmj4Ikd4ujnTGH3sPouBhlo=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/line-to-polygon/-/line-to-polygon-6.5.0.tgz", + "integrity": "sha512-qYBuRCJJL8Gx27OwCD1TMijM/9XjRgXH/m/TyuND4OXedBpIWlK5VbTIO2gJ8OCfznBBddpjiObLBrkuxTpN4Q==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/mask": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-5.1.5.tgz", - "integrity": "sha1-mrD+8aJyyY/j70kvn/thggayQtU=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/mask/-/mask-6.5.0.tgz", + "integrity": "sha512-RQha4aU8LpBrmrkH8CPaaoAfk0Egj5OuXtv6HuCQnHeGNOQt3TQVibTA3Sh4iduq4EPxnZfDjgsOeKtrCA19lg==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/union": "^5.1.5", - "rbush": "^2.0.1" - }, - "dependencies": { - "quickselect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/quickselect/-/quickselect-1.1.1.tgz", - "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" - }, - "rbush": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/rbush/-/rbush-2.0.2.tgz", - "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", - "requires": { - "quickselect": "^1.0.1" - } - } + "@turf/helpers": "^6.5.0", + "polygon-clipping": "^0.15.3" } }, "@turf/meta": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-5.1.6.tgz", - "integrity": "sha1-wgqGPt7Qhp+yhUje6Ik0G8y0akY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.5.0.tgz", + "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/midpoint": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-5.1.5.tgz", - "integrity": "sha1-4mH2srDqgSTM7/VSomLdRlydBfA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/midpoint/-/midpoint-6.5.0.tgz", + "integrity": "sha512-MyTzV44IwmVI6ec9fB2OgZ53JGNlgOpaYl9ArKoF49rXpL84F9rNATndbe0+MQIhdkw8IlzA6xVP4lZzfMNVCw==", + "requires": { + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" + } + }, + "@turf/moran-index": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/moran-index/-/moran-index-6.5.0.tgz", + "integrity": "sha512-ItsnhrU2XYtTtTudrM8so4afBCYWNaB0Mfy28NZwLjB5jWuAsvyV+YW+J88+neK/ougKMTawkmjQqodNJaBeLQ==", "requires": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/distance-weight": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/nearest-point": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-5.1.5.tgz", - "integrity": "sha1-EgUN5Bw5hEMiTHl43g9iE5ANNPs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point/-/nearest-point-6.5.0.tgz", + "integrity": "sha512-fguV09QxilZv/p94s8SMsXILIAMiaXI5PATq9d7YWijLxWUj6Q/r43kxyoi78Zmwwh1Zfqz9w+bCYUAxZ5+euA==", "requires": { - "@turf/clone": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/nearest-point-on-line": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-5.1.5.tgz", - "integrity": "sha1-VgauKX8VlHUkvqUaKp71HsG/nDY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz", + "integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==", "requires": { - "@turf/bearing": "^5.1.5", - "@turf/destination": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-intersect": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/bearing": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/nearest-point-to-line": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-5.1.6.tgz", - "integrity": "sha512-ZSvDIEiHhifn/vNwLXZI/E8xmEz5yBPqfUR7BVHRZrB1cP7jLhKZvkbidjG//uW8Fr1Ulc+PFOXczLspIcx/lw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/nearest-point-to-line/-/nearest-point-to-line-6.5.0.tgz", + "integrity": "sha512-PXV7cN0BVzUZdjj6oeb/ESnzXSfWmEMrsfZSDRgqyZ9ytdiIj/eRsnOXLR13LkTdXVOJYDBuf7xt1mLhM4p6+Q==", "requires": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x", - "@turf/meta": "6.x", - "@turf/point-to-line-distance": "^5.1.5", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/point-to-line-distance": "^6.5.0", "object-assign": "*" - }, - "dependencies": { - "@turf/helpers": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.4.tgz", - "integrity": "sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==" - }, - "@turf/invariant": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.1.2.tgz", - "integrity": "sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==", - "requires": { - "@turf/helpers": "6.x" - } - }, - "@turf/meta": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.0.2.tgz", - "integrity": "sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==", - "requires": { - "@turf/helpers": "6.x" - } - } } }, "@turf/planepoint": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-5.1.5.tgz", - "integrity": "sha1-GLvfAG91ne9eQsagBsn53oGyt/8=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/planepoint/-/planepoint-6.5.0.tgz", + "integrity": "sha512-R3AahA6DUvtFbka1kcJHqZ7DMHmPXDEQpbU5WaglNn7NaCQg9HB0XM0ZfqWcd5u92YXV+Gg8QhC8x5XojfcM4Q==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/point-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-5.1.5.tgz", - "integrity": "sha1-MFFBJI9Quv42zn5mukuX56sjaIc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-grid/-/point-grid-6.5.0.tgz", + "integrity": "sha512-Iq38lFokNNtQJnOj/RBKmyt6dlof0yhaHEDELaWHuECm1lIZLY3ZbVMwbs+nXkwTAHjKfS/OtMheUBkw+ee49w==", "requires": { - "@turf/boolean-within": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/boolean-within": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/point-on-feature": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-5.1.5.tgz", - "integrity": "sha1-MMfwMkMCd8ZBjZbSieRba/shP+c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-on-feature/-/point-on-feature-6.5.0.tgz", + "integrity": "sha512-bDpuIlvugJhfcF/0awAQ+QI6Om1Y1FFYE8Y/YdxGRongivix850dTeXCo0mDylFdWFPGDo7Mmh9Vo4VxNwW/TA==", "requires": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/center": "^5.1.5", - "@turf/explode": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/nearest-point": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/nearest-point": "^6.5.0" } }, "@turf/point-to-line-distance": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-5.1.6.tgz", - "integrity": "sha512-PE3hiTeeDEi4ZLPtI8XAzFYW9nHo1EVsZGm/4ZVV8jo39d3X1oLVHxY3e1PkCmWwRapXy4QLqvnTQ7nU4wspNw==", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/point-to-line-distance/-/point-to-line-distance-6.5.0.tgz", + "integrity": "sha512-opHVQ4vjUhNBly1bob6RWy+F+hsZDH9SA0UW36pIRzfpu27qipU18xup0XXEePfY6+wvhF6yL/WgCO2IbrLqEA==", "requires": { - "@turf/bearing": "6.x", - "@turf/distance": "6.x", - "@turf/helpers": "6.x", - "@turf/invariant": "6.x", - "@turf/meta": "6.x", - "@turf/projection": "6.x", - "@turf/rhumb-bearing": "6.x", - "@turf/rhumb-distance": "6.x" - }, - "dependencies": { - "@turf/bearing": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/bearing/-/bearing-6.0.1.tgz", - "integrity": "sha512-mXY1NozqV9EFfBTbUItujwfqfQF0G/Xe2fzvnZle90ekPEUfhi4Dgf5JswJTd96J9LiT8kcd6Jonp5khnx0wIg==", - "requires": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" - } - }, - "@turf/clone": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@turf/clone/-/clone-6.0.2.tgz", - "integrity": "sha512-UVpYPnW3wRj3bPncR6Z2PRbowBk+nEdVWgGewPxrKKLfvswtVtG9n/OIyvbU3E3ZOadBVxTH2uAMEMOz4800FA==", - "requires": { - "@turf/helpers": "6.x" - } - }, - "@turf/distance": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/distance/-/distance-6.0.1.tgz", - "integrity": "sha512-q7t7rWIWfkg7MP1Vt4uLjSEhe5rPfCO2JjpKmk7JC+QZKEQkuvHEqy3ejW1iC7Kw5ZcZNR3qdMGGz+6HnVwqvg==", - "requires": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" - } - }, - "@turf/helpers": { - "version": "6.1.4", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.1.4.tgz", - "integrity": "sha512-vJvrdOZy1ngC7r3MDA7zIGSoIgyrkWcGnNIEaqn/APmw+bVLF2gAW7HIsdTxd12s5wQMqEpqIQrmrbRRZ0xC7g==" - }, - "@turf/invariant": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.1.2.tgz", - "integrity": "sha512-WU08Ph8j0J2jVGlQCKChXoCtI50BB3yEH21V++V0T4cR1T27HKCxkehV2sYMwTierfMBgjwSwDIsxnR4/2mWXg==", - "requires": { - "@turf/helpers": "6.x" - } - }, - "@turf/meta": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/@turf/meta/-/meta-6.0.2.tgz", - "integrity": "sha512-VA7HJkx7qF1l3+GNGkDVn2oXy4+QoLP6LktXAaZKjuT1JI0YESat7quUkbCMy4zP9lAUuvS4YMslLyTtr919FA==", - "requires": { - "@turf/helpers": "6.x" - } - }, - "@turf/projection": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.0.1.tgz", - "integrity": "sha512-Y3RvGT6I53MjYKLG69e9sMk45wJXcLbrEO1t6P3WQQQGqA2gYhhMJyV41vE2Z2llrJpvs2dDx/tIeQzGd0HHMQ==", - "requires": { - "@turf/clone": "6.x", - "@turf/helpers": "6.x", - "@turf/meta": "6.x" - } - }, - "@turf/rhumb-bearing": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.0.1.tgz", - "integrity": "sha512-MVBra8OVfjM4+/N0B3o6cBIYg9p/uRKzA9uk05RfrzasEbUL1vdD23LkTooVL74Yw4UxL8BQD9hS5Re2COJFDA==", - "requires": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" - } - }, - "@turf/rhumb-distance": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.0.1.tgz", - "integrity": "sha512-3G45DQtQByzzfHFPcCyJdUZFwsd45zfZ7sAb1ddF7mhEj4G70+T2G3GKjInymqDNrbyh2gbG6wQiZSToC8Uf9g==", - "requires": { - "@turf/helpers": "6.x", - "@turf/invariant": "6.x" - } - } + "@turf/bearing": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/projection": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" } }, "@turf/points-within-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-5.1.5.tgz", - "integrity": "sha1-K4VaXfOq2lfC7oIKB1SrlJKKIzc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/points-within-polygon/-/points-within-polygon-6.5.0.tgz", + "integrity": "sha512-YyuheKqjliDsBDt3Ho73QVZk1VXX1+zIA2gwWvuz8bR1HXOkcuwk/1J76HuFMOQI3WK78wyAi+xbkx268PkQzQ==", + "requires": { + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" + } + }, + "@turf/polygon-smooth": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-smooth/-/polygon-smooth-6.5.0.tgz", + "integrity": "sha512-LO/X/5hfh/Rk4EfkDBpLlVwt3i6IXdtQccDT9rMjXEP32tRgy0VMFmdkNaXoGlSSKf/1mGqLl4y4wHd86DqKbg==", "requires": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/polygon-tangents": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-5.1.5.tgz", - "integrity": "sha1-K/AJkUcwJbF44lDcfLmuVAm71lI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-tangents/-/polygon-tangents-6.5.0.tgz", + "integrity": "sha512-sB4/IUqJMYRQH9jVBwqS/XDitkEfbyqRy+EH/cMRJURTg78eHunvJ708x5r6umXsbiUyQU4eqgPzEylWEQiunw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/boolean-within": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/nearest-point": "^6.5.0" } }, "@turf/polygon-to-line": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-5.1.5.tgz", - "integrity": "sha1-I7tEjYTcTGUZmaxhGjbZHFklA2o=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz", + "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/polygonize": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-5.1.5.tgz", - "integrity": "sha1-BJP6EYefOdELmtAs5qI+lC0IqjI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/polygonize/-/polygonize-6.5.0.tgz", + "integrity": "sha512-a/3GzHRaCyzg7tVYHo43QUChCspa99oK4yPqooVIwTC61npFzdrmnywMv0S+WZjHZwK37BrFJGFrZGf6ocmY5w==", "requires": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/envelope": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/envelope": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/projection": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-5.1.5.tgz", - "integrity": "sha1-JFF+7rLzaBa6n3EueubWo2jt91c=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/projection/-/projection-6.5.0.tgz", + "integrity": "sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg==", "requires": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/random": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/random/-/random-5.1.5.tgz", - "integrity": "sha1-sy78k0Vgroulfo67UfJBw5+6Lns=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/random/-/random-6.5.0.tgz", + "integrity": "sha512-8Q25gQ/XbA7HJAe+eXp4UhcXM9aOOJFaxZ02+XSNwMvY8gtWSCBLVqRcW4OhqilgZ8PeuQDWgBxeo+BIqqFWFQ==", + "requires": { + "@turf/helpers": "^6.5.0" + } + }, + "@turf/rectangle-grid": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rectangle-grid/-/rectangle-grid-6.5.0.tgz", + "integrity": "sha512-yQZ/1vbW68O2KsSB3OZYK+72aWz/Adnf7m2CMKcC+aq6TwjxZjAvlbCOsNUnMAuldRUVN1ph6RXMG4e9KEvKvg==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/boolean-intersects": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/rewind": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-5.1.5.tgz", - "integrity": "sha1-nqPbSmi3PB/R3RH1djGxQ8/vock=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rewind/-/rewind-6.5.0.tgz", + "integrity": "sha512-IoUAMcHWotBWYwSYuYypw/LlqZmO+wcBpn8ysrBNbazkFNkLf3btSDZMkKJO/bvOzl55imr/Xj4fi3DdsLsbzQ==", "requires": { - "@turf/boolean-clockwise": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/boolean-clockwise": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/rhumb-bearing": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-5.1.5.tgz", - "integrity": "sha1-rPalAkJ+uMSeGM2mrg7/qwxd3NI=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-bearing/-/rhumb-bearing-6.5.0.tgz", + "integrity": "sha512-jMyqiMRK4hzREjQmnLXmkJ+VTNTx1ii8vuqRwJPcTlKbNWfjDz/5JqJlb5NaFDcdMpftWovkW5GevfnuzHnOYA==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/rhumb-destination": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-5.1.5.tgz", - "integrity": "sha1-sbKuuSFUfyrAwamUtqEw+SRjx0I=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-destination/-/rhumb-destination-6.5.0.tgz", + "integrity": "sha512-RHNP1Oy+7xTTdRrTt375jOZeHceFbjwohPHlr9Hf68VdHHPMAWgAKqiX2YgSWDcvECVmiGaBKWus1Df+N7eE4Q==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/rhumb-distance": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-5.1.5.tgz", - "integrity": "sha1-GAaFdiX0IlOE2tQT5p85U4/192U=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/rhumb-distance/-/rhumb-distance-6.5.0.tgz", + "integrity": "sha512-oKp8KFE8E4huC2Z1a1KNcFwjVOqa99isxNOwfo4g3SUABQ6NezjKDDrnvC4yI5YZ3/huDjULLBvhed45xdCrzg==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0" } }, "@turf/sample": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-5.1.5.tgz", - "integrity": "sha1-6ctEikeJzFbuPeLdZ4HiNDQ1tBE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/sample/-/sample-6.5.0.tgz", + "integrity": "sha512-kSdCwY7el15xQjnXYW520heKUrHwRvnzx8ka4eYxX9NFeOxaFITLW2G7UtXb6LJK8mmPXI8Aexv23F2ERqzGFg==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/sector": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-5.1.5.tgz", - "integrity": "sha1-rCu5TBPt1gNPb9wrZwCBNdIPXgc=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/sector/-/sector-6.5.0.tgz", + "integrity": "sha512-cYUOkgCTWqa23SOJBqxoFAc/yGCUsPRdn/ovbRTn1zNTm/Spmk6hVB84LCKOgHqvSF25i0d2kWqpZDzLDdAPbw==", "requires": { - "@turf/circle": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/line-arc": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/circle": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/line-arc": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/shortest-path": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-5.1.5.tgz", - "integrity": "sha1-hUroCW9rw+EwD6ynfz6PZ9j5Nas=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/shortest-path/-/shortest-path-6.5.0.tgz", + "integrity": "sha512-4de5+G7+P4hgSoPwn+SO9QSi9HY5NEV/xRJ+cmoFVRwv2CDsuOPDheHKeuIAhKyeKDvPvPt04XYWbac4insJMg==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/bbox-polygon": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/clean-coords": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/transform-scale": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/clean-coords": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/transform-scale": "^6.5.0" } }, "@turf/simplify": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-5.1.5.tgz", - "integrity": "sha1-Csjyei60IYGD7dmZjDJ1q+QIuSY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/simplify/-/simplify-6.5.0.tgz", + "integrity": "sha512-USas3QqffPHUY184dwQdP8qsvcVH/PWBYdXY5am7YTBACaQOMAlf6AKJs9FT8jiO6fQpxfgxuEtwmox+pBtlOg==", "requires": { - "@turf/clean-coords": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/clean-coords": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/square": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/square/-/square-5.1.5.tgz", - "integrity": "sha1-qnsh5gM8ySUsOlvW89iNq9b+0YA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/square/-/square-6.5.0.tgz", + "integrity": "sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==", "requires": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0" } }, "@turf/square-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-5.1.5.tgz", - "integrity": "sha1-G9X3uesU8LYLwjH+/nNR0aMvGlE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/square-grid/-/square-grid-6.5.0.tgz", + "integrity": "sha512-mlR0ayUdA+L4c9h7p4k3pX6gPWHNGuZkt2c5II1TJRmhLkW2557d6b/Vjfd1z9OVaajb1HinIs1FMSAPXuuUrA==", "requires": { - "@turf/boolean-contains": "^5.1.5", - "@turf/boolean-overlap": "^5.1.5", - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/intersect": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/rectangle-grid": "^6.5.0" } }, "@turf/standard-deviational-ellipse": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-5.1.5.tgz", - "integrity": "sha1-hc0oO14ayljyG9ZkEuQUtW2FIyQ=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-6.5.0.tgz", + "integrity": "sha512-02CAlz8POvGPFK2BKK8uHGUk/LXb0MK459JVjKxLC2yJYieOBTqEbjP0qaWhiBhGzIxSMaqe8WxZ0KvqdnstHA==", "requires": { - "@turf/center-mean": "^5.1.5", - "@turf/ellipse": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/points-within-polygon": "^5.1.5" + "@turf/center-mean": "^6.5.0", + "@turf/ellipse": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/points-within-polygon": "^6.5.0" } }, "@turf/tag": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-5.1.5.tgz", - "integrity": "sha1-0e4aUIjs/UoUEQGcmCOczypJfSA=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tag/-/tag-6.5.0.tgz", + "integrity": "sha512-XwlBvrOV38CQsrNfrxvBaAPBQgXMljeU0DV8ExOyGM7/hvuGHJw3y8kKnQ4lmEQcmcrycjDQhP7JqoRv8vFssg==", "requires": { - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/tesselate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-5.1.5.tgz", - "integrity": "sha1-MqWU6cIaAEIKn5DSxD3z4RZgYc0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tesselate/-/tesselate-6.5.0.tgz", + "integrity": "sha512-M1HXuyZFCfEIIKkglh/r5L9H3c5QTEsnMBoZOFQiRnGPGmJWcaBissGb7mTFX2+DKE7FNWXh4TDnZlaLABB0dQ==", "requires": { - "@turf/helpers": "^5.1.5", + "@turf/helpers": "^6.5.0", "earcut": "^2.0.0" } }, "@turf/tin": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-5.1.5.tgz", - "integrity": "sha1-KCI+r8X76a6azKgc3P6l0UJMkX0=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/tin/-/tin-6.5.0.tgz", + "integrity": "sha512-YLYikRzKisfwj7+F+Tmyy/LE3d2H7D4kajajIfc9mlik2+esG7IolsX/+oUz1biguDYsG0DUA8kVYXDkobukfg==", "requires": { - "@turf/helpers": "^5.1.5" + "@turf/helpers": "^6.5.0" } }, "@turf/transform-rotate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-5.1.5.tgz", - "integrity": "sha1-0Jbt2eMA/jFQadVNjkWMQJIh7fs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-rotate/-/transform-rotate-6.5.0.tgz", + "integrity": "sha512-A2Ip1v4246ZmpssxpcL0hhiVBEf4L8lGnSPWTgSv5bWBEoya2fa/0SnFX9xJgP40rMP+ZzRaCN37vLHbv1Guag==", "requires": { - "@turf/centroid": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/rhumb-bearing": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5", - "@turf/rhumb-distance": "^5.1.5" + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" } }, "@turf/transform-scale": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-5.1.5.tgz", - "integrity": "sha1-cP064BhWz3uunxWtVhzf6PiQAbk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-scale/-/transform-scale-6.5.0.tgz", + "integrity": "sha512-VsATGXC9rYM8qTjbQJ/P7BswKWXHdnSJ35JlV4OsZyHBMxJQHftvmZJsFbOqVtQnIQIzf2OAly6rfzVV9QLr7g==", "requires": { - "@turf/bbox": "^5.1.5", - "@turf/center": "^5.1.5", - "@turf/centroid": "^5.1.5", - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/rhumb-bearing": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5", - "@turf/rhumb-distance": "^5.1.5" + "@turf/bbox": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0" } }, "@turf/transform-translate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-5.1.5.tgz", - "integrity": "sha1-Uwolf7Hccmja3Ks05nkB6yo97GM=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/transform-translate/-/transform-translate-6.5.0.tgz", + "integrity": "sha512-NABLw5VdtJt/9vSstChp93pc6oel4qXEos56RBMsPlYB8hzNTEKYtC146XJvyF4twJeeYS8RVe1u7KhoFwEM5w==", "requires": { - "@turf/clone": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", - "@turf/meta": "^5.1.5", - "@turf/rhumb-destination": "^5.1.5" + "@turf/clone": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0" } }, "@turf/triangle-grid": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-5.1.5.tgz", - "integrity": "sha1-ezZ2IQhVTBTyjK/zxIsc/ILI3IE=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/triangle-grid/-/triangle-grid-6.5.0.tgz", + "integrity": "sha512-2jToUSAS1R1htq4TyLQYPTIsoy6wg3e3BQXjm2rANzw4wPQCXGOxrur1Fy9RtzwqwljlC7DF4tg0OnWr8RjmfA==", "requires": { - "@turf/distance": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/intersect": "^5.1.5", - "@turf/invariant": "^5.1.5" + "@turf/distance": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/intersect": "^6.5.0" } }, "@turf/truncate": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-5.1.5.tgz", - "integrity": "sha1-nu37Oxi6gfLJjT6tCUMcyhiErYk=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/truncate/-/truncate-6.5.0.tgz", + "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5" + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0" } }, "@turf/turf": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-5.1.6.tgz", - "integrity": "sha1-wxIlkoh+0jS3VGi4qMRb+Ib7+PY=", - "requires": { - "@turf/along": "5.1.x", - "@turf/area": "5.1.x", - "@turf/bbox": "5.1.x", - "@turf/bbox-clip": "5.1.x", - "@turf/bbox-polygon": "5.1.x", - "@turf/bearing": "5.1.x", - "@turf/bezier-spline": "5.1.x", - "@turf/boolean-clockwise": "5.1.x", - "@turf/boolean-contains": "5.1.x", - "@turf/boolean-crosses": "5.1.x", - "@turf/boolean-disjoint": "5.1.x", - "@turf/boolean-equal": "5.1.x", - "@turf/boolean-overlap": "5.1.x", - "@turf/boolean-parallel": "5.1.x", - "@turf/boolean-point-in-polygon": "5.1.x", - "@turf/boolean-point-on-line": "5.1.x", - "@turf/boolean-within": "5.1.x", - "@turf/buffer": "5.1.x", - "@turf/center": "5.1.x", - "@turf/center-mean": "5.1.x", - "@turf/center-median": "5.1.x", - "@turf/center-of-mass": "5.1.x", - "@turf/centroid": "5.1.x", - "@turf/circle": "5.1.x", - "@turf/clean-coords": "5.1.x", - "@turf/clone": "5.1.x", - "@turf/clusters": "5.1.x", - "@turf/clusters-dbscan": "5.1.x", - "@turf/clusters-kmeans": "5.1.x", - "@turf/collect": "5.1.x", - "@turf/combine": "5.1.x", - "@turf/concave": "5.1.x", - "@turf/convex": "5.1.x", - "@turf/destination": "5.1.x", - "@turf/difference": "5.1.x", - "@turf/dissolve": "5.1.x", - "@turf/distance": "5.1.x", - "@turf/ellipse": "5.1.x", - "@turf/envelope": "5.1.x", - "@turf/explode": "5.1.x", - "@turf/flatten": "5.1.x", - "@turf/flip": "5.1.x", - "@turf/great-circle": "5.1.x", - "@turf/helpers": "5.1.x", - "@turf/hex-grid": "5.1.x", - "@turf/interpolate": "5.1.x", - "@turf/intersect": "5.1.x", - "@turf/invariant": "5.1.x", - "@turf/isobands": "5.1.x", - "@turf/isolines": "5.1.x", - "@turf/kinks": "5.1.x", - "@turf/length": "5.1.x", - "@turf/line-arc": "5.1.x", - "@turf/line-chunk": "5.1.x", - "@turf/line-intersect": "5.1.x", - "@turf/line-offset": "5.1.x", - "@turf/line-overlap": "5.1.x", - "@turf/line-segment": "5.1.x", - "@turf/line-slice": "5.1.x", - "@turf/line-slice-along": "5.1.x", - "@turf/line-split": "5.1.x", - "@turf/line-to-polygon": "5.1.x", - "@turf/mask": "5.1.x", - "@turf/meta": "5.1.x", - "@turf/midpoint": "5.1.x", - "@turf/nearest-point": "5.1.x", - "@turf/nearest-point-on-line": "5.1.x", - "@turf/nearest-point-to-line": "5.1.x", - "@turf/planepoint": "5.1.x", - "@turf/point-grid": "5.1.x", - "@turf/point-on-feature": "5.1.x", - "@turf/point-to-line-distance": "5.1.x", - "@turf/points-within-polygon": "5.1.x", - "@turf/polygon-tangents": "5.1.x", - "@turf/polygon-to-line": "5.1.x", - "@turf/polygonize": "5.1.x", - "@turf/projection": "5.1.x", - "@turf/random": "5.1.x", - "@turf/rewind": "5.1.x", - "@turf/rhumb-bearing": "5.1.x", - "@turf/rhumb-destination": "5.1.x", - "@turf/rhumb-distance": "5.1.x", - "@turf/sample": "5.1.x", - "@turf/sector": "5.1.x", - "@turf/shortest-path": "5.1.x", - "@turf/simplify": "5.1.x", - "@turf/square": "5.1.x", - "@turf/square-grid": "5.1.x", - "@turf/standard-deviational-ellipse": "5.1.x", - "@turf/tag": "5.1.x", - "@turf/tesselate": "5.1.x", - "@turf/tin": "5.1.x", - "@turf/transform-rotate": "5.1.x", - "@turf/transform-scale": "5.1.x", - "@turf/transform-translate": "5.1.x", - "@turf/triangle-grid": "5.1.x", - "@turf/truncate": "5.1.x", - "@turf/union": "5.1.x", - "@turf/unkink-polygon": "5.1.x", - "@turf/voronoi": "5.1.x" + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/turf/-/turf-6.5.0.tgz", + "integrity": "sha512-ipMCPnhu59bh92MNt8+pr1VZQhHVuTMHklciQURo54heoxRzt1neNYZOBR6jdL+hNsbDGAECMuIpAutX+a3Y+w==", + "requires": { + "@turf/along": "^6.5.0", + "@turf/angle": "^6.5.0", + "@turf/area": "^6.5.0", + "@turf/bbox": "^6.5.0", + "@turf/bbox-clip": "^6.5.0", + "@turf/bbox-polygon": "^6.5.0", + "@turf/bearing": "^6.5.0", + "@turf/bezier-spline": "^6.5.0", + "@turf/boolean-clockwise": "^6.5.0", + "@turf/boolean-contains": "^6.5.0", + "@turf/boolean-crosses": "^6.5.0", + "@turf/boolean-disjoint": "^6.5.0", + "@turf/boolean-equal": "^6.5.0", + "@turf/boolean-intersects": "^6.5.0", + "@turf/boolean-overlap": "^6.5.0", + "@turf/boolean-parallel": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/boolean-point-on-line": "^6.5.0", + "@turf/boolean-within": "^6.5.0", + "@turf/buffer": "^6.5.0", + "@turf/center": "^6.5.0", + "@turf/center-mean": "^6.5.0", + "@turf/center-median": "^6.5.0", + "@turf/center-of-mass": "^6.5.0", + "@turf/centroid": "^6.5.0", + "@turf/circle": "^6.5.0", + "@turf/clean-coords": "^6.5.0", + "@turf/clone": "^6.5.0", + "@turf/clusters": "^6.5.0", + "@turf/clusters-dbscan": "^6.5.0", + "@turf/clusters-kmeans": "^6.5.0", + "@turf/collect": "^6.5.0", + "@turf/combine": "^6.5.0", + "@turf/concave": "^6.5.0", + "@turf/convex": "^6.5.0", + "@turf/destination": "^6.5.0", + "@turf/difference": "^6.5.0", + "@turf/dissolve": "^6.5.0", + "@turf/distance": "^6.5.0", + "@turf/distance-weight": "^6.5.0", + "@turf/ellipse": "^6.5.0", + "@turf/envelope": "^6.5.0", + "@turf/explode": "^6.5.0", + "@turf/flatten": "^6.5.0", + "@turf/flip": "^6.5.0", + "@turf/great-circle": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/hex-grid": "^6.5.0", + "@turf/interpolate": "^6.5.0", + "@turf/intersect": "^6.5.0", + "@turf/invariant": "^6.5.0", + "@turf/isobands": "^6.5.0", + "@turf/isolines": "^6.5.0", + "@turf/kinks": "^6.5.0", + "@turf/length": "^6.5.0", + "@turf/line-arc": "^6.5.0", + "@turf/line-chunk": "^6.5.0", + "@turf/line-intersect": "^6.5.0", + "@turf/line-offset": "^6.5.0", + "@turf/line-overlap": "^6.5.0", + "@turf/line-segment": "^6.5.0", + "@turf/line-slice": "^6.5.0", + "@turf/line-slice-along": "^6.5.0", + "@turf/line-split": "^6.5.0", + "@turf/line-to-polygon": "^6.5.0", + "@turf/mask": "^6.5.0", + "@turf/meta": "^6.5.0", + "@turf/midpoint": "^6.5.0", + "@turf/moran-index": "^6.5.0", + "@turf/nearest-point": "^6.5.0", + "@turf/nearest-point-on-line": "^6.5.0", + "@turf/nearest-point-to-line": "^6.5.0", + "@turf/planepoint": "^6.5.0", + "@turf/point-grid": "^6.5.0", + "@turf/point-on-feature": "^6.5.0", + "@turf/point-to-line-distance": "^6.5.0", + "@turf/points-within-polygon": "^6.5.0", + "@turf/polygon-smooth": "^6.5.0", + "@turf/polygon-tangents": "^6.5.0", + "@turf/polygon-to-line": "^6.5.0", + "@turf/polygonize": "^6.5.0", + "@turf/projection": "^6.5.0", + "@turf/random": "^6.5.0", + "@turf/rewind": "^6.5.0", + "@turf/rhumb-bearing": "^6.5.0", + "@turf/rhumb-destination": "^6.5.0", + "@turf/rhumb-distance": "^6.5.0", + "@turf/sample": "^6.5.0", + "@turf/sector": "^6.5.0", + "@turf/shortest-path": "^6.5.0", + "@turf/simplify": "^6.5.0", + "@turf/square": "^6.5.0", + "@turf/square-grid": "^6.5.0", + "@turf/standard-deviational-ellipse": "^6.5.0", + "@turf/tag": "^6.5.0", + "@turf/tesselate": "^6.5.0", + "@turf/tin": "^6.5.0", + "@turf/transform-rotate": "^6.5.0", + "@turf/transform-scale": "^6.5.0", + "@turf/transform-translate": "^6.5.0", + "@turf/triangle-grid": "^6.5.0", + "@turf/truncate": "^6.5.0", + "@turf/union": "^6.5.0", + "@turf/unkink-polygon": "^6.5.0", + "@turf/voronoi": "^6.5.0" } }, "@turf/union": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/union/-/union-5.1.5.tgz", - "integrity": "sha1-UyhbYJQEf8WNlqrA6pCGXsNNRUs=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/union/-/union-6.5.0.tgz", + "integrity": "sha512-igYWCwP/f0RFHIlC2c0SKDuM/ObBaqSljI3IdV/x71805QbIvY/BYGcJdyNcgEA6cylIGl/0VSlIbpJHZ9ldhw==", "requires": { - "@turf/helpers": "^5.1.5", - "turf-jsts": "*" + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", + "polygon-clipping": "^0.15.3" } }, "@turf/unkink-polygon": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-5.1.5.tgz", - "integrity": "sha1-ewGEfFD7V0riV54Z5Ey6hSbSE8M=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/unkink-polygon/-/unkink-polygon-6.5.0.tgz", + "integrity": "sha512-8QswkzC0UqKmN1DT6HpA9upfa1HdAA5n6bbuzHy8NJOX8oVizVAqfEPY0wqqTgboDjmBR4yyImsdPGUl3gZ8JQ==", "requires": { - "@turf/area": "^5.1.5", - "@turf/boolean-point-in-polygon": "^5.1.5", - "@turf/helpers": "^5.1.5", - "@turf/meta": "^5.1.5", + "@turf/area": "^6.5.0", + "@turf/boolean-point-in-polygon": "^6.5.0", + "@turf/helpers": "^6.5.0", + "@turf/meta": "^6.5.0", "rbush": "^2.0.1" }, "dependencies": { @@ -23279,12 +23233,12 @@ } }, "@turf/voronoi": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-5.1.5.tgz", - "integrity": "sha1-6FbpQG3MLyXWbdyJhYTifC6/ymY=", + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@turf/voronoi/-/voronoi-6.5.0.tgz", + "integrity": "sha512-C/xUsywYX+7h1UyNqnydHXiun4UPjK88VDghtoRypR9cLlb7qozkiLRphQxxsCM0KxyxpVPHBVQXdAL3+Yurow==", "requires": { - "@turf/helpers": "^5.1.5", - "@turf/invariant": "^5.1.5", + "@turf/helpers": "^6.5.0", + "@turf/invariant": "^6.5.0", "d3-voronoi": "1.1.2" } }, @@ -25514,12 +25468,12 @@ } }, "concaveman": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.0.tgz", - "integrity": "sha512-OcqechF2/kubbffomKqjGEkb0ndlYhEbmyg/fxIGqdfYp5AZjD2Kl5hc97Hh3ngEuHU2314Z4KDbxL7qXGWrQQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/concaveman/-/concaveman-1.2.1.tgz", + "integrity": "sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==", "requires": { - "point-in-polygon": "^1.0.1", - "rbush": "^3.0.0", + "point-in-polygon": "^1.1.0", + "rbush": "^3.0.1", "robust-predicates": "^2.0.4", "tinyqueue": "^2.0.3" } @@ -28386,13 +28340,15 @@ "integrity": "sha1-q0g48SatxeFvj5TmVd74IPkRnbw=" }, "geojson-rbush": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-2.1.0.tgz", - "integrity": "sha1-O9c745H8ELCuaT2bis6iquC4Oo0=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/geojson-rbush/-/geojson-rbush-3.2.0.tgz", + "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", "requires": { - "@turf/helpers": "*", - "@turf/meta": "*", - "rbush": "*" + "@turf/bbox": "*", + "@turf/helpers": "6.x", + "@turf/meta": "6.x", + "@types/geojson": "7946.0.8", + "rbush": "^3.0.1" } }, "get-caller-file": { @@ -28400,11 +28356,6 @@ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" }, - "get-closest": { - "version": "0.0.4", - "resolved": "https://registry.npmjs.org/get-closest/-/get-closest-0.0.4.tgz", - "integrity": "sha1-JprHdtHmAiqg/Vht1wjop9Miaa8=" - }, "get-intrinsic": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.0.2.tgz", @@ -30371,11 +30322,6 @@ "type-check": "~0.3.2" } }, - "lineclip": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/lineclip/-/lineclip-1.1.5.tgz", - "integrity": "sha1-K/JgZ9lDVP6r+R5CdoI221YW/RM=" - }, "lines-and-columns": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", @@ -30391,39 +30337,6 @@ "3d-tiles-renderer": "^0.2.6", "proj4": "^2.7.0", "three": "^0.125.2" - }, - "dependencies": { - "@turf/circle": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/circle/-/circle-6.5.0.tgz", - "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==", - "requires": { - "@turf/destination": "^6.5.0", - "@turf/helpers": "^6.5.0" - } - }, - "@turf/destination": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/destination/-/destination-6.5.0.tgz", - "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==", - "requires": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - } - }, - "@turf/helpers": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/helpers/-/helpers-6.5.0.tgz", - "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==" - }, - "@turf/invariant": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/@turf/invariant/-/invariant-6.5.0.tgz", - "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", - "requires": { - "@turf/helpers": "^6.5.0" - } - } } }, "load-json-file": { @@ -31954,9 +31867,17 @@ } }, "point-in-polygon": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.0.1.tgz", - "integrity": "sha1-1Ztk6P7kHElFiqyCtWcYxZV7Kvc=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/point-in-polygon/-/point-in-polygon-1.1.0.tgz", + "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==" + }, + "polygon-clipping": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/polygon-clipping/-/polygon-clipping-0.15.3.tgz", + "integrity": "sha512-ho0Xx5DLkgxRx/+n4O74XyJ67DcyN3Tu9bGYKsnTukGAW6ssnuak6Mwcyb1wHy9MZc9xsUWqIoiazkZB5weECg==", + "requires": { + "splaytree": "^3.1.0" + } }, "portfinder": { "version": "1.0.28", @@ -34790,6 +34711,11 @@ "resolved": "https://registry.npmjs.org/spex/-/spex-3.2.0.tgz", "integrity": "sha512-9srjJM7NaymrpwMHvSmpDeIK5GoRMX/Tq0E8aOlDPS54dDnDUIp30DrP9SphMPEETDLzEM9+4qo+KipmbtPecg==" }, + "splaytree": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/splaytree/-/splaytree-3.1.0.tgz", + "integrity": "sha512-gvUGR7xnOy0fLKTCxDeUZYgU/I1Tdf8M/lM1Qrf8L2TIOR5ipZjGk02uYcdv0o2x7WjVRgpm3iS2clLyuVAt0Q==" + }, "split-string": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", diff --git a/package.json b/package.json index c11f9f73..48325170 100644 --- a/package.json +++ b/package.json @@ -47,7 +47,7 @@ "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.5.0", "@testing-library/user-event": "^7.2.1", - "@turf/turf": "^5.1.6", + "@turf/turf": "^6.5.0", "@typescript-eslint/eslint-plugin": "^2.10.0", "@typescript-eslint/parser": "^2.10.0", "babel-eslint": "10.1.0", diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index aabdd22d..4aff5271 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -443,7 +443,14 @@ var L_ = { }, setStyle(layer, newStyle) { try { - layer.setStyle(newStyle) + if (layer._layers) { + for (let lid in layer._layers) { + const lidl = layer._layers[lid] + if (lidl.isSublayer === true) + lidl.setStyle(lidl.options.style) + else lidl.setStyle(newStyle) + } + } else layer.setStyle(newStyle) } catch (err) {} }, highlight(layer) { @@ -472,6 +479,13 @@ var L_ = { if (layer._icon) layer._icon.style.filter = `drop-shadow(${color} 2px 0px 0px) drop-shadow(${color} -2px 0px 0px) drop-shadow(${color} 0px 2px 0px) drop-shadow(${color} 0px -2px 0px)` } + + if (layer._layers) { + for (let lid in layer._layers) { + const lidl = layer._layers[lid] + if (lidl.isSublayer === true) lidl.setStyle(lidl.options.style) + } + } }, addArrowToMap: function ( layerId, @@ -791,6 +805,8 @@ var L_ = { this.layersStyles[key].hasOwnProperty('fillColor') ) { this.layersGroup[key].eachLayer((layer) => { + console.log('RESUME CODING HERE') + if (true) return var fillColor = this.layersStyles[key].fillColor var opacity = layer.options.opacity var fillOpacity = layer.options.fillOpacity @@ -802,7 +818,7 @@ var L_ = { opacity: opacity, fillOpacity: fillOpacity, fillColor: layer.options.fillColor || fillColor, - weight: weight, + weight: parseInt(weight), }) } catch (err) { if (layer._icon) layer._icon.style.filter = '' diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 8d275b05..d36f4238 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -1,5 +1,6 @@ import $ from 'jquery' import * as d3 from 'd3' +import { ellipse } from '@turf/turf' import F_ from '../Formulae_/Formulae_' import L_ from '../Layers_/Layers_' import { captureVector } from '../Layers_/LayerCapturer' @@ -541,6 +542,12 @@ async function makeLayer(layerObj, evenIfOff) { //Default is onclick show full properties and onhover show 1st property Map_.onEachFeatureDefault = onEachFeatureDefault function onEachFeatureDefault(feature, layer) { + if (layer._layers) { + for (let lid in layer._layers) { + const lidl = layer._layers[lid] + if (lidl.isSublayer === true) lidl.setStyle(lidl.options.style) + } + } var pv = getLayersChosenNamePropVal(feature, layer) layer['useKeyAsName'] = pv.name @@ -904,24 +911,25 @@ async function makeLayer(layerObj, evenIfOff) { let layer = null const pixelBuffer = featureStyle.weight || 0 - //check for a bearing + // Bearing Attachment let yaw = 0 - if ( - layerObj.hasOwnProperty('variables') && - layerObj.variables.hasOwnProperty('markerBearing') - ) { - const markerBearing = - layerObj.variables.markerBearing.split(':') - const unit = markerBearing[0] - const bearingProp = markerBearing[1] - - yaw = parseFloat( - F_.getIn(feature.properties, bearingProp) - ) - if (unit === 'rad') { - yaw = yaw * (180 / Math.PI) + const bearingVar = F_.getIn( + layerObj, + 'variables.markerAttachments.bearing' + ) + if (bearingVar) { + const unit = bearingVar.angleUnit || 'deg' + const bearingProp = bearingVar.angleProp || false + + if (bearingProp !== false) { + yaw = parseFloat( + F_.getIn(feature.properties, bearingProp) + ) + if (unit === 'rad') { + yaw = yaw * (180 / Math.PI) + } + layerObj.shape = 'directional_circle' } - layerObj.shape = 'directional_circle' } switch (layerObj.shape) { @@ -943,8 +951,8 @@ async function makeLayer(layerObj, evenIfOff) { pixelBuffer + 6 )})"fill="${ - layerObj.variables - ?.markerBearingColor || + layerObj.variables?.markerAttachments + ?.bearing?.color || featureStyle.color }" stroke-width="1"/>`, ` { + let col = layerObj.style.color + let opa = String(layerObj.style.opacity) + let wei = String(layerObj.style.weight) + let fiC = layerObj.style.fillColor + let fiO = String(layerObj.style.fillOpacity) + let leafletLayerObject = { + style: function (feature) { + if (feature.properties.hasOwnProperty('style')) { + let className = layerObj.style.className + let layerName = layerObj.style.layerName + layerObj.style = JSON.parse( + JSON.stringify(feature.properties.style) + ) + + layerObj.style.className = className + layerObj.style.layerName = layerName + } else { + // Priority to prop, prop.color, then style color. + var finalCol = + col.toLowerCase().substring(0, 4) === 'prop' + ? F_.parseColor(feature.properties[col.substring(5)]) || + '#FFF' + : feature.style && feature.style.stroke != null + ? feature.style.stroke + : col + var finalOpa = + opa.toLowerCase().substring(0, 4) === 'prop' + ? feature.properties[opa.substring(5)] || '1' + : feature.style && feature.style.opacity != null + ? feature.style.opacity + : opa + var finalWei = + wei.toLowerCase().substring(0, 4) === 'prop' + ? feature.properties[wei.substring(5)] || '1' + : feature.style && feature.style.weight != null + ? feature.style.weight + : wei + if (!isNaN(parseInt(wei))) finalWei = parseInt(wei) + var finalFiC = + fiC.toLowerCase().substring(0, 4) === 'prop' + ? F_.parseColor(feature.properties[fiC.substring(5)]) || + '#000' + : feature.style && feature.style.fill != null + ? feature.style.fill + : fiC + var finalFiO = + fiO.toLowerCase().substring(0, 4) === 'prop' + ? feature.properties[fiO.substring(5)] || '1' + : feature.style && feature.style.fillopacity != null + ? feature.style.fillopacity + : fiO + + // Check for radius property if radius=1 (default/prop:radius) + layerObj.style.radius = + layerObj.radius == 1 + ? parseFloat(feature.properties['radius']) + : layerObj.radius + + var noPointerEventsClass = + feature.style && feature.style.nointeraction + ? ' noPointerEvents' + : '' + + layerObj.style.color = finalCol + layerObj.style.opacity = finalOpa + layerObj.style.weight = finalWei + layerObj.style.fillColor = finalFiC + layerObj.style.fillOpacity = finalFiO + } + layerObj.style.className = + layerObj.style.className + noPointerEventsClass + layerObj.style.metadata = geojson.metadata || {} + return layerObj.style + }, + onEachFeature: (function (layerObjName) { + return onEachFeatureDefault + })(layerObj.name), + } + + let hasSublayers = false + + if (layerObj.hasOwnProperty('radius')) { + let markerIcon = null + if ( + layerObj.hasOwnProperty('variables') && + layerObj.variables.hasOwnProperty('markerIcon') + ) { + let markerIconOptions = F_.clone(layerObj.variables.markerIcon) + if ( + markerIconOptions.iconUrl && + !F_.isUrlAbsolute(markerIconOptions.iconUrl) + ) + markerIconOptions.iconUrl = + L_.missionPath + markerIconOptions.iconUrl + if ( + markerIconOptions.shadowUrl && + !F_.isUrlAbsolute(markerIconOptions.shadowUrl) + ) + markerIconOptions.shadowUrl = + L_.missionPath + markerIconOptions.shadowUrl + + markerIcon = new L.icon(markerIconOptions) + } + + leafletLayerObject.pointToLayer = function (feature, latlong) { + const featureStyle = leafletLayerObject.style(feature) + let svg = '' + let layer = null + const pixelBuffer = featureStyle.weight || 0 + + // Bearing Attachment + let yaw = 0 + const bearingVar = F_.getIn( + layerObj, + 'variables.markerAttachments.bearing' + ) + if (bearingVar) { + const unit = bearingVar.angleUnit || 'deg' + const bearingProp = bearingVar.angleProp || false + + if (bearingProp !== false) { + yaw = parseFloat(F_.getIn(feature.properties, bearingProp)) + if (unit === 'rad') { + yaw = yaw * (180 / Math.PI) + } + layerObj.shape = 'directional_circle' + } + } + + switch (layerObj.shape) { + case 'circle': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'directional_circle': + svg = [ + `
    `, + ``, + ``, + ``, + ``, + `
    `, + ].join('\n') + break + case 'triangle': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'triangle-flipped': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'square': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'diamond': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'pentagon': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'hexagon': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'star': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'plus': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'pin': + svg = [ + ``, + ``, + ``, + ].join('\n') + break + case 'none': + default: + layer = L.circleMarker( + latlong, + leafletLayerObject.style + ).setRadius(layerObj.radius) + break + } + + if (markerIcon) { + const markerOptions = { + icon: markerIcon, + } + if (yaw != null && yaw !== 0) markerOptions.rotationAngle = yaw + if (markerIcon.options?.iconAnchor?.length >= 2) + markerOptions.rotationOrigin = `${markerIcon.options.iconAnchor[0]}px ${markerIcon.options.iconAnchor[1]}px` + layer = L.marker(latlong, markerOptions) + } else if (layer == null && svg != null) { + layer = L.marker(latlong, { + icon: L.divIcon({ + className: `leafletMarkerShape leafletMarkerShape_${layerObj.name + .replace(/\s/g, '') + .toLowerCase()}`, + iconSize: [ + (featureStyle.radius + pixelBuffer) * 2, + (featureStyle.radius + pixelBuffer) * 2, + ], + html: svg, + }), + }) + } + + if (layer == null) return + + layer.options.layerName = layerObj.name + return layer + } + } + + const layer = L.geoJson(geojson, leafletLayerObject) + + Object.keys(layer._layers).forEach((idx) => { + let l = layer._layers[idx] + const savedUseKeyAsName = l.useKeyAsName + const savedOptions = l.options + if (l.feature?.properties?.arrow === true) { + const c = l.feature.geometry.coordinates + const start = new L.LatLng(c[0][1], c[0][0]) + const end = new L.LatLng(c[1][1], c[1][0]) + + layer._layers[idx] = L_.addArrowToMap( + null, + start, + end, + l.feature?.properties?.style, + l.feature + ) + layer._layers[idx].useKeyAsName = savedUseKeyAsName + layer._layers[idx].options = savedOptions + Object.keys(layer._layers[idx]._layers).forEach((idx2) => { + layer._layers[idx]._layers[idx2].options.layerName = + savedOptions.layerName + layer._layers[idx]._layers[idx2].feature = l.feature + layer._layers[idx]._layers[idx2].useKeyAsName = + savedUseKeyAsName + l.feature.style = l.feature.style || {} + l.feature.style.noclick = true + onEachFeatureDefault( + l.feature, + layer._layers[idx]._layers[idx2] + ) + }) + } else if (l.feature?.properties?.annotation === true) { + layer._layers[idx] = L_.createAnnotation( + l.feature, + 'LayerAnnotation', + layer._layers[idx].options.layerName, + idx + ) + } + }) + + return layer +} + +export const constructSublayers = (geojson, layerObj) => { + const uncertaintyVar = F_.getIn( + layerObj, + 'variables.markerAttachments.uncertainty' + ) + const leafletLayerObjectUncertaintyEllipse = { + pointToLayer: (feature, latlong) => { + // Marker Attachment Uncertainty + let uncertaintyEllipse + let uncertaintyAngle = parseFloat( + F_.getIn(feature.properties, uncertaintyVar.angleProp, 0) + ) + if (uncertaintyVar.angleUnit === 'rad') + uncertaintyAngle = uncertaintyAngle * (180 / Math.PI) + uncertaintyEllipse = ellipse( + [latlong.lng, latlong.lat], + F_.getIn( + feature.properties, + uncertaintyVar.xAxisProp, + Math.random() + 0.5 + ), + F_.getIn( + feature.properties, + uncertaintyVar.yAxisProp, + Math.random() + 1 + ), + { + units: uncertaintyVar.axisUnits || 'meters', + steps: 32, + angle: uncertaintyAngle, + } + ) + uncertaintyEllipse = L.geoJSON(uncertaintyEllipse, { + style: { + fillOpacity: 0.25, + fillColor: uncertaintyVar.color || 'white', + color: 'black', + weight: 1, + opacity: 0.8, + className: 'noPointerEventsImportant', + }, + }) + return uncertaintyEllipse + }, + } + + const sublayers = { + uncertainty_ellipses: uncertaintyVar + ? { + on: + uncertaintyVar.initialVisibility != null + ? uncertaintyVar.initialVisibility + : true, + layer: L.geoJson( + geojson, + leafletLayerObjectUncertaintyEllipse + ), + } + : false, + } + + const sublayerArray = [] + + for (let s in sublayers) { + if (sublayers[s] !== false) { + sublayers[s].sublayerType = s + sublayerArray.push(sublayers[s]) + } + } + + if (sublayerArray.length > 0) return sublayers + return false +} diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 4aff5271..b3520643 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -29,6 +29,8 @@ var L_ = { layersNamed: {}, //was namedLayersData //Name -> leaflet layer layersGroup: {}, //was mainLayerGroup + //Name -> sublayer group + layersGroupSublayers: {}, //Index -> layer name layersOrdered: [], //was mainLayerOrder //Index -> layerName (an unchanging layersOrdered) @@ -189,10 +191,33 @@ var L_ = { $('.drawToolContextMenuHeaderClose').click() } catch (err) {} L_.Map_.map.removeLayer(L_.layersGroup[s.name]) + if (L_.layersGroupSublayers[s.name]) { + for (let sub in L_.layersGroupSublayers[s.name]) { + L_.Map_.rmNotNull( + L_.layersGroupSublayers[s.name][sub].layer + ) + } + } } L_.Globe_.litho.removeLayer(s.name) } else { if (L_.layersGroup[s.name]) { + if (L_.layersGroupSublayers[s.name]) { + for (let sub in L_.layersGroupSublayers[s.name]) { + if (L_.layersGroupSublayers[s.name][sub].on) { + L_.Map_.map.addLayer( + L_.layersGroupSublayers[s.name][sub].layer + ) + L_.layersGroupSublayers[s.name][ + sub + ].layer.setZIndex( + L_.layersOrdered.length + + 1 - + L_.layersOrdered.indexOf(s.name) + ) + } + } + } L_.Map_.map.addLayer(L_.layersGroup[s.name]) L_.layersGroup[s.name].setZIndex( L_.layersOrdered.length + @@ -302,6 +327,24 @@ var L_ = { L_.Map_.orderedBringToFront() } }, + toggleSublayer: function (layerName, sublayerName) { + const sublayers = L_.layersGroupSublayers[layerName] || {} + const sublayer = sublayers[sublayerName] + if (sublayer) { + if (sublayer.on === true) { + L_.Map_.rmNotNull(sublayer.layer) + sublayer.on = false + } else { + L_.Map_.map.addLayer(sublayer.layer) + sublayer.layer.setZIndex( + L_.layersOrdered.length + + 1 - + L_.layersOrdered.indexOf(layerName) + ) + sublayer.on = true + } + } + }, disableAllBut: function (name, skipDisabling) { if (L_.layersNamed.hasOwnProperty(name)) { var l @@ -330,7 +373,9 @@ var L_ = { var map = map_ if (map == null) { if (L_.Map_ == null) { - console.warn('Null addVisible') + console.warn( + "Can't addVisible layers before Map_ is initialized." + ) return } map = L_.Map_.map @@ -354,6 +399,23 @@ var L_ = { // Add Map layers if (L_.layersGroup[L_.layersData[i].name]) { try { + if (L_.layersGroupSublayers[L_.layersData[i].name]) { + for (let s in L_.layersGroupSublayers[ + L_.layersData[i].name + ]) { + if ( + L_.layersGroupSublayers[ + L_.layersData[i].name + ][s].on + ) { + map.addLayer( + L_.layersGroupSublayers[ + L_.layersData[i].name + ][s].layer + ) + } + } + } map.addLayer(L_.layersGroup[L_.layersData[i].name]) } catch (e) { console.log(e) @@ -443,14 +505,7 @@ var L_ = { }, setStyle(layer, newStyle) { try { - if (layer._layers) { - for (let lid in layer._layers) { - const lidl = layer._layers[lid] - if (lidl.isSublayer === true) - lidl.setStyle(lidl.options.style) - else lidl.setStyle(newStyle) - } - } else layer.setStyle(newStyle) + layer.setStyle(newStyle) } catch (err) {} }, highlight(layer) { @@ -479,13 +534,6 @@ var L_ = { if (layer._icon) layer._icon.style.filter = `drop-shadow(${color} 2px 0px 0px) drop-shadow(${color} -2px 0px 0px) drop-shadow(${color} 0px 2px 0px) drop-shadow(${color} 0px -2px 0px)` } - - if (layer._layers) { - for (let lid in layer._layers) { - const lidl = layer._layers[lid] - if (lidl.isSublayer === true) lidl.setStyle(lidl.options.style) - } - } }, addArrowToMap: function ( layerId, @@ -740,6 +788,7 @@ var L_ = { return popup }, setLayerOpacity: function (name, newOpacity) { + newOpacity = parseFloat(newOpacity) if (L_.Globe_) L_.Globe_.litho.setLayerOpacity(name, newOpacity) var l = L_.layersGroup[name] if (l) { @@ -747,6 +796,11 @@ var L_ = { l.setOpacity(newOpacity) } catch (error) { l.setStyle({ opacity: newOpacity, fillOpacity: newOpacity }) + $( + `.leafletMarkerShape_${name + .replace(/\s/g, '') + .toLowerCase()}` + ).css({ opacity: newOpacity }) } try { l.options.fillOpacity = newOpacity @@ -805,12 +859,10 @@ var L_ = { this.layersStyles[key].hasOwnProperty('fillColor') ) { this.layersGroup[key].eachLayer((layer) => { - console.log('RESUME CODING HERE') - if (true) return - var fillColor = this.layersStyles[key].fillColor - var opacity = layer.options.opacity - var fillOpacity = layer.options.fillOpacity - var weight = layer.options.weight + let fillColor = this.layersStyles[key].fillColor + let opacity = layer.options.opacity + let fillOpacity = layer.options.fillOpacity + let weight = layer.options.weight if (!layer._isAnnotation) L_.layersGroup[key].resetStyle(layer) try { diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index d36f4238..e20e6c58 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -1,9 +1,12 @@ import $ from 'jquery' import * as d3 from 'd3' -import { ellipse } from '@turf/turf' import F_ from '../Formulae_/Formulae_' import L_ from '../Layers_/Layers_' import { captureVector } from '../Layers_/LayerCapturer' +import { + constructVectorLayer, + constructSublayers, +} from '../Layers_/LayerConstructors' import Viewer_ from '../Viewer_/Viewer_' import Globe_ from '../Globe_/Globe_' import ToolController_ from '../ToolController_/ToolController_' @@ -329,19 +332,46 @@ let Map_ = { }, //Redraws all layers, starting with the bottom one orderedBringToFront: function () { - var hasIndex = [] - for (var i = L_.layersOrdered.length - 1; i >= 0; i--) { + let hasIndex = [] + for (let i = L_.layersOrdered.length - 1; i >= 0; i--) { if (Map_.hasLayer(L_.layersOrdered[i])) { if ( L_.layersNamed[L_.layersOrdered[i]] && - L_.layersNamed[L_.layersOrdered[i]].type == 'vector' + L_.layersNamed[L_.layersOrdered[i]].type === 'vector' ) { + if (L_.layersGroupSublayers[L_.layersOrdered[i]]) { + for (let s in L_.layersGroupSublayers[ + L_.layersOrdered[i] + ]) { + Map_.rmNotNull( + L_.layersGroupSublayers[L_.layersOrdered[i]][s] + .layer + ) + } + } Map_.map.removeLayer(L_.layersGroup[L_.layersOrdered[i]]) hasIndex.push(i) } } } - for (var i = 0; i < hasIndex.length; i++) { + for (let i = 0; i < hasIndex.length; i++) { + if (L_.layersGroupSublayers[L_.layersOrdered[hasIndex[i]]]) { + for (let s in L_.layersGroupSublayers[ + L_.layersOrdered[hasIndex[i]] + ]) { + if ( + L_.layersGroupSublayers[L_.layersOrdered[hasIndex[i]]][ + s + ].on + ) + Map_.map.addLayer( + L_.layersGroupSublayers[ + L_.layersOrdered[hasIndex[i]] + ][s].layer + ) + } + } + Map_.map.addLayer(L_.layersGroup[L_.layersOrdered[hasIndex[i]]]) } @@ -542,12 +572,6 @@ async function makeLayer(layerObj, evenIfOff) { //Default is onclick show full properties and onhover show 1st property Map_.onEachFeatureDefault = onEachFeatureDefault function onEachFeatureDefault(feature, layer) { - if (layer._layers) { - for (let lid in layer._layers) { - const lidl = layer._layers[lid] - if (lidl.isSublayer === true) lidl.setStyle(lidl.options.style) - } - } var pv = getLayersChosenNamePropVal(feature, layer) layer['useKeyAsName'] = pv.name @@ -789,344 +813,14 @@ async function makeLayer(layerObj, evenIfOff) { layerObj.style.opacity = L_.opacityArray[layerObj.name] //layerObj.style.fillOpacity = L_.opacityArray[layerObj.name] - var col = layerObj.style.color - var opa = String(layerObj.style.opacity) - var wei = String(layerObj.style.weight) - var fiC = layerObj.style.fillColor - var fiO = String(layerObj.style.fillOpacity) - var leafletLayerObject = { - style: function (feature) { - if (feature.properties.hasOwnProperty('style')) { - let className = layerObj.style.className - let layerName = layerObj.style.layerName - layerObj.style = JSON.parse( - JSON.stringify(feature.properties.style) - ) - - layerObj.style.className = className - layerObj.style.layerName = layerName - } else { - // Priority to prop, prop.color, then style color. - var finalCol = - col.toLowerCase().substring(0, 4) === 'prop' - ? F_.parseColor( - feature.properties[col.substring(5)] - ) || '#FFF' - : feature.style && - feature.style.stroke != null - ? feature.style.stroke - : col - var finalOpa = - opa.toLowerCase().substring(0, 4) === 'prop' - ? feature.properties[opa.substring(5)] || - '1' - : feature.style && - feature.style.opacity != null - ? feature.style.opacity - : opa - var finalWei = - wei.toLowerCase().substring(0, 4) === 'prop' - ? feature.properties[wei.substring(5)] || - '1' - : feature.style && - feature.style.weight != null - ? feature.style.weight - : wei - if (!isNaN(parseInt(wei))) finalWei = parseInt(wei) - var finalFiC = - fiC.toLowerCase().substring(0, 4) === 'prop' - ? F_.parseColor( - feature.properties[fiC.substring(5)] - ) || '#000' - : feature.style && - feature.style.fill != null - ? feature.style.fill - : fiC - var finalFiO = - fiO.toLowerCase().substring(0, 4) === 'prop' - ? feature.properties[fiO.substring(5)] || - '1' - : feature.style && - feature.style.fillopacity != null - ? feature.style.fillopacity - : fiO - - // Check for radius property if radius=1 (default/prop:radius) - layerObj.style.radius = - layerObj.radius == 1 - ? parseFloat(feature.properties['radius']) - : layerObj.radius - - var noPointerEventsClass = - feature.style && feature.style.nointeraction - ? ' noPointerEvents' - : '' - - layerObj.style.color = finalCol - layerObj.style.opacity = finalOpa - layerObj.style.weight = finalWei - layerObj.style.fillColor = finalFiC - layerObj.style.fillOpacity = finalFiO - } - layerObj.style.className = - layerObj.style.className + noPointerEventsClass - layerObj.style.metadata = data.metadata || {} - return layerObj.style - }, - onEachFeature: (function (layerObjName) { - return onEachFeatureDefault - })(layerObj.name), - } - if (layerObj.hasOwnProperty('radius')) { - let markerIcon = null - if ( - layerObj.hasOwnProperty('variables') && - layerObj.variables.hasOwnProperty('markerIcon') - ) { - let markerIconOptions = F_.clone( - layerObj.variables.markerIcon - ) - if ( - markerIconOptions.iconUrl && - !F_.isUrlAbsolute(markerIconOptions.iconUrl) - ) - markerIconOptions.iconUrl = - L_.missionPath + markerIconOptions.iconUrl - if ( - markerIconOptions.shadowUrl && - !F_.isUrlAbsolute(markerIconOptions.shadowUrl) - ) - markerIconOptions.shadowUrl = - L_.missionPath + markerIconOptions.shadowUrl - - markerIcon = new L.icon(markerIconOptions) - } - - leafletLayerObject.pointToLayer = function ( - feature, - latlong - ) { - const featureStyle = leafletLayerObject.style(feature) - let svg = '' - let layer = null - const pixelBuffer = featureStyle.weight || 0 - - // Bearing Attachment - let yaw = 0 - const bearingVar = F_.getIn( - layerObj, - 'variables.markerAttachments.bearing' - ) - if (bearingVar) { - const unit = bearingVar.angleUnit || 'deg' - const bearingProp = bearingVar.angleProp || false - - if (bearingProp !== false) { - yaw = parseFloat( - F_.getIn(feature.properties, bearingProp) - ) - if (unit === 'rad') { - yaw = yaw * (180 / Math.PI) - } - layerObj.shape = 'directional_circle' - } - } - - switch (layerObj.shape) { - case 'circle': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'directional_circle': - svg = [ - `
    `, - ``, - ``, - ``, - ``, - `
    `, - ].join('\n') - break - case 'triangle': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'triangle-flipped': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'square': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'diamond': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'pentagon': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'hexagon': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'star': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'plus': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'pin': - svg = [ - ``, - ``, - ``, - ].join('\n') - break - case 'none': - default: - layer = L.circleMarker( - latlong, - leafletLayerObject.style - ).setRadius(layerObj.radius) - break - } - - if (markerIcon) { - const markerOptions = { - icon: markerIcon, - } - if (yaw != null && yaw !== 0) - markerOptions.rotationAngle = yaw - if (markerIcon.options?.iconAnchor?.length >= 2) - markerOptions.rotationOrigin = `${markerIcon.options.iconAnchor[0]}px ${markerIcon.options.iconAnchor[1]}px` - layer = L.marker(latlong, markerOptions) - } else if (layer == null && svg != null) { - layer = L.marker(latlong, { - icon: L.divIcon({ - className: 'leafletMarkerShape', - iconSize: [ - (featureStyle.radius + pixelBuffer) * 2, - (featureStyle.radius + pixelBuffer) * 2, - ], - html: svg, - }), - }) - } - - if (layer == null) return - - // Marker Attachment Uncertainty - const uncertaintyVar = F_.getIn( - layerObj, - 'variables.markerAttachments.uncertainty' - ) - let uncertaintyEllipse - if (uncertaintyVar) { - let uncertaintyAngle = parseFloat( - F_.getIn( - feature.properties, - uncertaintyVar.angleProp, - 0 - ) - ) - if (uncertaintyVar.angleUnit === 'rad') - uncertaintyAngle = - uncertaintyAngle * (180 / Math.PI) - uncertaintyEllipse = ellipse( - [latlong.lng, latlong.lat], - F_.getIn( - feature.properties, - uncertaintyVar.xAxisProp, - Math.random() + 0.5 - ), - F_.getIn( - feature.properties, - uncertaintyVar.yAxisProp, - Math.random() + 1 - ), - { - units: uncertaintyVar.axisUnits || 'meters', - steps: 32, - angle: uncertaintyAngle, - } - ) - uncertaintyEllipse = L.geoJSON(uncertaintyEllipse, { - style: { - fillOpacity: 0.25, - fillColor: - uncertaintyVar.color || - featureStyle.fillColor, - color: featureStyle.color, - weight: 1, - opacity: 0.8, - className: 'noPointerEventsImportant', - }, - }) - uncertaintyEllipse.isSublayer = true - } - - if (uncertaintyEllipse) { - const groupedLayer = L.featureGroup([ - layer, - uncertaintyEllipse, - ]) - groupedLayer._latlng = layer._latlng - groupedLayer.options.layerName = layerObj.name - return groupedLayer - } - - layer.options.layerName = layerObj.name - return layer - } - } + L_.layersGroupSublayers[layerObj.name] = constructSublayers( + data, + layerObj + ) L_.layersGroup[layerObj.name] = constructVectorLayer( data, - leafletLayerObject + layerObj, + onEachFeatureDefault ) d3.selectAll( @@ -1140,57 +834,6 @@ async function makeLayer(layerObj, evenIfOff) { }) } - /** - * Takes regular geojson and makes it fancy with annotations and arrows when applicable - * @return leaflet geojson - */ - function constructVectorLayer(geojson, leafletLayerObject) { - const layer = L.geoJson(geojson, leafletLayerObject) - - Object.keys(layer._layers).forEach((idx) => { - let l = layer._layers[idx] - const savedUseKeyAsName = l.useKeyAsName - const savedOptions = l.options - if (l.feature?.properties?.arrow === true) { - const c = l.feature.geometry.coordinates - const start = new L.LatLng(c[0][1], c[0][0]) - const end = new L.LatLng(c[1][1], c[1][0]) - - layer._layers[idx] = L_.addArrowToMap( - null, - start, - end, - l.feature?.properties?.style, - l.feature - ) - layer._layers[idx].useKeyAsName = savedUseKeyAsName - layer._layers[idx].options = savedOptions - Object.keys(layer._layers[idx]._layers).forEach((idx2) => { - layer._layers[idx]._layers[idx2].options.layerName = - savedOptions.layerName - layer._layers[idx]._layers[idx2].feature = l.feature - layer._layers[idx]._layers[idx2].useKeyAsName = - savedUseKeyAsName - l.feature.style = l.feature.style || {} - l.feature.style.noclick = true - Map_.onEachFeatureDefault( - l.feature, - layer._layers[idx]._layers[idx2] - ) - }) - } else if (l.feature?.properties?.annotation === true) { - layer._layers[idx] = L_.createAnnotation( - l.feature, - 'LayerAnnotation', - layer._layers[idx].options.layerName, - idx - ) - } - }) - - return layer - } - function makeTileLayer() { var layerUrl = layerObj.url if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl @@ -1262,14 +905,7 @@ async function makeLayer(layerObj, evenIfOff) { if (L_.layersGroup[l]) { var highlight = L_.layersGroup[l].highlight if (highlight) { - const layer = L_.layersGroup[l] - if (layer._layers) { - for (let lid in layer._layers) { - const lidl = layer._layers[lid] - if (lidl.isSublayer !== true) - layer.resetFeatureStyle(highlight) - } - } else L_.layersGroup[l].resetFeatureStyle(highlight) + L_.layersGroup[l].resetFeatureStyle(highlight) } L_.layersGroup[l].highlight = null } diff --git a/src/essence/Tools/Kinds/Kinds.js b/src/essence/Tools/Kinds/Kinds.js index da53cf8a..57b00581 100644 --- a/src/essence/Tools/Kinds/Kinds.js +++ b/src/essence/Tools/Kinds/Kinds.js @@ -17,21 +17,62 @@ var Kinds = { ) { if (typeof kind !== 'string') return + const layerVar = L_.layersNamed[layer.options.layerName].variables + switch (kind.toLowerCase()) { case 'info': useInfo(true) break case 'waypoint': + let roverSettings = { + image: F_.getIn( + layerVar, + 'markerAttachments.rover.image', + 'public/images/rovers/PerseveranceTopDown.png' + ), + widthMeters: F_.getIn( + layerVar, + 'markerAttachments.rover.widthMeters', + 2.6924 + ), + widthPixels: F_.getIn( + layerVar, + 'markerAttachments.rover.widthPixels', + 420 + ), + heightPixels: F_.getIn( + layerVar, + 'markerAttachments.rover.heightPixels', + 600 + ), + angleProp: F_.getIn( + layerVar, + 'markerAttachments.rover.angleProp', + 'yaw_rad' + ), + angleUnit: F_.getIn( + layerVar, + 'markerAttachments.rover.angleUnit', + 'rad' + ), + } //Make rover image curiosity Map_.rmNotNull(Map_.tempOverlayImage) //256 x 338, 256 is 2.8m - var wm = 2.6924 - var w = 420 - var h = 600 - var lngM = F_.metersToDegrees(wm) / 2 - var latM = lngM * (h / w) - var center = [layer._latlng.lng, layer._latlng.lat] - var angle = -layer.feature.properties.yaw_rad || 0 + let wm = parseFloat(roverSettings.widthMeters) + let w = parseFloat(roverSettings.widthPixels) + let h = parseFloat(roverSettings.heightPixels) + let lngM = F_.metersToDegrees(wm) / 2 + let latM = lngM * (h / w) + let center = [layer._latlng.lng, layer._latlng.lat] + let angle = -F_.getIn( + layer.feature.properties, + roverSettings.angleProp, + 0 + ) + if (roverSettings.angleProp === 'deg') + angle = angle * (Math.PI / 180) + var topLeft = F_.rotatePoint( { y: layer._latlng.lat + latM, @@ -74,7 +115,7 @@ var Kinds = { try { Map_.tempOverlayImage = L.imageTransform( - 'public/images/rovers/PerseveranceTopDown.png', + roverSettings.image, anchors, { opacity: 1, clip: anchors } ) diff --git a/src/essence/Tools/Layers/LayersTool.css b/src/essence/Tools/Layers/LayersTool.css index d2112f2b..4ec150ee 100644 --- a/src/essence/Tools/Layers/LayersTool.css +++ b/src/essence/Tools/Layers/LayersTool.css @@ -182,7 +182,6 @@ margin: 0; } #layersTool .settings ul > li { - height: 24px; line-height: 24px; } #layersTool .settings ul > li > div { diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index c27c7385..26271b49 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -201,6 +201,17 @@ function interfaceWithMMGIS() { '
    Opacity
    ', '', '
    ', + L_.layersGroupSublayers[node[i].name] ? Object.keys(L_.layersGroupSublayers[node[i].name]).map((function(i){return function(s) { + return [ + '
    ', + `
    ${F_.prettifyName(s)}
    `, + '
    ', + `
    `, + '
    ', + '
    ', + '
    ', + ].join('\n') + }})(i)).join('\n') : null, '', '', '', @@ -461,6 +472,25 @@ function interfaceWithMMGIS() { } }) + //Makes sublayers clickable on and off + $('#layersToolList > li > .settings .sublayer .checkbox').on( + 'click', + async function () { + const layerName = $(this).attr('layername') + const sublayerName = $(this).attr('sublayername') + await L_.toggleSublayer(layerName, sublayerName) + + if ( + L_.layersGroupSublayers[layerName] && + L_.layersGroupSublayers[layerName][sublayerName] + ) { + if (L_.layersGroupSublayers[layerName][sublayerName].on) + $(this).addClass('on') + else $(this).removeClass('on') + } + } + ) + //Collapse header $('.layersToolHeader').on('click', function () { LayersTool.toggleHeader($(this).attr('id')) From 7bcc5efa4040562e1b14bd5d09a6ddc54a542c0a Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 2 Dec 2021 14:12:59 -0800 Subject: [PATCH 48/85] #115 MeasureTool - Color mode, 3D distance, Globe lines --- .../gdal2customtiles/gdal2customtiles.py | 3 +- src/essence/Tools/Measure/MeasureTool.css | 4 +- src/essence/Tools/Measure/MeasureTool.js | 314 +++++++++++++----- 3 files changed, 240 insertions(+), 81 deletions(-) diff --git a/auxiliary/gdal2customtiles/gdal2customtiles.py b/auxiliary/gdal2customtiles/gdal2customtiles.py index b41e4ebc..532a22c4 100644 --- a/auxiliary/gdal2customtiles/gdal2customtiles.py +++ b/auxiliary/gdal2customtiles/gdal2customtiles.py @@ -54,6 +54,8 @@ def binary(num): # 1bto4b # 1bto4b + + def getTilePxBounds(self, tx, ty, tz, ds): querysize = self.tilesize @@ -1988,7 +1990,6 @@ def generate_base_tiles(self, tz): data3s += struct.pack('B', data3[indx]) data4s += struct.pack('B', data4[indx]) indx += 1 - dstile.GetRasterBand(1).WriteRaster( wx, wy, wxsize + 1, wysize + 1, data1s, buf_type=gdal.GDT_Byte) dstile.GetRasterBand(2).WriteRaster( diff --git a/src/essence/Tools/Measure/MeasureTool.css b/src/essence/Tools/Measure/MeasureTool.css index 37a85372..5147e435 100644 --- a/src/essence/Tools/Measure/MeasureTool.css +++ b/src/essence/Tools/Measure/MeasureTool.css @@ -44,11 +44,11 @@ .MeasureTool #measureMode > select, .MeasureTool #measureSamples > select, .MeasureTool #measureUnit > select { - width: 100px; + width: 135px; } .MeasureTool #measureLeft { - width: 180px; + width: 220px; height: 100%; display: flex; flex-flow: column; diff --git a/src/essence/Tools/Measure/MeasureTool.js b/src/essence/Tools/Measure/MeasureTool.js index 4475616a..76a8bc3f 100644 --- a/src/essence/Tools/Measure/MeasureTool.js +++ b/src/essence/Tools/Measure/MeasureTool.js @@ -32,6 +32,7 @@ let profileData = [] let elevPoints = [] let profileDivId = 'measureToolProfile' let rAm = 100 //roundAmount +let globeMouseDownXY = {} const Measure = () => { const [profileData, setProfileData] = useState([]) @@ -46,8 +47,14 @@ const Measure = () => { .on('mouseout', MeasureTool.mouseOutMap) const globeCont = Globe_.litho.getContainer() - globeCont.addEventListener('click', MeasureTool.clickGlobe, false) + globeCont.addEventListener( + 'mousedown', + MeasureTool.mouseDownGlobe, + false + ) + globeCont.addEventListener('mouseup', MeasureTool.clickGlobe, false) globeCont.addEventListener('mousemove', MeasureTool.moveGlobe, false) + globeCont.addEventListener('mouseout', MeasureTool.mouseOutMap, false) Viewer_.imageViewerMap.addHandler( 'canvas-click', @@ -87,6 +94,9 @@ const Measure = () => { > +
    @@ -134,16 +144,30 @@ const Measure = () => { { label: 'Profile', data: profileData, - borderColor: ['rgba(255, 0, 47, 1)'], segment: { backgroundColor: (ctx) => { const i = MeasureTool.datasetMapping[ ctx.p0DataIndex - ] - return i % 2 === 0 - ? 'rgba(255, 0, 47, 0.2)' - : 'rgba(255, 0, 47, 0.1)' + ] - 1 + if (mode === 'continuous_color') { + return MeasureTool.getColor(i, 0.1) + } else + return i % 2 === 0 + ? 'rgba(255, 0, 47, 0.2)' + : 'rgba(255, 0, 47, 0.1)' + }, + borderColor: (ctx) => { + const i = + MeasureTool.datasetMapping[ + ctx.p0DataIndex + ] - 1 + if (mode === 'continuous_color') + return MeasureTool.getColor(i) + else + return i % 2 + ? 'rgba(255, 80, 112, 1)' + : 'rgba(255, 0, 47, 1)' }, }, spanGaps: true, @@ -166,6 +190,39 @@ const Measure = () => { legend: { display: false, }, + tooltip: { + intersect: false, + mode: 'nearest', + titleAlign: 'left', + bodyAlign: 'right', + callbacks: { + title: (item) => + `${MeasureTool.lastData[ + item[0].parsed.x + ][2].toFixed(2)}${ + distDisplayUnit === 'meters' + ? 'm' + : 'km' + } From Start (2D)\n${MeasureTool.lastData[ + item[0].parsed.x + ][3].toFixed(2)}${ + distDisplayUnit === 'meters' + ? 'm' + : 'km' + } (3D)`, + label: (item) => + `Elevation: ${item.parsed.y.toFixed( + 3 + )}m`, + labelColor: () => { + return { + backgroundColor: 'yellow', + borderColor: 'black', + borderRadius: 6, + } + }, + }, + }, }, layout: { padding: { @@ -188,24 +245,10 @@ const Measure = () => { }, }, }, - tooltips: { - intersect: false, - mode: 'nearest', - titleAlign: 'center', - bodyAlign: 'center', - footerAlign: 'center', - callbacks: { - label: (item) => `${item.yLabel}m`, - title: (item) => - distDisplayUnit === 'meters' - ? `${item[0].xLabel}m from start` - : `${item[0].xLabel}km from start,`, - }, - }, onHover: (e, el, el2) => { if (el[0]) { const d = MeasureTool.lastData[el[0].index] - MeasureTool.makeFocusPoint(d[1], d[0], d[3]) + MeasureTool.makeFocusPoint(d[1], d[0], d[4]) } else if (refLine && e.x != null) { const chartArea = refLine.current.chartArea const bestIndex = Math.round( @@ -220,7 +263,7 @@ const Measure = () => { bestIndex < MeasureTool.lastData.length ) { const d = MeasureTool.lastData[bestIndex] - MeasureTool.makeFocusPoint(d[1], d[0], d[3]) + MeasureTool.makeFocusPoint(d[1], d[0], d[4]) } } }, @@ -268,6 +311,29 @@ let MeasureTool = { data: [], lastData: [], mapFocusMarker: null, + colorRamp: [ + '#e60049', + '#0bb4ff', + '#50e991', + '#e6d800', + '#9b19f5', + '#ffa300', + '#dc0ab4', + '#b3d4ff', + '#00bfa0', + '#f0cccc', + //Same as above but with +25% lightness (mostly) + '#ff6696', + '#8adcff', + '#bff7d7', + '#fff566', + '#d093fb', + '#ffd080', + '#f86ddf', + '#ffffff', + '#3dffdf', + '#cc5200', + ], init: function () {}, make: function () { Map_.rmNotNull(measureToolLayer) @@ -292,8 +358,18 @@ let MeasureTool = { .off('mouseout', MeasureTool.mouseOutMap) const globeCont = Globe_.litho.getContainer() - globeCont.removeEventListener('click', MeasureTool.clickGlobe, false) + globeCont.removeEventListener( + 'mousedown', + MeasureTool.mouseDownGlobe, + false + ) + globeCont.removeEventListener('mouseup', MeasureTool.clickGlobe, false) globeCont.removeEventListener('mousemove', MeasureTool.moveGlobe, false) + globeCont.removeEventListener( + 'mouseout', + MeasureTool.mouseOutMap, + false + ) Viewer_.imageViewerMap.removeHandler( 'canvas-click', @@ -308,6 +384,7 @@ let MeasureTool = { Globe_.litho.removeLayer('_measure') Globe_.litho.removeLayer('_measurePoint') + Globe_.litho.removeLayer('_measurePolyline') CursorInfo.hide() @@ -335,12 +412,17 @@ let MeasureTool = { makeProfile() }, moveMap: function (e) { - if (mode === 'continuous' || clickedLatLngs.length === 1) + if ( + mode === 'continuous' || + mode === 'continuous_color' || + clickedLatLngs.length === 1 + ) makeGhostLine(e.latlng.lng, e.latlng.lat) }, mouseOutMap: function (e) { if (distLineToMouse != null) { Map_.map.removeLayer(distLineToMouse) + Globe_.litho.removeLayer('_measure') distLineToMouse = null } if (distMousePoint != null) { @@ -349,7 +431,16 @@ let MeasureTool = { } CursorInfo.hide() }, + mouseDownGlobe: function (e) { + globeMouseDownXY = { x: e.x, y: e.y } + }, clickGlobe: function (e) { + // Make sure the click isn't a drag + if ( + Math.abs(globeMouseDownXY.x - e.x) > 3 || + Math.abs(globeMouseDownXY.y - e.y) > 3 + ) + return if (mode === 'segment' && clickedLatLngs.length >= 2) { clickedLatLngs = [] profileData = [] @@ -371,7 +462,9 @@ let MeasureTool = { }, moveGlobe: function (e) { if ( - (mode === 'continuous' || clickedLatLngs.length === 1) && + (mode === 'continuous' || + mode === 'continuous_color' || + clickedLatLngs.length === 1) && Globe_.litho.mouse.lng != null && Globe_.litho.mouse.lat != null ) { @@ -427,7 +520,7 @@ let MeasureTool = { type: 'Feature', geometry: { type: 'Point', - coordinates: [[lng, lat, 3 + z]], + coordinates: [[lng, lat, 2 + z]], }, }, ], @@ -460,6 +553,7 @@ let MeasureTool = { makeMeasureToolLayer() Globe_.litho.removeLayer('_measure') Globe_.litho.removeLayer('_measurePoint') + Globe_.litho.removeLayer('_measurePolyline') MeasureTool.clearFocusPoint() @@ -478,6 +572,7 @@ let MeasureTool = { Map_.rmNotNull(measureToolLayer) Globe_.litho.removeLayer('_measure') Globe_.litho.removeLayer('_measurePoint') + Globe_.litho.removeLayer('_measurePolyline') d3.select('#' + profileDivId) .selectAll('*') @@ -510,11 +605,24 @@ let MeasureTool = { }, download: function (e) { F_.downloadArrayAsCSV( - ['longitude', 'latitude', 'distance', 'elevation'], + ['longitude', 'latitude', 'distance', 'distance_3d', 'elevation'], MeasureTool.lastData, 'profiledata' ) }, + getColor: function (idx, alpha) { + if (alpha != null) { + const rgb = F_.hexToRGB( + MeasureTool.colorRamp[idx % MeasureTool.colorRamp.length] || + '#FFFFFF' + ) || { r: 255, g: 255, b: 255 } + return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${alpha})` + } else + return ( + MeasureTool.colorRamp[idx % MeasureTool.colorRamp.length] || + '#FFFFFF' + ) + }, } function makeMeasureToolLayer() { @@ -595,15 +703,26 @@ function makeMeasureToolLayer() { new L.LatLng(clickedLatLngs[i].x, clickedLatLngs[i].y) ) } - pointsAndPathArr.unshift( - new L.Polyline( - MeasureTool.data.map(function (v) { - return new L.LatLng(v[1], v[0]) - }), - { color: '#ff002f', weight: 3 } + const segments = [] + for (let i = 1; i < polylinePoints.length; i++) { + segments.push( + new L.Polyline([polylinePoints[i - 1], polylinePoints[i]], { + color: + mode === 'continuous_color' + ? MeasureTool.getColor(i - 1) + : mode === 'continuous' + ? i % 2 + ? '#ff002f' + : '#ff5070' + : '#ff002f', + weight: 3, + }) ) - ) + } + pointsAndPathArr.unshift(...segments) measureToolLayer = L.featureGroup(pointsAndPathArr).addTo(Map_.map) + + makeGlobePolyline(polylinePoints) } function makeProfile() { var numOfPts = clickedLatLngs.length @@ -682,9 +801,12 @@ function makeProfile() { let currentDataset = 0 let currentDatasetStart = 0 let lastDistance = 0 + let lastDistance3d = 0 let currentDatasetDistanceStart = 0 + for (let i = 0; i < MeasureTool.lastData.length; i++) { let distance = 0 + let distance3d = 0 if (MeasureTool.datasetMapping[i] - 1 !== currentDataset) { currentDataset = MeasureTool.datasetMapping[i] - 1 currentDatasetStart = i @@ -698,13 +820,39 @@ function makeProfile() { MeasureTool.lastData[currentDatasetStart][0], MeasureTool.lastData[currentDatasetStart][1] ) + currentDatasetDistanceStart - if (F_.dam) - distance = - F_.metersToDegrees(distance) + - currentDatasetDistanceStart + // Pythag theorem + // Calculates the hypotenuse between each sample point + // 2d distance is one leg and elevation difference is the second leg + // 4 in lastData[i - 1] because we're shifting the distances to 2 and 3 + distance3d = Math.sqrt( + Math.pow( + F_.lngLatDistBetween( + MeasureTool.lastData[i][0], + MeasureTool.lastData[i][1], + MeasureTool.lastData[i - 1][0], + MeasureTool.lastData[i - 1][1] + ), + 2 + ) + + Math.pow( + Math.abs( + MeasureTool.lastData[i][2] - + MeasureTool.lastData[i - 1][4] + ), + 2 + ) + ) + distance3d += lastDistance3d + + lastDistance3d = distance3d + if (F_.dam) { + distance = F_.metersToDegrees(distance) + distance3d = F_.metersToDegrees(distance3d) + } } lastDistance = distance MeasureTool.lastData[i].splice(2, 0, distance) + MeasureTool.lastData[i].splice(3, 0, distance3d) } profileData = [] @@ -803,7 +951,6 @@ function makeGhostLine(lng, lat) { var i1 = clickedLatLngs.length - 1 var endDC = clickedLatLngs[i1] - //console.log(clickedLatLngs[i1].x + " " + clickedLatLngs[i1].y + " " + e.latlng.lat + " " + e.latlng.lng); var distAzimuth = Math.round( F_.bearingBetweenTwoLatLngs( @@ -902,6 +1049,7 @@ function makeGhostLine(lng, lat) { ], }, }, + null, 1 ) //distMousePoint.bindTooltip("" + roundedTotalDist + "m\n (+" + roundedDist + "m) " + distAzimuth + "°", @@ -937,48 +1085,10 @@ function makeGhostLine(lng, lat) { } } -function getCorrectedProfileData() { - var pts = elevPoints - var overheadLength = 0 - var segmentLengths = [] //summed - - //calculate total and segment lengths - for (var i = 0; i < pts.length; i++) { - segmentLengths[i] = overheadLength - overheadLength += latLongDistBetween( - pts[i][0].y, - pts[i][0].x, - pts[i][1].y, - pts[i][1].x - ) - } - segmentLengths[segmentLengths.length] = overheadLength - - var newProfileData = [] - var distStep = overheadLength / steps - var cur, scaleLat, scaleLng - for (var i = 0; i < lineSteps; i++) { - cur = i * distStep - for (var j = 0; j < segmentLengths.length - 1; j++) { - if (cur >= segmentLengths[j] && cur < segmentLengths[j + 1]) { - scaleLat = d3 - .scaleLinear() - .domain([segmentLengths[j], segmentLengths[j + 1]]) - .range([pts[j][0].x, pts[j][1].x]) - scaleLng = d3 - .scaleLinear() - .domain([segmentLengths[j], segmentLengths[j + 1]]) - .range([pts[j][0].y, pts[j][1].y]) - //newProfileData.push({"x": scaleLat(cur), "y": scaleLng(cur), "value": }); - } - } - } -} - function totalDistToIndex(l) { var totalDistance = 0 for (var i = 1; i < l; i++) { - //Sum up segement distance + //Sum up segment distance if (F_.dam) { totalDistance += F_.distanceFormula( clickedLatLngs[i].y, @@ -1000,6 +1110,54 @@ function totalDistToIndex(l) { return totalDistance } +function makeGlobePolyline(polylinePoints) { + const features = [] + for (let i = 1; i < polylinePoints.length; i++) { + features.push({ + type: 'Feature', + properties: { + color: + mode === 'continuous_color' + ? MeasureTool.getColor(i - 1) + : mode === 'continuous' + ? i % 2 + ? '#ff002f' + : '#ff5070' + : '#ff002f', + }, + geometry: { + type: 'LineString', + coordinates: [ + [polylinePoints[i - 1].lng, polylinePoints[i - 1].lat], + [polylinePoints[i].lng, polylinePoints[i].lat], + ], + }, + }) + } + + const globeBCR = Globe_.litho.getContainer()?.getBoundingClientRect() || {} + if (globeBCR.width > 0) + Globe_.litho.addLayer('clamped', { + name: '_measurePolyline', + id: '_measurePolyline', + on: true, + order: 10, + opacity: 1, + minZoom: 0, + maxZoom: 30, + style: { + default: { + weight: 3, + color: 'prop=color', + }, + }, + geojson: { + type: 'FeatureCollection', + features: features, + }, + }) +} + MeasureTool.init() export default MeasureTool From 84ae2bf8d259ea12f3c1e4c1ba982466f076a14e Mon Sep 17 00:00:00 2001 From: Joe Roberts Date: Mon, 6 Dec 2021 10:24:57 -0800 Subject: [PATCH 49/85] #117 Increased width of legend tool and allow line breaks when needed --- src/essence/Tools/Legend/LegendTool.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/essence/Tools/Legend/LegendTool.js b/src/essence/Tools/Legend/LegendTool.js index eea5dc87..318285ae 100644 --- a/src/essence/Tools/Legend/LegendTool.js +++ b/src/essence/Tools/Legend/LegendTool.js @@ -8,7 +8,7 @@ var markup = [].join('\n') var LegendTool = { height: 0, - width: 180, + width: 200, activeLayerNames: null, MMWebGISInterface: null, make: function () { @@ -184,6 +184,7 @@ function interfaceWithMMWebGIS() { .style('height', '100%') .style('line-height', '21px') .style('font-size', '14px') + .style('overflow', 'auto') .html(L_.layersLegendsData[l][d].value) } else if ( shape == 'continuous' || From b290735c7175c2edc9fced8c637c56f6cc3245cc Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 8 Dec 2021 18:04:30 -0800 Subject: [PATCH 50/85] #114 Model layer and 3d bearing support (warning uses local litho) --- package-lock.json | 14 +++--- package.json | 2 +- src/essence/Basics/Layers_/Layers_.js | 64 ++++++++++++++++++++++++-- src/essence/Basics/Map_/Map_.js | 6 +++ src/essence/Tools/Layers/LayersTool.js | 33 +++++++++---- 5 files changed, 100 insertions(+), 19 deletions(-) diff --git a/package-lock.json b/package-lock.json index 30cae884..c119f3ce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.5", + "lithosphere": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", @@ -11898,9 +11898,10 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/lithosphere": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.5.tgz", - "integrity": "sha512-KUNGQx3AxmijI4cJDa3yWP/Q6GCHJbnpRkqa9HfBQVCH8lE2csCJ1IYfvFFwX2KBaSqdZvIdxxxvclqboTbuYA==", + "version": "1.0.6", + "resolved": "file:../../npm-local/lithosphere-1.0.6.tgz", + "integrity": "sha512-rgMjuzso8eUmJ+raWP68d+i3VP2UOux4fvm+GoYyxJe2B1KyBd3qgycqTWF6gmGqFM0/ziUJxthlzm74PBGL1w==", + "license": "Apache-2.0", "dependencies": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", @@ -30328,9 +30329,8 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "lithosphere": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.0.5.tgz", - "integrity": "sha512-KUNGQx3AxmijI4cJDa3yWP/Q6GCHJbnpRkqa9HfBQVCH8lE2csCJ1IYfvFFwX2KBaSqdZvIdxxxvclqboTbuYA==", + "version": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", + "integrity": "sha512-rgMjuzso8eUmJ+raWP68d+i3VP2UOux4fvm+GoYyxJe2B1KyBd3qgycqTWF6gmGqFM0/ziUJxthlzm74PBGL1w==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/package.json b/package.json index 48325170..73014612 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "^1.0.5", + "lithosphere": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index b3520643..9ab0f5c1 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -199,7 +199,9 @@ var L_ = { } } } - L_.Globe_.litho.removeLayer(s.name) + if (s.type === 'model') { + L_.Globe_.litho.toggleLayer(s.name, false) + } else L_.Globe_.litho.removeLayer(s.name) } else { if (L_.layersGroup[s.name]) { if (L_.layersGroupSublayers[s.name]) { @@ -255,6 +257,33 @@ var L_ = { //time: s.time == null ? '' : s.time.end, }) } else if (s.type === 'data') { + } else if (s.type === 'model') { + if (L_.Globe_.litho.hasLayer(s.name)) { + L_.Globe_.litho.toggleLayer(s.name, true) + } else { + let modelUrl = s.url + if (!F_.isUrlAbsolute(modelUrl)) + modelUrl = L_.missionPath + modelUrl + L_.Globe_.litho.addLayer('model', { + name: s.name, + order: 1, + on: true, + path: modelUrl, + opacity: s.initialOpacity, + position: { + longitude: s.position?.longitude || 0, + latitude: s.position?.latitude || 0, + elevation: s.position?.elevation || 0, + }, + scale: s.scale || 1, + rotation: { + // y-up is away from planet center. x is pitch, y is yaw, z is roll + x: s.rotation?.x || 0, + y: s.rotation?.y || 0, + z: s.rotation?.z || 0, + }, + }) + } } else { let hadToMake = false if (L_.layersGroup[s.name] === false) { @@ -288,7 +317,7 @@ var L_ = { 1 - L_.layersOrdered.indexOf(s.name) ) - if (s.type === 'vector') + if (s.type === 'vector') { L_.Globe_.litho.addLayer('clamped', { name: s.name, order: 1000 - L_.layersIndex[s.name], // Since higher order in litho is on top @@ -310,11 +339,16 @@ var L_ = { weight: s.style.weight, radius: s.radius, }, + bearing: s.variables?.markerAttachments + ?.bearing + ? s.variables.markerAttachments.bearing + : null, }, opacity: L_.opacityArray[s.name], minZoom: 0, //s.minZoom, maxZoom: 100, //s.maxNativeZoom, }) + } } } } @@ -385,7 +419,8 @@ var L_ = { for (var i = L_.layersData.length - 1; i >= 0; i--) { if ( L_.toggledArray[L_.layersData[i].name] === true && - L_.layersGroup[L_.layersData[i].name] != null + (L_.layersData[i].type === 'model' || + L_.layersGroup[L_.layersData[i].name] != null) ) { if (L_.layersData[i].type === 'tile') { // Make sure all tile layers follow z-index order at start instead of element order @@ -467,6 +502,26 @@ var L_ = { //boundingBox: s.boundingBox, //time: s.time == null ? '' : s.time.end, }) + } else if (L_.layersData[i].type === 'model') { + L_.Globe_.litho.addLayer('model', { + name: s.name, + order: 99999 - L_.layersIndex[s.name], + on: true, + path: layerUrl, + opacity: L_.opacityArray[s.name], + position: { + longitude: s.position?.longitude || 0, + latitude: s.position?.latitude || 0, + elevation: s.position?.elevation || 0, + }, + scale: s.scale || 1, + rotation: { + // y-up is away from planet center. x is pitch, y is yaw, z is roll + x: s.rotation?.x || 0, + y: s.rotation?.y || 0, + z: s.rotation?.z || 0, + }, + }) } else if (L_.layersData[i].type != 'header') { L_.Globe_.litho.addLayer( L_.layersData[i].type == 'vector' @@ -493,6 +548,9 @@ var L_ = { weight: s.style.weight, radius: s.radius, }, + bearing: s.variables?.markerAttachments?.bearing + ? s.variables.markerAttachments.bearing + : null, }, opacity: L_.opacityArray[s.name], minZoom: 0, //s.minZoom, diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index e20e6c58..cd846b4a 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -563,6 +563,7 @@ async function makeLayer(layerObj, evenIfOff) { break case 'model': //Globe only + makeModelLayer() break default: console.warn('Unknown layer type: ' + layerObj.type) @@ -1053,6 +1054,11 @@ async function makeLayer(layerObj, evenIfOff) { allLayersLoaded() } + function makeModelLayer() { + L_.layersLoaded[L_.layersOrdered.indexOf(layerObj.name)] = true + allLayersLoaded() + } + function makeDataLayer() { let layerUrl = layerObj.demtileurl if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index 26271b49..4df84865 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -19,6 +19,7 @@ var markup = [ "
    ", "
    ", '
    ', + '
    ', '
    ', '
    ', '
    ', @@ -365,10 +366,15 @@ function interfaceWithMMGIS() { case 'model': // prettier-ignore settings = [ - '
      ', - '
    • vectortransparency
    • ', - '
    ', - ].join('\n') + '
      ', + '
    • ', + '
      ', + '
      Opacity
      ', + '', + '
      ', + '
    • ', + '
    ', + ].join('\n') break default: settings = '' @@ -401,7 +407,7 @@ function interfaceWithMMGIS() { // prettier-ignore $('#layersToolList').append( [ - '
  • ', + '
  • ', '
    ', '
    ', '
    ', @@ -466,8 +472,12 @@ function interfaceWithMMGIS() { $(this).addClass('loading') await L_.toggleLayer(L_.layersNamed[li.attr('name')]) $(this).removeClass('loading') - if (L_.layersGroup[li.attr('name')]) $(this).toggleClass('on') - else if (L_.layersGroup[li.attr('name')] == null) + if (li.attr('type') === 'model' || L_.layersGroup[li.attr('name')]) + $(this).toggleClass('on') + else if ( + li.attr('type') !== 'model' && + L_.layersGroup[li.attr('name')] == null + ) li.addClass('layernotfound') } }) @@ -647,6 +657,7 @@ function interfaceWithMMGIS() { var type = $(this).attr('type') const ons = { vector: $('#filterLayers .right > .vector').hasClass('on'), + vectortile: $('#filterLayers .right > .vectortile').hasClass('on'), tile: $('#filterLayers .right > .tile').hasClass('on'), data: $('#filterLayers .right > .data').hasClass('on'), model: $('#filterLayers .right > .model').hasClass('on'), @@ -661,7 +672,13 @@ function interfaceWithMMGIS() { else $(this).addClass('forceOff2') } else $(this).removeClass('forceOff2') } else { - if (!ons.vector && !ons.tile && !ons.data && !ons.data) + if ( + !ons.vector && + !ons.vectortile && + !ons.tile && + !ons.data && + !ons.model + ) $(this).removeClass('forceOff') else { const liType = $(this).attr('type') From 7bc13e8cc5d203dc89870813fcb86b138ddaddb2 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 9 Dec 2021 09:58:57 -0800 Subject: [PATCH 51/85] #119 Python3 version of gdal2customtiles.py --- .../gdal2customtiles/gdal2customtiles.py | 21 +- .../gdal2customtiles/gdal2customtiles_py27.py | 3218 +++++++++++++++++ 2 files changed, 3227 insertions(+), 12 deletions(-) create mode 100644 auxiliary/gdal2customtiles/gdal2customtiles_py27.py diff --git a/auxiliary/gdal2customtiles/gdal2customtiles.py b/auxiliary/gdal2customtiles/gdal2customtiles.py index 532a22c4..2e4c1655 100644 --- a/auxiliary/gdal2customtiles/gdal2customtiles.py +++ b/auxiliary/gdal2customtiles/gdal2customtiles.py @@ -49,13 +49,10 @@ def binary(num): # 1bto4b # 1bto4b - return ''.join(bin(ord(c)).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num)) + return ''.join(bin(c).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num)) # 1bto4b - - - def getTilePxBounds(self, tx, ty, tz, ds): querysize = self.tilesize @@ -1979,10 +1976,10 @@ def generate_base_tiles(self, tz): data3.append(int(f[16:24], 2)) data4.append(int(f[24:], 2)) - data1s = '' - data2s = '' - data3s = '' - data4s = '' + data1s = b'' + data2s = b'' + data3s = b'' + data4s = b'' indx = 0 for v in data1: data1s += struct.pack('B', data1[indx]) @@ -2024,10 +2021,10 @@ def generate_base_tiles(self, tz): data3.append(int(f[16:24], 2)) data4.append(int(f[24:], 2)) - data1s = '' - data2s = '' - data3s = '' - data4s = '' + data1s = b'' + data2s = b'' + data3s = b'' + data4s = b'' indx = 0 for v in data1: data1s += struct.pack('B', data1[indx]) diff --git a/auxiliary/gdal2customtiles/gdal2customtiles_py27.py b/auxiliary/gdal2customtiles/gdal2customtiles_py27.py new file mode 100644 index 00000000..8b6421d6 --- /dev/null +++ b/auxiliary/gdal2customtiles/gdal2customtiles_py27.py @@ -0,0 +1,3218 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# ****************************************************************************** +# $Id$ +# +# Project: Google Summer of Code 2007, 2008 (http://code.google.com/soc/) +# Support: BRGM (http://www.brgm.fr) +# Purpose: Convert a raster into TMS (Tile Map Service) tiles in a directory. +# - generate Google Earth metadata (KML SuperOverlay) +# - generate simple HTML viewer based on Google Maps and OpenLayers +# - support of global tiles (Spherical Mercator) for compatibility +# with interactive web maps a la Google Maps +# Author: Klokan Petr Pridal, klokan at klokan dot cz +# Web: http://www.klokan.cz/projects/gdal2tiles/ +# GUI: http://www.maptiler.org/ +# +############################################################################### +# Copyright (c) 2008, Klokan Petr Pridal +# Copyright (c) 2010-2013, Even Rouault +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included +# in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# ****************************************************************************** + +import math +import os +import sys + +from osgeo import gdal +from osgeo import osr + +import struct # 1bto4b + + +def binary(num): # 1bto4b + # 1bto4b + return ''.join(bin(ord(c)).replace('0b', '').rjust(8, '0') for c in struct.pack('!f', num)) + +# 1bto4b + +def getTilePxBounds(self, tx, ty, tz, ds): + + querysize = self.tilesize + + if self.isRasterBounded: # 'raster' profile: + # tilesize in raster coordinates for actual zoom + tsize = int(self.tsize[tz]) + xsize = self.out_ds.fWorldXSize + ysize = self.out_ds.fWorldYSize + if tz >= self.tmaxz: + querysize = self.tilesize + + rx = (tx) * tsize - self.out_ds.fRasterXOriginWorld + #print("rx", rx) + rxsize = 0 + rxsize = tsize + + rysize = 0 + rysize = tsize + + ry = ysize - (ty * tsize) - rysize - \ + self.out_ds.fRasterYOriginWorld + + wx, wy = 0, 0 + wxsize = int(rxsize/float(tsize) * self.tilesize) + wysize = int(rysize/float(tsize) * self.tilesize) + if wysize != self.tilesize: + wy = self.tilesize - wysize + + if rx < 0: + rxsize = tsize + rx + wx = -rx + wxsize = int(rxsize/float(tsize) * self.tilesize) + rx = 0 + if ry < 0: + rysize = tsize + ry + wy = -ry + wysize = int(rysize/float(tsize) * self.tilesize) + ry = 0 + if rx + rxsize > self.out_ds.fRasterXSizeWorld: + rxsize = self.out_ds.fRasterXSizeWorld - rx + wxsize = int(rxsize/float(tsize) * self.tilesize) + if ry + rysize > self.out_ds.fRasterYSizeWorld: + rysize = self.out_ds.fRasterYSizeWorld - ry + wysize = int(rysize/float(tsize) * self.tilesize) + + # Convert rx, ry back to non-world coordinates + rx = int(float(self.out_ds.RasterXSize) * + (float(rx) / self.out_ds.fRasterXSizeWorld)) + ry = int(float(self.out_ds.RasterYSize) * + (float(ry) / self.out_ds.fRasterYSizeWorld)) + rxsize = int(float(self.out_ds.RasterXSize) * + (float(rxsize) / self.out_ds.fRasterXSizeWorld)) + rysize = int(float(self.out_ds.RasterYSize) * + (float(rysize) / self.out_ds.fRasterYSizeWorld)) + else: + b = self.mercator.TileBounds(tx, ty, tz) + rb, wb = self.geo_query( + ds, b[0], b[3], b[2], b[1], querysize=querysize) + rx, ry, rxsize, rysize = rb + wx, wy, wxsize, wysize = wb + + return [rx, ry, rxsize, rysize, wxsize, wysize] + + +try: + from PIL import Image + import numpy + import osgeo.gdal_array as gdalarray +except Exception: + # 'antialias' resampling is not available + pass + +__version__ = "$Id$" + +resampling_list = ('average', 'near', 'bilinear', 'cubic', + 'cubicspline', 'lanczos', 'antialias') +profile_list = ('mercator', 'geodetic', 'raster') +webviewer_list = ('all', 'google', 'openlayers', 'leaflet', 'none') + +# ============================================================================= +# ============================================================================= +# ============================================================================= + +__doc__globalmaptiles = """ +globalmaptiles.py + +Global Map Tiles as defined in Tile Map Service (TMS) Profiles +============================================================== + +Functions necessary for generation of global tiles used on the web. +It contains classes implementing coordinate conversions for: + + - GlobalMercator (based on EPSG:3857) + for Google Maps, Yahoo Maps, Bing Maps compatible tiles + - GlobalGeodetic (based on EPSG:4326) + for OpenLayers Base Map and Google Earth compatible tiles + +More info at: + +http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification +http://wiki.osgeo.org/wiki/WMS_Tiling_Client_Recommendation +http://msdn.microsoft.com/en-us/library/bb259689.aspx +http://code.google.com/apis/maps/documentation/overlays.html#Google_Maps_Coordinates + +Created by Klokan Petr Pridal on 2008-07-03. +Google Summer of Code 2008, project GDAL2Tiles for OSGEO. + +In case you use this class in your product, translate it to another language +or find it useful for your project please let me know. +My email: klokan at klokan dot cz. +I would like to know where it was used. + +Class is available under the open-source GDAL license (www.gdal.org). +""" + +MAXZOOMLEVEL = 32 + + +class GlobalMercator(object): + r""" + TMS Global Mercator Profile + --------------------------- + + Functions necessary for generation of tiles in Spherical Mercator projection, + EPSG:3857. + + Such tiles are compatible with Google Maps, Bing Maps, Yahoo Maps, + UK Ordnance Survey OpenSpace API, ... + and you can overlay them on top of base maps of those web mapping applications. + + Pixel and tile coordinates are in TMS notation (origin [0,0] in bottom-left). + + What coordinate conversions do we need for TMS Global Mercator tiles:: + + LatLon <-> Meters <-> Pixels <-> Tile + + WGS84 coordinates Spherical Mercator Pixels in pyramid Tiles in pyramid + lat/lon XY in meters XY pixels Z zoom XYZ from TMS + EPSG:4326 EPSG:387 + .----. --------- -- TMS + / \ <-> | | <-> /----/ <-> Google + \ / | | /--------/ QuadTree + ----- --------- /------------/ + KML, public WebMapService Web Clients TileMapService + + What is the coordinate extent of Earth in EPSG:3857? + + [-20037508.342789244, -20037508.342789244, + 20037508.342789244, 20037508.342789244] + Constant 20037508.342789244 comes from the circumference of the Earth in meters, + which is 40 thousand kilometers, the coordinate origin is in the middle of extent. + In fact you can calculate the constant as: 2 * math.pi * 6378137 / 2.0 + $ echo 180 85 | gdaltransform -s_srs EPSG:4326 -t_srs EPSG:3857 + Polar areas with abs(latitude) bigger then 85.05112878 are clipped off. + + What are zoom level constants (pixels/meter) for pyramid with EPSG:3857? + + whole region is on top of pyramid (zoom=0) covered by 256x256 pixels tile, + every lower zoom level resolution is always divided by two + initialResolution = 20037508.342789244 * 2 / 256 = 156543.03392804062 + + What is the difference between TMS and Google Maps/QuadTree tile name convention? + + The tile raster itself is the same (equal extent, projection, pixel size), + there is just different identification of the same raster tile. + Tiles in TMS are counted from [0,0] in the bottom-left corner, id is XYZ. + Google placed the origin [0,0] to the top-left corner, reference is XYZ. + Microsoft is referencing tiles by a QuadTree name, defined on the website: + http://msdn2.microsoft.com/en-us/library/bb259689.aspx + + The lat/lon coordinates are using WGS84 datum, yes? + + Yes, all lat/lon we are mentioning should use WGS84 Geodetic Datum. + Well, the web clients like Google Maps are projecting those coordinates by + Spherical Mercator, so in fact lat/lon coordinates on sphere are treated as if + the were on the WGS84 ellipsoid. + + From MSDN documentation: + To simplify the calculations, we use the spherical form of projection, not + the ellipsoidal form. Since the projection is used only for map display, + and not for displaying numeric coordinates, we don't need the extra precision + of an ellipsoidal projection. The spherical projection causes approximately + 0.33 percent scale distortion in the Y direction, which is not visually + noticeable. + + How do I create a raster in EPSG:3857 and convert coordinates with PROJ.4? + + You can use standard GIS tools like gdalwarp, cs2cs or gdaltransform. + All of the tools supports -t_srs 'epsg:3857'. + + For other GIS programs check the exact definition of the projection: + More info at http://spatialreference.org/ref/user/google-projection/ + The same projection is designated as EPSG:3857. WKT definition is in the + official EPSG database. + + Proj4 Text: + +proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 + +k=1.0 +units=m +nadgrids=@null +no_defs + + Human readable WKT format of EPSG:3857: + PROJCS["Google Maps Global Mercator", + GEOGCS["WGS 84", + DATUM["WGS_1984", + SPHEROID["WGS 84",6378137,298.257223563, + AUTHORITY["EPSG","7030"]], + AUTHORITY["EPSG","6326"]], + PRIMEM["Greenwich",0], + UNIT["degree",0.0174532925199433], + AUTHORITY["EPSG","4326"]], + PROJECTION["Mercator_1SP"], + PARAMETER["central_meridian",0], + PARAMETER["scale_factor",1], + PARAMETER["false_easting",0], + PARAMETER["false_northing",0], + UNIT["metre",1, + AUTHORITY["EPSG","9001"]]] + """ + + def __init__(self, tileSize=256): + "Initialize the TMS Global Mercator pyramid" + self.tileSize = tileSize + self.initialResolution = 2 * math.pi * 6378137 / self.tileSize + # 156543.03392804062 for tileSize 256 pixels + self.originShift = 2 * math.pi * 6378137 / 2.0 + # 20037508.342789244 + + def LatLonToMeters(self, lat, lon): + "Converts given lat/lon in WGS84 Datum to XY in Spherical Mercator EPSG:3857" + + mx = lon * self.originShift / 180.0 + my = math.log(math.tan((90 + lat) * math.pi / 360.0)) / \ + (math.pi / 180.0) + + my = my * self.originShift / 180.0 + return mx, my + + def MetersToLatLon(self, mx, my): + "Converts XY point from Spherical Mercator EPSG:3857 to lat/lon in WGS84 Datum" + + lon = (mx / self.originShift) * 180.0 + lat = (my / self.originShift) * 180.0 + + lat = 180 / math.pi * \ + (2 * math.atan(math.exp(lat * math.pi / 180.0)) - math.pi / 2.0) + return lat, lon + + def PixelsToMeters(self, px, py, zoom): + "Converts pixel coordinates in given zoom level of pyramid to EPSG:3857" + + res = self.Resolution(zoom) + mx = px * res - self.originShift + my = py * res - self.originShift + return mx, my + + def MetersToPixels(self, mx, my, zoom): + "Converts EPSG:3857 to pyramid pixel coordinates in given zoom level" + + res = self.Resolution(zoom) + px = (mx + self.originShift) / res + py = (my + self.originShift) / res + return px, py + + def PixelsToTile(self, px, py): + "Returns a tile covering region in given pixel coordinates" + + tx = int(math.ceil(px / float(self.tileSize)) - 1) + ty = int(math.ceil(py / float(self.tileSize)) - 1) + return tx, ty + + def PixelsToRaster(self, px, py, zoom): + "Move the origin of pixel coordinates to top-left corner" + + mapSize = self.tileSize << zoom + return px, mapSize - py + + def MetersToTile(self, mx, my, zoom): + "Returns tile for given mercator coordinates" + + px, py = self.MetersToPixels(mx, my, zoom) + return self.PixelsToTile(px, py) + + def TileBounds(self, tx, ty, zoom): + "Returns bounds of the given tile in EPSG:3857 coordinates" + + minx, miny = self.PixelsToMeters( + tx*self.tileSize, ty*self.tileSize, zoom) + maxx, maxy = self.PixelsToMeters( + (tx+1)*self.tileSize, (ty+1)*self.tileSize, zoom) + return (minx, miny, maxx, maxy) + + def TileLatLonBounds(self, tx, ty, zoom): + "Returns bounds of the given tile in latitude/longitude using WGS84 datum" + + bounds = self.TileBounds(tx, ty, zoom) + minLat, minLon = self.MetersToLatLon(bounds[0], bounds[1]) + maxLat, maxLon = self.MetersToLatLon(bounds[2], bounds[3]) + + return (minLat, minLon, maxLat, maxLon) + + def Resolution(self, zoom): + "Resolution (meters/pixel) for given zoom level (measured at Equator)" + + # return (2 * math.pi * 6378137) / (self.tileSize * 2**zoom) + return self.initialResolution / (2**zoom) + + def ZoomForPixelSize(self, pixelSize): + "Maximal scaledown zoom of the pyramid closest to the pixelSize." + + for i in range(MAXZOOMLEVEL): + if pixelSize > self.Resolution(i): + if i != -1: + return i-1 + else: + return 0 # We don't want to scale up + + def GoogleTile(self, tx, ty, zoom): + "Converts TMS tile coordinates to Google Tile coordinates" + + # coordinate origin is moved from bottom-left to top-left corner of the extent + return tx, (2**zoom - 1) - ty + + def QuadTree(self, tx, ty, zoom): + "Converts TMS tile coordinates to Microsoft QuadTree" + + quadKey = "" + ty = (2**zoom - 1) - ty + for i in range(zoom, 0, -1): + digit = 0 + mask = 1 << (i-1) + if (tx & mask) != 0: + digit += 1 + if (ty & mask) != 0: + digit += 2 + quadKey += str(digit) + + return quadKey + + +class GlobalGeodetic(object): + r""" + TMS Global Geodetic Profile + --------------------------- + + Functions necessary for generation of global tiles in Plate Carre projection, + EPSG:4326, "unprojected profile". + + Such tiles are compatible with Google Earth (as any other EPSG:4326 rasters) + and you can overlay the tiles on top of OpenLayers base map. + + Pixel and tile coordinates are in TMS notation (origin [0,0] in bottom-left). + + What coordinate conversions do we need for TMS Global Geodetic tiles? + + Global Geodetic tiles are using geodetic coordinates (latitude,longitude) + directly as planar coordinates XY (it is also called Unprojected or Plate + Carre). We need only scaling to pixel pyramid and cutting to tiles. + Pyramid has on top level two tiles, so it is not square but rectangle. + Area [-180,-90,180,90] is scaled to 512x256 pixels. + TMS has coordinate origin (for pixels and tiles) in bottom-left corner. + Rasters are in EPSG:4326 and therefore are compatible with Google Earth. + + LatLon <-> Pixels <-> Tiles + + WGS84 coordinates Pixels in pyramid Tiles in pyramid + lat/lon XY pixels Z zoom XYZ from TMS + EPSG:4326 + .----. ---- + / \ <-> /--------/ <-> TMS + \ / /--------------/ + ----- /--------------------/ + WMS, KML Web Clients, Google Earth TileMapService + """ + + def __init__(self, tmscompatible, tileSize=256): + self.tileSize = tileSize + if tmscompatible is not None: + # Defaults the resolution factor to 0.703125 (2 tiles @ level 0) + # Adhers to OSGeo TMS spec + # http://wiki.osgeo.org/wiki/Tile_Map_Service_Specification#global-geodetic + self.resFact = 180.0 / self.tileSize + else: + # Defaults the resolution factor to 1.40625 (1 tile @ level 0) + # Adheres OpenLayers, MapProxy, etc default resolution for WMTS + self.resFact = 360.0 / self.tileSize + + def LonLatToPixels(self, lon, lat, zoom): + "Converts lon/lat to pixel coordinates in given zoom of the EPSG:4326 pyramid" + + res = self.resFact / 2**zoom + px = (180 + lon) / res + py = (90 + lat) / res + return px, py + + def PixelsToTile(self, px, py): + "Returns coordinates of the tile covering region in pixel coordinates" + + tx = int(math.ceil(px / float(self.tileSize)) - 1) + ty = int(math.ceil(py / float(self.tileSize)) - 1) + return tx, ty + + def LonLatToTile(self, lon, lat, zoom): + "Returns the tile for zoom which covers given lon/lat coordinates" + + px, py = self.LonLatToPixels(lon, lat, zoom) + return self.PixelsToTile(px, py) + + def Resolution(self, zoom): + "Resolution (arc/pixel) for given zoom level (measured at Equator)" + + return self.resFact / 2**zoom + + def ZoomForPixelSize(self, pixelSize): + "Maximal scaledown zoom of the pyramid closest to the pixelSize." + + for i in range(MAXZOOMLEVEL): + if pixelSize > self.Resolution(i): + if i != 0: + return i-1 + else: + return 0 # We don't want to scale up + + def TileBounds(self, tx, ty, zoom): + "Returns bounds of the given tile" + res = self.resFact / 2**zoom + return ( + tx*self.tileSize*res - 180, + ty*self.tileSize*res - 90, + (tx+1)*self.tileSize*res - 180, + (ty+1)*self.tileSize*res - 90 + ) + + def TileLatLonBounds(self, tx, ty, zoom): + "Returns bounds of the given tile in the SWNE form" + b = self.TileBounds(tx, ty, zoom) + return (b[1], b[0], b[3], b[2]) + + +class Zoomify(object): + """ + Tiles compatible with the Zoomify viewer + ---------------------------------------- + """ + + def __init__(self, width, height, tilesize=256, tileformat='jpg'): + """Initialization of the Zoomify tile tree""" + + self.tilesize = tilesize + self.tileformat = tileformat + imagesize = (width, height) + tiles = (math.ceil(width / tilesize), math.ceil(height / tilesize)) + + # Size (in tiles) for each tier of pyramid. + self.tierSizeInTiles = [] + self.tierSizeInTiles.append(tiles) + + # Image size in pixels for each pyramid tierself + self.tierImageSize = [] + self.tierImageSize.append(imagesize) + + while (imagesize[0] > tilesize or imagesize[1] > tilesize): + imagesize = (math.floor( + imagesize[0] / 2), math.floor(imagesize[1] / 2)) + tiles = (math.ceil(imagesize[0] / tilesize), + math.ceil(imagesize[1] / tilesize)) + self.tierSizeInTiles.append(tiles) + self.tierImageSize.append(imagesize) + + self.tierSizeInTiles.reverse() + self.tierImageSize.reverse() + + # Depth of the Zoomify pyramid, number of tiers (zoom levels) + self.numberOfTiers = len(self.tierSizeInTiles) + + # Number of tiles up to the given tier of pyramid. + self.tileCountUpToTier = [] + self.tileCountUpToTier[0] = 0 + for i in range(1, self.numberOfTiers+1): + self.tileCountUpToTier.append( + self.tierSizeInTiles[i-1][0] * self.tierSizeInTiles[i-1][1] + + self.tileCountUpToTier[i-1] + ) + + def tilefilename(self, x, y, z): + """Returns filename for tile with given coordinates""" + + tileIndex = x + y * \ + self.tierSizeInTiles[z][0] + self.tileCountUpToTier[z] + return os.path.join("TileGroup%.0f" % math.floor(tileIndex / 256), + "%s-%s-%s.%s" % (z, x, y, self.tileformat)) + + +class Gdal2TilesError(Exception): + pass + + +class GDAL2Tiles(object): + + def process(self): + """The main processing function, runs all the main steps of processing""" + + # Opening and preprocessing of the input file + self.open_input() + + # Generation of main metadata files and HTML viewers + self.generate_metadata() + + # 1bto4b + if self.isDEMtile: + for z in range(self.tminz, self.tmaxz + int(abs(math.log(self.tilesize, 2) - 8))): # 1bto4b + self.generate_base_tiles(z) + print(' Zoom ' + str(z) + ' tiles done!') + else: + # Generation of the lowest tiles + self.generate_base_tiles(self.tmaxz) + + # Generation of the overview tiles (higher in the pyramid) + self.generate_overview_tiles() + + def error(self, msg, details=""): + """Print an error message and stop the processing""" + if details: + self.parser.error(msg + "\n\n" + details) + else: + self.parser.error(msg) + + def progressbar(self, complete=0.0): + """Print progressbar for float value 0..1""" + gdal.TermProgress_nocb(complete) + + def gettempfilename(self, suffix): + """Returns a temporary filename""" + if '_' in os.environ: + # tempfile.mktemp() crashes on some Wine versions (the one of Ubuntu 12.04 particularly) + if os.environ['_'].find('wine') >= 0: + tmpdir = '.' + if 'TMP' in os.environ: + tmpdir = os.environ['TMP'] + import time + import random + random.seed(time.time()) + random_part = 'file%d' % random.randint(0, 1000000000) + return os.path.join(tmpdir, random_part + suffix) + + import tempfile + return tempfile.mktemp(suffix) + + def stop(self): + """Stop the rendering immediately""" + self.stopped = True + + def __init__(self, arguments): + """Constructor function - initialization""" + self.out_drv = None + self.mem_drv = None + self.in_ds = None + self.out_ds = None + self.out_srs = None + self.nativezoom = None + self.tminmax = None + self.tsize = None + self.mercator = None + self.geodetic = None + self.alphaband = None + self.dataBandsCount = None + self.out_gt = None + self.tileswne = None + self.swne = None + self.ominx = None + self.omaxx = None + self.omaxy = None + self.ominy = None + + # MMGIS + self.isRasterBounded = False + + # 1bto4b + self.isDEMtile = False + + # MMGIS + self.fminx = None + self.fmaxx = None + self.fminy = None + self.fmaxy = None + self.fPixelSize = None + + self.stopped = False + self.input = None + self.output = None + + # Tile format + self.tilesize = 256 + self.tiledriver = 'PNG' + self.tileext = 'png' + + # Should we read bigger window of the input raster and scale it down? + # Note: Modified later by open_input() + # Not for 'near' resampling + # Not for Wavelet based drivers (JPEG2000, ECW, MrSID) + # Not for 'raster' profile + self.scaledquery = True + # How big should be query window be for scaling down + # Later on reset according the chosen resampling algorightm + self.querysize = 4 * self.tilesize + + # Should we use Read on the input file for generating overview tiles? + # Note: Modified later by open_input() + # Otherwise the overview tiles are generated from existing underlying tiles + self.overviewquery = False + + # RUN THE ARGUMENT PARSER: + + self.optparse_init() + self.options, self.args = self.parser.parse_args(args=arguments) + if not self.args: + self.error("No input file specified") + + # POSTPROCESSING OF PARSED ARGUMENTS: + + # Workaround for old versions of GDAL + try: + if ((self.options.verbose and self.options.resampling == 'near') or + gdal.TermProgress_nocb): + pass + except Exception: + self.error( + "This version of GDAL is not supported. Please upgrade to 1.6+.") + + # Is output directory the last argument? + + # Test output directory, if it doesn't exist + if (os.path.isdir(self.args[-1]) or + (len(self.args) > 1 and not os.path.exists(self.args[-1]))): + self.output = self.args[-1] + self.args = self.args[:-1] + + # More files on the input not directly supported yet + + if (len(self.args) > 1): + self.error("Processing of several input files is not supported.", + "Please first use a tool like gdal_vrtmerge.py or gdal_merge.py on the " + "files: gdal_vrtmerge.py -o merged.vrt %s" % " ".join(self.args)) + + self.input = self.args[0] + + # MMGIS + if self.options.extentworld: + extentworld = self.options.extentworld.split(",") + self.isRasterBounded = True + self.fminx = float(extentworld[0]) + self.fmaxx = float(extentworld[2]) + self.fminy = float(extentworld[3]) + self.fmaxy = float(extentworld[1]) + self.fPixelSize = float(extentworld[4]) + + # 1bto4b + if self.options.isDEMtile: + self.isDEMtile = True + self.tilesize = 32 + self.querysize = 4 * self.tilesize + + # Default values for not given options + + if not self.output: + # Directory with input filename without extension in actual directory + self.output = os.path.splitext(os.path.basename(self.input))[0] + + if not self.options.title: + self.options.title = os.path.basename(self.input) + + if self.options.url and not self.options.url.endswith('/'): + self.options.url += '/' + if self.options.url: + self.options.url += os.path.basename(self.output) + '/' + + # Supported options + + self.resampling = None + + if self.options.resampling == 'average': + try: + if gdal.RegenerateOverview: + pass + except Exception: + self.error("'average' resampling algorithm is not available.", + "Please use -r 'near' argument or upgrade to newer version of GDAL.") + + elif self.options.resampling == 'antialias': + try: + if numpy: # pylint:disable=W0125 + pass + except Exception: + self.error("'antialias' resampling algorithm is not available.", + "Install PIL (Python Imaging Library) and numpy.") + + elif self.options.resampling == 'near': + self.resampling = gdal.GRA_NearestNeighbour + self.querysize = self.tilesize + + elif self.options.resampling == 'bilinear': + self.resampling = gdal.GRA_Bilinear + self.querysize = self.tilesize * 2 + + elif self.options.resampling == 'cubic': + self.resampling = gdal.GRA_Cubic + + elif self.options.resampling == 'cubicspline': + self.resampling = gdal.GRA_CubicSpline + + elif self.options.resampling == 'lanczos': + self.resampling = gdal.GRA_Lanczos + + # User specified zoom levels + self.tminz = None + self.tmaxz = None + if self.options.zoom: + minmax = self.options.zoom.split('-', 1) + minmax.extend(['']) + zoom_min, zoom_max = minmax[:2] + self.tminz = int(zoom_min) + if zoom_max: + self.tmaxz = int(zoom_max) + else: + self.tmaxz = int(zoom_min) + + # KML generation + self.kml = self.options.kml + + # Check if the input filename is full ascii or not + try: + os.path.basename(self.input).encode('ascii') + except UnicodeEncodeError: + full_ascii = False + else: + full_ascii = True + + # LC_CTYPE check + if not full_ascii and 'UTF-8' not in os.environ.get("LC_CTYPE", ""): + if not self.options.quiet: + print("\nWARNING: " + "You are running gdal2tiles.py with a LC_CTYPE environment variable that is " + "not UTF-8 compatible, and your input file contains non-ascii characters. " + "The generated sample googlemaps, openlayers or " + "leaflet files might contain some invalid characters as a result\n") + + # Output the results + if self.options.verbose: + print("Options:", self.options) + print("Input:", self.input) + print("Output:", self.output) + print("Cache: %s MB" % (gdal.GetCacheMax() / 1024 / 1024)) + print('') + + def optparse_init(self): + """Prepare the option parser for input (argv)""" + + from optparse import OptionParser, OptionGroup + usage = "Usage: %prog [options] input_file(s) [output]" + p = OptionParser(usage, version="%prog " + __version__) + p.add_option("-p", "--profile", dest='profile', + type='choice', choices=profile_list, + help=("Tile cutting profile (%s) - default 'mercator' " + "(Google Maps compatible)" % ",".join(profile_list))) + p.add_option("-r", "--resampling", dest="resampling", + type='choice', choices=resampling_list, + help="Resampling method (%s) - default 'average'" % ",".join(resampling_list)) + p.add_option('-s', '--s_srs', dest="s_srs", metavar="SRS", + help="The spatial reference system used for the source input data") + p.add_option('-z', '--zoom', dest="zoom", + help="Zoom levels to render (format:'2-5' or '10').") + p.add_option('-e', '--resume', dest="resume", action="store_true", + help="Resume mode. Generate only missing files.") + p.add_option('-a', '--srcnodata', dest="srcnodata", metavar="NODATA", + help="NODATA transparency value to assign to the input data") + p.add_option('-d', '--tmscompatible', dest="tmscompatible", action="store_true", + help=("When using the geodetic profile, specifies the base resolution " + "as 0.703125 or 2 tiles at zoom level 0.")) + p.add_option("-v", "--verbose", + action="store_true", dest="verbose", + help="Print status messages to stdout") + p.add_option("-q", "--quiet", + action="store_true", dest="quiet", + help="Disable messages and status to stdout") + # MMGIS + p.add_option("-x", "--extentworld", dest="extentworld", + help="The full world meter extent (comma-separated as minx,maxx,miny,maxy,pixelsize) of an inner raster profile.") + # 1bto4b + p.add_option("-m", "--dem", action="store_true", dest="isDEMtile", + help="Indicate if the input is a Digital Elevation Model") + # KML options + g = OptionGroup(p, "KML (Google Earth) options", + "Options for generated Google Earth SuperOverlay metadata") + g.add_option("-k", "--force-kml", dest='kml', action="store_true", + help=("Generate KML for Google Earth - default for 'geodetic' profile and " + "'raster' in EPSG:4326. For a dataset with different projection use " + "with caution!")) + g.add_option("-n", "--no-kml", dest='kml', action="store_false", + help="Avoid automatic generation of KML files for EPSG:4326") + g.add_option("-u", "--url", dest='url', + help="URL address where the generated tiles are going to be published") + p.add_option_group(g) + + # HTML options + g = OptionGroup(p, "Web viewer options", + "Options for generated HTML viewers a la Google Maps") + g.add_option("-w", "--webviewer", dest='webviewer', type='choice', choices=webviewer_list, + help="Web viewer to generate (%s) - default 'all'" % ",".join(webviewer_list)) + g.add_option("-t", "--title", dest='title', + help="Title of the map") + g.add_option("-c", "--copyright", dest='copyright', + help="Copyright for the map") + g.add_option("-g", "--googlekey", dest='googlekey', + help="Google Maps API key from http://code.google.com/apis/maps/signup.html") + g.add_option("-b", "--bingkey", dest='bingkey', + help="Bing Maps API key from https://www.bingmapsportal.com/") + p.add_option_group(g) + + p.set_defaults(verbose=False, profile="mercator", kml=False, url='', + webviewer='all', copyright='', resampling='average', resume=False, + googlekey='INSERT_YOUR_KEY_HERE', bingkey='INSERT_YOUR_KEY_HERE') + + self.parser = p + + # ------------------------------------------------------------------------- + def open_input(self): + """Initialization of the input raster, reprojection if necessary""" + gdal.AllRegister() + + self.out_drv = gdal.GetDriverByName(self.tiledriver) + self.mem_drv = gdal.GetDriverByName('MEM') + + if not self.out_drv: + raise Exception("The '%s' driver was not found, is it available in this GDAL build?", + self.tiledriver) + if not self.mem_drv: + raise Exception( + "The 'MEM' driver was not found, is it available in this GDAL build?") + + # Open the input file + + if self.input: + self.in_ds = gdal.Open(self.input, gdal.GA_ReadOnly) + else: + raise Exception("No input file was specified") + + if self.options.verbose: + print("Input file:", + "( %sP x %sL - %s bands)" % (self.in_ds.RasterXSize, self.in_ds.RasterYSize, + self.in_ds.RasterCount)) + + if not self.in_ds: + # Note: GDAL prints the ERROR message too + self.error( + "It is not possible to open the input file '%s'." % self.input) + + # Read metadata from the input file + if self.in_ds.RasterCount == 0: + self.error("Input file '%s' has no raster band" % self.input) + + if self.in_ds.GetRasterBand(1).GetRasterColorTable(): + self.error("Please convert this file to RGB/RGBA and run gdal2tiles on the result.", + "From paletted file you can create RGBA file (temp.vrt) by:\n" + "gdal_translate -of vrt -expand rgba %s temp.vrt\n" + "then run:\n" + "gdal2tiles temp.vrt" % self.input) + + # Get NODATA value + in_nodata = [] + for i in range(1, self.in_ds.RasterCount+1): + if self.in_ds.GetRasterBand(i).GetNoDataValue() is not None: + in_nodata.append(self.in_ds.GetRasterBand(i).GetNoDataValue()) + if self.options.srcnodata: + nds = list(map(float, self.options.srcnodata.split(','))) + if len(nds) < self.in_ds.RasterCount: + in_nodata = ( + nds * self.in_ds.RasterCount)[:self.in_ds.RasterCount] + else: + in_nodata = nds + + if self.options.verbose: + print("NODATA: %s" % in_nodata) + + if self.options.verbose: + print("Preprocessed file:", + "( %sP x %sL - %s bands)" % (self.in_ds.RasterXSize, self.in_ds.RasterYSize, + self.in_ds.RasterCount)) + + in_srs = None + + if self.options.s_srs: + in_srs = osr.SpatialReference() + in_srs.SetFromUserInput(self.options.s_srs) + in_srs_wkt = in_srs.ExportToWkt() + else: + in_srs_wkt = self.in_ds.GetProjection() + if not in_srs_wkt and self.in_ds.GetGCPCount() != 0: + in_srs_wkt = self.in_ds.GetGCPProjection() + if in_srs_wkt: + in_srs = osr.SpatialReference() + in_srs.ImportFromWkt(in_srs_wkt) + + self.out_srs = osr.SpatialReference() + + if self.options.profile == 'mercator': + self.out_srs.ImportFromEPSG(3857) + elif self.options.profile == 'geodetic': + self.out_srs.ImportFromEPSG(4326) + else: + self.out_srs = in_srs + + # Are the reference systems the same? Reproject if necessary. + + self.out_ds = None + + if self.options.profile in ('mercator', 'geodetic'): + + if ((self.in_ds.GetGeoTransform() == (0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) and + (self.in_ds.GetGCPCount() == 0)): + self.error("There is no georeference - neither affine transformation (worldfile) " + "nor GCPs. You can generate only 'raster' profile tiles.", + "Either gdal2tiles with parameter -p 'raster' or use another GIS " + "software for georeference e.g. gdal_transform -gcp / -a_ullr / -a_srs") + + if in_srs: + if ((in_srs.ExportToProj4() != self.out_srs.ExportToProj4()) or + (self.in_ds.GetGCPCount() != 0)): + # Generation of VRT dataset in tile projection, + # default 'nearest neighbour' warping + self.out_ds = gdal.AutoCreateWarpedVRT( + self.in_ds, in_srs_wkt, self.out_srs.ExportToWkt()) + + if self.options.verbose: + print("Warping of the raster by AutoCreateWarpedVRT " + "(result saved into 'tiles.vrt')") + self.out_ds.GetDriver().CreateCopy("tiles.vrt", self.out_ds) + + # Correction of AutoCreateWarpedVRT for NODATA values + if in_nodata != []: + tempfilename = self.gettempfilename('-gdal2tiles.vrt') + self.out_ds.GetDriver().CreateCopy(tempfilename, self.out_ds) + # open as a text file + s = open(tempfilename).read() + # Add the warping options + s = s.replace( + "", + """ + + + + """) + # replace BandMapping tag for NODATA bands.... + for i in range(len(in_nodata)): + s = s.replace( + '' % ( + (i+1), (i+1)), + """ + + %i + 0 + %i + 0 + + """ % ((i+1), (i+1), in_nodata[i], in_nodata[i])) + # save the corrected VRT + open(tempfilename, "w").write(s) + # open by GDAL as self.out_ds + self.out_ds = gdal.Open(tempfilename) + # delete the temporary file + os.unlink(tempfilename) + + # set NODATA_VALUE metadata + self.out_ds.SetMetadataItem( + 'NODATA_VALUES', ' '.join([str(i) for i in in_nodata])) + + if self.options.verbose: + print("Modified warping result saved into 'tiles1.vrt'") + open("tiles1.vrt", "w").write(s) + + # Correction of AutoCreateWarpedVRT for Mono (1 band) and RGB (3 bands) files + # without NODATA: + # equivalent of gdalwarp -dstalpha + if in_nodata == [] and self.out_ds.RasterCount in [1, 3]: + tempfilename = self.gettempfilename('-gdal2tiles.vrt') + self.out_ds.GetDriver().CreateCopy(tempfilename, self.out_ds) + # open as a text file + s = open(tempfilename).read() + # Add the warping options + s = s.replace( + "", + """ + + Alpha + + + """ % (self.out_ds.RasterCount + 1)) + s = s.replace( + "", + """ + %i + + """ % (self.out_ds.RasterCount + 1)) + s = s.replace( + "", + """ + + + """) + # save the corrected VRT + open(tempfilename, "w").write(s) + # open by GDAL as self.out_ds + self.out_ds = gdal.Open(tempfilename) + # delete the temporary file + os.unlink(tempfilename) + + if self.options.verbose: + print( + "Modified -dstalpha warping result saved into 'tiles1.vrt'") + open("tiles1.vrt", "w").write(s) + s = ''' + ''' + + else: + self.error("Input file has unknown SRS.", + "Use --s_srs ESPG:xyz (or similar) to provide source reference system.") + + if self.out_ds and self.options.verbose: + print("Projected file:", "tiles.vrt", "( %sP x %sL - %s bands)" % ( + self.out_ds.RasterXSize, self.out_ds.RasterYSize, self.out_ds.RasterCount)) + + if not self.out_ds: + self.out_ds = self.in_ds + + # + # Here we should have a raster (out_ds) in the correct Spatial Reference system + # + + # Get alpha band (either directly or from NODATA value) + self.alphaband = self.out_ds.GetRasterBand(1).GetMaskBand() + if ((self.alphaband.GetMaskFlags() & gdal.GMF_ALPHA) or + self.out_ds.RasterCount == 4 or + self.out_ds.RasterCount == 2): + self.dataBandsCount = self.out_ds.RasterCount - 1 + else: + self.dataBandsCount = self.out_ds.RasterCount + + # KML test + isepsg4326 = False + srs4326 = osr.SpatialReference() + srs4326.ImportFromEPSG(4326) + if self.out_srs and srs4326.ExportToProj4() == self.out_srs.ExportToProj4(): + self.kml = True + isepsg4326 = True + if self.options.verbose: + print("KML autotest OK!") + + # Read the georeference + self.out_gt = self.out_ds.GetGeoTransform() + + # Test the size of the pixel + + # Report error in case rotation/skew is in geotransform (possible only in 'raster' profile) + if (self.out_gt[2], self.out_gt[4]) != (0, 0): + self.error("Georeference of the raster contains rotation or skew. " + "Such raster is not supported. Please use gdalwarp first.") + + # Here we expect: pixel is square, no rotation on the raster + + # Output Bounds - coordinates in the output SRS + self.ominx = self.out_gt[0] + self.omaxx = self.out_gt[0] + self.out_ds.RasterXSize * self.out_gt[1] + self.omaxy = self.out_gt[3] + self.ominy = self.out_gt[3] - self.out_ds.RasterYSize * self.out_gt[1] + + # Note: maybe round(x, 14) to avoid the gdal_translate behaviour, when 0 becomes -1e-15 + + # MMGIS + def linearScale(domain, rang, value): + return ( + ((rang[1] - rang[0]) * (value - domain[0])) / + (domain[1] - domain[0]) + + rang[0] + ) + # MMGIS + self.out_ds.fRasterXSize = self.out_ds.RasterXSize + self.out_ds.fRasterYSize = self.out_ds.RasterYSize + self.out_ds.fRasterXOrigin = 0 + self.out_ds.fRasterYOrigin = 0 + self.out_ds.PixelSize = self.out_gt[1] + self.out_ds.fPixelSize = self.fPixelSize + # print("ominx", self.ominx, "omaxx", self.omaxx, "ominy", self.ominy, "omaxy", self.omaxy) + # print("fminx", self.fminx, "fmaxx", self.fmaxx, "fminy", self.fminy, "fmaxy", self.fmaxy) + if self.isRasterBounded: + self.out_ds.fRasterXSize = int(math.floor(self.out_ds.RasterXSize * (self.fmaxx - self.fminx) / ( + self.omaxx - self.ominx) * (self.out_ds.PixelSize / self.out_ds.fPixelSize))) + self.out_ds.fRasterYSize = int(math.ceil(self.out_ds.RasterYSize * (self.fmaxy - self.fminy) / ( + self.omaxy - self.ominy) * (self.out_ds.PixelSize / self.out_ds.fPixelSize))) + self.out_ds.fRasterXSizeRaw = int(math.floor( + self.out_ds.RasterXSize * (self.fmaxx - self.fminx) / (self.omaxx - self.ominx))) + self.out_ds.fRasterYSizeRaw = int(math.ceil( + self.out_ds.RasterYSize * (self.fmaxy - self.fminy) / (self.omaxy - self.ominy))) + # print("Full Raster Size: ", self.out_ds.fRasterXSize, self.out_ds.fRasterYSize ) + self.out_ds.fRasterXOrigin = int(math.floor(linearScale( + [self.fminx, self.fmaxx], [0, self.out_ds.fRasterXSize], self.out_gt[0]))) + self.out_ds.fRasterYOrigin = int(math.ceil(linearScale( + [self.fminy, self.fmaxy], [self.out_ds.fRasterYSize, 0], self.out_gt[3]))) + self.out_ds.fRasterXOriginRaw = int(math.floor(linearScale([self.fminx, self.fmaxx], [ + 0, self.out_ds.fRasterXSize], self.out_gt[0]) * (self.out_ds.fPixelSize / self.out_ds.PixelSize))) + self.out_ds.fRasterYOriginRaw = int(math.ceil(linearScale([self.fminy, self.fmaxy], [ + self.out_ds.fRasterYSize, 0], self.out_gt[3]) * (self.out_ds.fPixelSize / self.out_ds.PixelSize))) + self.out_ds.fRasterXWidth = int(math.floor(linearScale( + [self.fminx, self.fmaxx], [0, self.out_ds.fRasterXSize], self.omaxx))) - self.out_ds.fRasterXOrigin + self.out_ds.fRasterYHeight = int(math.ceil(linearScale( + [self.fminy, self.fmaxy], [0, self.out_ds.fRasterYSize], self.omaxy))) - self.out_ds.fRasterYOrigin + + if self.options.verbose: + print("Bounds (output srs):", round(self.ominx, 13), + self.ominy, self.omaxx, self.omaxy) + + # print("Input Raster Size: ", self.out_ds.RasterXSize, self.out_ds.RasterYSize) + # print("fmaxx-fminx", self.fmaxx - self.fminx, "omaxx-ominx", self.omaxx - self.ominx, "fmaxy-fminy", self.fmaxy - self.fminy, "omaxy-ominy", self.omaxy - self.ominy) + # print("Full Raster Size: ", self.out_ds.fRasterXSize, self.out_ds.fRasterYSize) + # print("Full Raster Size Raw: ", self.out_ds.fRasterXSizeRaw, self.out_ds.fRasterYSizeRaw) + # print("Raster Origin: ", self.out_ds.fRasterXOrigin, self.out_ds.fRasterYOrigin) + # print("Raster Origin Raw: ", self.out_ds.fRasterXOriginRaw, self.out_ds.fRasterYOriginRaw) + # print("Raster Width Height: ", self.out_ds.fRasterXWidth, self.out_ds.fRasterYHeight) + + # Calculating ranges for tiles in different zoom levels + if self.options.profile == 'mercator': + + self.mercator = GlobalMercator() + + # Function which generates SWNE in LatLong for given tile + self.tileswne = self.mercator.TileLatLonBounds + + # Generate table with min max tile coordinates for all zoomlevels + self.tminmax = list(range(0, 32)) + for tz in range(0, 32): + tminx, tminy = self.mercator.MetersToTile( + self.ominx, self.ominy, tz) + tmaxx, tmaxy = self.mercator.MetersToTile( + self.omaxx, self.omaxy, tz) + # crop tiles extending world limits (+-180,+-90) + tminx, tminy = max(0, tminx), max(0, tminy) + tmaxx, tmaxy = min(2**tz-1, tmaxx), min(2**tz-1, tmaxy) + self.tminmax[tz] = (tminx, tminy, tmaxx, tmaxy) + + # TODO: Maps crossing 180E (Alaska?) + + # Get the minimal zoom level (map covers area equivalent to one tile) + if self.tminz is None: + self.tminz = self.mercator.ZoomForPixelSize( + self.out_gt[1] * max(self.out_ds.RasterXSize, + self.out_ds.RasterYSize) / float(self.tilesize)) + + # Get the maximal zoom level + # (closest possible zoom level up on the resolution of raster) + if self.tmaxz is None: + self.tmaxz = self.mercator.ZoomForPixelSize(self.out_gt[1]) + + if self.options.verbose: + print("Bounds (latlong):", + self.mercator.MetersToLatLon(self.ominx, self.ominy), + self.mercator.MetersToLatLon(self.omaxx, self.omaxy)) + print('MinZoomLevel:', self.tminz) + print("MaxZoomLevel:", + self.tmaxz, + "(", + self.mercator.Resolution(self.tmaxz), + ")") + + if self.options.profile == 'geodetic': + + self.geodetic = GlobalGeodetic(self.options.tmscompatible) + + # Function which generates SWNE in LatLong for given tile + self.tileswne = self.geodetic.TileLatLonBounds + + # Generate table with min max tile coordinates for all zoomlevels + self.tminmax = list(range(0, 32)) + for tz in range(0, 32): + tminx, tminy = self.geodetic.LonLatToTile( + self.ominx, self.ominy, tz) + tmaxx, tmaxy = self.geodetic.LonLatToTile( + self.omaxx, self.omaxy, tz) + # crop tiles extending world limits (+-180,+-90) + tminx, tminy = max(0, tminx), max(0, tminy) + tmaxx, tmaxy = min(2**(tz+1)-1, tmaxx), min(2**tz-1, tmaxy) + self.tminmax[tz] = (tminx, tminy, tmaxx, tmaxy) + + # TODO: Maps crossing 180E (Alaska?) + + # Get the maximal zoom level + # (closest possible zoom level up on the resolution of raster) + if self.tminz is None: + self.tminz = self.geodetic.ZoomForPixelSize( + self.out_gt[1] * max(self.out_ds.RasterXSize, + self.out_ds.RasterYSize) / float(self.tilesize)) + + # Get the maximal zoom level + # (closest possible zoom level up on the resolution of raster) + if self.tmaxz is None: + self.tmaxz = self.geodetic.ZoomForPixelSize(self.out_gt[1]) + + if self.options.verbose: + print("Bounds (latlong):", self.ominx, + self.ominy, self.omaxx, self.omaxy) + + # MMGIS + if self.options.profile == 'raster' and self.isRasterBounded: + + def log2(x): + return math.log10(x) / math.log10(2) + + # MMGIS added 'f'* + self.nativezoom = int( + max(math.ceil(log2(self.out_ds.fRasterXSizeRaw/float(self.tilesize))), + math.ceil(log2(self.out_ds.fRasterYSizeRaw/float(self.tilesize))))) + + self.basenativezoom = int( + max(math.ceil(log2(self.out_ds.fRasterXSize/float(self.tilesize))), + math.ceil(log2(self.out_ds.fRasterYSize/float(self.tilesize))))) + + # MMGIS + self.out_ds.fWorldXSize = int( + float(self.out_ds.fRasterXSize) * (2**(self.nativezoom - self.basenativezoom))) + self.out_ds.fWorldYSize = int( + float(self.out_ds.fRasterYSize) * (2**(self.nativezoom - self.basenativezoom))) + self.out_ds.fRasterXOriginWorld = int(float( + self.out_ds.fWorldXSize) * (float(self.out_ds.fRasterXOrigin) / self.out_ds.fRasterXSize)) + self.out_ds.fRasterYOriginWorld = int(float( + self.out_ds.fWorldYSize) * (float(self.out_ds.fRasterYOrigin) / self.out_ds.fRasterYSize)) + self.out_ds.fRasterXSizeWorld = int(float( + self.out_ds.fWorldXSize) * (float(self.out_ds.fRasterXWidth) / self.out_ds.fRasterXSize)) + self.out_ds.fRasterYSizeWorld = int(float( + self.out_ds.RasterYSize) * (float(self.out_ds.fRasterXSizeWorld) / self.out_ds.RasterXSize)) + # print("World Size", self.out_ds.fWorldXSize, self.out_ds.fWorldYSize) + # print("Raster Origin World", self.out_ds.fRasterXOriginWorld, self.out_ds.fRasterYOriginWorld) + # print("Raster Size World", self.out_ds.fRasterXSizeWorld, self.out_ds.fRasterYSizeWorld) + + if self.options.verbose: + print("Native zoom of the raster:", self.nativezoom) + + # Get the minimal zoom level (whole raster in one tile) + if self.tminz is None: + self.tminz = 0 + + # Get the maximal zoom level (native resolution of the raster) + if self.tmaxz is None: + self.tmaxz = self.nativezoom + + # MMGIS added 'f'* + # Generate table with min max tile coordinates for all zoomlevels + self.tminmax = list(range(0, self.tmaxz+1)) + self.tsize = list(range(0, self.tmaxz+1)) + # print("Raster Size:", self.out_ds.RasterXSize,self.out_ds.RasterYSize) + # print("Pixel Size Ratio:", (self.out_ds.fPixelSize / self.out_ds.PixelSize)) + # print("nativezoom", self.nativezoom, "basenativezoom", self.basenativezoom, "tminz", self.tminz, "tmaxz", self.tmaxz) + for tz in range(0, self.tmaxz+1): + tsize = 2.0**(self.tmaxz-tz)*self.tilesize + toffsetx = int(math.floor( + 2.0**(tz) * self.out_ds.fRasterXOriginRaw / self.out_ds.fRasterXSizeRaw)) + toffsety = int(math.floor( + 2.0**(tz) * (self.out_ds.fRasterYOriginRaw) / self.out_ds.fRasterYSizeRaw)) + # print("tsize", tsize, "toffsetx", toffsetx, "toffsety", toffsety) + toffsetx = int(math.floor( + self.out_ds.fRasterXOriginWorld / tsize)) + toffsety = int(math.floor( + self.out_ds.fRasterYOriginWorld / tsize)) + # print("tsize", tsize, "toffsetx", toffsetx, "toffsety", toffsety) + tmaxx = int(math.floor( + self.out_ds.fRasterXSizeWorld / tsize)) + toffsetx + 1 + + tmaxy = int(math.floor( + self.out_ds.fRasterYSizeWorld / tsize)) + toffsety + 1 + self.tsize[tz] = math.ceil(tsize) + #tminx = toffsetx + tminx = int(tmaxx - ((tmaxx - toffsetx) / (0.75))) - 1 + tminy = int(tmaxy - ((tmaxy - toffsety) / (0.75))) - 1 + + self.tminmax[tz] = (tminx, tminy, tmaxx, tmaxy) + # print("tminx", tminx, "tminy", tminy, "tmaxx", tmaxx, "tmaxy", tmaxy, "tz", tz) + + elif self.options.profile == 'raster': + + def log2(x): + return math.log10(x) / math.log10(2) + self.nativezoom = int( + max(math.ceil(log2(self.out_ds.RasterXSize/float(self.tilesize))), + math.ceil(log2(self.out_ds.RasterYSize/float(self.tilesize))))) + + if self.options.verbose: + print("Native zoom of the raster:", self.nativezoom) + + # Get the minimal zoom level (whole raster in one tile) + if self.tminz is None: + self.tminz = 0 + + # Get the maximal zoom level (native resolution of the raster) + if self.tmaxz is None: + self.tmaxz = self.nativezoom + + # Generate table with min max tile coordinates for all zoomlevels + self.tminmax = list(range(0, self.tmaxz+1)) + self.tsize = list(range(0, self.tmaxz+1)) + for tz in range(0, self.tmaxz+1): + tsize = 2.0**(self.tmaxz-tz)*self.tilesize + tminx, tminy = 0, 0 + tmaxx = int(math.ceil(self.out_ds.RasterXSize / tsize)) - 1 + tmaxy = int(math.ceil(self.out_ds.RasterYSize / tsize)) - 1 + self.tsize[tz] = math.ceil(tsize) + self.tminmax[tz] = (tminx, tminy, tmaxx, tmaxy) + + # Function which generates SWNE in LatLong for given tile + if self.kml and in_srs_wkt: + ct = osr.CoordinateTransformation(in_srs, srs4326) + + def rastertileswne(x, y, z): + # X-pixel size in level + pixelsizex = (2**(self.tmaxz-z) * self.out_gt[1]) + west = self.out_gt[0] + x*self.tilesize*pixelsizex + east = west + self.tilesize*pixelsizex + south = self.ominy + y*self.tilesize*pixelsizex + north = south + self.tilesize*pixelsizex + if not isepsg4326: + # Transformation to EPSG:4326 (WGS84 datum) + west, south = ct.TransformPoint(west, south)[:2] + east, north = ct.TransformPoint(east, north)[:2] + return south, west, north, east + + self.tileswne = rastertileswne + else: + self.tileswne = lambda x, y, z: (0, 0, 0, 0) # noqa + + def generate_metadata(self): + """ + Generation of main metadata files and HTML viewers (metadata related to particular + tiles are generated during the tile processing). + """ + + if not os.path.exists(self.output): + os.makedirs(self.output) + + if self.options.profile == 'mercator': + + south, west = self.mercator.MetersToLatLon(self.ominx, self.ominy) + north, east = self.mercator.MetersToLatLon(self.omaxx, self.omaxy) + south, west = max(-85.05112878, south), max(-180.0, west) + north, east = min(85.05112878, north), min(180.0, east) + self.swne = (south, west, north, east) + + # Generate googlemaps.html + if self.options.webviewer in ('all', 'google') and self.options.profile == 'mercator': + if (not self.options.resume or not + os.path.exists(os.path.join(self.output, 'googlemaps.html'))): + f = open(os.path.join(self.output, 'googlemaps.html'), 'wb') + f.write(self.generate_googlemaps().encode('utf-8')) + f.close() + + # Generate openlayers.html + if self.options.webviewer in ('all', 'openlayers'): + if (not self.options.resume or not + os.path.exists(os.path.join(self.output, 'openlayers.html'))): + f = open(os.path.join(self.output, 'openlayers.html'), 'wb') + f.write(self.generate_openlayers().encode('utf-8')) + f.close() + + # Generate leaflet.html + if self.options.webviewer in ('all', 'leaflet'): + if (not self.options.resume or not + os.path.exists(os.path.join(self.output, 'leaflet.html'))): + f = open(os.path.join(self.output, 'leaflet.html'), 'wb') + f.write(self.generate_leaflet().encode('utf-8')) + f.close() + + elif self.options.profile == 'geodetic': + + west, south = self.ominx, self.ominy + east, north = self.omaxx, self.omaxy + south, west = max(-90.0, south), max(-180.0, west) + north, east = min(90.0, north), min(180.0, east) + self.swne = (south, west, north, east) + + # Generate openlayers.html + if self.options.webviewer in ('all', 'openlayers'): + if (not self.options.resume or not + os.path.exists(os.path.join(self.output, 'openlayers.html'))): + f = open(os.path.join(self.output, 'openlayers.html'), 'wb') + f.write(self.generate_openlayers().encode('utf-8')) + f.close() + + elif self.options.profile == 'raster': + + west, south = self.ominx, self.ominy + east, north = self.omaxx, self.omaxy + + # MMGIS + if self.isRasterBounded: + west = self.fminx + east = self.fmaxx + south = self.fminy + north = self.fmaxy + + self.swne = (south, west, north, east) + + # Generate openlayers.html + if self.options.webviewer in ('all', 'openlayers'): + if (not self.options.resume or not + os.path.exists(os.path.join(self.output, 'openlayers.html'))): + f = open(os.path.join(self.output, 'openlayers.html'), 'wb') + f.write(self.generate_openlayers().encode('utf-8')) + f.close() + + # Generate tilemapresource.xml. + if not self.options.resume or not os.path.exists(os.path.join(self.output, 'tilemapresource.xml')): + f = open(os.path.join(self.output, 'tilemapresource.xml'), 'wb') + f.write(self.generate_tilemapresource().encode('utf-8')) + f.close() + + if self.kml: + # TODO: Maybe problem for not automatically generated tminz + # The root KML should contain links to all tiles in the tminz level + children = [] + xmin, ymin, xmax, ymax = self.tminmax[self.tminz] + for x in range(xmin, xmax+1): + for y in range(ymin, ymax+1): + children.append([x, y, self.tminz]) + # Generate Root KML + if self.kml: + if (not self.options.resume or not + os.path.exists(os.path.join(self.output, 'doc.kml'))): + f = open(os.path.join(self.output, 'doc.kml'), 'wb') + f.write(self.generate_kml( + None, None, None, children).encode('utf-8')) + f.close() + + def generate_base_tiles(self, tz): + """ + Generation of the base tiles (the lowest in the pyramid) directly from the input raster + """ + + if self.isDEMtile: + print("Generating Tiles at Zoom " + str(tz) + ": ") + + if not self.options.quiet: + print("Generating Base Tiles:") + + if self.options.verbose: + print('') + print("Tiles generated from the max zoom level:") + print("----------------------------------------") + print('') + + ds = self.out_ds + + querysize = self.querysize + + # 1bto4b + if self.isDEMtile: + tilebands = 4 + querysize = self.tilesize + else: + tilebands = self.dataBandsCount + 1 + tz = self.tmaxz + + try: + self.tminmax[tz] + except IndexError: + print(" Won't make zoom level " + str(tz)) + return + + # Set the bounds + tminx, tminy, tmaxx, tmaxy = self.tminmax[tz] + + if self.options.verbose: + print("dataBandsCount: ", self.dataBandsCount) + print("tilebands: ", tilebands) + + tcount = (1+abs(tmaxx-tminx)) * (1+abs(tmaxy-tminy)) + ti = 0 + + for ty in range(tmaxy, tminy-1, -1): + for tx in range(tminx, tmaxx+1): + + if self.stopped: + break + ti += 1 + tilefilename = os.path.join( + self.output, str(tz), str(tx), "%s.%s" % (ty, self.tileext)) + if self.options.verbose: + print(ti, '/', tcount, tilefilename) + + if self.options.resume and os.path.exists(tilefilename): + if self.options.verbose: + print("Tile generation skipped because of --resume") + else: + self.progressbar(ti / float(tcount)) + continue + + # Create directories for the tile + if not os.path.exists(os.path.dirname(tilefilename)): + os.makedirs(os.path.dirname(tilefilename)) + + if self.options.profile == 'mercator': + # Tile bounds in EPSG:3857 + b = self.mercator.TileBounds(tx, ty, tz) + elif self.options.profile == 'geodetic': + b = self.geodetic.TileBounds(tx, ty, tz) + + # Don't scale up by nearest neighbour, better change the querysize + # to the native resolution (and return smaller query tile) for scaling + + if self.options.profile in ('mercator', 'geodetic'): + rb, wb = self.geo_query(ds, b[0], b[3], b[2], b[1]) + + # Pixel size in the raster covering query geo extent + nativesize = wb[0] + wb[2] + if self.options.verbose: + print("\tNative Extent (querysize", + nativesize, "): ", rb, wb) + + # Tile bounds in raster coordinates for ReadRaster query + rb, wb = self.geo_query( + ds, b[0], b[3], b[2], b[1], querysize=querysize) + + rx, ry, rxsize, rysize = rb + wx, wy, wxsize, wysize = wb + wxsize -= 1 # 1bto4b + wysize -= 1 # 1bto4b + + # MMGIS + elif self.isRasterBounded: # 'raster' profile: + + # tilesize in raster coordinates for actual zoom + tsize = int(self.tsize[tz]) + xsize = self.out_ds.fWorldXSize + ysize = self.out_ds.fWorldYSize + if tz >= self.tmaxz: + querysize = self.tilesize + + rx = (tx) * tsize - self.out_ds.fRasterXOriginWorld + #print("rx", rx) + rxsize = 0 + rxsize = tsize + + rysize = 0 + rysize = tsize + + ry = ysize - (ty * tsize) - rysize - \ + self.out_ds.fRasterYOriginWorld + + wx, wy = 0, 0 + wxsize = int(rxsize/float(tsize) * self.tilesize) + wysize = int(rysize/float(tsize) * self.tilesize) + if wysize != self.tilesize: + wy = self.tilesize - wysize + + if rx < 0: + rxsize = tsize + rx + wx = -rx + wxsize = int(rxsize/float(tsize) * self.tilesize) + rx = 0 + if ry < 0: + rysize = tsize + ry + wy = -ry + wysize = int(rysize/float(tsize) * self.tilesize) + ry = 0 + if rx + rxsize > self.out_ds.fRasterXSizeWorld: + rxsize = self.out_ds.fRasterXSizeWorld - rx + wxsize = int(rxsize/float(tsize) * self.tilesize) + if ry + rysize > self.out_ds.fRasterYSizeWorld: + rysize = self.out_ds.fRasterYSizeWorld - ry + wysize = int(rysize/float(tsize) * self.tilesize) + + # Convert rx, ry back to non-world coordinates + rx = int(float(self.out_ds.RasterXSize) * + (float(rx) / self.out_ds.fRasterXSizeWorld)) + ry = int(float(self.out_ds.RasterYSize) * + (float(ry) / self.out_ds.fRasterYSizeWorld)) + rxsize = int(float(self.out_ds.RasterXSize) * + (float(rxsize) / self.out_ds.fRasterXSizeWorld)) + rysize = int(float(self.out_ds.RasterYSize) * + (float(rysize) / self.out_ds.fRasterYSizeWorld)) + + wxsize -= 1 # 1bto4b + wysize -= 1 # 1bto4b + + #print("Extent: ", (tx, ty, tz, tsize), (rx, ry, rxsize, rysize), (wx, wy, wxsize, wysize), (self.out_ds.fRasterXOrigin, self.out_ds.fRasterYOrigin)) + else: # 'raster' profile: + # tilesize in raster coordinates for actual zoom + tsize = int(self.tsize[tz]) + xsize = self.out_ds.RasterXSize # size of the raster in pixels + ysize = self.out_ds.RasterYSize + if tz >= self.tmaxz: + querysize = self.tilesize + + rx = (tx) * tsize + rxsize = 0 + if tx == tmaxx: + rxsize = xsize % tsize + if rxsize == 0: + rxsize = tsize + + rysize = 0 + if ty == tmaxy: + rysize = ysize % tsize + if rysize == 0: + rysize = tsize + ry = ysize - (ty * tsize) - rysize + + wx, wy = 0, 0 + wxsize = int(rxsize/float(tsize) * self.tilesize) + wysize = int(rysize/float(tsize) * self.tilesize) + if wysize != self.tilesize: + wy = self.tilesize - wysize + + if self.options.verbose: + print("\tReadRaster Extent: ", + (rx, ry, rxsize, rysize), (wx, wy, wxsize, wysize)) + + # Query is in 'nearest neighbour' but can be bigger in then the tilesize + # We scale down the query to the tilesize by supplied algorithm. + + # Tile dataset in memory + + # 1bto4b + if self.isDEMtile: + dstile = self.mem_drv.Create( + '', self.tilesize, self.tilesize, tilebands, gdal.GDT_Byte) + else: + dstile = self.mem_drv.Create( + '', self.tilesize, self.tilesize, tilebands) + + data = alpha = None + # Read the source raster if anything is going inside the tile as per the computed + # geo_query + if rxsize != 0 and rysize != 0 and wxsize != 0 and wysize != 0: + # 1bto4b + if self.isDEMtile: + data = ds.GetRasterBand(1).ReadRaster( + rx, ry, rxsize, rysize, wxsize, wysize, buf_type=gdal.GDT_Float32) + else: + data = ds.ReadRaster(rx, ry, rxsize, rysize, wxsize, wysize, + band_list=list(range(1, self.dataBandsCount+1))) + alpha = self.alphaband.ReadRaster( + rx, ry, rxsize, rysize, wxsize, wysize) + + # The tile in memory is a transparent file by default. Write pixel values into it if + # any + if data: + # 1bto4b - both this full if and else + if self.isDEMtile: + if (wxsize * wysize) > 0: + data = struct.unpack('f' * wxsize * wysize, data) + else: + return + + if self.tilesize == querysize: + # Interpolate the values from four surrounding + + # This takes our 1d list of WxH data and pads it with a rect of none values + dataPad = list(data) + for i in reversed(range(1, wysize)): + dataPad.insert(wxsize * i, 0) + dataPad.insert(wxsize * i, 0) + for i in range(wxsize + 3): + dataPad.insert(0, 0) + for i in range(wxsize + 3): + dataPad.append(0) + + dataIn = [] + # Resample based on average of four + # averaging over: i, i + 1, i + wxsize, i + wxsize + 1 + for y in range(wysize+2 - 1): + for x in range(wxsize+2 - 1): + i = x+(y*(wxsize+2)) + nW = dataPad[i] + nE = dataPad[i+1] + sW = dataPad[i+(wxsize+2)] + sE = dataPad[i+(wxsize+2)+1] + dataIn.append((nW + nE + sW + sE)/float(4)) + + # Get the surrounding eight tiles + # Get NW + if tx - 1 >= tminx and ty + 1 <= tmaxy: + rxNW, ryNW, rxsizeNW, rysizeNW, wxsizeNW, wysizeNW = getTilePxBounds(self, + tx - 1, ty + 1, tz, ds) + wxsizeNW -= 1 + wysizeNW -= 1 + if wxsizeNW != 0 and wysizeNW != 0: + dataNW = ds.GetRasterBand(1).ReadRaster( + rxNW, ryNW, rxsizeNW, rysizeNW, wxsizeNW, wysizeNW, buf_type=gdal.GDT_Float32) + if dataNW is not None and (wxsizeNW * wysizeNW) > 0: + dataNW = struct.unpack( + 'f' * wxsizeNW * wysizeNW, dataNW) + else: + dataNW = None + else: + dataNW = None + + # Get N + if ty + 1 <= tmaxy: + rxN, ryN, rxsizeN, rysizeN, wxsizeN, wysizeN = getTilePxBounds( + self, tx, ty + 1, tz, ds) + wxsizeN -= 1 + wysizeN -= 1 + if wxsizeN != 0 and wysizeN != 0: + dataN = ds.GetRasterBand(1).ReadRaster( + rxN, ryN, rxsizeN, rysizeN, wxsizeN, wysizeN, buf_type=gdal.GDT_Float32) + if dataN is not None and (wxsizeN * wysizeN) > 0: + dataN = struct.unpack( + 'f' * wxsizeN * wysizeN, dataN) + else: + dataN = None + else: + dataN = None + # Get NE + if tx + 1 <= tmaxx and ty + 1 <= tmaxy: + rxNE, ryNE, rxsizeNE, rysizeNE, wxsizeNE, wysizeNE = getTilePxBounds( + self, tx + 1, ty + 1, tz, ds) + wxsizeNE -= 1 + wysizeNE -= 1 + if wxsizeNE != 0 and wysizeNE != 0: + dataNE = ds.GetRasterBand(1).ReadRaster( + rxNE, ryNE, rxsizeNE, rysizeNE, wxsizeNE, wysizeNE, buf_type=gdal.GDT_Float32) + if dataNE is not None and (wxsizeNE * wysizeNE) > 0: + dataNE = struct.unpack( + 'f' * wxsizeNE * wysizeNE, dataNE) + else: + dataNE = None + else: + dataNE = None + # Get E + if tx + 1 <= tmaxx: + rxE, ryE, rxsizeE, rysizeE, wxsizeE, wysizeE = getTilePxBounds( + self, tx + 1, ty, tz, ds) + wxsizeE -= 1 + wysizeE -= 1 + if wxsizeE != 0 and wysizeE != 0: + dataE = ds.GetRasterBand(1).ReadRaster( + rxE, ryE, rxsizeE, rysizeE, wxsizeE, wysizeE, buf_type=gdal.GDT_Float32) + if dataE is not None and (wxsizeE * wysizeE) > 0: + dataE = struct.unpack( + 'f' * wxsizeE * wysizeE, dataE) + else: + dataE = None + else: + dataE = None + # Get SE + if tx + 1 <= tmaxx and ty - 1 >= tminy: + rxSE, rySE, rxsizeSE, rysizeSE, wxsizeSE, wysizeSE = getTilePxBounds( + self, tx + 1, ty - 1, tz, ds) + wxsizeSE -= 1 + wysizeSE -= 1 + if wxsizeSE != 0 and wysizeSE != 0: + dataSE = ds.GetRasterBand(1).ReadRaster( + rxSE, rySE, rxsizeSE, rysizeSE, wxsizeSE, wysizeSE, buf_type=gdal.GDT_Float32) + if dataSE is not None and (wxsizeSE * wysizeSE) > 0: + dataSE = struct.unpack( + 'f' * wxsizeSE * wysizeSE, dataSE) + else: + dataSE = None + else: + dataSE = None + # Get S + if ty - 1 >= tminy: + rxS, ryS, rxsizeS, rysizeS, wxsizeS, wysizeS = getTilePxBounds( + self, tx, ty - 1, tz, ds) + wxsizeS -= 1 + wysizeS -= 1 + if wxsizeS != 0 and wysizeS != 0: + dataS = ds.GetRasterBand(1).ReadRaster( + rxS, ryS, rxsizeS, rysizeS, wxsizeS, wysizeS, buf_type=gdal.GDT_Float32) + if dataS is not None and (wxsizeS * wysizeS) > 0: + dataS = struct.unpack( + 'f' * wxsizeS * wysizeS, dataS) + else: + dataS = None + else: + dataS = None + # Get SW + if tx - 1 >= tminx and ty - 1 >= tminy: + rxSW, rySW, rxsizeSW, rysizeSW, wxsizeSW, wysizeSW = getTilePxBounds( + self, tx - 1, ty - 1, tz, ds) + wxsizeSW -= 1 + wysizeSW -= 1 + if wxsizeSW != 0 and wysizeSW != 0: + dataSW = ds.GetRasterBand(1).ReadRaster( + rxSW, rySW, rxsizeSW, rysizeSW, wxsizeSW, wysizeSW, buf_type=gdal.GDT_Float32) + if dataSW is not None and (wxsizeSW * wysizeSW) > 0: + dataSW = struct.unpack( + 'f' * wxsizeSW * wysizeSW, dataSW) + else: + dataSW = None + else: + dataSW = None + # Get W + if tx - 1 >= tminx: + rxW, ryW, rxsizeW, rysizeW, wxsizeW, wysizeW = getTilePxBounds( + self, tx - 1, ty, tz, ds) + wxsizeW -= 1 + wysizeW -= 1 + if wxsizeW != 0 and wysizeW != 0: + dataW = ds.GetRasterBand(1).ReadRaster( + rxW, ryW, rxsizeW, rysizeW, wxsizeW, wysizeW, buf_type=gdal.GDT_Float32) + if dataW is not None and (wxsizeW * wysizeW) > 0: + dataW = struct.unpack( + 'f' * wxsizeW * wysizeW, dataW) + else: + dataW = None + else: + dataW = None + + # NW (uses N, NW, W) + fN = fNE = fE = fSE = fS = fSW = fW = fNW = 0 + values = 1 + if dataN is not None: + fN = dataN[len(dataN)-wxsizeN] + values = values + 1 + if dataNW is not None: + fNW = dataNW[len(dataNW)-1] + values = values + 1 + if dataW is not None: + fW = dataW[wxsizeW-1] + values = values + 1 + dataIn[0] = ((dataIn[0]*4) + fN + + fNW + fW)/float(values) + + # NE (uses N, NE, E) + fN = fNE = fE = fSE = fS = fSW = fW = fNW = 0 + values = 1 + if dataN is not None: + fN = dataN[len(dataN)-1] + values = values + 1 + if dataNE is not None: + fNE = dataNE[len(dataNE)-wxsizeNE] + values = values + 1 + if dataE is not None: + fE = dataE[0] + values = values + 1 + dataIn[wxsize] = ( + (dataIn[wxsize]*4) + fN + fNE + fE)/float(values) + + # SE (uses S, SE, E) + fN = fNE = fE = fSE = fS = fSW = fW = fNW = 0 + values = 1 + if dataS is not None: + fS = dataS[wxsizeS-1] + values = values + 1 + if dataSE is not None: + fSE = dataSE[0] + values = values + 1 + if dataE is not None: + fE = dataE[len(dataE)-wxsizeE] + values = values + 1 + dataIn[len(dataIn)-1] = ((dataIn[len(dataIn)-1] + * 4) + fS + fSE + fE)/float(values) + + # SW (uses S, SW, W) + fN = fNE = fE = fSE = fS = fSW = fW = fNW = 0 + values = 1 + if dataS is not None: + fS = dataS[0] + values = values + 1 + if dataSW is not None: + fSW = dataSW[wxsizeSW-1] + values = values + 1 + if dataW is not None: + fW = dataW[len(dataW)-1] + values = values + 1 + dataIn[len( + dataIn)-wxsize-1] = ((dataIn[len(dataIn)-wxsize-1]*4) + fS + fSW + fW)/float(values) + + # Then the edges minus corners + # N + if dataN is not None: + for i in range(1, wxsize): + dataIn[i] = ( + (dataIn[i]*4) + dataN[len(dataN)-wxsizeN-1+i] + dataN[len(dataN)-wxsizeN-1+i+1])/float(4) + else: + for i in range(1, wxsize): + dataIn[i] = (dataIn[i]*4)/float(2) + + # E + if dataE is not None: + for i in range(1, wysize): + dataIn[((i+1)*(wxsize+1)-1)] = ((dataIn[((i+1)*(wxsize+1)-1)] + * 4) + dataE[(i-1)*wxsizeE] + dataE[i*wxsizeE])/float(4) + else: + for i in range(1, wysize): + dataIn[( + (i+1)*(wxsize+1)-1)] = (dataIn[((i+1)*(wxsize+1)-1)]*4)/float(2) + + # S + if dataS is not None: + for i in range(1, wxsize): + dataIn[len(dataIn)-wxsize-1+i] = ( + (dataIn[len(dataIn)-wxsize-1+i]*4) + dataS[i-1] + dataS[i])/float(4) + else: + for i in range(1, wxsize): + dataIn[len( + dataIn)-wxsize-1+i] = (dataIn[len(dataIn)-wxsize-1+i]*4)/float(2) + + # W + if dataW is not None: + for i in range(1, wysize): + dataIn[(i)*(wxsize+1)] = ((dataIn[(i)*(wxsize+1)]*4) + + dataW[i*wxsizeW-1] + dataW[(i+1)*wxsizeW-1])/float(4) + else: + for i in range(1, wysize): + dataIn[(i)*(wxsize+1)] = (dataIn[(i) + * (wxsize+1)]*4)/float(2) + + data1 = [] + data2 = [] + data3 = [] + data4 = [] + for f in dataIn: + f = str(binary(f)) + data1.append(int(f[:8], 2)) + data2.append(int(f[8:16], 2)) + data3.append(int(f[16:24], 2)) + data4.append(int(f[24:], 2)) + + data1s = '' + data2s = '' + data3s = '' + data4s = '' + indx = 0 + for v in data1: + data1s += struct.pack('B', data1[indx]) + data2s += struct.pack('B', data2[indx]) + data3s += struct.pack('B', data3[indx]) + data4s += struct.pack('B', data4[indx]) + indx += 1 + dstile.GetRasterBand(1).WriteRaster( + wx, wy, wxsize + 1, wysize + 1, data1s, buf_type=gdal.GDT_Byte) + dstile.GetRasterBand(2).WriteRaster( + wx, wy, wxsize + 1, wysize + 1, data2s, buf_type=gdal.GDT_Byte) + dstile.GetRasterBand(3).WriteRaster( + wx, wy, wxsize + 1, wysize + 1, data3s, buf_type=gdal.GDT_Byte) + dstile.GetRasterBand(4).WriteRaster( + wx, wy, wxsize + 1, wysize + 1, data4s, buf_type=gdal.GDT_Byte) + elif wxsize != 0 and wysize != 0: + # Big ReadRaster query in memory scaled to the tilesize - all but 'near' algo + dsquery = self.mem_drv.Create( + '', querysize, querysize, tilebands, gdal.GDT_Byte) # 1bto4b + # TODO: fill the null value in case a tile without alpha is produced (now only png tiles are supported) + # for i in range(1, tilebands+1): + # dsquery.GetRasterBand(1).Fill(tilenodata) + # dsquery.WriteRaster(wx, wy, wxsize, wysize, data, band_list=list(range(1,self.dataBandsCount+1)))###############1bto4b + # dsquery.WriteRaster(wx, wy, wxsize, wysize, alpha, band_list=[tilebands])###############################1bto4b + + # 1bto4b + data = ds.GetRasterBand(1).ReadRaster( + rx, ry, rxsize, rysize, wxsize, wysize, buf_type=gdal.GDT_Float32) + + data = struct.unpack('f' * wxsize * wysize, data) + data1 = [] + data2 = [] + data3 = [] + data4 = [] + for f in data: + f = str(binary(f)) + data1.append(int(f[:8], 2)) + data2.append(int(f[8:16], 2)) + data3.append(int(f[16:24], 2)) + data4.append(int(f[24:], 2)) + + data1s = '' + data2s = '' + data3s = '' + data4s = '' + indx = 0 + for v in data1: + data1s += struct.pack('B', data1[indx]) + data2s += struct.pack('B', data2[indx]) + data3s += struct.pack('B', data3[indx]) + data4s += struct.pack('B', data4[indx]) + indx += 1 + + dsquery.GetRasterBand(1).WriteRaster( + wx, wy, wxsize, wysize, data1s, buf_type=gdal.GDT_Byte) + dsquery.GetRasterBand(2).WriteRaster( + wx, wy, wxsize, wysize, data2s, buf_type=gdal.GDT_Byte) + dsquery.GetRasterBand(3).WriteRaster( + wx, wy, wxsize, wysize, data3s, buf_type=gdal.GDT_Byte) + dsquery.GetRasterBand(4).WriteRaster( + wx, wy, wxsize, wysize, data4s, buf_type=gdal.GDT_Byte) + # sys.exit('done') + # 1bto4b + + self.scale_query_to_tile( + dsquery, dstile, tilefilename) + del dsquery + + else: + if self.tilesize == querysize: + # Use the ReadRaster result directly in tiles ('nearest neighbour' query) + dstile.WriteRaster(wx, wy, wxsize, wysize, data, + band_list=list(range(1, self.dataBandsCount+1))) + dstile.WriteRaster( + wx, wy, wxsize, wysize, alpha, band_list=[tilebands]) + + # Note: For source drivers based on WaveLet compression (JPEG2000, ECW, + # MrSID) the ReadRaster function returns high-quality raster (not ugly + # nearest neighbour) + # TODO: Use directly 'near' for WaveLet files + else: + # Big ReadRaster query in memory scaled to the tilesize - all but 'near' + # algo + dsquery = self.mem_drv.Create( + '', querysize, querysize, tilebands) + # TODO: fill the null value in case a tile without alpha is produced (now + # only png tiles are supported) + dsquery.WriteRaster(wx, wy, wxsize, wysize, data, + band_list=list(range(1, self.dataBandsCount+1))) + dsquery.WriteRaster( + wx, wy, wxsize, wysize, alpha, band_list=[tilebands]) + + self.scale_query_to_tile( + dsquery, dstile, tilefilename) + del dsquery + + del data + + if self.options.resampling != 'antialias': + # Write a copy of tile to png/jpg + self.out_drv.CreateCopy(tilefilename, dstile, strict=0) + + del dstile + + # Create a KML file for this tile. + if self.kml: + kmlfilename = os.path.join( + self.output, str(tz), str(tx), '%d.kml' % ty) + if not self.options.resume or not os.path.exists(kmlfilename): + f = open(kmlfilename, 'wb') + f.write(self.generate_kml(tx, ty, tz).encode('utf-8')) + f.close() + + if not self.options.verbose and not self.options.quiet: + self.progressbar(ti / float(tcount)) + + def generate_overview_tiles(self): + """Generation of the overview tiles (higher in the pyramid) based on existing tiles""" + + if not self.options.quiet: + print("Generating Overview Tiles:") + + # 1bto4b + if self.isDEMtile: + tilebands = 4 + else: + tilebands = self.dataBandsCount + 1 + + # Usage of existing tiles: from 4 underlying tiles generate one as overview. + + tcount = 0 + for tz in range(self.tmaxz-1, self.tminz-1, -1): + tminx, tminy, tmaxx, tmaxy = self.tminmax[tz] + tcount += (1+abs(tmaxx-tminx)) * (1+abs(tmaxy-tminy)) + + ti = 0 + + for tz in range(self.tmaxz-1, self.tminz-1, -1): + tminx, tminy, tmaxx, tmaxy = self.tminmax[tz] + for ty in range(tmaxy, tminy-1, -1): + for tx in range(tminx, tmaxx+1): + + if self.stopped: + break + + ti += 1 + tilefilename = os.path.join(self.output, + str(tz), + str(tx), + "%s.%s" % (ty, self.tileext)) + + if self.options.verbose: + print(ti, '/', tcount, tilefilename) + + if self.options.resume and os.path.exists(tilefilename): + if self.options.verbose: + print("Tile generation skipped because of --resume") + else: + self.progressbar(ti / float(tcount)) + continue + + # Create directories for the tile + if not os.path.exists(os.path.dirname(tilefilename)): + os.makedirs(os.path.dirname(tilefilename)) + + dsquery = self.mem_drv.Create( + '', 2*self.tilesize, 2*self.tilesize, tilebands) + # TODO: fill the null value + dstile = self.mem_drv.Create( + '', self.tilesize, self.tilesize, tilebands) + + # TODO: Implement more clever walking on the tiles with cache functionality + # probably walk should start with reading of four tiles from top left corner + # Hilbert curve + + children = [] + # Read the tiles and write them to query window + for y in range(2*ty, 2*ty+2): + for x in range(2*tx, 2*tx+2): + minx, miny, maxx, maxy = self.tminmax[tz+1] + if x >= minx and x <= maxx and y >= miny and y <= maxy: + dsquerytile = gdal.Open( + os.path.join(self.output, str(tz+1), str(x), + "%s.%s" % (y, self.tileext)), + gdal.GA_ReadOnly) + if (ty == 0 and y == 1) or (ty != 0 and (y % (2*ty)) != 0): + tileposy = 0 + else: + tileposy = self.tilesize + if tx: + tileposx = x % (2*tx) * self.tilesize + elif tx == 0 and x == 1: + tileposx = self.tilesize + else: + tileposx = 0 + dsquery.WriteRaster( + tileposx, tileposy, self.tilesize, self.tilesize, + dsquerytile.ReadRaster( + 0, 0, self.tilesize, self.tilesize), + band_list=list(range(1, tilebands+1))) + children.append([x, y, tz+1]) + + self.scale_query_to_tile(dsquery, dstile, tilefilename) + # Write a copy of tile to png/jpg + if self.options.resampling != 'antialias': + # Write a copy of tile to png/jpg + self.out_drv.CreateCopy(tilefilename, dstile, strict=0) + + if self.options.verbose: + print("\tbuild from zoom", tz+1, + " tiles:", (2*tx, 2*ty), (2*tx+1, 2*ty), + (2*tx, 2*ty+1), (2*tx+1, 2*ty+1)) + + # Create a KML file for this tile. + if self.kml: + f = open(os.path.join( + self.output, '%d/%d/%d.kml' % (tz, tx, ty)), 'wb') + f.write(self.generate_kml( + tx, ty, tz, children).encode('utf-8')) + f.close() + + if not self.options.verbose and not self.options.quiet: + self.progressbar(ti / float(tcount)) + + def geo_query(self, ds, ulx, uly, lrx, lry, querysize=0): + """ + For given dataset and query in cartographic coordinates returns parameters for ReadRaster() + in raster coordinates and x/y shifts (for border tiles). If the querysize is not given, the + extent is returned in the native resolution of dataset ds. + + raises Gdal2TilesError if the dataset does not contain anything inside this geo_query + """ + geotran = ds.GetGeoTransform() + rx = int((ulx - geotran[0]) / geotran[1] + 0.001) + ry = int((uly - geotran[3]) / geotran[5] + 0.001) + rxsize = int((lrx - ulx) / geotran[1] + 0.5) + rysize = int((lry - uly) / geotran[5] + 0.5) + + if not querysize: + wxsize, wysize = rxsize, rysize + else: + wxsize, wysize = querysize, querysize + + # Coordinates should not go out of the bounds of the raster + wx = 0 + if rx < 0: + rxshift = abs(rx) + wx = int(wxsize * (float(rxshift) / rxsize)) + wxsize = wxsize - wx + rxsize = rxsize - int(rxsize * (float(rxshift) / rxsize)) + rx = 0 + if rx+rxsize > ds.RasterXSize: + wxsize = int(wxsize * (float(ds.RasterXSize - rx) / rxsize)) + rxsize = ds.RasterXSize - rx + + wy = 0 + if ry < 0: + ryshift = abs(ry) + wy = int(wysize * (float(ryshift) / rysize)) + wysize = wysize - wy + rysize = rysize - int(rysize * (float(ryshift) / rysize)) + ry = 0 + if ry+rysize > ds.RasterYSize: + wysize = int(wysize * (float(ds.RasterYSize - ry) / rysize)) + rysize = ds.RasterYSize - ry + + return (rx, ry, rxsize, rysize), (wx, wy, wxsize, wysize) + + def scale_query_to_tile(self, dsquery, dstile, tilefilename=''): + """Scales down query dataset to the tile dataset""" + + querysize = dsquery.RasterXSize + tilesize = dstile.RasterXSize + tilebands = dstile.RasterCount + + if self.options.resampling == 'average': + + # Function: gdal.RegenerateOverview() + for i in range(1, tilebands+1): + # Black border around NODATA + res = gdal.RegenerateOverview(dsquery.GetRasterBand(i), dstile.GetRasterBand(i), + 'average') + if res != 0: + self.error("RegenerateOverview() failed on %s, error %d" % ( + tilefilename, res)) + + elif self.options.resampling == 'antialias': + + # Scaling by PIL (Python Imaging Library) - improved Lanczos + array = numpy.zeros((querysize, querysize, tilebands), numpy.uint8) + for i in range(tilebands): + array[:, :, i] = gdalarray.BandReadAsArray(dsquery.GetRasterBand(i+1), + 0, 0, querysize, querysize) + im = Image.fromarray(array, 'RGBA') # Always four bands + im1 = im.resize((tilesize, tilesize), Image.ANTIALIAS) + if os.path.exists(tilefilename): + im0 = Image.open(tilefilename) + im1 = Image.composite(im1, im0, im1) + im1.save(tilefilename, self.tiledriver) + + else: + + # Other algorithms are implemented by gdal.ReprojectImage(). + dsquery.SetGeoTransform((0.0, tilesize / float(querysize), 0.0, 0.0, 0.0, + tilesize / float(querysize))) + dstile.SetGeoTransform((0.0, 1.0, 0.0, 0.0, 0.0, 1.0)) + + res = gdal.ReprojectImage( + dsquery, dstile, None, None, self.resampling) + if res != 0: + self.error("ReprojectImage() failed on %s, error %d" % + (tilefilename, res)) + + def generate_tilemapresource(self): + """ + Template for tilemapresource.xml. Returns filled string. Expected variables: + title, north, south, east, west, isepsg4326, projection, publishurl, + zoompixels, tilesize, tileformat, profile + """ + + args = {} + args['title'] = self.options.title + args['south'], args['west'], args['north'], args['east'] = self.swne + args['tilesize'] = self.tilesize + args['tileformat'] = self.tileext + args['publishurl'] = self.options.url + args['profile'] = self.options.profile + + if self.options.profile == 'mercator': + args['srs'] = "EPSG:3857" + elif self.options.profile == 'geodetic': + args['srs'] = "EPSG:4326" + elif self.options.s_srs: + args['srs'] = self.options.s_srs + elif self.out_srs: + args['srs'] = self.out_srs.ExportToWkt() + else: + args['srs'] = "" + + s = """ + + %(title)s + + %(srs)s + + + + +""" % args # noqa + for z in range(self.tminz, self.tmaxz+1): + if self.options.profile == 'raster': + s += """ \n""" % ( + args['publishurl'], z, (2**(self.nativezoom-z) * self.out_gt[1]), z) + elif self.options.profile == 'mercator': + s += """ \n""" % ( + args['publishurl'], z, 156543.0339/2**z, z) + elif self.options.profile == 'geodetic': + s += """ \n""" % ( + args['publishurl'], z, 0.703125/2**z, z) + s += """ + + """ + return s + + def generate_kml(self, tx, ty, tz, children=None, **args): + """ + Template for the KML. Returns filled string. + """ + if not children: + children = [] + + args['tx'], args['ty'], args['tz'] = tx, ty, tz + args['tileformat'] = self.tileext + if 'tilesize' not in args: + args['tilesize'] = self.tilesize + + if 'minlodpixels' not in args: + args['minlodpixels'] = int(args['tilesize'] / 2) + if 'maxlodpixels' not in args: + args['maxlodpixels'] = int(args['tilesize'] * 8) + if children == []: + args['maxlodpixels'] = -1 + + if tx is None: + tilekml = False + args['title'] = self.options.title + else: + tilekml = True + args['title'] = "%d/%d/%d.kml" % (tz, tx, ty) + args['south'], args['west'], args['north'], args['east'] = self.tileswne( + tx, ty, tz) + + if tx == 0: + args['drawOrder'] = 2 * tz + 1 + elif tx is not None: + args['drawOrder'] = 2 * tz + else: + args['drawOrder'] = 0 + + url = self.options.url + if not url: + if tilekml: + url = "../../" + else: + url = "" + + s = """ + + + %(title)s + + """ % args + if tilekml: + s += """ + + + %(north).14f + %(south).14f + %(east).14f + %(west).14f + + + %(minlodpixels)d + %(maxlodpixels)d + + + + %(drawOrder)d + + %(ty)d.%(tileformat)s + + + %(north).14f + %(south).14f + %(east).14f + %(west).14f + + + """ % args + + for cx, cy, cz in children: + csouth, cwest, cnorth, ceast = self.tileswne(cx, cy, cz) + s += """ + + %d/%d/%d.%s + + + %.14f + %.14f + %.14f + %.14f + + + %d + -1 + + + + %s%d/%d/%d.kml + onRegion + + + + """ % (cz, cx, cy, args['tileformat'], cnorth, csouth, ceast, cwest, + args['minlodpixels'], url, cz, cx, cy) + + s += """ + + """ + return s + + def generate_googlemaps(self): + """ + Template for googlemaps.html implementing Overlay of tiles for 'mercator' profile. + It returns filled string. Expected variables: + title, googlemapskey, north, south, east, west, minzoom, maxzoom, tilesize, tileformat, + publishurl + """ + args = {} + args['title'] = self.options.title + args['googlemapskey'] = self.options.googlekey + args['south'], args['west'], args['north'], args['east'] = self.swne + args['minzoom'] = self.tminz + args['maxzoom'] = self.tmaxz + args['tilesize'] = self.tilesize + args['tileformat'] = self.tileext + args['publishurl'] = self.options.url + args['copyright'] = self.options.copyright + + s = r""" + + + %(title)s + + + + + + + + +
    Generated by GDAL2Tiles, Copyright © 2008 Klokan Petr Pridal, GDAL & OSGeo GSoC + +
    +
    + + + """ % args # noqa + + return s + + def generate_leaflet(self): + """ + Template for leaflet.html implementing overlay of tiles for 'mercator' profile. + It returns filled string. Expected variables: + title, north, south, east, west, minzoom, maxzoom, tilesize, tileformat, publishurl + """ + + args = {} + args['title'] = self.options.title.replace('"', '\\"') + args['htmltitle'] = self.options.title + args['south'], args['west'], args['north'], args['east'] = self.swne + args['centerlon'] = (args['north'] + args['south']) / 2. + args['centerlat'] = (args['west'] + args['east']) / 2. + args['minzoom'] = self.tminz + args['maxzoom'] = self.tmaxz + args['beginzoom'] = self.tmaxz + args['tilesize'] = self.tilesize # not used + args['tileformat'] = self.tileext + args['publishurl'] = self.options.url # not used + args['copyright'] = self.options.copyright.replace('"', '\\"') + + s = """ + + + + + %(htmltitle)s + + + + + + + + + + +
    + + + + + + + """ % args # noqa + + return s + + def generate_openlayers(self): + """ + Template for openlayers.html implementing overlay of available Spherical Mercator layers. + + It returns filled string. Expected variables: + title, bingkey, north, south, east, west, minzoom, maxzoom, tilesize, tileformat, publishurl + """ + + args = {} + args['title'] = self.options.title + args['bingkey'] = self.options.bingkey + args['south'], args['west'], args['north'], args['east'] = self.swne + args['minzoom'] = self.tminz + args['maxzoom'] = self.tmaxz + args['tilesize'] = self.tilesize + args['tileformat'] = self.tileext + args['publishurl'] = self.options.url + args['copyright'] = self.options.copyright + if self.options.tmscompatible: + args['tmsoffset'] = "-1" + else: + args['tmsoffset'] = "" + if self.options.profile == 'raster': + args['rasterzoomlevels'] = self.tmaxz+1 + args['rastermaxresolution'] = 2**(self.nativezoom) * self.out_gt[1] + + s = r""" + + %(title)s + + """ % args # noqa + + if self.options.profile == 'mercator': + s += """ + + """ % args + + s += """ + + + + + +
    Generated by GDAL2Tiles, Copyright © 2008 Klokan Petr Pridal, GDAL & OSGeo GSoC + +
    +
    + + + """ % args # noqa + + return s + + +def main(): + argv = gdal.GeneralCmdLineProcessor(sys.argv) + if argv: + gdal2tiles = GDAL2Tiles(argv[1:]) + gdal2tiles.process() + + +if __name__ == '__main__': + main() + +# vim: set tabstop=4 shiftwidth=4 expandtab: From e3a59e8da7a3ab00f956b28be725d7776750f606 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 9 Dec 2021 18:22:00 -0800 Subject: [PATCH 52/85] #114 Image and Model markerAttachments --- config/js/config.js | 25 +++- docs/pages/markdowns/Kinds.md | 35 +++++ docs/pages/markdowns/Layers_Tab.md | 98 +++++++++++-- package-lock.json | 4 +- .../Basics/Layers_/LayerConstructors.js | 130 ++++++++++++++++++ src/essence/Basics/Map_/Map_.js | 4 + src/essence/Tools/Layers/LayersTool.js | 6 +- 7 files changed, 285 insertions(+), 17 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index bc0c33d4..79ebd48b 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2767,14 +2767,33 @@ function layerPopulateVariable(modalId, layerType) { angleUnit: "deg || rad", color: "#888888", }, - rover: { - image: - "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", + image: { + initialVisibility: true, + path: "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", + pathProp: "path to image. take priority over path", widthMeters: 2.6924, widthPixels: 420, heightPixels: 600, angleProp: "path.to.angle.prop", angleUnit: "deg || rad", + show: "click || always", + }, + model: { + path: "path to model (.dae, .glb, .gltf, .obj)", + pathProp: "path to model. take priority over path", + mtlPath: "if .obj, path to material file (.mtl)", + yawProp: "path.to.yaw.prop", + yawUnit: "deg || rad", + invertYaw: false, + pitchProp: "path.to.pitch.prop", + pitchUnit: "deg || rad", + invertPitch: true, + rollProp: "path.to.roll.prop", + rollUnit: "deg || rad", + invertRoll: false, + elevationProp: "path.to.elev.prop", + scaleProp: "path.to.scale.prop", + show: "click || always", }, }; currentLayerVars.datasetLinks = currentLayerVars.datasetLinks || [ diff --git a/docs/pages/markdowns/Kinds.md b/docs/pages/markdowns/Kinds.md index 23bdecd2..82b7712d 100644 --- a/docs/pages/markdowns/Kinds.md +++ b/docs/pages/markdowns/Kinds.md @@ -15,6 +15,41 @@ Works just like the None Kind but automatically opens the Info Tool too (if it's This Kind is very specific to the Curiosity Rover and only works on point features. It takes hardcoded rover dimensions, `public/images/rovers/CuriosityTopDownOrthoSmall.png` and the geojson feature property `yaw_rad` to orient a to scale Curiosity Rover image under the clicked point. +The Waypoint Kind only applies to point features and uses the `markerAttachments.image` and `markerAttachments.model` layer raw variables. When `show` is set to "click" (or undefined), clicking on a point will draw an image in the Map and a model in the Globe. Both image and model can be set, scaled and rotated dynamically. The Waypoint Kind is specifically useful for rover images and models. See [Vector Layer Raw Variables](Layers_Tab#raw-variables-2) for more information about the image and model marker attachments. + +```javascript +markerAttachments: { + image: { + initialVisibility: true, + path: "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", + pathProp: "path to image. take priority over path", + widthMeters: 2.6924, + widthPixels: 420, + heightPixels: 600, + angleProp: "path.to.angle.prop", + angleUnit: "deg || rad", + show: "click || always", + }, + model: { + path: "path to mode (.dae, .glb, .gltf, .obj)", + pathProp: "path to model. take priority over path", + mtlPath: "if .obj, path to material file (.mtl)", + yawProp: "path.to.yaw.prop", + yawUnit: "deg || rad", + invertYaw: false, + pitchProp: "path.to.pitch.prop", + pitchUnit: "deg || rad", + invertPitch: true, + rollProp: "path.to.roll.prop", + rollUnit: "deg || rad", + invertRoll: false, + elevationProp: "path.to.elev.prop", + scaleProp: "path.to.scale.prop", + show: "click || always", + } +} +``` + ### Chemistry Tool This Kind is used for the Chemistry Tool. Because chemistry data can be big and it's advise to link to it via a dataset, this Kind waits diff --git a/docs/pages/markdowns/Layers_Tab.md b/docs/pages/markdowns/Layers_Tab.md index 3361c76b..fc1cf571 100644 --- a/docs/pages/markdowns/Layers_Tab.md +++ b/docs/pages/markdowns/Layers_Tab.md @@ -478,15 +478,57 @@ Example: "value": "Prop: {prop}" } ], - "markerBearing": "unit:prop", - "markerBearingColor": "css color", + "markerAttachments": { + "bearing": { + "angleProp": "path.to.angle.prop", + "angleUnit": "deg || rad", + "color": "#FFFFFF", + }, + "uncertainty": { + "initialVisibility": true, + "xAxisProp": "path.to.x.prop", + "yAxisProp": "path.to.y.prop", + "axisUnit": "meters || kilometers", + "angleProp": "path.to.angle.prop", + "angleUnit": "deg || rad", + "color": "#888888", + }, + "image": { + "initialVisibility": true, + "path": "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", + "pathProp": "path to image. take priority over path", + "widthMeters": 2.6924, + "widthPixels": 420, + "heightPixels": 600, + "angleProp": "path.to.angle.prop", + "angleUnit": "deg || rad", + "show": "click || always", + }, + "model": { + "path": "path to model (.dae, .glb, .gltf, .obj)", + "pathProp": "path to model. take priority over path", + "mtlPath": "if .obj, path to material file (.mtl)", + "yawProp": "path.to.yaw.prop", + "yawUnit": "deg || rad", + "invertYaw": false, + "pitchProp": "path.to.pitch.prop", + "pitchUnit": "deg || rad", + "invertPitch": true, + "rollProp": "path.to.roll.prop", + "rollUnit": "deg || rad", + "invertRoll": false, + "elevationProp": "path.to.elev.prop", + "scaleProp": "path.to.scale.prop", + "show": "click || always", + }, + }, "markerIcon": { //See: https://leafletjs.com/reference-1.7.1.html#icon-l-icon - iconUrl: "pathToMainIconImage.png", - shadowUrl: "(opt)pathToShadowImage.png", - iconSize: [38, 95], // size of the icon - shadowSize: [50, 64], // size of the shadow - iconAnchor: [22, 94], // point of the icon which will correspond to marker's location - shadowAnchor: [4, 62], // the same for the shadow + "iconUrl": "pathToMainIconImage.png", + "shadowUrl": "(opt)pathToShadowImage.png", + "iconSize": [38, 95], // size of the icon + "shadowSize": [50, 64], // size of the shadow + "iconAnchor": [22, 94], // point of the icon which will correspond to marker's location + "shadowAnchor": [4, 62], // the same for the shadow }. "search": "(prop1) round(prop2.1) rmunder(prop_3)" } @@ -506,7 +548,45 @@ Example: - `icon`: Any [Material Design Icon](http://materialdesignicons.com/) name - `value`: A name to display. All `{prop}`s will be replaced by their corresponding `features[which].properties[prop]` value. - `markerBearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). `{unit}` is either `deg` or `rad` and `{prop}` is the dot notated path to the feature properties that contains the desired rotation angle. Ex. `deg:headings.yaw`. -- `markerBearingColor`: A css color for the directional arrow for non-markerIcon bearings. +- `markerAttachments`: An object for attaching dynamic items to point features. + - `bearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). Overrides the layer's shape dropdown value. + - `angleProp`: The dot notated path to the feature properties that contains the desired rotation angle. Ex. `headings.yaw`. + - `angleUnit`: Unit of the value of `angleProp`. Either `deg` or `rad`. + - `color`: A css color for the directional arrow for non-markerIcon bearings. + - `uncertainty`: A sublayer feature that places ellipses about point features to indicate positional uncertainty + - `initialVisibility`: Whether the uncertainty sublayer is initially on. Users can toggle sublayers on and off in the layer settings in the LayersTool. + - `xAxisProp`: Prop path to the x axis radius value of the ellipse. + - `yAxisProp`: Prop path to the y axis radius value of the ellipse. + - `axisUnit`: "meters || kilometers", + - `angleProp`: Prop path to the rotation of the ellipse. + - `angleUnit`: "deg || rad" + - `color`: A css fill color. Will be made more transparent than set. + - `image`: Places a scaled and orientated image under each marker. A sublayer. + - `initialVisibility`: Whether the image sublayer is initially on. Users can toggle sublayers on and off in the layer settings in the LayersTool. + - `path`: A url to a (preferably) top-down north-facing orthographic image. + - `pathProp`: A prop path to an image url. Take priority over path. Useful if the path is feature specific. + - `widthMeters`: Width of image in meters in order to calculate scale. + - `widthPixels`: Image width in pixels. + - `heightPixels`: Image height in pixel. + - `angleProp`: Prop path to the rotation of the image. + - `angleUnit`: "deg || rad" + - `show`: "click || always". If set to "always", overrides the Waypoints Kind (if set) and always renders the image under the marker. "click" just shows the image on click and requires the layer to have the Waypoints Kind. + - `model`: + - `path`: Path to model (.dae, .glb, .gltf, .obj) + - `pathProp`: A prop path to a model. Takes priority over path. Useful if model is feature specific. + - `mtlPath`: If .obj, the path to its material file (.mtl) + - `yawProp`: Prop path to the model's yaw. If this value is a number, uses it directly. + - `yawUnit`: "deg || rad" + - `invertYaw`: Boolean that, if true, multiplies yaw by -1. + - `pitchProp`: Prop path to the model's pitch. If this value is a number, uses it directly. + - `pitchUnit`: "deg || rad" + - `invertPitch`: Boolean that, if true, multiplies pitch by -1. + - `rollProp`: Prop path to the model's roll. If this value is a number, uses it directly. + - `rollUnit`: "deg || rad" + - `invertRoll`: Boolean that, if true, multiplies roll by -1. + - `elevationProp`: Prop path to the model's elevation (in meters). If this value is a number, uses it directly. Default 0. + - `scaleProp`: Prop path to the model's scale. If this value is a number, uses it directly. Default 1. + - `show`: "click || always", - `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. If you're using this as a bearing marker, make sure the base icon is pointing north. - `search`: This requires the "Minimalist" option in the Look Tab to be unchecked. When set, this layer will become searchable through the search bar at the top. The search will look for and autocomplete on the properties specified. All properties are enclosed by parentheses and space-separated. `round` can be used like a function to round the property beforehand. `rmunder` works similarly but removes all underscores instead. diff --git a/package-lock.json b/package-lock.json index c119f3ce..dccd3f5a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11900,7 +11900,7 @@ "node_modules/lithosphere": { "version": "1.0.6", "resolved": "file:../../npm-local/lithosphere-1.0.6.tgz", - "integrity": "sha512-rgMjuzso8eUmJ+raWP68d+i3VP2UOux4fvm+GoYyxJe2B1KyBd3qgycqTWF6gmGqFM0/ziUJxthlzm74PBGL1w==", + "integrity": "sha512-4e6i6EFRV8BzuGXCet2Yj14RYFp4rnoXkEm/s8ALuADzD9Bt+mDO/PJceKovUPPKtPg6fA6mdOjpEbHycoSm+w==", "license": "Apache-2.0", "dependencies": { "@turf/boolean-intersects": "^6.3.0", @@ -30330,7 +30330,7 @@ }, "lithosphere": { "version": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", - "integrity": "sha512-rgMjuzso8eUmJ+raWP68d+i3VP2UOux4fvm+GoYyxJe2B1KyBd3qgycqTWF6gmGqFM0/ziUJxthlzm74PBGL1w==", + "integrity": "sha512-4e6i6EFRV8BzuGXCet2Yj14RYFp4rnoXkEm/s8ALuADzD9Bt+mDO/PJceKovUPPKtPg6fA6mdOjpEbHycoSm+w==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/src/essence/Basics/Layers_/LayerConstructors.js b/src/essence/Basics/Layers_/LayerConstructors.js index 93cc2de8..4cf7b32f 100644 --- a/src/essence/Basics/Layers_/LayerConstructors.js +++ b/src/essence/Basics/Layers_/LayerConstructors.js @@ -258,6 +258,8 @@ export const constructVectorLayer = ( layer = L.marker(latlong, { icon: L.divIcon({ className: `leafletMarkerShape leafletMarkerShape_${layerObj.name + .replace(/\s/g, '') + .toLowerCase()} ${layerObj.name .replace(/\s/g, '') .toLowerCase()}`, iconSize: [ @@ -323,6 +325,7 @@ export const constructVectorLayer = ( } export const constructSublayers = (geojson, layerObj) => { + //UNCERTAINTY const uncertaintyVar = F_.getIn( layerObj, 'variables.markerAttachments.uncertainty' @@ -368,6 +371,123 @@ export const constructSublayers = (geojson, layerObj) => { }, } + // IMAGE + const imageVar = F_.getIn(layerObj, 'variables.markerAttachments.image') + const imageShow = F_.getIn( + layerObj, + 'variables.markerAttachments.image.show', + 'click' + ) + const leafletLayerObjectImageOverlay = { + pointToLayer: (feature, latlong) => { + const path = F_.getIn( + layerObj, + 'variables.markerAttachments.image.path', + 'public/images/rovers/PerseveranceTopDown.png' + ) + let imageSettings = { + image: F_.getIn( + feature.properties, + F_.getIn( + layerObj, + 'variables.markerAttachments.image.pathProp', + path + ), + path + ), + widthMeters: F_.getIn( + layerObj, + 'variables.markerAttachments.image.widthMeters', + 2.6924 + ), + widthPixels: F_.getIn( + layerObj, + 'variables.markerAttachments.image.widthPixels', + 420 + ), + heightPixels: F_.getIn( + layerObj, + 'variables.markerAttachments.image.heightPixels', + 600 + ), + angleProp: F_.getIn( + layerObj, + 'variables.markerAttachments.image.angleProp', + 'yaw_rad' + ), + angleUnit: F_.getIn( + layerObj, + 'variables.markerAttachments.image.angleUnit', + 'rad' + ), + show: F_.getIn( + layerObj, + 'variables.markerAttachments.image.show', + 'click' + ), + } + let wm = parseFloat(imageSettings.widthMeters) + let w = parseFloat(imageSettings.widthPixels) + let h = parseFloat(imageSettings.heightPixels) + let lngM = F_.metersToDegrees(wm) / 2 + let latM = lngM * (h / w) + let center = [latlong.lng, latlong.lat] + let angle = -F_.getIn( + feature.properties, + imageSettings.angleProp, + 0 + ) + if (imageSettings.angleProp === 'deg') + angle = angle * (Math.PI / 180) + + var topLeft = F_.rotatePoint( + { + y: latlong.lat + latM, + x: latlong.lng - lngM, + }, + center, + angle + ) + var topRight = F_.rotatePoint( + { + y: latlong.lat + latM, + x: latlong.lng + lngM, + }, + center, + angle + ) + var bottomRight = F_.rotatePoint( + { + y: latlong.lat - latM, + x: latlong.lng + lngM, + }, + center, + angle + ) + var bottomLeft = F_.rotatePoint( + { + y: latlong.lat - latM, + x: latlong.lng - lngM, + }, + center, + angle + ) + + var anchors = [ + [topLeft.y, topLeft.x], + [topRight.y, topRight.x], + [bottomRight.y, bottomRight.x], + [bottomLeft.y, bottomLeft.x], + ] + return L.layerGroup([ + L.imageTransform(imageSettings.image, anchors, { + opacity: 1, + clip: anchors, + }), + ]) + }, + } + const sublayers = { uncertainty_ellipses: uncertaintyVar ? { @@ -381,6 +501,16 @@ export const constructSublayers = (geojson, layerObj) => { ), } : false, + image_overlays: + imageVar && imageShow === 'always' + ? { + on: + imageVar.initialVisibility != null + ? imageVar.initialVisibility + : true, + layer: L.geoJson(geojson, leafletLayerObjectImageOverlay), + } + : false, } const sublayerArray = [] diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index cd846b4a..12bd20a2 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -1142,14 +1142,18 @@ function enforceVisibilityCutoffs() { if (vc > 0) { if (Map_.map.getZoom() < vc && settingsEnforceVC) { layerElements.attr('display', 'none') + layerElements.style('display', 'none') } else { layerElements.attr('display', 'inherit') + layerElements.style('display', 'inherit') } } else { if (Map_.map.getZoom() > Math.abs(vc) && settingsEnforceVC) { layerElements.attr('display', 'none') + layerElements.style('display', 'none') } else { layerElements.attr('display', 'inherit') + layerElements.style('display', 'inherit') } } } diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index 4df84865..aa504d1c 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -194,6 +194,7 @@ function interfaceWithMMGIS() { currentOpacity = L_.getLayerOpacity(node[i].name) if (currentOpacity == null) currentOpacity = L_.opacityArray[node[i].name] + // prettier-ignore settings = [ '
      ', @@ -206,9 +207,8 @@ function interfaceWithMMGIS() { return [ '
      ', `
      ${F_.prettifyName(s)}
      `, - '
      ', - `
      `, - '
      ', + '
      ', + `
      `, '
      ', '
      ', ].join('\n') From e6871473b681238cfa701072a5cc3e500f4fa68d Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 10 Dec 2021 17:36:24 -0800 Subject: [PATCH 53/85] #114 Model sublayers --- config/js/config.js | 1 + docs/pages/markdowns/Layers_Tab.md | 4 +- package-lock.json | 4 +- .../Basics/Layers_/LayerConstructors.js | 118 ++++++ src/essence/Basics/Layers_/Layers_.js | 88 +++-- src/essence/Basics/Map_/Map_.js | 12 +- src/essence/Tools/Kinds/Kinds.js | 371 +++++++++++++----- 7 files changed, 472 insertions(+), 126 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 79ebd48b..32bfe26d 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2794,6 +2794,7 @@ function layerPopulateVariable(modalId, layerType) { elevationProp: "path.to.elev.prop", scaleProp: "path.to.scale.prop", show: "click || always", + onlyLastN: false, }, }; currentLayerVars.datasetLinks = currentLayerVars.datasetLinks || [ diff --git a/docs/pages/markdowns/Layers_Tab.md b/docs/pages/markdowns/Layers_Tab.md index fc1cf571..77909f27 100644 --- a/docs/pages/markdowns/Layers_Tab.md +++ b/docs/pages/markdowns/Layers_Tab.md @@ -520,6 +520,7 @@ Example: "elevationProp": "path.to.elev.prop", "scaleProp": "path.to.scale.prop", "show": "click || always", + "onlyLastN": false }, }, "markerIcon": { //See: https://leafletjs.com/reference-1.7.1.html#icon-l-icon @@ -586,7 +587,8 @@ Example: - `invertRoll`: Boolean that, if true, multiplies roll by -1. - `elevationProp`: Prop path to the model's elevation (in meters). If this value is a number, uses it directly. Default 0. - `scaleProp`: Prop path to the model's scale. If this value is a number, uses it directly. Default 1. - - `show`: "click || always", + - `show`: "click || always" + - `onlyLastN`: If false, shows models at all points. If a number, only shows models for the last n points. - `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. If you're using this as a bearing marker, make sure the base icon is pointing north. - `search`: This requires the "Minimalist" option in the Look Tab to be unchecked. When set, this layer will become searchable through the search bar at the top. The search will look for and autocomplete on the properties specified. All properties are enclosed by parentheses and space-separated. `round` can be used like a function to round the property beforehand. `rmunder` works similarly but removes all underscores instead. diff --git a/package-lock.json b/package-lock.json index dccd3f5a..89c64f28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11900,7 +11900,7 @@ "node_modules/lithosphere": { "version": "1.0.6", "resolved": "file:../../npm-local/lithosphere-1.0.6.tgz", - "integrity": "sha512-4e6i6EFRV8BzuGXCet2Yj14RYFp4rnoXkEm/s8ALuADzD9Bt+mDO/PJceKovUPPKtPg6fA6mdOjpEbHycoSm+w==", + "integrity": "sha512-TktL4ciNuXoO2fl9aRr4/SdWC/G59sWtkQ7TrXFW8aUWD8Exn+ZDMSU3UreN5rX0zK4Kw1zFU4nXH35tCFrOew==", "license": "Apache-2.0", "dependencies": { "@turf/boolean-intersects": "^6.3.0", @@ -30330,7 +30330,7 @@ }, "lithosphere": { "version": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", - "integrity": "sha512-4e6i6EFRV8BzuGXCet2Yj14RYFp4rnoXkEm/s8ALuADzD9Bt+mDO/PJceKovUPPKtPg6fA6mdOjpEbHycoSm+w==", + "integrity": "sha512-TktL4ciNuXoO2fl9aRr4/SdWC/G59sWtkQ7TrXFW8aUWD8Exn+ZDMSU3UreN5rX0zK4Kw1zFU4nXH35tCFrOew==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/src/essence/Basics/Layers_/LayerConstructors.js b/src/essence/Basics/Layers_/LayerConstructors.js index 4cf7b32f..233514ff 100644 --- a/src/essence/Basics/Layers_/LayerConstructors.js +++ b/src/essence/Basics/Layers_/LayerConstructors.js @@ -488,6 +488,112 @@ export const constructSublayers = (geojson, layerObj) => { }, } + // MODEL + const modelVar = F_.getIn(layerObj, 'variables.markerAttachments.model') + const modelShow = F_.getIn(modelVar, 'show', 'click') + const modelPositions = [] + const modelRotations = [] + const modelScales = [] + + const modelSettings = { + model: F_.getIn(modelVar, 'path', null), + mtlPath: F_.getIn(modelVar, 'mtlPath', null), + yawProp: F_.getIn(modelVar, 'yawProp', 0), + yawUnit: F_.getIn(modelVar, 'yawUnit', 'rad'), + invertYaw: F_.getIn(modelVar, 'invertYaw', false), + pitchProp: F_.getIn(modelVar, 'pitchProp', 0), + pitchUnit: F_.getIn(modelVar, 'pitchUnit', 'rad'), + invertPitch: F_.getIn(modelVar, 'invertPitch', false), + rollProp: F_.getIn(modelVar, 'rollProp', 0), + rollUnit: F_.getIn(modelVar, 'rollUnit', 'rad'), + invertRoll: F_.getIn(modelVar, 'invertRoll', false), + elevationProp: F_.getIn(modelVar, 'elevationProp', 0), + scaleProp: F_.getIn(modelVar, 'scaleProp', 1), + show: F_.getIn(modelVar, 'show', 'click'), + onlyLastN: F_.getIn(modelVar, 'onlyLastN', false), + } + let modelOptions + + if (modelSettings.model && modelSettings.show === 'always') { + if ( + !F_.isUrlAbsolute(modelSettings.model) && + !modelSettings.model.startsWith('public') + ) + modelSettings.model = L_.missionPath + modelSettings.model + + geojson.features.forEach((f, idx) => { + if (typeof modelSettings.onlyLastN === 'number') { + if (idx < geojson.features.length - modelSettings.onlyLastN) + return + } + + if (f.geometry.type.toLowerCase() === 'point') { + const coords = f.geometry.coordinates + const position = { + latitude: coords[1], + longitude: coords[0], + elevation: + typeof modelSettings.elevationProp === 'number' + ? modelSettings.elevationProp + : F_.getIn( + f.properties, + modelSettings.elevationProp, + coords[2] + ), + } + + const rotation = { + y: + typeof modelSettings.yawProp === 'number' + ? modelSettings.yawProp + : F_.getIn(f.properties, modelSettings.yawProp, 0), + x: + typeof modelSettings.pitchProp === 'number' + ? modelSettings.pitchProp + : F_.getIn( + f.properties, + modelSettings.pitchProp, + 0 + ), + z: + typeof modelSettings.rollProp === 'number' + ? modelSettings.rollProp + : F_.getIn(f.properties, modelSettings.rollProp, 0), + } + if (modelSettings.yawUnit === 'deg') rotation.y *= Math.PI / 180 + if (modelSettings.invertYaw) rotation.y *= -1 + if (modelSettings.pitchUnit === 'deg') + rotation.x *= Math.PI / 180 + if (modelSettings.invertPitch) rotation.x *= -1 + if (modelSettings.rollUnit === 'deg') + rotation.z *= Math.PI / 180 + if (modelSettings.invertRoll) rotation.z *= -1 + + const scale = + typeof modelSettings.scaleProp === 'number' + ? modelSettings.scaleProp + : F_.getIn(f.properties, modelSettings.scaleProp, 1) + + modelPositions.push(position) + modelRotations.push(rotation) + modelScales.push(scale) + } + }) + + modelOptions = { + name: `markerAttachmentModel_${layerObj.name}`, + order: 99999, + on: true, + path: modelSettings.model, + mtlPath: modelSettings.mtlPath, + opacity: 1, + isArrayed: true, + position: modelPositions, + rotation: modelRotations, + scale: modelScales, + } + } + const sublayers = { uncertainty_ellipses: uncertaintyVar ? { @@ -511,6 +617,18 @@ export const constructSublayers = (geojson, layerObj) => { layer: L.geoJson(geojson, leafletLayerObjectImageOverlay), } : false, + models: + modelVar && modelShow === 'always' && modelOptions + ? { + on: + modelVar.initialVisibility != null + ? modelVar.initialVisibility + : true, + type: 'model', + layerId: modelOptions.name, + modelOptions: modelOptions, + } + : false, } const sublayerArray = [] diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 9ab0f5c1..04db7c28 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -193,9 +193,18 @@ var L_ = { L_.Map_.map.removeLayer(L_.layersGroup[s.name]) if (L_.layersGroupSublayers[s.name]) { for (let sub in L_.layersGroupSublayers[s.name]) { - L_.Map_.rmNotNull( - L_.layersGroupSublayers[s.name][sub].layer - ) + if ( + L_.layersGroupSublayers[s.name][sub].type === + 'model' + ) { + L_.Globe_.litho.removeLayer( + L_.layersGroupSublayers[s.name][sub].layerId + ) + } else { + L_.Map_.rmNotNull( + L_.layersGroupSublayers[s.name][sub].layer + ) + } } } } @@ -207,16 +216,28 @@ var L_ = { if (L_.layersGroupSublayers[s.name]) { for (let sub in L_.layersGroupSublayers[s.name]) { if (L_.layersGroupSublayers[s.name][sub].on) { - L_.Map_.map.addLayer( - L_.layersGroupSublayers[s.name][sub].layer - ) - L_.layersGroupSublayers[s.name][ - sub - ].layer.setZIndex( - L_.layersOrdered.length + - 1 - - L_.layersOrdered.indexOf(s.name) - ) + if ( + L_.layersGroupSublayers[s.name][sub] + .type === 'model' + ) { + L_.Globe_.litho.addLayer( + 'model', + L_.layersGroupSublayers[s.name][sub] + .modelOptions + ) + } else { + L_.Map_.map.addLayer( + L_.layersGroupSublayers[s.name][sub] + .layer + ) + L_.layersGroupSublayers[s.name][ + sub + ].layer.setZIndex( + L_.layersOrdered.length + + 1 - + L_.layersOrdered.indexOf(s.name) + ) + } } } } @@ -366,15 +387,23 @@ var L_ = { const sublayer = sublayers[sublayerName] if (sublayer) { if (sublayer.on === true) { - L_.Map_.rmNotNull(sublayer.layer) + if (sublayer.type === 'model') { + L_.Globe_.litho.removeLayer(sublayer.layerId) + } else { + L_.Map_.rmNotNull(sublayer.layer) + } sublayer.on = false } else { - L_.Map_.map.addLayer(sublayer.layer) - sublayer.layer.setZIndex( - L_.layersOrdered.length + - 1 - - L_.layersOrdered.indexOf(layerName) - ) + if (sublayer.type === 'model') { + L_.Globe_.litho.addLayer('model', sublayer.modelOptions) + } else { + L_.Map_.map.addLayer(sublayer.layer) + sublayer.layer.setZIndex( + L_.layersOrdered.length + + 1 - + L_.layersOrdered.indexOf(layerName) + ) + } sublayer.on = true } } @@ -438,16 +467,19 @@ var L_ = { for (let s in L_.layersGroupSublayers[ L_.layersData[i].name ]) { - if ( + const sublayer = L_.layersGroupSublayers[ L_.layersData[i].name - ][s].on - ) { - map.addLayer( - L_.layersGroupSublayers[ - L_.layersData[i].name - ][s].layer - ) + ][s] + if (sublayer.on) { + if (sublayer.type === 'model') { + L_.Globe_.litho.addLayer( + 'model', + sublayer.modelOptions + ) + } else { + map.addLayer(sublayer.layer) + } } } } diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 12bd20a2..60dfa70f 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -363,12 +363,18 @@ let Map_ = { L_.layersGroupSublayers[L_.layersOrdered[hasIndex[i]]][ s ].on - ) - Map_.map.addLayer( + ) { + if ( L_.layersGroupSublayers[ L_.layersOrdered[hasIndex[i]] - ][s].layer + ][s].type !== 'model' ) + Map_.map.addLayer( + L_.layersGroupSublayers[ + L_.layersOrdered[hasIndex[i]] + ][s].layer + ) + } } } diff --git a/src/essence/Tools/Kinds/Kinds.js b/src/essence/Tools/Kinds/Kinds.js index 57b00581..7be1b323 100644 --- a/src/essence/Tools/Kinds/Kinds.js +++ b/src/essence/Tools/Kinds/Kinds.js @@ -19,108 +19,295 @@ var Kinds = { const layerVar = L_.layersNamed[layer.options.layerName].variables + // Remove temp layers + Map_.rmNotNull(Map_.tempOverlayImage) + L_.Globe_.litho.removeLayer('markerAttachmentTempModel') + switch (kind.toLowerCase()) { case 'info': useInfo(true) break case 'waypoint': - let roverSettings = { - image: F_.getIn( + // Add image overlay + if (F_.getIn(layerVar, 'markerAttachments.image', false)) { + const path = F_.getIn( layerVar, - 'markerAttachments.rover.image', + 'markerAttachments.image.path', 'public/images/rovers/PerseveranceTopDown.png' - ), - widthMeters: F_.getIn( - layerVar, - 'markerAttachments.rover.widthMeters', - 2.6924 - ), - widthPixels: F_.getIn( - layerVar, - 'markerAttachments.rover.widthPixels', - 420 - ), - heightPixels: F_.getIn( - layerVar, - 'markerAttachments.rover.heightPixels', - 600 - ), - angleProp: F_.getIn( - layerVar, - 'markerAttachments.rover.angleProp', - 'yaw_rad' - ), - angleUnit: F_.getIn( - layerVar, - 'markerAttachments.rover.angleUnit', - 'rad' - ), + ) + let roverSettings = { + image: F_.getIn( + layer.feature.properties, + F_.getIn( + layerVar, + 'markerAttachments.image.pathProp', + path + ), + path + ), + widthMeters: F_.getIn( + layerVar, + 'markerAttachments.image.widthMeters', + 2.6924 + ), + widthPixels: F_.getIn( + layerVar, + 'markerAttachments.image.widthPixels', + 420 + ), + heightPixels: F_.getIn( + layerVar, + 'markerAttachments.image.heightPixels', + 600 + ), + angleProp: F_.getIn( + layerVar, + 'markerAttachments.image.angleProp', + 'yaw_rad' + ), + angleUnit: F_.getIn( + layerVar, + 'markerAttachments.image.angleUnit', + 'rad' + ), + show: F_.getIn( + layerVar, + 'markerAttachments.image.show', + 'click' + ), + } + if ( + !F_.isUrlAbsolute(roverSettings.image) && + !roverSettings.image.startsWith('public') + ) + roverSettings.image = + L_.missionPath + roverSettings.image + if (roverSettings.image && roverSettings.show === 'click') { + //Make rover image curiosity + let wm = parseFloat(roverSettings.widthMeters) + let w = parseFloat(roverSettings.widthPixels) + let h = parseFloat(roverSettings.heightPixels) + let lngM = F_.metersToDegrees(wm) / 2 + let latM = lngM * (h / w) + let center = [layer._latlng.lng, layer._latlng.lat] + let angle = -F_.getIn( + layer.feature.properties, + roverSettings.angleProp, + 0 + ) + if (roverSettings.angleProp === 'deg') + angle = angle * (Math.PI / 180) + + var topLeft = F_.rotatePoint( + { + y: layer._latlng.lat + latM, + x: layer._latlng.lng - lngM, + }, + center, + angle + ) + var topRight = F_.rotatePoint( + { + y: layer._latlng.lat + latM, + x: layer._latlng.lng + lngM, + }, + center, + angle + ) + var bottomRight = F_.rotatePoint( + { + y: layer._latlng.lat - latM, + x: layer._latlng.lng + lngM, + }, + center, + angle + ) + var bottomLeft = F_.rotatePoint( + { + y: layer._latlng.lat - latM, + x: layer._latlng.lng - lngM, + }, + center, + angle + ) + + var anchors = [ + [topLeft.y, topLeft.x], + [topRight.y, topRight.x], + [bottomRight.y, bottomRight.x], + [bottomLeft.y, bottomLeft.x], + ] + + try { + Map_.tempOverlayImage = L.imageTransform( + roverSettings.image, + anchors, + { opacity: 1, clip: anchors } + ) + Map_.tempOverlayImage.addTo(Map_.map).bringToBack() + } catch (err) {} + } } - //Make rover image curiosity - Map_.rmNotNull(Map_.tempOverlayImage) - //256 x 338, 256 is 2.8m - let wm = parseFloat(roverSettings.widthMeters) - let w = parseFloat(roverSettings.widthPixels) - let h = parseFloat(roverSettings.heightPixels) - let lngM = F_.metersToDegrees(wm) / 2 - let latM = lngM * (h / w) - let center = [layer._latlng.lng, layer._latlng.lat] - let angle = -F_.getIn( - layer.feature.properties, - roverSettings.angleProp, - 0 - ) - if (roverSettings.angleProp === 'deg') - angle = angle * (Math.PI / 180) - - var topLeft = F_.rotatePoint( - { - y: layer._latlng.lat + latM, - x: layer._latlng.lng - lngM, - }, - center, - angle - ) - var topRight = F_.rotatePoint( - { - y: layer._latlng.lat + latM, - x: layer._latlng.lng + lngM, - }, - center, - angle - ) - var bottomRight = F_.rotatePoint( - { - y: layer._latlng.lat - latM, - x: layer._latlng.lng + lngM, - }, - center, - angle - ) - var bottomLeft = F_.rotatePoint( - { - y: layer._latlng.lat - latM, - x: layer._latlng.lng - lngM, - }, - center, - angle - ) - var anchors = [ - [topLeft.y, topLeft.x], - [topRight.y, topRight.x], - [bottomRight.y, bottomRight.x], - [bottomLeft.y, bottomLeft.x], - ] - - try { - Map_.tempOverlayImage = L.imageTransform( - roverSettings.image, - anchors, - { opacity: 1, clip: anchors } + // Add model to globe + if (F_.getIn(layerVar, 'markerAttachments.model', false)) { + const path = F_.getIn( + layerVar, + 'markerAttachments.model.path', + null ) - Map_.tempOverlayImage.addTo(Map_.map).bringToBack() - } catch (err) {} + let modelSettings = { + model: F_.getIn( + layer.feature.properties, + F_.getIn( + layerVar, + 'markerAttachments.model.pathProp', + path + ), + path + ), + mtlPath: F_.getIn( + layerVar, + 'markerAttachments.model.mtlPath', + null + ), + yawProp: F_.getIn( + layerVar, + 'markerAttachments.model.yawProp', + 0 + ), + yawUnit: F_.getIn( + layerVar, + 'markerAttachments.model.yawUnit', + 'rad' + ), + invertYaw: F_.getIn( + layerVar, + 'markerAttachments.model.invertYaw', + false + ), + pitchProp: F_.getIn( + layerVar, + 'markerAttachments.model.pitchProp', + 0 + ), + pitchUnit: F_.getIn( + layerVar, + 'markerAttachments.model.pitchUnit', + 'rad' + ), + invertPitch: F_.getIn( + layerVar, + 'markerAttachments.model.invertPitch', + false + ), + rollProp: F_.getIn( + layerVar, + 'markerAttachments.model.rollProp', + 0 + ), + rollUnit: F_.getIn( + layerVar, + 'markerAttachments.model.rollUnit', + 'rad' + ), + invertRoll: F_.getIn( + layerVar, + 'markerAttachments.model.invertRoll', + false + ), + elevationProp: F_.getIn( + layerVar, + 'markerAttachments.model.elevationProp', + 0 + ), + scaleProp: F_.getIn( + layerVar, + 'markerAttachments.model.scaleProp', + 1 + ), + show: F_.getIn( + layerVar, + 'markerAttachments.model.show', + 'click' + ), + } + + if (modelSettings.model && modelSettings.show === 'click') { + if ( + !F_.isUrlAbsolute(modelSettings.image) && + !modelSettings.model.startsWith('public') + ) + modelSettings.model = + L_.missionPath + modelSettings.model + const rotation = { + y: + typeof modelSettings.yawProp === 'number' + ? modelSettings.yawProp + : F_.getIn( + layer.feature.properties, + modelSettings.yawProp, + 0 + ), + x: + typeof modelSettings.pitchProp === 'number' + ? modelSettings.pitchProp + : F_.getIn( + layer.feature.properties, + modelSettings.pitchProp, + 0 + ), + z: + typeof modelSettings.rollProp === 'number' + ? modelSettings.rollProp + : F_.getIn( + layer.feature.properties, + modelSettings.rollProp, + 0 + ), + } + if (modelSettings.yawUnit === 'deg') + rotation.y *= Math.PI / 180 + if (modelSettings.invertYaw) rotation.y *= -1 + if (modelSettings.pitchUnit === 'deg') + rotation.x *= Math.PI / 180 + if (modelSettings.invertPitch) rotation.x *= -1 + if (modelSettings.rollUnit === 'deg') + rotation.z *= Math.PI / 180 + if (modelSettings.invertRoll) rotation.z *= -1 + + L_.Globe_.litho.addLayer('model', { + name: 'markerAttachmentTempModel', + order: 99999, + on: true, + path: modelSettings.model, + mtlPath: modelSettings.mtlPath, + opacity: 1, + position: { + longitude: layer._latlng.lng || 0, + latitude: layer._latlng.lat || 0, + elevation: + typeof modelSettings.elevationProp === + 'number' + ? modelSettings.elevationProp + : F_.getIn( + layer.feature.properties, + modelSettings.elevationProp, + 0 + ), + }, + scale: + typeof modelSettings.scaleProp === 'number' + ? modelSettings.scaleProp + : F_.getIn( + layer.feature.properties, + modelSettings.scaleProp, + 1 + ), + rotation: rotation, + }) + } + } useInfo(false) break From 64302b89a8aebdda2c8b71240ac96095f9b3cb88 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 13 Dec 2021 09:30:12 -0800 Subject: [PATCH 54/85] Use published lithosphere --- package-lock.json | 14 +++++++------- package.json | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 89c64f28..00bf9177 100644 --- a/package-lock.json +++ b/package-lock.json @@ -60,7 +60,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", + "lithosphere": "^1.1.0", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", @@ -11898,10 +11898,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "node_modules/lithosphere": { - "version": "1.0.6", - "resolved": "file:../../npm-local/lithosphere-1.0.6.tgz", - "integrity": "sha512-TktL4ciNuXoO2fl9aRr4/SdWC/G59sWtkQ7TrXFW8aUWD8Exn+ZDMSU3UreN5rX0zK4Kw1zFU4nXH35tCFrOew==", - "license": "Apache-2.0", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.1.0.tgz", + "integrity": "sha512-EXdddtN1ModnPN6s3aMSSe9W19qWWt01EGhlGhk1RxAwboXkjIwTeVmIT40PXwIWcjyL7wLH3VHPPoYdnW67eg==", "dependencies": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", @@ -30329,8 +30328,9 @@ "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=" }, "lithosphere": { - "version": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", - "integrity": "sha512-TktL4ciNuXoO2fl9aRr4/SdWC/G59sWtkQ7TrXFW8aUWD8Exn+ZDMSU3UreN5rX0zK4Kw1zFU4nXH35tCFrOew==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/lithosphere/-/lithosphere-1.1.0.tgz", + "integrity": "sha512-EXdddtN1ModnPN6s3aMSSe9W19qWWt01EGhlGhk1RxAwboXkjIwTeVmIT40PXwIWcjyL7wLH3VHPPoYdnW67eg==", "requires": { "@turf/boolean-intersects": "^6.3.0", "@turf/circle": "^6.3.0", diff --git a/package.json b/package.json index 73014612..92846b7a 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "jest-resolve": "24.9.0", "jest-watch-typeahead": "0.4.2", "jquery": "^3.5.1", - "lithosphere": "file:..\\..\\npm-local\\lithosphere-1.0.6.tgz", + "lithosphere": "^1.1.0", "mark.js": "^8.11.1", "memorystore": "^1.6.2", "mini-css-extract-plugin": "0.9.0", From c4d04b39b3b25eec339a8c4abf932f83d373b222 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 15 Dec 2021 18:12:45 -0800 Subject: [PATCH 55/85] #122 Layer Filter part 1 --- package-lock.json | 14 + package.json | 1 + src/css/mmgisUI.css | 16 + src/essence/Ancillary/DataShaders.js | 4 +- src/essence/Basics/Layers_/Layers_.js | 9 + .../Tools/Layers/Filtering/ESFilterer.js | 0 .../Tools/Layers/Filtering/Filtering.css | 92 ++++++ .../Tools/Layers/Filtering/Filtering.js | 285 ++++++++++++++++++ .../Tools/Layers/Filtering/LocalFilterer.js | 122 ++++++++ src/essence/Tools/Layers/LayersTool.css | 59 ++-- src/essence/Tools/Layers/LayersTool.js | 14 +- src/essence/Tools/Legend/LegendTool.js | 9 +- src/essence/Tools/New Tool Template.js | 13 +- 13 files changed, 603 insertions(+), 35 deletions(-) create mode 100644 src/essence/Tools/Layers/Filtering/ESFilterer.js create mode 100644 src/essence/Tools/Layers/Filtering/Filtering.css create mode 100644 src/essence/Tools/Layers/Filtering/Filtering.js create mode 100644 src/essence/Tools/Layers/Filtering/LocalFilterer.js diff --git a/package-lock.json b/package-lock.json index 09268a1b..1ddfd235 100644 --- a/package-lock.json +++ b/package-lock.json @@ -49,6 +49,7 @@ "express-session": "^1.17.1", "file-loader": "4.3.0", "file-saver": "^2.0.2", + "flat": "^5.0.2", "fs-extra": "^8.1.0", "hammerjs": "^2.0.8", "helmet": "^4.1.1", @@ -9087,6 +9088,14 @@ "node": ">=6" } }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, "node_modules/flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", @@ -28023,6 +28032,11 @@ "locate-path": "^3.0.0" } }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" + }, "flat-cache": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-2.0.1.tgz", diff --git a/package.json b/package.json index 024643cc..5de93c29 100644 --- a/package.json +++ b/package.json @@ -83,6 +83,7 @@ "express-session": "^1.17.1", "file-loader": "4.3.0", "file-saver": "^2.0.2", + "flat": "^5.0.2", "fs-extra": "^8.1.0", "hammerjs": "^2.0.8", "helmet": "^4.1.1", diff --git a/src/css/mmgisUI.css b/src/css/mmgisUI.css index 6b5fd9da..debe275e 100644 --- a/src/css/mmgisUI.css +++ b/src/css/mmgisUI.css @@ -108,6 +108,22 @@ background-color: #fffdf5; } +/*Button5*/ +.mmgisButton5 { + height: 30px; + line-height: 30px; + padding: 0px 4px; + font-size: 14px; + text-align: center; + cursor: pointer; + display: flex; + transition: all 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95); +} +.mmgisButton5:hover { + color: var(--color-mmgis); + background: var(--color-m1); +} + /*RadioBar*/ .mmgisRadioBar { display: inline-block; diff --git a/src/essence/Ancillary/DataShaders.js b/src/essence/Ancillary/DataShaders.js index 81afd4bd..07b7d6f6 100644 --- a/src/essence/Ancillary/DataShaders.js +++ b/src/essence/Ancillary/DataShaders.js @@ -132,13 +132,13 @@ let DataShaders = { `
    • `, '
      ', '
      Min Value
      ', - ``, + ``, '
      ', '
    • ', `
    • `, '
      ', '
      Max Value
      ', - ``, + ``, '
      ', '
    • ', `
    • `, diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 04db7c28..df57480a 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -484,6 +484,15 @@ var L_ = { } } map.addLayer(L_.layersGroup[L_.layersData[i].name]) + // Set markerDiv based opacities if any + $( + `.leafletMarkerShape_${L_.layersData[i].name + .replace(/\s/g, '') + .toLowerCase()}` + ).css({ + opacity: + L_.opacityArray[L_.layersData[i].name] || 0, + }) } catch (e) { console.log(e) console.warn( diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js new file mode 100644 index 00000000..e69de29b diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css new file mode 100644 index 00000000..07b53ce8 --- /dev/null +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -0,0 +1,92 @@ +#layersTool_filtering { + border-top: 1px solid var(--color-k); + border-left: 6px solid #0f77bd; +} +#layersTool_filtering_header { + display: flex; + justify-content: space-between; + height: 30px; + line-height: 30px; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} +#layersTool_filtering_title { + font-size: 16px; + padding-left: 8px; +} + +#layersTool_filtering_footer { + display: flex; + justify-content: space-between; + height: 30px; + line-height: 30px; + border-top: 1px solid rgba(255, 255, 255, 0.2); +} +#layersTool_filtering_adds { + display: flex; + justify-content: space-between; +} +#layersTool_filtering_adds > div > div { + padding-left: 2px; +} + +.layersTool_filtering_value { + display: flex; + height: 30px; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} +.layersTool_filtering_value .layersTool_filtering_value_key { + flex: 1; +} +.layersTool_filtering_value .layersTool_filtering_value_operator { +} +.layersTool_filtering_value .layersTool_filtering_value_value { + flex: 1; +} +#layersTool_filtering input { + background: #111; + color: #ccc; + width: calc(100% - 2px); + box-sizing: border-box; + height: 30px; + padding-left: 8px; + border: 0px solid rgba(255, 255, 255, 0); + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} +#layersTool_filtering select { + background: #111; + color: #ccc; + height: 30px; +} +.layersTool_filtering_value_operator_select { + background: var(--color-a); + color: var(--color-f); + border: none; + border-right: 1px solid var(--color-b); + cursor: pointer; + height: 30px; + border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} + +.layersTool_filtering_value_remove .mmgisButton5 { + width: 22px; +} + +#layersTool_filtering .dropy, +#layersTool_filtering .dropy__title { + height: 30px; +} +#layersTool_filtering .dropy__title span { + padding: 6px; +} +#layersTool_filtering .dropy .dropy__content li a { + padding: 6px; + border-top: 1px solid var(--color-m); + margin-bottom: 0px; + height: 30px; +} +#layersTool_filtering .dropy__content .dropy__header { + display: none; +} +#layersTool_filtering .dropy__content ul { + transition: none; +} diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js new file mode 100644 index 00000000..514fefe7 --- /dev/null +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -0,0 +1,285 @@ +// Part of the LayersTool that deals with filtering + +import $ from 'jquery' +import F_ from '../../../Basics/Formulae_/Formulae_' +import L_ from '../../../Basics/Layers_/Layers_' + +import LocalFilterer from './LocalFilterer' +import ESFilterer from './ESFilterer' + +import Dropy from '../../../../external/Dropy/dropy' + +import './Filtering.css' + +const filters = { + Waypoints: { + spatial: { + feature: {}, + operator: 'intersects | contains', + }, + property: [ + { + type: 'string | number', + key: '', + operator: '<, =, >, []', + value: '', + }, + ], + }, +} + +const Filtering = { + filters: {}, + current: {}, + make: function (container, layerName) { + const layerObj = L_.layersNamed[layerName] + + if (layerObj == null) return + + Filtering.filters[layerName] = Filtering.filters[layerName] || { + spatial: {}, + values: [], + geojson: L_.layersGroup[layerName].toGeoJSON(), + } + Filtering.current = { + layerName: layerName, + layerObj: layerObj, + type: layerObj.type, + } + + if (Filtering.current.type === 'vector') { + Filtering.filters[layerName].aggs = LocalFilterer.getAggregations( + Filtering.filters[layerName].geojson + ) + } else if (Filtering.current.type === 'query') { + } + + // prettier-ignore + const markup = [ + "
      ", + "
      ", + "
      Filter
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
      ", + "
        ", + "
      ", + "
        ", + "
        ", + "", + "
        ", + ].join('\n') + + container.append(markup) + + Filtering.filters[layerName].values.forEach((v) => { + Filtering.addValue(layerName, v) + }) + + // Add Spatial + $('#layersTool_filtering_add_spatial').on('click', function () { + const spatialMarkup = [].join('\n') + }) + + // Add Value + $('#layersTool_filtering_add_value').on('click', function () { + Filtering.addValue(layerName) + }) + }, + destroy: function (layerName) { + $('#layersTool_filtering').remove() + }, + addValue: function (layerName, value) { + let id, key, op, val + if (value) { + id = value.id + key = ` value='${value.key}'` + op = value.op + val = ` value='${value.value}'` + } else id = Filtering.filters[layerName].values.length + + // prettier-ignore + const valueMarkup = [ + `
        `, + "
        ", + ``, + "
        ", + "
        ", + `
        `, + "
        ", + "
        ", + ``, + "
        ", + "
        ", + ].join('\n') + + $('#layerTool_filtering_filters_list').append(valueMarkup) + + if (value == null) { + Filtering.filters[layerName].values.push({ + id: id, + type: null, + key: null, + op: '=', + value: null, + }) + } + + Filtering.attachEvents(id, layerName, { op: op }) + }, + attachEvents: function (id, layerName, options) { + Filtering.attachValueEvents(id, layerName, options) + + // Submit + $(`#layersTool_filtering_submit`).on('click', () => { + console.log(Filtering.filters) + if (Filtering.current.type === 'vector') { + LocalFilterer.filter(Filtering.filters[layerName], layerName) + } else if (Filtering.current.type === 'query') { + } + }) + + // Clear + $(`#layersTool_filtering_clear`).on('click', () => { + Filtering.filters[layerName].values = Filtering.filters[ + layerName + ].values.filter((v) => { + $(`#layersTool_filtering_value_${layerName}_${v.id}`).remove() + return false + }) + }) + }, + attachValueEvents: function (id, layerName, options) { + options = options || {} + + let elmId + + // Property Autocomplete + elmId = `#layersTool_filtering_value_key_input_${layerName}_${id}` + + let arrayToSearch = Object.keys(Filtering.filters[layerName].aggs) + arrayToSearch = arrayToSearch.sort((a, b) => b.localeCompare(a)) + + $(elmId).autocomplete({ + lookup: arrayToSearch, + lookupLimit: 100, + minChars: 0, + transformResult: function (response, originalQuery) { + let resultSuggestions = [] + $.map(response, function (jsonItem) { + if (typeof jsonItem != 'string') { + $.map(jsonItem, function (suggestionItem) { + resultSuggestions.push(suggestionItem) + }) + } + }) + resultSuggestions.sort(function (a, b) { + const aStart = String(a.value).match( + new RegExp(originalQuery, 'i') + ) || { index: -1 }, + bStart = String(b.value).match( + new RegExp(originalQuery, 'i') + ) || { index: -1 } + if (aStart.index != bStart.index) + return aStart.index - bStart.index + else return a > b ? 1 : -1 + }) + response.suggestions = resultSuggestions + return response + }, + onSelect: function (event) { + const property = Filtering.filters[layerName].aggs[event.value] + Filtering.filters[layerName].values[id].type = property.type + Filtering.filters[layerName].values[id].key = event.value + Filtering.updateValuesAutoComplete(id, layerName) + }, + }) + + // Operator Dropdown + elmId = `#layersTool_filtering_value_operator_${layerName}_${id}` + + const ops = ['=', '<', '>'] + const opId = Math.max(ops.indexOf(options.op), 0) + $(elmId).html( + Dropy.construct( + [ + ``, + ``, + ``, + ], + 'op', + opId + ) + ) + Dropy.init($(elmId), function (idx) { + Filtering.filters[layerName].values[id].op = ops[idx] + }) + + // Value AutoComplete + Filtering.updateValuesAutoComplete(id, layerName) + }, + updateValuesAutoComplete: function (id, layerName) { + let elmId = `#layersTool_filtering_value_value_input_${layerName}_${id}` + let arrayToSearch = [] + if ( + Filtering.filters[layerName].values[id].key && + Filtering.filters[layerName].aggs[ + Filtering.filters[layerName].values[id].key + ] + ) + arrayToSearch = Object.keys( + Filtering.filters[layerName].aggs[ + Filtering.filters[layerName].values[id].key + ].aggs || {} + ) + $(elmId).autocomplete({ + lookup: arrayToSearch, + lookupLimit: 100, + minChars: 0, + transformResult: function (response, originalQuery) { + let resultSuggestions = [] + $.map(response, function (jsonItem) { + if (typeof jsonItem != 'string') { + $.map(jsonItem, function (suggestionItem) { + resultSuggestions.push(suggestionItem) + }) + } + }) + resultSuggestions.sort(function (a, b) { + const aStart = String(a.value).match( + new RegExp(originalQuery, 'i') + ) || { index: -1 }, + bStart = String(b.value).match( + new RegExp(originalQuery, 'i') + ) || { index: -1 } + if (aStart.index != bStart.index) + return aStart.index - bStart.index + else return a > b ? 1 : -1 + }) + response.suggestions = resultSuggestions + return response + }, + onSelect: function (event) { + Filtering.filters[layerName].values[id].value = event.value + }, + }) + $(elmId).on('keyup', function (e) { + Filtering.filters[layerName].values[id].value = $(this).val() + }) + + $('.autocomplete-suggestions').css({ + 'max-height': '300px', + 'overflow-y': 'auto', + 'overflow-x': 'hidden', + 'border-top': 'none', + 'background-color': 'var(--color-a)', + }) + }, +} + +export default Filtering diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js new file mode 100644 index 00000000..44162592 --- /dev/null +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -0,0 +1,122 @@ +// Part of the LayersTool that deals with filtering + +import $ from 'jquery' +import F_ from '../../../Basics/Formulae_/Formulae_' +import L_ from '../../../Basics/Layers_/Layers_' + +import flat from 'flat' + +const filters = { + Waypoints: { + spatial: { + feature: {}, + operator: 'intersects | contains', + }, + property: [ + { + type: 'string | number', + key: '', + operator: '<, =, >, []', + value: '', + }, + ], + }, +} + +const LocalFilterer = { + make: function (container, layerName) { + const layerObj = L_.layersNamed[layerName] + + if (layerObj == null) return + + const type = layerObj.type + + if (type === 'vector') { + } else if (type === 'query') { + } + }, + destroy: function (layerName) {}, + getAggregations: function (geojson) { + const aggs = {} + + geojson.features.forEach((feature) => { + const flatProps = flat.flatten(feature.properties) + for (let p in flatProps) { + let value = flatProps[p] + let type + + if (!isNaN(value) && !isNaN(parseFloat(value))) type = 'number' + else if (typeof value === 'string') type = 'string' + else if (typeof value === 'number') type = 'number' + + if (type != null) { + // First type will be from index 0 + aggs[p] = aggs[p] || { type: type, aggs: {} } + // Because of that, strings can usurp numbers (ex. ["1", "2", "Melon", "Pastry"]) + if (aggs[p].type === 'number' && type === 'string') + aggs[p].type = type + aggs[p].aggs[flatProps[p]] = aggs[p].aggs[flatProps[p]] || 0 + aggs[p].aggs[flatProps[p]]++ + } + } + }) + return aggs + }, + filter: function (filter, layerName) { + console.log(filter, layerName) + + const geojson = filter.geojson + console.log(geojson) + const filteredGeoJSON = JSON.parse(JSON.stringify(geojson)) + filteredGeoJSON.features = [] + + geojson.features.forEach((f) => { + if (LocalFilterer.match(f, filter)) filteredGeoJSON.features.push(f) + }) + console.log(filteredGeoJSON) + + L_.clearVectorLayer(layerName) + L_.updateVectorLayer(layerName, filteredGeoJSON) + }, + match: function (feature, filter) { + let matches = false + for (let i = 0; i < filter.values.length; i++) { + const v = filter.values[i] + const featureValue = F_.getIn(feature.properties, v.key) + let filterValue = v.value + if (v.type === 'number') filterValue = parseFloat(filterValue) + if (featureValue != null) { + switch (v.op) { + case '=': + if (featureValue == filterValue) matches = true + else matches = false + break + case '<': + if ( + v.type === 'string' + ? featureValue.localeCompare(filterValue) > 0 + : featureValue < filterValue + ) + matches = true + else matches = false + break + case '>': + if ( + v.type === 'string' + ? featureValue.localeCompare(filterValue) < 0 + : featureValue > filterValue + ) + matches = true + else matches = false + break + default: + break + } + if (!matches) return false + } + } + return matches + }, +} + +export default LocalFilterer diff --git a/src/essence/Tools/Layers/LayersTool.css b/src/essence/Tools/Layers/LayersTool.css index 4ec150ee..d960c0e1 100644 --- a/src/essence/Tools/Layers/LayersTool.css +++ b/src/essence/Tools/Layers/LayersTool.css @@ -116,13 +116,14 @@ } #layersToolList > li { + height: 30px; cursor: pointer; display: flex; flex-flow: column; font-size: 14px; margin: 1px 0px; + color: var(--color-f); background: var(--color-j); - overflow: hidden; } #layersToolList > li.forceOff { height: 0 !important; @@ -139,8 +140,8 @@ } #layersToolList .title { - height: 24px; - line-height: 24px; + height: 30px; + line-height: 30px; justify-content: space-between; display: flex; width: 100%; @@ -182,7 +183,7 @@ margin: 0; } #layersTool .settings ul > li { - line-height: 24px; + line-height: 30px; } #layersTool .settings ul > li > div { display: flex; @@ -192,7 +193,7 @@ color: white; } #layersTool .settings ul > li > div > div { - font-size: 13px; + font-size: 14px; color: #ddd; } #layersTool .settings ul > li .right { @@ -209,8 +210,8 @@ border: 1px solid rgba(255, 255, 255, 0.2); } #layersTool .settings ul > li input[type='range'] { - width: 100px; - margin-right: 0; + width: 120px; + margin: 6px 0px; } #layersTool .settings span { font-size: 12px; @@ -233,19 +234,25 @@ #layersTool .reset, #layersTool .layerDownload, #layersTool .gears { - width: 24px; + width: 30px; height: 100%; text-align: center; - line-height: 24px; + line-height: 30px; cursor: pointer; color: #ccc; - transition: color 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95); + transition: color 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95), + background 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95); } #layersTool .layerDownload, #layersTool .gears { color: transparent; } +#layersTool .reset:hover, +#layersTool .layerDownload:hover, +#layersTool .gears:hover { + background: var(--color-k); +} #layersTool .reset { display: none; } @@ -274,7 +281,7 @@ } #layersTool .layerName { - line-height: 25px; + line-height: 31px; height: 100%; flex: 1; user-select: none; @@ -326,13 +333,13 @@ } #layersTool .checkboxcont { - width: 24px; - height: 24px; + width: 30px; + height: 30px; } #layersTool .checkbox { margin: 5px; - width: 14px; - height: 14px; + width: 20px; + height: 20px; border: 2px solid #777; border-radius: 3px; transition: background 0.2s cubic-bezier(0.39, 0.575, 0.565, 1), @@ -343,6 +350,9 @@ background: white; border: 0px solid #777; } +#layersTool .checkbox:not(.on):hover { + background: rgba(255, 255, 255, 0.1); +} #layersTool .checkbox.loading { background: transparent; border: 3px solid rgba(255, 255, 255, 0.3); @@ -428,13 +438,20 @@ #layersTool .dropdown { background-color: #222; border: none; - margin-top: 1px; - width: 100px; - height: 20px; - font-size: 12px; + margin: 1px 0px; + width: 120px; + height: 28px; + font-size: 14px; + color: var(--color-f); + padding: 0px 2px; +} +#layersTool .dropdown2 { + background-color: #222; + border: none; + height: 30px; + font-size: 14px; color: var(--color-f); - padding-left: 3px; - appearance: none; + padding-left: 10px; } #layersTool .layernotfound { diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index aa504d1c..c24e853f 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -5,6 +5,7 @@ import L_ from '../../Basics/Layers_/Layers_' import Map_ from '../../Basics/Map_/Map_' import DataShaders from '../../Ancillary/DataShaders' +import Filtering from './Filtering/Filtering' import './LayersTool.css' @@ -42,7 +43,7 @@ var markup = [ var LayersTool = { height: 0, - width: 250, + width: 280, vars: {}, MMGISInterface: null, initialize: function () { @@ -518,11 +519,20 @@ function interfaceWithMMGIS() { //Enables the setting dialogue box $('.layerName, .gears').on('click', function () { var li = $(this).parent().parent() - if (li.attr('type') == 'header') return + const type = li.attr('type') + const layerName = li.attr('name') + if (type === 'header') return + var wasOn = li.hasClass('gears_on') $('.layerDownload').parent().parent().removeClass('download_on') $('.gears').parent().parent().removeClass('gears_on') if (!wasOn) li.addClass('gears_on') + + //Support Filtering + if (['vector', 'query'].includes(type)) { + Filtering.destroy($('.gears').parent().parent()) + if (!wasOn) Filtering.make(li, layerName) + } }) //Enables the time dialogue box $('.layerName, .time').on('click', function () { diff --git a/src/essence/Tools/Legend/LegendTool.js b/src/essence/Tools/Legend/LegendTool.js index 318285ae..dc7260f3 100644 --- a/src/essence/Tools/Legend/LegendTool.js +++ b/src/essence/Tools/Legend/LegendTool.js @@ -47,9 +47,8 @@ function interfaceWithMMWebGIS() { tools = tools .append('div') .attr('id', 'LegendTool') - .attr('class', 'mmgisScrollbar') .style('color', '#dcdcdc') - .style('height', '100%') + .style('height', 'calc(100% - 40px)') .style('overflow-y', 'auto') //Add the markup to tools or do it manually @@ -86,7 +85,7 @@ function interfaceWithMMWebGIS() { if ( shape == 'circle' || shape == 'square' || - shape == 'rect' || + shape == 'rect' || shape == 'triangle' ) { // finalize discreet and continuous @@ -160,8 +159,8 @@ function interfaceWithMMWebGIS() { var trianglePoints = '0 0, 10 20, 20 0' svg.append('polyline') .attr('class', l + '_legendshape') - .attr('width',20) - .attr('height',20) + .attr('width', 20) + .attr('height', 20) .attr('points', trianglePoints) .attr( 'fill', diff --git a/src/essence/Tools/New Tool Template.js b/src/essence/Tools/New Tool Template.js index 95de6c32..5126908b 100644 --- a/src/essence/Tools/New Tool Template.js +++ b/src/essence/Tools/New Tool Template.js @@ -1,3 +1,6 @@ +// ! OUTDATED +// ! Just copy from existing tools + //New Tool Template //In the very least, each tool needs to be defined through require.js and return // an object with 'make' and 'destroy' functions @@ -9,7 +12,7 @@ define([ 'Globe_', 'Map_', 'Viewer_', -], function($, d3, F_, L_, Globe_, Map_, Viewer_) { +], function ($, d3, F_, L_, Globe_, Map_, Viewer_) { //Add the tool markup if you want to do it this way // prettier-ignore var markup = [].join('\n'); @@ -18,20 +21,20 @@ define([ height: 48, width: 200, MMGISInterface: null, - make: function() { + make: function () { this.MMGISInterface = new interfaceWithMMGIS() }, - destroy: function() { + destroy: function () { this.MMGISInterface.separateFromMMGIS() }, - getUrlString: function() { + getUrlString: function () { return '' }, } // function interfaceWithMMGIS() { - this.separateFromMMGIS = function() { + this.separateFromMMGIS = function () { separateFromMMGIS() } From 502c8712d86af06346bba028006f05a0413e6c81 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Thu, 16 Dec 2021 18:07:49 -0800 Subject: [PATCH 56/85] #122 Layer Filter - clean up UI so far --- src/css/mmgisUI.css | 4 +- .../Tools/Layers/Filtering/Filtering.css | 56 ++++++++++--- .../Tools/Layers/Filtering/Filtering.js | 83 +++++++++++++++++-- .../Tools/Layers/Filtering/LocalFilterer.js | 13 ++- src/essence/Tools/Layers/LayersTool.css | 28 +------ src/essence/Tools/Layers/LayersTool.js | 45 ++++++---- 6 files changed, 168 insertions(+), 61 deletions(-) diff --git a/src/css/mmgisUI.css b/src/css/mmgisUI.css index debe275e..5419af12 100644 --- a/src/css/mmgisUI.css +++ b/src/css/mmgisUI.css @@ -120,8 +120,8 @@ transition: all 0.2s cubic-bezier(0.445, 0.05, 0.55, 0.95); } .mmgisButton5:hover { - color: var(--color-mmgis); - background: var(--color-m1); + color: white; + background: var(--color-k); } /*RadioBar*/ diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index 07b53ce8..2981be17 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -1,17 +1,23 @@ #layersTool_filtering { border-top: 1px solid var(--color-k); - border-left: 6px solid #0f77bd; } #layersTool_filtering_header { display: flex; justify-content: space-between; height: 30px; line-height: 30px; - border-bottom: 1px solid rgba(255, 255, 255, 0.2); +} +#layersTool_filtering_title_left { + display: flex; } #layersTool_filtering_title { font-size: 16px; - padding-left: 8px; + padding-left: 14px; +} +#layersTool_filtering_count { + font-size: 12px; + padding: 0px 4px; + color: #d6d6d6; } #layersTool_filtering_footer { @@ -19,7 +25,6 @@ justify-content: space-between; height: 30px; line-height: 30px; - border-top: 1px solid rgba(255, 255, 255, 0.2); } #layersTool_filtering_adds { display: flex; @@ -32,7 +37,7 @@ .layersTool_filtering_value { display: flex; height: 30px; - border-bottom: 1px solid rgba(255, 255, 255, 0.2); + border-bottom: 1px solid var(--color-k); } .layersTool_filtering_value .layersTool_filtering_value_key { flex: 1; @@ -41,16 +46,36 @@ } .layersTool_filtering_value .layersTool_filtering_value_value { flex: 1; + position: relative; +} + +.layersTool_filtering_value_value_type { + position: absolute; + right: 0; + top: 0; + pointer-events: none; + height: 30px; + line-height: 30px; + width: 30px; + text-align: center; + color: #999; } +.layersTool_filtering_value_value_type > i:first-child { + color: var(--color-yellow); +} +.layersTool_filtering_value_value_type > i:last-child { + color: var(--color-green); +} + #layersTool_filtering input { background: #111; color: #ccc; - width: calc(100% - 2px); + width: 100%; box-sizing: border-box; height: 30px; padding-left: 8px; - border: 0px solid rgba(255, 255, 255, 0); - border-bottom: 1px solid rgba(255, 255, 255, 0.2); + border: none; + font-size: 14px; } #layersTool_filtering select { background: #111; @@ -58,22 +83,31 @@ height: 30px; } .layersTool_filtering_value_operator_select { - background: var(--color-a); + background: #111111; color: var(--color-f); border: none; - border-right: 1px solid var(--color-b); cursor: pointer; height: 30px; - border-bottom: 1px solid rgba(255, 255, 255, 0.2); + transition: background 0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86); +} +.layersTool_filtering_value_operator_select:hover { + background: var(--color-r4); } .layersTool_filtering_value_remove .mmgisButton5 { width: 22px; } +#layersTool_filtering_clear { + padding: 0px 14px; +} +#layersTool_filtering_submit { + padding: 0px 8px; +} #layersTool_filtering .dropy, #layersTool_filtering .dropy__title { height: 30px; + border: none; } #layersTool_filtering .dropy__title span { padding: 6px; diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 514fefe7..aec14121 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -39,7 +39,6 @@ const Filtering = { Filtering.filters[layerName] = Filtering.filters[layerName] || { spatial: {}, values: [], - geojson: L_.layersGroup[layerName].toGeoJSON(), } Filtering.current = { layerName: layerName, @@ -48,6 +47,15 @@ const Filtering = { } if (Filtering.current.type === 'vector') { + try { + Filtering.filters[layerName].geojson = + L_.layersGroup[layerName].toGeoJSON() + } catch (err) { + console.warn( + `Filtering - Cannot find GeoJSON to filter on for layer: ${layerName}` + ) + return + } Filtering.filters[layerName].aggs = LocalFilterer.getAggregations( Filtering.filters[layerName].geojson ) @@ -58,7 +66,10 @@ const Filtering = { const markup = [ "
        ", "
        ", - "
        Filter
        ", + "
        ", + "
        Filter
        ", + "
        ", + "
        ", "
        ", "
        ", "
        ", @@ -68,7 +79,7 @@ const Filtering = { "
      ", "
        ", "
        ", - "", "
        ", ``, + `
        `, + ``, + ``, + `
        `, "
        ", "
        ", ].join('\n') @@ -131,6 +152,12 @@ const Filtering = { } Filtering.attachEvents(id, layerName, { op: op }) + + // Show footer iff value rows exist + $('#layersTool_filtering_footer').css( + 'display', + Filtering.filters[layerName].values.length === 0 ? 'none' : 'flex' + ) }, attachEvents: function (id, layerName, options) { Filtering.attachValueEvents(id, layerName, options) @@ -152,6 +179,19 @@ const Filtering = { $(`#layersTool_filtering_value_${layerName}_${v.id}`).remove() return false }) + + if (Filtering.current.type === 'vector') { + LocalFilterer.filter(Filtering.filters[layerName], layerName) + } else if (Filtering.current.type === 'query') { + } + + // Show footer iff value rows exist + $('#layersTool_filtering_footer').css( + 'display', + Filtering.filters[layerName].values.length === 0 + ? 'none' + : 'flex' + ) }) }, attachValueEvents: function (id, layerName, options) { @@ -197,9 +237,24 @@ const Filtering = { Filtering.filters[layerName].values[id].type = property.type Filtering.filters[layerName].values[id].key = event.value Filtering.updateValuesAutoComplete(id, layerName) + $(this).css('border', 'none') }, }) + $(elmId).on('blur', function (event) { + const property = Filtering.filters[layerName].aggs[event.value] + if (property) { + if ( + Filtering.filters[layerName].values[id].key !== event.value + ) { + Filtering.filters[layerName].values[id].key = event.value + Filtering.filters[layerName].values[id].type = property.type + Filtering.updateValuesAutoComplete(id, layerName) + } + $(this).css('border', 'none') + } else $(this).css('border', '1px solid red') + }) + // Operator Dropdown elmId = `#layersTool_filtering_value_operator_${layerName}_${id}` @@ -279,6 +334,24 @@ const Filtering = { 'border-top': 'none', 'background-color': 'var(--color-a)', }) + + // Change type indicator icons too + const numberElmId = `#layersTool_filtering_value_value_type_number_${layerName}_${id}` + const stringElmId = `#layersTool_filtering_value_value_type_string_${layerName}_${id}` + switch (Filtering.filters[layerName].values[id].type) { + case 'number': + $(numberElmId).css('display', 'inherit') + $(stringElmId).css('display', 'none') + break + case 'string': + $(stringElmId).css('display', 'inherit') + $(numberElmId).css('display', 'none') + break + default: + $(numberElmId).css('display', 'none') + $(stringElmId).css('display', 'none') + break + } }, } diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js index 44162592..8e512074 100644 --- a/src/essence/Tools/Layers/Filtering/LocalFilterer.js +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -63,22 +63,27 @@ const LocalFilterer = { return aggs }, filter: function (filter, layerName) { - console.log(filter, layerName) - const geojson = filter.geojson - console.log(geojson) const filteredGeoJSON = JSON.parse(JSON.stringify(geojson)) filteredGeoJSON.features = [] + // Filter geojson.features.forEach((f) => { if (LocalFilterer.match(f, filter)) filteredGeoJSON.features.push(f) }) - console.log(filteredGeoJSON) + // Set count + $('#layersTool_filtering_count').text( + `(${filteredGeoJSON.features.length}/${geojson.features.length})` + ) + + // Update layer L_.clearVectorLayer(layerName) L_.updateVectorLayer(layerName, filteredGeoJSON) }, match: function (feature, filter) { + if (filter.values.length === 0) return true + let matches = false for (let i = 0; i < filter.values.length; i++) { const v = filter.values[i] diff --git a/src/essence/Tools/Layers/LayersTool.css b/src/essence/Tools/Layers/LayersTool.css index d960c0e1..665be1b3 100644 --- a/src/essence/Tools/Layers/LayersTool.css +++ b/src/essence/Tools/Layers/LayersTool.css @@ -77,7 +77,7 @@ } #layersTool #searchLayers input { background: #111; - width: 187px; + width: 229px; color: #ccc; padding-left: 12px; border: 1px solid rgba(255, 255, 255, 0.2); @@ -117,7 +117,6 @@ #layersToolList > li { height: 30px; - cursor: pointer; display: flex; flex-flow: column; font-size: 14px; @@ -151,30 +150,9 @@ #layersTool .settings { height: 0px; opacity: 0; - border-left: 6px solid transparent; overflow: hidden; color: #ccc; } -#layersTool .layerExport.vector, -#layersTool .settings.vector { - border-color: rgb(15, 119, 189); -} -#layersTool .layerExport.tile, -#layersTool .settings.tile { - border-color: rgb(119, 15, 189); -} -#layersTool .layerExport.vectortile, -#layersTool .settings.vectortile { - border-color: #bd0f8e; -} -#layersTool .layerExport.data, -#layersTool .settings.data { - border-color: rgb(189, 15, 50); -} -#layersTool .layerExport.model, -#layersTool .settings.model { - border-color: rgb(189, 189, 15); -} #layersTool .layerExport ul, #layersTool .settings ul { @@ -228,7 +206,7 @@ #layersTool #layersToolList > li.gears_on .settings { height: auto; opacity: 1; - padding: 2px 6px; + padding: 2px 6px 2px 12px; } #layersTool .reset, @@ -281,6 +259,7 @@ } #layersTool .layerName { + cursor: pointer; line-height: 31px; height: 100%; flex: 1; @@ -335,6 +314,7 @@ #layersTool .checkboxcont { width: 30px; height: 30px; + cursor: pointer; } #layersTool .checkbox { margin: 5px; diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index c24e853f..2d2ce2c6 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -43,7 +43,7 @@ var markup = [ var LayersTool = { height: 0, - width: 280, + width: 290, vars: {}, MMGISInterface: null, initialize: function () { @@ -465,22 +465,25 @@ function interfaceWithMMGIS() { } } - //Add event functions and whatnot - //Makes layers clickable on and off - $('#layersToolList > li > .title .checkbox').on('click', async function () { - let li = $(this).parent().parent().parent() + async function toggleLayer(checkbox) { + let li = checkbox.parent().parent().parent() if (li.attr('type') !== 'header') { - $(this).addClass('loading') + checkbox.addClass('loading') await L_.toggleLayer(L_.layersNamed[li.attr('name')]) - $(this).removeClass('loading') + checkbox.removeClass('loading') if (li.attr('type') === 'model' || L_.layersGroup[li.attr('name')]) - $(this).toggleClass('on') + checkbox.toggleClass('on') else if ( li.attr('type') !== 'model' && L_.layersGroup[li.attr('name')] == null ) li.addClass('layernotfound') } + } + //Add event functions and whatnot + //Makes layers clickable on and off + $('#layersToolList > li > .title .checkbox').on('click', function () { + toggleLayer($(this)) }) //Makes sublayers clickable on and off @@ -517,21 +520,33 @@ function interfaceWithMMGIS() { if (!wasOn) li.addClass('download_on') }) //Enables the setting dialogue box - $('.layerName, .gears').on('click', function () { - var li = $(this).parent().parent() + $('.layerName, .gears').on('click', async function () { + const li = $(this).parent().parent() const type = li.attr('type') const layerName = li.attr('name') if (type === 'header') return - var wasOn = li.hasClass('gears_on') + const wasOn = li.hasClass('gears_on') $('.layerDownload').parent().parent().removeClass('download_on') $('.gears').parent().parent().removeClass('gears_on') if (!wasOn) li.addClass('gears_on') - //Support Filtering - if (['vector', 'query'].includes(type)) { - Filtering.destroy($('.gears').parent().parent()) - if (!wasOn) Filtering.make(li, layerName) + //Support Filtering 1 + if (!wasOn) { + if (['vector', 'query'].includes(type)) { + Filtering.destroy($('.gears').parent().parent()) + } + } + + // Turn layer on if off + const checkbox = $(this).parent().find('.checkboxcont .checkbox') + if (!checkbox.hasClass('on')) await toggleLayer(checkbox) + + //Support Filtering 2 + if (!wasOn) { + if (['vector', 'query'].includes(type)) { + if (!wasOn) Filtering.make(li, layerName) + } } }) //Enables the time dialogue box From 92d7d2c203114231104604b454ae5d1f9e2032e8 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 13:15:18 -0800 Subject: [PATCH 57/85] #122 Query Layer test 1 --- config/js/config.js | 176 ++++++++++++------ docs/pages/markdowns/ENVs.md | 2 +- src/essence/Basics/Map_/Map_.js | 8 + .../Tools/Layers/Filtering/ESFilterer.js | 175 +++++++++++++++++ .../Tools/Layers/Filtering/Filtering.js | 31 ++- src/essence/Tools/Layers/LayersTool.css | 9 + src/essence/Tools/Layers/LayersTool.js | 66 ++++--- 7 files changed, 375 insertions(+), 92 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 32bfe26d..c8244284 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -734,37 +734,39 @@ function makeLayerBarAndModal(d, level) { var nameEl = "block", kindEl = "block", typeEl = "block", urlEl = "block", demtileurlEl = "block", demparserEl = "block", controlledEl = "block", legendEl = "block", visEl = "block", viscutEl = "block", initOpacEl = "block", togwheadEl = "block", minzEl = "block", tileformatEl = "block", - visEl = "block", - viscutEl = "block", - togwheadEl = "block", - minzEl = "block", - modelLonEl = "block", - modelLatEl = "block", - modelElevEl = "block", - modelRotXEl = "block", - modelRotYEl = "block", - modelRotZEl = "block", - modelScaleEl = "block", - maxnzEl = "block", - maxzEl = "block", - strcolEl = "block", - filcolEl = "block", - weightEl = "block", - opacityEl = "block", - radiusEl = "block", - variableEl = "block", - xmlEl = "block", - bbEl = "block", - vtLayerEl = "block", - vtIdEl = "block", - vtKeyEl = "block", - vtLayerSetStylesEl = "block", - timeEl = "block", - timeTypeEl = "block", - timeFormatEl = "block", - timeRefreshEl = "none", - timeIncrementEl = "none"; - shapeEl = "none"; + visEl = "block", + viscutEl = "block", + togwheadEl = "block", + minzEl = "block", + modelLonEl = "block", + modelLatEl = "block", + modelElevEl = "block", + modelRotXEl = "block", + modelRotYEl = "block", + modelRotZEl = "block", + modelScaleEl = "block", + maxnzEl = "block", + maxzEl = "block", + strcolEl = "block", + filcolEl = "block", + weightEl = "block", + opacityEl = "block", + radiusEl = "block", + variableEl = "block", + xmlEl = "block", + bbEl = "block", + vtLayerEl = "block", + vtIdEl = "block", + vtKeyEl = "block", + vtLayerSetStylesEl = "block", + timeEl = "block", + timeTypeEl = "block", + timeFormatEl = "block", + timeRefreshEl = "none", + timeIncrementEl = "none", + shapeEl = "none", + queryEndpointEl = "none", + queryTypeEl = "none"; // prettier-ignore switch( d.type ) { @@ -778,6 +780,7 @@ function makeLayerBarAndModal(d, level) { weightEl = "none"; opacityEl = "none"; radiusEl = "none"; variableEl = "none"; xmlEl = "none"; bbEl = "none"; vtLayerEl = "none"; vtIdEl = "none"; vtKeyEl = "none"; vtLayerSetStylesEl = "none"; timeEl = "none"; timeTypeEl = "none"; timeFormatEl = "none"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "none"; + queryEndpointEl = "none"; queryTypeEl = "none"; break; case "tile": nameEl = "block"; kindEl = "none"; typeEl = "block"; urlEl = "block"; demtileurlEl = "block"; demparserEl = "block"; controlledEl = "none"; legendEl = "block"; @@ -789,6 +792,7 @@ function makeLayerBarAndModal(d, level) { weightEl = "none"; opacityEl = "none"; radiusEl = "none"; variableEl = "none"; xmlEl = "block"; bbEl = "block"; vtLayerEl = "none"; vtIdEl = "none"; vtKeyEl = "none"; vtLayerSetStylesEl = "none"; timeEl = "block"; timeTypeEl = "block"; timeFormatEl = "block"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "none"; + queryEndpointEl = "none"; queryTypeEl = "none"; break; case "vectortile": nameEl = "block"; kindEl = "block"; typeEl = "block"; urlEl = "block"; demtileurlEl = "block"; demparserEl = "block"; controlledEl = "none"; legendEl = "block"; @@ -800,6 +804,7 @@ function makeLayerBarAndModal(d, level) { weightEl = "none"; opacityEl = "none"; radiusEl = "none"; variableEl = "block"; xmlEl = "none"; bbEl = "none"; vtLayerEl = "block"; vtIdEl = "block"; vtKeyEl = "block"; vtLayerSetStylesEl = "block"; timeEl = "block"; timeTypeEl = "block"; timeFormatEl = "block"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "block"; + queryEndpointEl = "none"; queryTypeEl = "none"; break; case "data": nameEl = "block"; kindEl = "none"; typeEl = "block"; urlEl = "none"; demtileurlEl = "block"; demparserEl = "block"; controlledEl = "none"; legendEl = "block"; @@ -811,17 +816,19 @@ function makeLayerBarAndModal(d, level) { weightEl = "none"; opacityEl = "none"; radiusEl = "none"; variableEl = "block"; xmlEl = "block"; bbEl = "block"; vtLayerEl = "none"; vtIdEl = "none"; vtKeyEl = "none"; vtLayerSetStylesEl = "none"; timeEl = "block"; timeTypeEl = "block"; timeFormatEl = "block"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "none"; + queryEndpointEl = "none"; queryTypeEl = "none"; break; - case "point": - nameEl = "block"; kindEl = "block"; typeEl = "block"; urlEl = "block"; demtileurlEl = "none"; demparserEl = "none"; controlledEl = "none"; legendEl = "block"; - visEl = "block"; viscutEl = "block"; initOpacEl = "block"; togwheadEl = "block"; minzEl = "none"; + case "query": + nameEl = "block"; kindEl = "none"; typeEl = "block"; urlEl = "none"; demtileurlEl = "none"; demparserEl = "none"; controlledEl = "none"; legendEl = "none"; + visEl = "none"; viscutEl = "none"; initOpacEl = "none"; togwheadEl = "none"; minzEl = "none"; tileformatEl = "none"; modelLonEl = "none"; modelLatEl = "none"; modelElevEl = "none"; modelRotXEl = "none"; modelRotYEl = "none"; modelRotZEl = "none"; modelScaleEl = "none"; maxnzEl = "none"; maxzEl = "none"; strcolEl = "block"; filcolEl = "block"; weightEl = "block"; opacityEl = "block"; radiusEl = "block"; variableEl = "block"; xmlEl = "none"; bbEl = "none"; vtLayerEl = "none"; vtIdEl = "none"; vtKeyEl = "none"; vtLayerSetStylesEl = "none"; - timeEl = "block"; timeTypeEl = "block"; timeFormatEl = "block"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "none"; + timeEl = "none"; timeTypeEl = "none"; timeFormatEl = "none"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "none"; + queryEndpointEl = "block"; queryTypeEl = "block"; break; case "vector": nameEl = "block"; kindEl = "block"; typeEl = "block"; urlEl = "block"; controlledEl = "block"; demtileurlEl = "none"; demparserEl = "none"; legendEl = "block"; @@ -844,6 +851,7 @@ function makeLayerBarAndModal(d, level) { weightEl = "none"; opacityEl = "none"; radiusEl = "none"; variableEl = "none"; xmlEl = "none"; bbEl = "none"; vtLayerEl = "none"; vtIdEl = "none"; vtKeyEl = "none"; vtLayerSetStylesEl = "none"; timeEl = "block"; timeTypeEl = "block"; timeFormatEl = "block"; timeRefreshEl = "none"; timeIncrementEl = "none"; shapeEl = "none"; + queryEndpointEl = "none"; queryTypeEl = "none"; break; default: console.warn(`Unknown layer type: ${d.type}`) @@ -854,7 +862,7 @@ function makeLayerBarAndModal(d, level) { tileSel = "", vectortileSel = "", dataSel = "", - pointSel = "", + querySel = "", vectorSel = "", modelSel = ""; @@ -875,9 +883,9 @@ function makeLayerBarAndModal(d, level) { barColor = "rgb(189, 15, 50)"; dataSel = "selected"; break; - case "point": - barColor = "#892f45"; - pointSel = "selected"; + case "query": + barColor = "#0fbd4d"; + querySel = "selected"; break; case "vector": barColor = "rgb(15, 119, 189)"; @@ -891,6 +899,8 @@ function makeLayerBarAndModal(d, level) { console.warn(`Unknown layer type: ${d.type}`); } + var queryTypeESSel = "selected"; + var tileformatTMSSel = "", tileformatWMTSSel = "", tileformatWMSSel = ""; @@ -1080,7 +1090,7 @@ function makeLayerBarAndModal(d, level) { // prettier-ignore $( "#modal_divs" ).append( "
      • ', + '
      • ', '
        ', '
        ', '
        ', @@ -471,10 +476,13 @@ function interfaceWithMMGIS() { checkbox.addClass('loading') await L_.toggleLayer(L_.layersNamed[li.attr('name')]) checkbox.removeClass('loading') - if (li.attr('type') === 'model' || L_.layersGroup[li.attr('name')]) + if ( + quasiLayers.includes(li.attr('type')) || + L_.layersGroup[li.attr('name')] + ) checkbox.toggleClass('on') else if ( - li.attr('type') !== 'model' && + !quasiLayers.includes(li.attr('type')) && L_.layersGroup[li.attr('name')] == null ) li.addClass('layernotfound') @@ -684,13 +692,14 @@ function interfaceWithMMGIS() { vector: $('#filterLayers .right > .vector').hasClass('on'), vectortile: $('#filterLayers .right > .vectortile').hasClass('on'), tile: $('#filterLayers .right > .tile').hasClass('on'), + query: $('#filterLayers .right > .query').hasClass('on'), data: $('#filterLayers .right > .data').hasClass('on'), model: $('#filterLayers .right > .model').hasClass('on'), visible: $('#filterLayers .right > .visible').hasClass('on'), } $('#layersToolList > li').each(function () { - if ($(this).attr('type') != 'header') { - if (type == 'visible') { + if ($(this).attr('type') !== 'header') { + if (type === 'visible') { var layerOn = $(this).find('.checkbox').hasClass('on') if (isOn) { if (layerOn) $(this).removeClass('forceOff2') @@ -701,6 +710,7 @@ function interfaceWithMMGIS() { !ons.vector && !ons.vectortile && !ons.tile && + !ons.query && !ons.data && !ons.model ) From 865ee897a04a37b5b50168a5fc11409beecbbd98 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 15:41:38 -0800 Subject: [PATCH 58/85] #122 Body Wrapper --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 5a33bd98..514c2b67 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -112,7 +112,8 @@ const ESFilterer = { if (config.stringifyBody) body = JSON.stringify(body) let finalBody - if (config.bodyFormatter) finalBody = finalBody.replace('{BODY}', body) + if (config.bodyWrapper) + finalBody = config.bodyWrapper.replace('{BODY}', body) else finalBody = body console.log(query, finalBody) @@ -120,6 +121,7 @@ const ESFilterer = { method: 'POST', headers: { accept: 'application/json', + credentials: 'include', ...(config.headers || {}), }, body: finalBody, From 1adf3962af7267001a5c875f9ed9176ec9386ce6 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 15:54:58 -0800 Subject: [PATCH 59/85] #122 withCreds --- config/js/config.js | 1 + src/essence/Tools/Layers/Filtering/ESFilterer.js | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/config/js/config.js b/config/js/config.js index c8244284..01fcb0b7 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2792,6 +2792,7 @@ function layerPopulateVariable(modalId, layerType) { currentLayerVars.query = { bodyWrapper: `{"preference":"site"}\n{BODY}\n`, stringifyBody: true, + withCredentials: false, headers: { "Content-Type": "application/x-ndjson", }, diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 514c2b67..0ae9d41c 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -121,9 +121,9 @@ const ESFilterer = { method: 'POST', headers: { accept: 'application/json', - credentials: 'include', ...(config.headers || {}), }, + credentials: config.withCredentials ? 'include' : '', body: finalBody, }) .then((res) => res.json()) From a314a1304556938d308a536a2414e280c52d4487 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 16:14:04 -0800 Subject: [PATCH 60/85] #122 more logs --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 0ae9d41c..e47ec442 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -60,7 +60,7 @@ const config = { const ESFilterer = { getAggregations: async function (layerName, config) { const results = await ESFilterer.filter(layerName, null, config) - + console.log('RESULTS', results) const aggs = {} if (results) { for (let a in results.aggregations) { @@ -75,7 +75,7 @@ const ESFilterer = { } } } - + console.log('aggs', aggs) return aggs }, filter: async function (layerName, filter, config) { @@ -160,17 +160,6 @@ const ESFilterer = { .catch((err) => { console.log(err) }) - - /* - // Set count - $('#layersTool_filtering_count').text( - `(${filteredGeoJSON.features.length}/${geojson.features.length})` - ) - - // Update layer - L_.clearVectorLayer(layerName) - L_.updateVectorLayer(layerName, filteredGeoJSON) - */ }, } From ee055efe2b8dc86627670eb2dd6e82cf74f49c68 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 16:28:08 -0800 Subject: [PATCH 61/85] #122 esFilter promise --- .../Tools/Layers/Filtering/ESFilterer.js | 154 ++++++++++-------- 1 file changed, 82 insertions(+), 72 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index e47ec442..6fcb09a9 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -79,87 +79,97 @@ const ESFilterer = { return aggs }, filter: async function (layerName, filter, config) { - console.log(layerName, filter, config) - - let aggs = {} - config.fields.forEach((f) => { - aggs[f] = { - terms: { - field: f, - size: 1000, - }, - } - }) + return new Promise((resolve, reject) => { + console.log(layerName, filter, config) + + let aggs = {} + config.fields.forEach((f) => { + aggs[f] = { + terms: { + field: f, + size: 1000, + }, + } + }) - let must = [] - if (config.must) must = must.concat(config.must) - //{ match: { site: 3 } }, - //{ match: { drive: 1374 } }, + let must = [] + if (config.must) must = must.concat(config.must) + //{ match: { site: 3 } }, + //{ match: { drive: 1374 } }, - let query = { - query: { - bool: { - must: must, + let query = { + query: { + bool: { + must: must, + }, }, - }, - aggs: aggs, - from: 0, - size: config.size || 1000, - version: true, - } + aggs: aggs, + from: 0, + size: config.size || 1000, + version: true, + } - let body = query - if (config.stringifyBody) body = JSON.stringify(body) + let body = query + if (config.stringifyBody) body = JSON.stringify(body) - let finalBody - if (config.bodyWrapper) - finalBody = config.bodyWrapper.replace('{BODY}', body) - else finalBody = body + let finalBody + if (config.bodyWrapper) + finalBody = config.bodyWrapper.replace('{BODY}', body) + else finalBody = body - console.log(query, finalBody) - fetch(config.endpoint, { - method: 'POST', - headers: { - accept: 'application/json', - ...(config.headers || {}), - }, - credentials: config.withCredentials ? 'include' : '', - body: finalBody, - }) - .then((res) => res.json()) - .then((json) => { - console.log(json) - const geojson = F_.getBaseGeoJSON() - const hits = F_.getIn(json, 'responses.0.hits.hits') - hits.forEach((hit) => { - const properties = hit._source || {} - let geometry - for (let p in properties) { - if (properties[p].coordinates && properties[p].type) { - geometry = JSON.parse(JSON.stringify(properties[p])) - delete properties[p] + console.log(query, finalBody) + fetch(config.endpoint, { + method: 'POST', + headers: { + accept: 'application/json', + ...(config.headers || {}), + }, + credentials: config.withCredentials ? 'include' : '', + body: finalBody, + }) + .then((res) => res.json()) + .then((json) => { + console.log(json) + const geojson = F_.getBaseGeoJSON() + const hits = F_.getIn(json, 'responses.0.hits.hits') + hits.forEach((hit) => { + const properties = hit._source || {} + let geometry + for (let p in properties) { + if ( + properties[p].coordinates && + properties[p].type + ) { + geometry = JSON.parse( + JSON.stringify(properties[p]) + ) + delete properties[p] + } } - } - if (geometry) - geojson.features.push({ - type: 'Feature', - properties, - geometry, - }) - }) + if (geometry) + geojson.features.push({ + type: 'Feature', + properties, + geometry, + }) + }) - // Set count - $('#layersTool_filtering_count').text( - `${geojson.features.length})` - ) + // Set count + $('#layersTool_filtering_count').text( + `${geojson.features.length})` + ) - // Update layer - L_.clearVectorLayer(layerName) - L_.updateVectorLayer(layerName, geojson) - }) - .catch((err) => { - console.log(err) - }) + // Update layer + L_.clearVectorLayer(layerName) + L_.updateVectorLayer(layerName, geojson) + + resolve(F_.getIn(json, 'responses.0')) + }) + .catch((err) => { + console.log(err) + resolve() + }) + }) }, } From 29a138fbf53363b11b7368222396f2faf461bbd7 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 16:38:38 -0800 Subject: [PATCH 62/85] #122 esFilter prop object --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 6fcb09a9..7e2ccb1d 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -137,6 +137,8 @@ const ESFilterer = { let geometry for (let p in properties) { if ( + properties[p] != null && + typeof properties[p] === 'object' && properties[p].coordinates && properties[p].type ) { @@ -144,6 +146,7 @@ const ESFilterer = { JSON.stringify(properties[p]) ) delete properties[p] + break } } if (geometry) From eb11ff877df862be23823e6300bf1ae68f157911 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 17:00:28 -0800 Subject: [PATCH 63/85] #122 Query Layer as empty vector --- src/essence/Basics/Layers_/LayerCapturer.js | 20 ++++++++++++++----- src/essence/Basics/Map_/Map_.js | 18 +++++++---------- .../Tools/Layers/Filtering/ESFilterer.js | 2 +- 3 files changed, 23 insertions(+), 17 deletions(-) diff --git a/src/essence/Basics/Layers_/LayerCapturer.js b/src/essence/Basics/Layers_/LayerCapturer.js index d0672e27..8c721e68 100644 --- a/src/essence/Basics/Layers_/LayerCapturer.js +++ b/src/essence/Basics/Layers_/LayerCapturer.js @@ -9,16 +9,28 @@ export const captureVector = (layerObj, options, cb) => { options = options || {} let layerUrl = layerObj.url - if (options.evenIfOff !== true && !layerObj.visibility) { + if ( + options.evenIfOff !== true && + !layerObj.visibility && + !options.useEmptyGeoJSON + ) { cb('off') return } - if (typeof layerUrl !== 'string' || layerUrl.length === 0) { + if ( + (typeof layerUrl !== 'string' || layerUrl.length === 0) && + !options.useEmptyGeoJSON + ) { cb(null) return } + if (options.useEmptyGeoJSON) { + cb(F_.getBaseGeoJSON()) + return + } + // Give time enabled layers a default start and end time to avoid errors const layerTimeFormat = layerObj.time == null @@ -172,9 +184,7 @@ export const captureVector = (layerObj, options, cb) => { // create the geoJSON layer with empty GeoJSON data const layerData = L_.layersDataByName[layerObj.name] if (L_.missionPath === layerUrl && layerData.controlled) { - // Empty GeoJSON data - const geojson = { type: 'FeatureCollection', features: [] } - cb(geojson) + cb(F_.getBaseGeoJSON()) } else { $.getJSON(layerUrl, function (data) { if (data.hasOwnProperty('Features')) { diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 59e34333..92415106 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -555,9 +555,6 @@ async function makeLayer(layerObj, evenIfOff) { case 'vector': await makeVectorLayer(evenIfOff) break - case 'point': - await makeVectorLayer(evenIfOff) //makePointLayer(); //DEATH TO POINT - break case 'tile': makeTileLayer() break @@ -565,7 +562,7 @@ async function makeLayer(layerObj, evenIfOff) { makeVectorTileLayer() break case 'query': - makeQueryLayer() + await makeVectorLayer(false, true) break case 'data': makeDataLayer() @@ -803,9 +800,13 @@ async function makeLayer(layerObj, evenIfOff) { } //Pretty much like makePointLayer but without the pointToLayer stuff - async function makeVectorLayer(evenIfOff) { + async function makeVectorLayer(evenIfOff, useEmptyGeoJSON) { return new Promise((resolve, reject) => { - captureVector(layerObj, { evenIfOff: evenIfOff }, add) + captureVector( + layerObj, + { evenIfOff: evenIfOff, useEmptyGeoJSON: useEmptyGeoJSON }, + add + ) function add(data) { if (data == null || data === 'off') { @@ -1068,11 +1069,6 @@ async function makeLayer(layerObj, evenIfOff) { allLayersLoaded() } - function makeQueryLayer() { - L_.layersLoaded[L_.layersOrdered.indexOf(layerObj.name)] = true - allLayersLoaded() - } - function makeDataLayer() { let layerUrl = layerObj.demtileurl if (!F_.isUrlAbsolute(layerUrl)) layerUrl = L_.missionPath + layerUrl diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 7e2ccb1d..b2ccfc68 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -156,7 +156,7 @@ const ESFilterer = { geometry, }) }) - + console.log('geojson', geojson) // Set count $('#layersTool_filtering_count').text( `${geojson.features.length})` From eda38672bfc498b5f4d9ce56981963e812c5b63b Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 17:27:36 -0800 Subject: [PATCH 64/85] #122 Actual ES Filter --- .../Tools/Layers/Filtering/ESFilterer.js | 39 ++++++++++++++++++- .../Tools/Layers/Filtering/Filtering.css | 4 ++ .../Tools/Layers/Filtering/Filtering.js | 7 +++- src/essence/Tools/Layers/LayersTool.css | 1 - src/essence/Tools/Layers/LayersTool.js | 6 +-- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index b2ccfc68..b2e8a5fb 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -94,6 +94,7 @@ const ESFilterer = { let must = [] if (config.must) must = must.concat(config.must) + must = must.concat(ESFilterer.getFilterMust(filter)) //{ match: { site: 3 } }, //{ match: { drive: 1374 } }, @@ -117,7 +118,6 @@ const ESFilterer = { finalBody = config.bodyWrapper.replace('{BODY}', body) else finalBody = body - console.log(query, finalBody) fetch(config.endpoint, { method: 'POST', headers: { @@ -174,6 +174,43 @@ const ESFilterer = { }) }) }, + getFilterMust: function (filter) { + let must = [] + if (filter.values && filter.values.length > 0) { + filter.values.forEach((v) => { + switch (v.op) { + case '=': + must.push({ + match: { + [v.key]: v.value, + }, + }) + break + case '>': + must.push({ + range: { + [v.key]: { + gt: v.value, + }, + }, + }) + break + case '<': + must.push({ + range: { + [v.key]: { + lt: v.value, + }, + }, + }) + break + default: + break + } + }) + } + return must + }, } export default ESFilterer diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index 2981be17..06ac9e19 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -1,5 +1,9 @@ #layersTool_filtering { border-top: 1px solid var(--color-k); + display: none; +} +.gears_on #layersTool_filtering { + display: block; } #layersTool_filtering_header { display: flex; diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index fe40ccc3..477902ce 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -113,7 +113,7 @@ const Filtering = { Filtering.addValue(layerName) }) }, - destroy: function (layerName) { + destroy: function () { $('#layersTool_filtering').remove() }, addValue: function (layerName, value) { @@ -173,6 +173,11 @@ const Filtering = { if (Filtering.current.type === 'vector') { LocalFilterer.filter(Filtering.filters[layerName], layerName) } else if (Filtering.current.type === 'query') { + ESFilterer.filter( + layerName, + Filtering.filters[layerName], + Filtering.getConfig() + ) } }) diff --git a/src/essence/Tools/Layers/LayersTool.css b/src/essence/Tools/Layers/LayersTool.css index 95ad6434..38afbd44 100644 --- a/src/essence/Tools/Layers/LayersTool.css +++ b/src/essence/Tools/Layers/LayersTool.css @@ -126,7 +126,6 @@ margin: 1px 0px; color: var(--color-f); background: var(--color-j); - overflow: hidden; } #layersToolList > li.forceOff { height: 0 !important; diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index cc8eef3a..7191735e 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -441,7 +441,7 @@ function interfaceWithMMGIS() { '
        ', timeDisplay, '
        ', - '
        ', + '
        ', settings, '
        ', '
      • ', @@ -542,7 +542,7 @@ function interfaceWithMMGIS() { //Support Filtering 1 if (!wasOn) { if (['vector', 'query'].includes(type)) { - Filtering.destroy($('.gears').parent().parent()) + Filtering.destroy() } } @@ -553,7 +553,7 @@ function interfaceWithMMGIS() { //Support Filtering 2 if (!wasOn) { if (['vector', 'query'].includes(type)) { - if (!wasOn) Filtering.make(li, layerName) + if (!wasOn) Filtering.make($(this).parent().parent(), layerName) } } }) From deb6f9de015c6eec7961c8f7af896b1c7608c7e9 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Tue, 4 Jan 2022 17:32:55 -0800 Subject: [PATCH 65/85] #122 Check for empty filter --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index b2e8a5fb..f60aca22 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -176,7 +176,7 @@ const ESFilterer = { }, getFilterMust: function (filter) { let must = [] - if (filter.values && filter.values.length > 0) { + if (filter && filter.values && filter.values.length > 0) { filter.values.forEach((v) => { switch (v.op) { case '=': From ecae439209b14bc6045788185ff3c360ac8eb787 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 08:38:59 -0800 Subject: [PATCH 66/85] #122 Reduce ESFilterer Return size --- config/js/config.js | 2 +- .../Tools/Layers/Filtering/ESFilterer.js | 38 +++++++++++-------- 2 files changed, 23 insertions(+), 17 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 01fcb0b7..11a151a6 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2796,7 +2796,7 @@ function layerPopulateVariable(modalId, layerType) { headers: { "Content-Type": "application/x-ndjson", }, - fields: ["field1", "field2"], + fields: { field1: "max_agg_size_number(0 for no agging)", field2: 0 }, must: [ { match: { diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index f60aca22..2a537c73 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -83,20 +83,19 @@ const ESFilterer = { console.log(layerName, filter, config) let aggs = {} - config.fields.forEach((f) => { + config.fields = config.fields = {} + for (let f in config.fields) { aggs[f] = { terms: { field: f, - size: 1000, + size: config.fields[f] || 0, }, } - }) + } let must = [] if (config.must) must = must.concat(config.must) must = must.concat(ESFilterer.getFilterMust(filter)) - //{ match: { site: 3 } }, - //{ match: { drive: 1374 } }, let query = { query: { @@ -106,7 +105,7 @@ const ESFilterer = { }, aggs: aggs, from: 0, - size: config.size || 1000, + size: config.size || 500, version: true, } @@ -118,15 +117,18 @@ const ESFilterer = { finalBody = config.bodyWrapper.replace('{BODY}', body) else finalBody = body - fetch(config.endpoint, { - method: 'POST', - headers: { - accept: 'application/json', - ...(config.headers || {}), - }, - credentials: config.withCredentials ? 'include' : '', - body: finalBody, - }) + fetch( + `${config.endpoint}?filter_path=hits.hits._source,hits.total,aggregations`, + { + method: 'POST', + headers: { + accept: 'application/json', + ...(config.headers || {}), + }, + credentials: config.withCredentials ? 'include' : '', + body: finalBody, + } + ) .then((res) => res.json()) .then((json) => { console.log(json) @@ -159,7 +161,11 @@ const ESFilterer = { console.log('geojson', geojson) // Set count $('#layersTool_filtering_count').text( - `${geojson.features.length})` + `(${geojson.features.length} out of ${F_.getIn( + json, + 'responses.0.hits.total', + 0 + )})` ) // Update layer From faa8c1b66c70fb5dda318d0956465785f9f05300 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 08:52:30 -0800 Subject: [PATCH 67/85] #122 esResponses --- config/js/config.js | 2 ++ src/essence/Tools/Layers/Filtering/ESFilterer.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/config/js/config.js b/config/js/config.js index 11a151a6..72cda821 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2793,6 +2793,8 @@ function layerPopulateVariable(modalId, layerType) { bodyWrapper: `{"preference":"site"}\n{BODY}\n`, stringifyBody: true, withCredentials: false, + esResponses: + "boolean - is the es responses nested in a responses object", headers: { "Content-Type": "application/x-ndjson", }, diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 2a537c73..9e0a3a55 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -117,8 +117,9 @@ const ESFilterer = { finalBody = config.bodyWrapper.replace('{BODY}', body) else finalBody = body + const resp = config.esResponses ? 'responses.' : '' fetch( - `${config.endpoint}?filter_path=hits.hits._source,hits.total,aggregations`, + `${config.endpoint}?filter_path=${resp}hits.hits._source,${resp}hits.total,${resp}aggregations`, { method: 'POST', headers: { From 6d20f2fe25e94fe2ab6274417be82b4a5c021c18 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 09:01:56 -0800 Subject: [PATCH 68/85] #122 Fix ESFilterer fields --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 9e0a3a55..8abea63e 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -83,7 +83,7 @@ const ESFilterer = { console.log(layerName, filter, config) let aggs = {} - config.fields = config.fields = {} + config.fields = config.fields || {} for (let f in config.fields) { aggs[f] = { terms: { From 60e5877c26014cdd14e3b287608b379aad7f2c95 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 09:42:26 -0800 Subject: [PATCH 69/85] #122 Link replace With --- config/js/config.js | 18 +++++++++++++ src/essence/Ancillary/Description.js | 3 ++- src/essence/Basics/Formulae_/Formulae_.js | 25 +++++++++++++++---- .../Tools/Layers/Filtering/ESFilterer.js | 2 +- 4 files changed, 41 insertions(+), 7 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 72cda821..4bf37d17 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2789,6 +2789,18 @@ function layerPopulateVariable(modalId, layerType) { }; } else if (layerType == "query") { currentLayerVars.useKeyAsName = currentLayerVars.useKeyAsName || "prop"; + currentLayerVars.links = currentLayerVars.links || [ + { + name: "example", + link: "url/?param={prop}", + replace: { + propName: [ + ["this", "withThis"], + ["andThis", "withThisToo"], + ], + }, + }, + ]; currentLayerVars.query = { bodyWrapper: `{"preference":"site"}\n{BODY}\n`, stringifyBody: true, @@ -2869,6 +2881,12 @@ function layerPopulateVariable(modalId, layerType) { { name: "example", link: "url/?param={prop}", + replace: { + propName: [ + ["this", "withThis"], + ["andThis", "withThisToo"], + ], + }, }, ]; diff --git a/src/essence/Ancillary/Description.js b/src/essence/Ancillary/Description.js index 9b397c53..d91f8350 100644 --- a/src/essence/Ancillary/Description.js +++ b/src/essence/Ancillary/Description.js @@ -190,7 +190,8 @@ var Description = { " { - str = str.replace( - new RegExp(v, 'g'), - Formulae_.getIn(obj, v.replace(/[\{\}]/g, '').split('.')) - ) + const replaceProp = v.replace(/[\{\}]/g, '') + let replaceWith = + Formulae_.getIn(obj, replaceProp.split('.'), '') + '' + + // Modify the prop value directly too + if ( + replace && + replace[replaceProp] && + replace[replaceProp].length > 0 + ) { + replace[replaceProp].forEach((rp) => { + replaceWith = replaceWith.replace( + new RegExp(rp[0], 'g'), + rp[1] + ) + }) + } + + str = str.replace(new RegExp(v, 'g'), replaceWith) }) return str }, diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 8abea63e..d397c696 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -88,7 +88,7 @@ const ESFilterer = { aggs[f] = { terms: { field: f, - size: config.fields[f] || 0, + size: config.fields[f] || 10, }, } } From 5d163b2d032a2d3b7c13b3207070d8c3ff8c9d7f Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 15:38:19 -0800 Subject: [PATCH 70/85] #122 Spatial Filters --- config/js/config.js | 1 + src/essence/Tools/Info/InfoTool.css | 2 +- src/essence/Tools/Info/InfoTool.js | 56 +++--- .../Tools/Layers/Filtering/ESFilterer.js | 98 +++++------ .../Tools/Layers/Filtering/Filtering.css | 53 ++++++ .../Tools/Layers/Filtering/Filtering.js | 161 +++++++++++++----- .../Tools/Layers/Filtering/LocalFilterer.js | 118 +++++++------ 7 files changed, 320 insertions(+), 169 deletions(-) diff --git a/config/js/config.js b/config/js/config.js index 4bf37d17..59e7139c 100644 --- a/config/js/config.js +++ b/config/js/config.js @@ -2811,6 +2811,7 @@ function layerPopulateVariable(modalId, layerType) { "Content-Type": "application/x-ndjson", }, fields: { field1: "max_agg_size_number(0 for no agging)", field2: 0 }, + geoshapeProp: "propName of es geoshape field for spatial searches", must: [ { match: { diff --git a/src/essence/Tools/Info/InfoTool.css b/src/essence/Tools/Info/InfoTool.css index 5fca62d4..faeb130f 100644 --- a/src/essence/Tools/Info/InfoTool.css +++ b/src/essence/Tools/Info/InfoTool.css @@ -93,7 +93,7 @@ } #infoToolFilter input { background: #0f0f0f; - width: 220px; + width: 260px; color: #ccc; padding-left: 9px; border: 1px solid rgba(255, 255, 255, 0.2); diff --git a/src/essence/Tools/Info/InfoTool.js b/src/essence/Tools/Info/InfoTool.js index cc1a15a8..ad40a8bf 100644 --- a/src/essence/Tools/Info/InfoTool.js +++ b/src/essence/Tools/Info/InfoTool.js @@ -14,41 +14,41 @@ import './InfoTool.css' //Add the tool markup if you want to do it this way // prettier-ignore var markup = [ - "
        ", - "
        ", - "
        ", - "
        Info
        ", - "
        ", - "
        ", - "
        ", - "
        ", - "", - "
        ", - "
        ", - "", - "
        ", - "
        ", + "
        ", + "
        ", + "
        ", + "
        Info
        ", + "
        ", "
        ", - "
        ", - "
        ", - "
        ", - "
        ", - "", - "", - "
        ", - "", + "
        ", + "
        ", + "", + "
        ", + "
        ", + "", "
        ", "
        ", - "
        ", - "
          ", - "
          No feature selected
          ", + "
          ", + "
          ", + "
          ", + "
          ", + "
          ", + "", + "", + "
          ", + "", "
          ", - "
          " - ].join('\n'); + "
          ", + "
          ", + "
            ", + "
            No feature selected
            ", + "
            ", + "
            " +].join('\n'); var InfoTool = { height: 0, - width: 250, + width: 290, currentLayer: null, currentLayerName: null, info: null, diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index d397c696..187c20a5 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -4,59 +4,6 @@ import $ from 'jquery' import F_ from '../../../Basics/Formulae_/Formulae_' import L_ from '../../../Basics/Layers_/Layers_' -import flat from 'flat' - -const filters = { - Waypoints: { - spatial: { - feature: {}, - operator: 'intersects | contains', - }, - property: [ - { - type: 'string | number', - key: '', - operator: '<, =, >, []', - value: '', - }, - ], - }, -} - -const config = { - type: 'elasticsearch', - endpoint: - 'https://es-ocs.dev.m20.jpl.nasa.gov/m20-dev-cs3-ocs-es-prod/_msearch', - bodyFormatter: `{"preference":"site"}\n{BODY}\n`, - stringifyBody: true, - headers: { - 'Content-Type': 'application/x-ndjson', - accept: 'application/json', - }, - fields: [ - 'activity_id_rtt', - 'drive', - 'footprint_derived_from', - 'instrument_id', - 'orbital_index', - 'seq_id_rtt', - 'site', - 'sol', - 'target_id_rtt', - 'target_name_rtt', - 'version', - 'vicar_label.IDENTIFICATION.START_TIME', - ], - must: [ - { - match: { - ocs_type_name: 'm20-ids-scilo-footprint', - }, - }, - ], - size: 1000, -} - const ESFilterer = { getAggregations: async function (layerName, config) { const results = await ESFilterer.filter(layerName, null, config) @@ -109,6 +56,50 @@ const ESFilterer = { version: true, } + // Spatial Filter + let spatialFilter + if ( + config.geoshapeProp && + filter.spatial && + filter.spatial.center != null && + filter.spatial.feature?.geometry?.type != null + ) { + if (filter.spatial.radius > 0) { + spatialFilter = { + geo_shape: { + [config.geoshapeProp]: { + shape: { + type: filter.spatial.feature.geometry.type.toLowerCase(), + coordinates: + filter.spatial.feature.geometry + .coordinates, + relation: 'intersects', + }, + }, + }, + } + } else { + spatialFilter = { + geo_shape: { + [config.geoshapeProp]: { + shape: { + type: 'point', + coordinates: [ + filter.spatial.center.lng, + filter.spatial.center.lat, + ], + relation: 'contains', + }, + }, + }, + } + } + } + if (spatialFilter) { + query.query.bool.filter = spatialFilter + } + + // Format query let body = query if (config.stringifyBody) body = JSON.stringify(body) @@ -117,6 +108,7 @@ const ESFilterer = { finalBody = config.bodyWrapper.replace('{BODY}', body) else finalBody = body + // Fetch const resp = config.esResponses ? 'responses.' : '' fetch( `${config.endpoint}?filter_path=${resp}hits.hits._source,${resp}hits.total,${resp}aggregations`, diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index 06ac9e19..ec89981a 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -24,6 +24,55 @@ color: #d6d6d6; } +#layerTool_filtering_filters_spatial { + display: flex; +} +#layerTool_filtering_filters_spatial_draw { + padding: 0px 20px; + background: var(--color-o); +} +#layerTool_filtering_filters_spatial_draw > div { + margin-left: 8px; + line-height: 32px; +} +#layerTool_filtering_filters_spatial_draw > i { + color: lime; +} +#layerTool_filtering_filters_spatial_draw:hover { + background: #165379; +} +#layerTool_filtering_filters_spatial_clear { + width: 30px; +} +#layerTool_filtering_filters_spatial_radius_wrapper { + display: flex; +} +#layersTool_filtering + #layerTool_filtering_filters_spatial_radius_wrapper + > input { + background: var(--color-k); + padding-left: 0px; + text-align: right; +} +#layersTool_filtering + #layerTool_filtering_filters_spatial_radius_wrapper + > input:hover { + background: #333; +} +#layerTool_filtering_filters_spatial_radius_wrapper > div:first-child { + background: var(--color-k); + line-height: 30px; + padding: 0px 8px; + font-size: 12px; +} +#layerTool_filtering_filters_spatial_radius_wrapper > div:last-child { + background: var(--color-k); + line-height: 32px; + height: 30px; + padding: 0px 8px 0px 1px; + font-size: 12px; +} + #layersTool_filtering_footer { display: flex; justify-content: space-between; @@ -80,6 +129,10 @@ padding-left: 8px; border: none; font-size: 14px; + transition: background 0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86); +} +#layersTool_filtering input:hover { + background: #222; } #layersTool_filtering select { background: #111; diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 477902ce..4a1a855c 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -3,41 +3,30 @@ import $ from 'jquery' import F_ from '../../../Basics/Formulae_/Formulae_' import L_ from '../../../Basics/Layers_/Layers_' +import Map_ from '../../../Basics/Map_/Map_' import LocalFilterer from './LocalFilterer' import ESFilterer from './ESFilterer' import Dropy from '../../../../external/Dropy/dropy' +import { circle } from '@turf/turf' import './Filtering.css' -const filters = { - Waypoints: { - spatial: { - feature: {}, - operator: 'intersects | contains', - }, - property: [ - { - type: 'string | number', - key: '', - operator: '<, =, >, []', - value: '', - }, - ], - }, -} - const Filtering = { filters: {}, current: {}, + mapSpatialLayer: null, make: async function (container, layerName) { const layerObj = L_.layersNamed[layerName] if (layerObj == null) return Filtering.filters[layerName] = Filtering.filters[layerName] || { - spatial: {}, + spatial: { + center: null, + radius: 0, + }, values: [], } Filtering.current = { @@ -81,11 +70,18 @@ const Filtering = { "
            ", "
            ", "
              ", + "
              Draw
              ", + "
              ", + "
              Radius:
              ", + ``, + "
              m
              ", + "
              ", + "
              ", "
            ", "
              ", "
              ", `", "
              ", @@ -97,21 +93,7 @@ const Filtering = { Filtering.addValue(layerName, v) }) - // Show footer iff value rows exist - $('#layersTool_filtering_footer').css( - 'display', - Filtering.filters[layerName].values.length === 0 ? 'none' : 'flex' - ) - - // Add Spatial - $('#layersTool_filtering_add_spatial').on('click', function () { - const spatialMarkup = [].join('\n') - }) - - // Add Value - $('#layersTool_filtering_add_value').on('click', function () { - Filtering.addValue(layerName) - }) + Filtering.attachEvents(layerName) }, destroy: function () { $('#layersTool_filtering').remove() @@ -156,7 +138,7 @@ const Filtering = { }) } - Filtering.attachEvents(id, layerName, { op: op }) + Filtering.attachValueEvents(id, layerName, { op: op }) // Show footer iff value rows exist $('#layersTool_filtering_footer').css( @@ -164,14 +146,115 @@ const Filtering = { Filtering.filters[layerName].values.length === 0 ? 'none' : 'flex' ) }, - attachEvents: function (id, layerName, options) { - Filtering.attachValueEvents(id, layerName, options) + drawSpatialLayer: function (layerName, center, radius) { + Map_.rmNotNull(Filtering.mapSpatialLayer) + if (center == null) return + + const style = { + fillOpacity: 0.1, + fillColor: 'white', + color: 'lime', + weight: 2, + opacity: 1, + className: 'noPointerEventsImportant', + } + + if (radius > 0) { + // Buffered Circle + const geojson = F_.getBaseGeoJSON() + geojson.features.push( + circle([center.lng, center.lat], radius * 0.001) + ) + + Filtering.mapSpatialLayer = L.geoJSON(geojson, { + style: style, + }).addTo(Map_.map) + Filtering.filters[layerName].spatial.feature = geojson.features[0] + } else { + // Circle marker + Filtering.mapSpatialLayer = new L.circleMarker( + [center.lat, center.lng], + style + ) + .setRadius(4) + .addTo(Map_.map) + + Filtering.filters[layerName].spatial.feature = { + type: 'Feature', + properties: {}, + geometry: { + type: 'Point', + coordinates: [center.lng, center.lat], + }, + } + } + }, + attachEvents: function (layerName) { + // Add Value + $('#layersTool_filtering_add_value').on('click', function () { + Filtering.addValue(layerName) + }) + + // Draw + $('#layerTool_filtering_filters_spatial_draw').on('click', function () { + Map_.rmNotNull(Filtering.mapSpatialLayer) + $('#map').css('cursor', 'crosshair') + $('#layerTool_filtering_filters_spatial_draw > div').text('Drawing') + Map_.map.on('click', spatialOnClick) + }) + function spatialOnClick(e) { + Map_.map.off('click', spatialOnClick) + $('#map').css('cursor', 'grab') + $('#layerTool_filtering_filters_spatial_draw > div').text('Draw') + + Filtering.filters[layerName].spatial.center = { + lng: e.latlng.lng, + lat: e.latlng.lat, + } + Filtering.drawSpatialLayer( + layerName, + Filtering.filters[layerName].spatial.center, + Filtering.filters[layerName].spatial.radius + ) + } + // Draw - Radius + $('#layerTool_filtering_filters_spatial_radius').on( + 'input', + function (e) { + Filtering.filters[layerName].spatial.radius = parseFloat( + $(this).val() + ) + Filtering.drawSpatialLayer( + layerName, + Filtering.filters[layerName].spatial.center, + Filtering.filters[layerName].spatial.radius + ) + } + ) + // Draw - Clear + $('#layerTool_filtering_filters_spatial_clear').on( + 'click', + function () { + Filtering.filters[layerName].spatial.center = null + Map_.map.off('click', spatialOnClick) + $('#map').css('cursor', 'grab') + $('#layerTool_filtering_filters_spatial_draw > div').text( + 'Draw' + ) + + Filtering.drawSpatialLayer( + layerName, + Filtering.filters[layerName].spatial.center, + Filtering.filters[layerName].spatial.radius + ) + } + ) // Submit $(`#layersTool_filtering_submit`).on('click', () => { console.log(Filtering.filters) if (Filtering.current.type === 'vector') { - LocalFilterer.filter(Filtering.filters[layerName], layerName) + LocalFilterer.filter(layerName, Filtering.filters[layerName]) } else if (Filtering.current.type === 'query') { ESFilterer.filter( layerName, @@ -183,6 +266,8 @@ const Filtering = { // Clear $(`#layersTool_filtering_clear`).on('click', async () => { + $('#layerTool_filtering_filters_spatial_clear').click() + Filtering.filters[layerName].values = Filtering.filters[ layerName ].values.filter((v) => { diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js index 8e512074..8e980a38 100644 --- a/src/essence/Tools/Layers/Filtering/LocalFilterer.js +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -5,23 +5,7 @@ import F_ from '../../../Basics/Formulae_/Formulae_' import L_ from '../../../Basics/Layers_/Layers_' import flat from 'flat' - -const filters = { - Waypoints: { - spatial: { - feature: {}, - operator: 'intersects | contains', - }, - property: [ - { - type: 'string | number', - key: '', - operator: '<, =, >, []', - value: '', - }, - ], - }, -} +import { booleanIntersects, booleanContains } from '@turf/turf' const LocalFilterer = { make: function (container, layerName) { @@ -62,14 +46,43 @@ const LocalFilterer = { }) return aggs }, - filter: function (filter, layerName) { + filter: function (layerName, filter) { const geojson = filter.geojson const filteredGeoJSON = JSON.parse(JSON.stringify(geojson)) filteredGeoJSON.features = [] // Filter + const halfFilteredGeoJSONFeatures = [] geojson.features.forEach((f) => { - if (LocalFilterer.match(f, filter)) filteredGeoJSON.features.push(f) + if (LocalFilterer.match(f, filter)) + halfFilteredGeoJSONFeatures.push(f) + }) + + // Spatial Filter (after filter to make it quicker) + halfFilteredGeoJSONFeatures.forEach((f) => { + if (filter.spatial.center == null) { + filteredGeoJSON.features.push(f) + } else { + if (filter.spatial.radius > 0) { + // Circle Intersects + if ( + booleanIntersects( + filter.spatial.feature.geometry, + f.geometry + ) + ) + filteredGeoJSON.features.push(f) + } else { + // Point Contained + if ( + booleanContains( + f.geometry, + filter.spatial.feature.geometry + ) + ) + filteredGeoJSON.features.push(f) + } + } }) // Set count @@ -87,37 +100,44 @@ const LocalFilterer = { let matches = false for (let i = 0; i < filter.values.length; i++) { const v = filter.values[i] - const featureValue = F_.getIn(feature.properties, v.key) - let filterValue = v.value - if (v.type === 'number') filterValue = parseFloat(filterValue) - if (featureValue != null) { - switch (v.op) { - case '=': - if (featureValue == filterValue) matches = true - else matches = false - break - case '<': - if ( - v.type === 'string' - ? featureValue.localeCompare(filterValue) > 0 - : featureValue < filterValue - ) - matches = true - else matches = false - break - case '>': - if ( - v.type === 'string' - ? featureValue.localeCompare(filterValue) < 0 - : featureValue > filterValue - ) - matches = true - else matches = false - break - default: - break + if (v.key != null) { + const featureValue = F_.getIn(feature.properties, v.key) + let filterValue = v.value + if (v.type === 'number') filterValue = parseFloat(filterValue) + if (featureValue != null) { + switch (v.op) { + case '=': + if (featureValue == filterValue) matches = true + else matches = false + break + case '<': + if ( + v.type === 'string' + ? featureValue.localeCompare(filterValue) > + 0 + : featureValue < filterValue + ) + matches = true + else matches = false + break + case '>': + if ( + v.type === 'string' + ? featureValue.localeCompare(filterValue) < + 0 + : featureValue > filterValue + ) + matches = true + else matches = false + break + default: + break + } + if (!matches) return false } - if (!matches) return false + } else { + // True if user never set a key for the filter row + matches = true } } return matches From 181cdc6519d2953f0102a50726653cd51685c588 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 15:44:18 -0800 Subject: [PATCH 71/85] #122 Spatial Filters 2 --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 187c20a5..b8909227 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -60,9 +60,8 @@ const ESFilterer = { let spatialFilter if ( config.geoshapeProp && - filter.spatial && - filter.spatial.center != null && - filter.spatial.feature?.geometry?.type != null + filter?.spatial?.center != null && + filter?.spatial?.feature?.geometry?.type != null ) { if (filter.spatial.radius > 0) { spatialFilter = { From fc1fbd18463ffce4e60039e727ba35ee6d0f51f6 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 17:19:59 -0800 Subject: [PATCH 72/85] #122 Spatial Filters 3 --- .../Tools/Layers/Filtering/ESFilterer.js | 1 + .../Tools/Layers/Filtering/Filtering.css | 55 +++++++++++++++---- .../Tools/Layers/Filtering/Filtering.js | 34 +++++++----- 3 files changed, 65 insertions(+), 25 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index b8909227..22076900 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -176,6 +176,7 @@ const ESFilterer = { let must = [] if (filter && filter.values && filter.values.length > 0) { filter.values.forEach((v) => { + if (v.key == null || v.value == null) return switch (v.op) { case '=': must.push({ diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index ec89981a..3c029aa2 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -23,50 +23,80 @@ padding: 0px 4px; color: #d6d6d6; } +#layersTool_filtering_add_value { + width: 30px; + padding: 0px 6px; +} #layerTool_filtering_filters_spatial { display: flex; + border-bottom: 1px solid #353535; } #layerTool_filtering_filters_spatial_draw { - padding: 0px 20px; - background: var(--color-o); + background: #111; + width: 145px; + display: flex; } #layerTool_filtering_filters_spatial_draw > div { - margin-left: 8px; + margin-left: 4px; line-height: 32px; + font-size: 13px; } #layerTool_filtering_filters_spatial_draw > i { + color: #888; +} +#layerTool_filtering_filters_spatial.drawing + #layerTool_filtering_filters_spatial_draw + > i { + color: var(--color-r7); +} +#layerTool_filtering_filters_spatial.drawn + #layerTool_filtering_filters_spatial_draw + > i { color: lime; } #layerTool_filtering_filters_spatial_draw:hover { - background: #165379; + background: #222; } #layerTool_filtering_filters_spatial_clear { width: 30px; + background: #111; + padding: 0px 6px; + color: #ccc; +} +#layerTool_filtering_filters_spatial_clear:hover { + background: #222; + color: #fff; } #layerTool_filtering_filters_spatial_radius_wrapper { display: flex; + color: #ccc; + width: 85px; + box-sizing: border-box; + border-left: 1px solid #333; + border-right: 1px solid #333; } #layersTool_filtering #layerTool_filtering_filters_spatial_radius_wrapper > input { - background: var(--color-k); + background: #111; padding-left: 0px; text-align: right; + font-size: 13px; } #layersTool_filtering #layerTool_filtering_filters_spatial_radius_wrapper > input:hover { - background: #333; + background: #222; } #layerTool_filtering_filters_spatial_radius_wrapper > div:first-child { - background: var(--color-k); + background: #111; line-height: 30px; padding: 0px 8px; font-size: 12px; } #layerTool_filtering_filters_spatial_radius_wrapper > div:last-child { - background: var(--color-k); + background: #111; line-height: 32px; height: 30px; padding: 0px 8px 0px 1px; @@ -89,13 +119,16 @@ .layersTool_filtering_value { display: flex; - height: 30px; - border-bottom: 1px solid var(--color-k); + height: 31px; + border-bottom: 1px solid #353535; } .layersTool_filtering_value .layersTool_filtering_value_key { flex: 1; } -.layersTool_filtering_value .layersTool_filtering_value_operator { +.layersTool_filtering_value_operator { + box-sizing: border-box; + border-left: 1px solid #333; + border-right: 1px solid #333; } .layersTool_filtering_value .layersTool_filtering_value_value { flex: 1; diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 4a1a855c..43a52444 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -69,19 +69,19 @@ const Filtering = { "
              ", "
              ", "
              ", + "
                ", "
                  ", - "
                  Draw
                  ", + "
                  Draw Spatial Filter
                  ", "
                  ", - "
                  Radius:
                  ", + "
                  R:
                  ", ``, "
                  m
                  ", "
                  ", "
                  ", "
                ", - "
                  ", "
                  ", `", "
                  ", @@ -199,13 +199,19 @@ const Filtering = { $('#layerTool_filtering_filters_spatial_draw').on('click', function () { Map_.rmNotNull(Filtering.mapSpatialLayer) $('#map').css('cursor', 'crosshair') - $('#layerTool_filtering_filters_spatial_draw > div').text('Drawing') + $('#layerTool_filtering_filters_spatial_draw > div').text( + 'Drawing Point' + ) + $('#layerTool_filtering_filters_spatial').removeClass('drawn') + $('#layerTool_filtering_filters_spatial').addClass('drawing') Map_.map.on('click', spatialOnClick) }) function spatialOnClick(e) { Map_.map.off('click', spatialOnClick) $('#map').css('cursor', 'grab') - $('#layerTool_filtering_filters_spatial_draw > div').text('Draw') + $('#layerTool_filtering_filters_spatial_draw > div').text('Drawn') + $('#layerTool_filtering_filters_spatial').removeClass('drawing') + $('#layerTool_filtering_filters_spatial').addClass('drawn') Filtering.filters[layerName].spatial.center = { lng: e.latlng.lng, @@ -239,8 +245,10 @@ const Filtering = { Map_.map.off('click', spatialOnClick) $('#map').css('cursor', 'grab') $('#layerTool_filtering_filters_spatial_draw > div').text( - 'Draw' + 'Draw Spatial Filter' ) + $('#layerTool_filtering_filters_spatial').removeClass('drawn') + $('#layerTool_filtering_filters_spatial').removeClass('drawing') Filtering.drawSpatialLayer( layerName, @@ -266,8 +274,10 @@ const Filtering = { // Clear $(`#layersTool_filtering_clear`).on('click', async () => { + // Clear Spatial Filter $('#layerTool_filtering_filters_spatial_clear').click() + // Clear value filter elements Filtering.filters[layerName].values = Filtering.filters[ layerName ].values.filter((v) => { @@ -275,6 +285,7 @@ const Filtering = { return false }) + // Refilter to show all if (Filtering.current.type === 'vector') { LocalFilterer.filter(layerName, Filtering.filters[layerName]) } else if (Filtering.current.type === 'query') { @@ -285,13 +296,8 @@ const Filtering = { ) } - // Show footer iff value rows exist - $('#layersTool_filtering_footer').css( - 'display', - Filtering.filters[layerName].values.length === 0 - ? 'none' - : 'flex' - ) + // Reset count + $('#layersTool_filtering_count').text('') }) }, attachValueEvents: function (id, layerName, options) { From 8d103e7eb453560a8b16d7482921f3dde2c39a3a Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 17:38:51 -0800 Subject: [PATCH 73/85] #122 Spatial Filters Cleanup --- src/essence/Tools/Info/InfoTool.css | 2 +- src/essence/Tools/Info/InfoTool.js | 2 +- .../Tools/Layers/Filtering/ESFilterer.js | 17 +++++++++-------- .../Tools/Layers/Filtering/Filtering.css | 6 ++++-- src/essence/Tools/Layers/Filtering/Filtering.js | 1 - src/essence/Tools/Layers/LayersTool.js | 2 +- 6 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/essence/Tools/Info/InfoTool.css b/src/essence/Tools/Info/InfoTool.css index faeb130f..a8594323 100644 --- a/src/essence/Tools/Info/InfoTool.css +++ b/src/essence/Tools/Info/InfoTool.css @@ -93,7 +93,7 @@ } #infoToolFilter input { background: #0f0f0f; - width: 260px; + width: 270px; color: #ccc; padding-left: 9px; border: 1px solid rgba(255, 255, 255, 0.2); diff --git a/src/essence/Tools/Info/InfoTool.js b/src/essence/Tools/Info/InfoTool.js index ad40a8bf..09f61225 100644 --- a/src/essence/Tools/Info/InfoTool.js +++ b/src/essence/Tools/Info/InfoTool.js @@ -48,7 +48,7 @@ var markup = [ var InfoTool = { height: 0, - width: 290, + width: 300, currentLayer: null, currentLayerName: null, info: null, diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 22076900..31047498 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -7,7 +7,7 @@ import L_ from '../../../Basics/Layers_/Layers_' const ESFilterer = { getAggregations: async function (layerName, config) { const results = await ESFilterer.filter(layerName, null, config) - console.log('RESULTS', results) + const aggs = {} if (results) { for (let a in results.aggregations) { @@ -22,13 +22,10 @@ const ESFilterer = { } } } - console.log('aggs', aggs) return aggs }, filter: async function (layerName, filter, config) { return new Promise((resolve, reject) => { - console.log(layerName, filter, config) - let aggs = {} config.fields = config.fields || {} for (let f in config.fields) { @@ -123,7 +120,6 @@ const ESFilterer = { ) .then((res) => res.json()) .then((json) => { - console.log(json) const geojson = F_.getBaseGeoJSON() const hits = F_.getIn(json, 'responses.0.hits.hits') hits.forEach((hit) => { @@ -150,12 +146,13 @@ const ESFilterer = { geometry, }) }) - console.log('geojson', geojson) // Set count $('#layersTool_filtering_count').text( `(${geojson.features.length} out of ${F_.getIn( json, - 'responses.0.hits.total', + config.esResponses + ? 'responses.0.hits.total' + : 'hits.total', 0 )})` ) @@ -164,7 +161,11 @@ const ESFilterer = { L_.clearVectorLayer(layerName) L_.updateVectorLayer(layerName, geojson) - resolve(F_.getIn(json, 'responses.0')) + resolve( + config.esResponses + ? F_.getIn(json, 'responses.0') + : json + ) }) .catch((err) => { console.log(err) diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index 3c029aa2..132545c7 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -34,8 +34,10 @@ } #layerTool_filtering_filters_spatial_draw { background: #111; - width: 145px; + flex: 1; display: flex; + overflow: hidden; + white-space: nowrap; } #layerTool_filtering_filters_spatial_draw > div { margin-left: 4px; @@ -71,7 +73,7 @@ #layerTool_filtering_filters_spatial_radius_wrapper { display: flex; color: #ccc; - width: 85px; + width: 90px; box-sizing: border-box; border-left: 1px solid #333; border-right: 1px solid #333; diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 43a52444..f892c5de 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -260,7 +260,6 @@ const Filtering = { // Submit $(`#layersTool_filtering_submit`).on('click', () => { - console.log(Filtering.filters) if (Filtering.current.type === 'vector') { LocalFilterer.filter(layerName, Filtering.filters[layerName]) } else if (Filtering.current.type === 'query') { diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index 7191735e..edadb3de 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -48,7 +48,7 @@ const quasiLayers = ['model', 'query'] var LayersTool = { height: 0, - width: 290, + width: 300, vars: {}, MMGISInterface: null, initialize: function () { From b397ccfcee472198ea977cef84846c74ae69603d Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Wed, 5 Jan 2022 17:46:25 -0800 Subject: [PATCH 74/85] #122 EsFilter account for 0 results --- src/essence/Tools/Layers/Filtering/ESFilterer.js | 2 +- src/essence/Tools/Layers/Filtering/Filtering.css | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 31047498..71f1335a 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -121,7 +121,7 @@ const ESFilterer = { .then((res) => res.json()) .then((json) => { const geojson = F_.getBaseGeoJSON() - const hits = F_.getIn(json, 'responses.0.hits.hits') + const hits = F_.getIn(json, 'responses.0.hits.hits', []) hits.forEach((hit) => { const properties = hit._source || {} let geometry diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index 132545c7..7add8e16 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -183,7 +183,7 @@ transition: background 0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86); } .layersTool_filtering_value_operator_select:hover { - background: var(--color-r4); + background: #222; } .layersTool_filtering_value_remove .mmgisButton5 { From a595e383d456b403eec2da9f6652ce20e65e9fa0 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 7 Jan 2022 15:01:42 -0800 Subject: [PATCH 75/85] #122 Filtering Touchups --- src/essence/Basics/Formulae_/Formulae_.js | 5 +- src/essence/Basics/Layers_/Layers_.js | 16 ++ src/essence/Basics/Map_/Map_.js | 15 -- src/essence/Tools/Info/InfoTool.css | 2 +- src/essence/Tools/Info/InfoTool.js | 26 ++- src/essence/Tools/Kinds/Kinds.js | 30 ++- .../Tools/Layers/Filtering/ESFilterer.js | 16 +- .../Tools/Layers/Filtering/Filtering.css | 74 +++++-- .../Tools/Layers/Filtering/Filtering.js | 167 ++++++++++++--- .../Tools/Layers/Filtering/LocalFilterer.js | 13 ++ src/essence/Tools/Layers/LayersTool.css | 17 +- src/essence/Tools/Layers/LayersTool.js | 198 +++++++++--------- 12 files changed, 404 insertions(+), 175 deletions(-) diff --git a/src/essence/Basics/Formulae_/Formulae_.js b/src/essence/Basics/Formulae_/Formulae_.js index 6fb0a0dd..5c58877a 100644 --- a/src/essence/Basics/Formulae_/Formulae_.js +++ b/src/essence/Basics/Formulae_/Formulae_.js @@ -392,6 +392,9 @@ var Formulae_ = { a: data[position + 3], } }, + getSafeName: function (name) { + return (name || '').replace(/\s/g, '') + }, /** * Traverses an object with an array of keys * @param {*} obj @@ -1392,7 +1395,7 @@ var Formulae_ = { l[i].feature.geometry.coordinates[0] == point[0] && l[i].feature.geometry.coordinates[1] == point[1] ) - points.push(l[i].feature) + points.push(l[i]) } return points diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index df57480a..4b083f02 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -607,6 +607,22 @@ var L_ = { layer.setStyle(newStyle) } catch (err) {} }, + select(layer) { + L_.setLastActivePoint(layer) + L_.resetLayerFills() + L_.highlight(layer) + L_.Map_.activeLayer = layer + Description.updatePoint(L_.Map_.activeLayer) + + L_.Globe_.highlight( + L_.Globe_.findSpriteObject( + layer.options.layerName, + layer.feature.properties[layer.useKeyAsName] + ), + false + ) + L_.Viewer_.highlight(layer) + }, highlight(layer) { const color = (L_.configData.look && L_.configData.look.highlightcolor) || 'red' diff --git a/src/essence/Basics/Map_/Map_.js b/src/essence/Basics/Map_/Map_.js index 92415106..a12168f2 100644 --- a/src/essence/Basics/Map_/Map_.js +++ b/src/essence/Basics/Map_/Map_.js @@ -688,12 +688,6 @@ async function makeLayer(layerObj, evenIfOff) { } function keepGoing() { - L_.setLastActivePoint(layer) - L_.resetLayerFills() - L_.highlight(layer) - Map_.activeLayer = layer - Description.updatePoint(Map_.activeLayer) - //View images var propImages = propertiesToImages( feature.properties, @@ -712,15 +706,6 @@ async function makeLayer(layerObj, evenIfOff) { e ) - Globe_.highlight( - Globe_.findSpriteObject( - layer.options.layerName, - layer.feature.properties[layer.useKeyAsName] - ), - false - ) - Viewer_.highlight(layer) - //update url if (layer != null && layer.hasOwnProperty('options')) { var keyAsName diff --git a/src/essence/Tools/Info/InfoTool.css b/src/essence/Tools/Info/InfoTool.css index a8594323..1003864f 100644 --- a/src/essence/Tools/Info/InfoTool.css +++ b/src/essence/Tools/Info/InfoTool.css @@ -35,7 +35,7 @@ height: 18px; min-width: 18px; text-align: center; - margin: 9px 4px 7px 4px; + margin: 12px 4px 10px 4px; color: var(--color-l); cursor: default; display: none; diff --git a/src/essence/Tools/Info/InfoTool.js b/src/essence/Tools/Info/InfoTool.js index 09f61225..85b1550e 100644 --- a/src/essence/Tools/Info/InfoTool.js +++ b/src/essence/Tools/Info/InfoTool.js @@ -54,6 +54,7 @@ var InfoTool = { info: null, variables: null, activeFeatureI: null, + featureLayers: [], filterString: '', hiddenShown: false, hiddenRootFields: ['_', 'style', 'images'], @@ -77,7 +78,8 @@ var InfoTool = { activeI, open, initialEvent, - additional + additional, + featureLayers ) { let toolActive = $('#InfoTool').hasClass('active') @@ -89,10 +91,15 @@ var InfoTool = { } if (additional && additional.idx) activeI = additional.idx - if (currentLayer != null && currentLayerName != null) { this.currentLayer = currentLayer this.currentLayerName = currentLayerName + if (this.currentLayer.options == null) { + this.currentLayer.options = {} + } + if (this.currentLayer.options.layerName == null) { + this.currentLayer.options.layerName = this.currentLayerName + } this.info = features this.variables = variables let activeIndex = activeI @@ -102,11 +109,14 @@ var InfoTool = { } this.activeFeatureI = activeIndex this.initialEvent = initialEvent + + // Always highlight even if redundant } + this.featureLayers = featureLayers || [] if (open != true) return - //MMGIS should always have a div with id 'tools' - var tools = d3.select('#toolPanel') + // MMGIS should always have a div with id 'tools' + let tools = d3.select('#toolPanel') tools.style('background', 'var(--color-k)') //Clear it tools.selectAll('*').remove() @@ -154,7 +164,7 @@ var InfoTool = { ) name = this.info[i].properties[this.variables.useKeyAsName] - nameItems.push(name) + nameItems.push(this.info.length > 1 ? `${i + 1}. ${name}` : name) } $('#infoToolSelectedDropdown').html( @@ -168,16 +178,18 @@ var InfoTool = { ) Dropy.init($('#infoToolSelectedDropdown'), function (idx) { let e = JSON.parse(JSON.stringify(InfoTool.initialEvent)) + Kinds.use( L_.layersNamed[InfoTool.currentLayerName].kind, Map_, InfoTool.info[idx], - InfoTool.currentLayer, + InfoTool.featureLayers[idx] || InfoTool.currentLayer, InfoTool.currentLayerName, null, e, { idx: idx }, - InfoTool.info + InfoTool.info, + InfoTool.featureLayers[idx] ? InfoTool.featureLayers : null ) }) diff --git a/src/essence/Tools/Kinds/Kinds.js b/src/essence/Tools/Kinds/Kinds.js index 7be1b323..fa7970c1 100644 --- a/src/essence/Tools/Kinds/Kinds.js +++ b/src/essence/Tools/Kinds/Kinds.js @@ -13,8 +13,10 @@ var Kinds = { propImages, e, additional, - preFeatures + preFeatures, + lastFeatureLayers ) { + L_.select(layer) if (typeof kind !== 'string') return const layerVar = L_.layersNamed[layer.options.layerName].variables @@ -336,6 +338,7 @@ var Kinds = { } function useInfo(open) { let features = [] + let featureLayers = [] if (preFeatures == null) { if ( e.latlng == null && @@ -387,9 +390,25 @@ var Kinds = { ) ) .reverse() - - if (features[0] == null || features[0].properties == null) - features = [feature] + if (features[0] == null) features = [feature] + else { + const swapFeatures = [] + features.forEach((f) => { + if ( + typeof f.type === 'string' && + f.type.toLowerCase() === 'feature' + ) + swapFeatures.push(f) + else if ( + f.feature && + typeof f.feature.type === 'string' && + f.feature.type.toLowerCase() === 'feature' + ) + swapFeatures.push(f.feature) + }) + featureLayers = features + features = swapFeatures + } } } else { features = preFeatures @@ -409,7 +428,8 @@ var Kinds = { null, open, ell, - additional + additional, + lastFeatureLayers || featureLayers ) } }, diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 71f1335a..c17bbb9c 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -49,7 +49,7 @@ const ESFilterer = { }, aggs: aggs, from: 0, - size: config.size || 500, + size: filter == null ? 0 : config.size || 500, version: true, } @@ -186,6 +186,20 @@ const ESFilterer = { }, }) break + case ',': + const stringValue = v.value + '' + must.push({ + bool: { + should: stringValue.split(',').map((sv) => { + return { + match: { + [v.key]: sv, + }, + } + }), + }, + }) + break case '>': must.push({ range: { diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index 7add8e16..b92f6624 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -1,5 +1,6 @@ #layersTool_filtering { border-top: 1px solid var(--color-k); + background: var(--color-i); display: none; } .gears_on #layersTool_filtering { @@ -33,47 +34,54 @@ border-bottom: 1px solid #353535; } #layerTool_filtering_filters_spatial_draw { - background: #111; flex: 1; display: flex; overflow: hidden; white-space: nowrap; + padding-left: 0; } #layerTool_filtering_filters_spatial_draw > div { - margin-left: 4px; line-height: 32px; font-size: 13px; } #layerTool_filtering_filters_spatial_draw > i { color: #888; + width: 20px; + height: 20px; + line-height: 20px; + margin: 5px; + border-radius: 4px; } #layerTool_filtering_filters_spatial.drawing #layerTool_filtering_filters_spatial_draw > i { - color: var(--color-r7); + background: var(--color-r7); + color: black; } #layerTool_filtering_filters_spatial.drawn #layerTool_filtering_filters_spatial_draw > i { - color: lime; + background: white; + color: black; } #layerTool_filtering_filters_spatial_draw:hover { - background: #222; + background: #111; } -#layerTool_filtering_filters_spatial_clear { +.layerTool_filtering_filters_clear { width: 30px; background: #111; padding: 0px 6px; - color: #ccc; + color: #888; } -#layerTool_filtering_filters_spatial_clear:hover { - background: #222; +.layerTool_filtering_filters_clear:hover { + background: #333; color: #fff; } #layerTool_filtering_filters_spatial_radius_wrapper { display: flex; + background: var(--color-a1); color: #ccc; - width: 90px; + width: 105px; box-sizing: border-box; border-left: 1px solid #333; border-right: 1px solid #333; @@ -81,7 +89,7 @@ #layersTool_filtering #layerTool_filtering_filters_spatial_radius_wrapper > input { - background: #111; + background: var(--color-a1); padding-left: 0px; text-align: right; font-size: 13px; @@ -89,16 +97,14 @@ #layersTool_filtering #layerTool_filtering_filters_spatial_radius_wrapper > input:hover { - background: #222; + background: #111; } #layerTool_filtering_filters_spatial_radius_wrapper > div:first-child { - background: #111; line-height: 30px; padding: 0px 8px; font-size: 12px; } #layerTool_filtering_filters_spatial_radius_wrapper > div:last-child { - background: #111; line-height: 32px; height: 30px; padding: 0px 8px 0px 1px; @@ -156,7 +162,7 @@ } #layersTool_filtering input { - background: #111; + background: var(--color-a1); color: #ccc; width: 100%; box-sizing: border-box; @@ -167,7 +173,10 @@ transition: background 0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86); } #layersTool_filtering input:hover { - background: #222; + background: #111; +} +.layersTool_filtering_value_value_input { + border-right: 1px solid #333 !important; } #layersTool_filtering select { background: #111; @@ -175,7 +184,7 @@ height: 30px; } .layersTool_filtering_value_operator_select { - background: #111111; + background: #333; color: var(--color-f); border: none; cursor: pointer; @@ -183,7 +192,7 @@ transition: background 0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86); } .layersTool_filtering_value_operator_select:hover { - background: #222; + background: #111; } .layersTool_filtering_value_remove .mmgisButton5 { @@ -194,6 +203,14 @@ } #layersTool_filtering_submit { padding: 0px 8px; + transition: background 0.2s cubic-bezier(0.785, 0.135, 0.15, 0.86); +} +#layersTool_filtering_submit.active { + background: var(--color-h); + color: black; +} +#layersTool_filtering_submit.active:hover { + background: #fffb80; } #layersTool_filtering .dropy, @@ -216,3 +233,24 @@ #layersTool_filtering .dropy__content ul { transition: none; } + +#layersTool_filtering_submit_loading { + display: none; + padding: 6px 6px 6px 0px; +} +#layersTool_filtering_submit_loading.active { + display: block; +} +#layersTool_filtering_submit_loading.active > div { + width: 18px; + height: 18px; + border-radius: 50%; + border: 3px solid black; + border-top: 3px solid transparent; + animation: submitLoadingSpin 1s ease-in-out infinite; +} +@keyframes submitLoadingSpin { + to { + transform: rotate(360deg); + } +} diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index f892c5de..9253dbf6 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -28,6 +28,7 @@ const Filtering = { radius: 0, }, values: [], + geojson: null, } Filtering.current = { layerName: layerName, @@ -38,6 +39,7 @@ const Filtering = { if (Filtering.current.type === 'vector') { try { Filtering.filters[layerName].geojson = + Filtering.filters[layerName].geojson || L_.layersGroup[layerName].toGeoJSON() } catch (err) { console.warn( @@ -65,24 +67,24 @@ const Filtering = { "
                  ", "", "
                  ", - "
                  ", + "
                  ", "
                  ", "", "
                  ", "
                    ", "
                      ", - "
                      Draw Spatial Filter
                      ", + "
                      Place Point
                      ", "
                      ", "
                      R:
                      ", - ``, + ``, "
                      m
                      ", "
                      ", - "
                      ", + "
                      ", "
                    ", "
                    ", `", "", ].join('\n') @@ -94,8 +96,24 @@ const Filtering = { }) Filtering.attachEvents(layerName) + + Filtering.drawSpatialLayer( + layerName, + Filtering.filters[layerName].spatial.center, + Filtering.filters[layerName].spatial.radius + ) }, destroy: function () { + // Clear Spatial Filter + // We save the center because we're not completely clearing it + if (Filtering.filters[Filtering.current.layerName]) { + const savedCenter = + Filtering.filters[Filtering.current.layerName].spatial.center + $('#layerTool_filtering_filters_spatial_clear').click() + Filtering.filters[Filtering.current.layerName].spatial.center = + savedCenter + } + $('#layersTool_filtering').remove() }, addValue: function (layerName, value) { @@ -109,20 +127,21 @@ const Filtering = { // prettier-ignore const valueMarkup = [ - `
                    `, + `
                    `, "
                    ", - ``, + ``, "
                    ", "
                    ", - `
                    `, + `
                    `, "
                    ", "
                    ", - ``, + ``, `
                    `, - ``, - ``, + ``, + ``, `
                    `, "
                    ", + `
                    `, "
                    ", ].join('\n') @@ -148,6 +167,8 @@ const Filtering = { }, drawSpatialLayer: function (layerName, center, radius) { Map_.rmNotNull(Filtering.mapSpatialLayer) + + Filtering.setSubmitButtonState(true) if (center == null) return const style = { @@ -188,6 +209,17 @@ const Filtering = { }, } } + Filtering.mapSpatialLayer.bringToFront() + }, + // To highlight the submit button to indicate a change's been made in the form + setSubmitButtonState: function (active) { + if (active) { + $('#layersTool_filtering_submit_text').text('Submit') + $('#layersTool_filtering_submit').addClass('active') + } else if ($('#layersTool_filtering_submit').hasClass('active')) { + $('#layersTool_filtering_submit_text').text('Submitted') + $('#layersTool_filtering_submit').removeClass('active') + } }, attachEvents: function (layerName) { // Add Value @@ -200,7 +232,7 @@ const Filtering = { Map_.rmNotNull(Filtering.mapSpatialLayer) $('#map').css('cursor', 'crosshair') $('#layerTool_filtering_filters_spatial_draw > div').text( - 'Drawing Point' + 'Placing Point' ) $('#layerTool_filtering_filters_spatial').removeClass('drawn') $('#layerTool_filtering_filters_spatial').addClass('drawing') @@ -209,7 +241,7 @@ const Filtering = { function spatialOnClick(e) { Map_.map.off('click', spatialOnClick) $('#map').css('cursor', 'grab') - $('#layerTool_filtering_filters_spatial_draw > div').text('Drawn') + $('#layerTool_filtering_filters_spatial_draw > div').text('Active') $('#layerTool_filtering_filters_spatial').removeClass('drawing') $('#layerTool_filtering_filters_spatial').addClass('drawn') @@ -245,7 +277,7 @@ const Filtering = { Map_.map.off('click', spatialOnClick) $('#map').css('cursor', 'grab') $('#layerTool_filtering_filters_spatial_draw > div').text( - 'Draw Spatial Filter' + 'Place Point' ) $('#layerTool_filtering_filters_spatial').removeClass('drawn') $('#layerTool_filtering_filters_spatial').removeClass('drawing') @@ -259,28 +291,43 @@ const Filtering = { ) // Submit - $(`#layersTool_filtering_submit`).on('click', () => { + $(`#layersTool_filtering_submit`).on('click', async () => { + Filtering.setSubmitButtonState(true) + $(`#layersTool_filtering_submit_loading`).addClass('active') if (Filtering.current.type === 'vector') { LocalFilterer.filter(layerName, Filtering.filters[layerName]) } else if (Filtering.current.type === 'query') { - ESFilterer.filter( + await ESFilterer.filter( layerName, Filtering.filters[layerName], Filtering.getConfig() ) } + + $(`#layersTool_filtering_submit_loading`).removeClass('active') + Filtering.setSubmitButtonState(false) + + if (Filtering.mapSpatialLayer) + Filtering.mapSpatialLayer.bringToFront() + + console.log(L_) }) // Clear $(`#layersTool_filtering_clear`).on('click', async () => { // Clear Spatial Filter $('#layerTool_filtering_filters_spatial_clear').click() + $(`#layersTool_filtering_submit_loading`).addClass('active') // Clear value filter elements Filtering.filters[layerName].values = Filtering.filters[ layerName ].values.filter((v) => { - $(`#layersTool_filtering_value_${layerName}_${v.id}`).remove() + $( + `#layersTool_filtering_value_${F_.getSafeName(layerName)}_${ + v.id + }` + ).remove() return false }) @@ -297,6 +344,13 @@ const Filtering = { // Reset count $('#layersTool_filtering_count').text('') + + Filtering.setSubmitButtonState(false) + + $(`#layersTool_filtering_submit_loading`).removeClass('active') + + if (Filtering.mapSpatialLayer) + Filtering.mapSpatialLayer.bringToFront() }) }, attachValueEvents: function (id, layerName, options) { @@ -304,8 +358,53 @@ const Filtering = { let elmId + // Expand input boxes on focus + // Contract input boxes on blur + elmId = `#layersTool_filtering_value_key_input_${F_.getSafeName( + layerName + )}_${id}` + $(elmId).on('focus', function () { + $(this).parent().css('flex', '2 1') + }) + $(elmId).on('blur', function () { + $(this).parent().css('flex', '1 1') + }) + elmId = `#layersTool_filtering_value_value_input_${F_.getSafeName( + layerName + )}_${id}` + $(elmId).on('focus', function () { + $(this).parent().css('flex', '2 1') + }) + $(elmId).on('blur', function () { + $(this).parent().css('flex', '1 1') + }) + // Clear + elmId = `#layersTool_filtering_value_clear_${F_.getSafeName( + layerName + )}_${id}` + + $(elmId).on('click', () => { + // Clear value filter element + Filtering.filters[layerName].values = Filtering.filters[ + layerName + ].values.filter((v) => { + if (v.id === id) { + $( + `#layersTool_filtering_value_${F_.getSafeName( + layerName + )}_${v.id}` + ).remove() + return false + } + return true + }) + Filtering.setSubmitButtonState(true) + }) + // Property Autocomplete - elmId = `#layersTool_filtering_value_key_input_${layerName}_${id}` + elmId = `#layersTool_filtering_value_key_input_${F_.getSafeName( + layerName + )}_${id}` let arrayToSearch = Object.keys(Filtering.filters[layerName].aggs) arrayToSearch = arrayToSearch.sort((a, b) => b.localeCompare(a)) @@ -342,6 +441,7 @@ const Filtering = { Filtering.filters[layerName].values[id].type = property.type Filtering.filters[layerName].values[id].key = event.value Filtering.updateValuesAutoComplete(id, layerName) + Filtering.setSubmitButtonState(true) $(this).css('border', 'none') }, }) @@ -355,22 +455,26 @@ const Filtering = { Filtering.filters[layerName].values[id].key = event.value Filtering.filters[layerName].values[id].type = property.type Filtering.updateValuesAutoComplete(id, layerName) + Filtering.setSubmitButtonState(true) } $(this).css('border', 'none') } else $(this).css('border', '1px solid red') }) // Operator Dropdown - elmId = `#layersTool_filtering_value_operator_${layerName}_${id}` + elmId = `#layersTool_filtering_value_operator_${F_.getSafeName( + layerName + )}_${id}` - const ops = ['=', '<', '>'] + const ops = ['=', ',', '<', '>'] const opId = Math.max(ops.indexOf(options.op), 0) $(elmId).html( Dropy.construct( [ - ``, - ``, - ``, + ``, + ``, + ``, + ``, ], 'op', opId @@ -378,13 +482,16 @@ const Filtering = { ) Dropy.init($(elmId), function (idx) { Filtering.filters[layerName].values[id].op = ops[idx] + Filtering.setSubmitButtonState(true) }) // Value AutoComplete Filtering.updateValuesAutoComplete(id, layerName) }, updateValuesAutoComplete: function (id, layerName) { - let elmId = `#layersTool_filtering_value_value_input_${layerName}_${id}` + let elmId = `#layersTool_filtering_value_value_input_${F_.getSafeName( + layerName + )}_${id}` let arrayToSearch = [] if ( Filtering.filters[layerName].values[id].key && @@ -426,10 +533,12 @@ const Filtering = { }, onSelect: function (event) { Filtering.filters[layerName].values[id].value = event.value + Filtering.setSubmitButtonState(true) }, }) $(elmId).on('keyup', function (e) { Filtering.filters[layerName].values[id].value = $(this).val() + Filtering.setSubmitButtonState(true) }) $('.autocomplete-suggestions').css({ @@ -441,8 +550,12 @@ const Filtering = { }) // Change type indicator icons too - const numberElmId = `#layersTool_filtering_value_value_type_number_${layerName}_${id}` - const stringElmId = `#layersTool_filtering_value_value_type_string_${layerName}_${id}` + const numberElmId = `#layersTool_filtering_value_value_type_number_${F_.getSafeName( + layerName + )}_${id}` + const stringElmId = `#layersTool_filtering_value_value_type_string_${F_.getSafeName( + layerName + )}_${id}` switch (Filtering.filters[layerName].values[id].type) { case 'number': $(numberElmId).css('display', 'inherit') diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js index 8e980a38..e0e149d6 100644 --- a/src/essence/Tools/Layers/Filtering/LocalFilterer.js +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -110,6 +110,19 @@ const LocalFilterer = { if (featureValue == filterValue) matches = true else matches = false break + case ',': + if (filterValue != null) { + const stringFilterValue = filterValue + '' + const stringFeatureValue = featureValue + '' + if ( + stringFilterValue + .split(',') + .includes(stringFeatureValue) + ) + matches = true + else matches = false + } else matches = false + break case '<': if ( v.type === 'string' diff --git a/src/essence/Tools/Layers/LayersTool.css b/src/essence/Tools/Layers/LayersTool.css index 38afbd44..4f8d74ca 100644 --- a/src/essence/Tools/Layers/LayersTool.css +++ b/src/essence/Tools/Layers/LayersTool.css @@ -80,7 +80,7 @@ } #layersTool #searchLayers input { background: #111; - width: 229px; + width: 239px; color: #ccc; padding-left: 12px; border: 1px solid rgba(255, 255, 255, 0.2); @@ -158,7 +158,9 @@ overflow: hidden; color: #ccc; } - +#layersTool .layerExport { + padding: 0 !important; +} #layersTool .layerExport ul, #layersTool .settings ul { list-style-type: none; @@ -172,6 +174,17 @@ display: flex; justify-content: space-between; } +#layersTool .layerExport li { + height: 30px; + line-height: 30px; + padding: 2px 6px 2px 12px; + cursor: pointer; + color: #ddd; +} +#layersTool .layerExport li:hover { + background: var(--color-b); +} + #layersTool .layerExport ul > li > div:hover { color: white; } diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index edadb3de..79ca968f 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -146,16 +146,17 @@ function interfaceWithMMGIS() { var layerExport switch (node[i].type) { case 'vector': + case 'query': // prettier-ignore layerExport = [ - '
                      ', - '
                    • ', - '
                      ', - '
                      Export as GeoJSON
                      ', - '
                      ', - '
                    • ', - '
                    ', - ].join('\n') + '
                      ', + '
                    • ', + '
                      ', + '
                      Export as GeoJSON
                      ', + '
                      ', + '
                    • ', + '
                    ', + ].join('\n') break default: layerExport = '' @@ -171,7 +172,7 @@ function interfaceWithMMGIS() { '
                    ', '
                    Start Time
                    ', '', @@ -181,7 +182,7 @@ function interfaceWithMMGIS() { '
                    ', '
                    End Time
                    ', '', @@ -203,26 +204,26 @@ function interfaceWithMMGIS() { // prettier-ignore settings = [ - '
                      ', - '
                    • ', - '
                      ', - '
                      Opacity
                      ', - '', + '
                        ', + '
                      • ', + '
                        ', + '
                        Opacity
                        ', + '', + '
                        ', + L_.layersGroupSublayers[node[i].name] ? Object.keys(L_.layersGroupSublayers[node[i].name]).map((function(i){return function(s) { + return [ + '
                        ', + `
                        ${F_.prettifyName(s)}
                        `, + '
                        ', + `
                        `, + '
                        ', '
                        ', - L_.layersGroupSublayers[node[i].name] ? Object.keys(L_.layersGroupSublayers[node[i].name]).map((function(i){return function(s) { - return [ - '
                        ', - `
                        ${F_.prettifyName(s)}
                        `, - '
                        ', - `
                        `, - '
                        ', - '
                        ', - ].join('\n') - }})(i)).join('\n') : null, - '
                      ', - '
                    • ', - '
                    ', - ].join('\n') + ].join('\n') + }})(i)).join('\n') : null, + '
                    ', + '', + '', + ].join('\n') break case 'tile': currentOpacity = L_.getLayerOpacity(node[i].name) @@ -256,70 +257,70 @@ function interfaceWithMMGIS() { // prettier-ignore settings = [ - '
                      ', - '
                    • ', - '
                      ', - '
                      Opacity
                      ', - '', - '
                      ', - '
                    • ', - '
                    • ', - '
                      ', - '
                      Brightness
                      ', - '', - '
                      ', - '
                    • ', - '
                    • ', - '
                      ', - '
                      Contrast
                      ', - '', - '
                      ', - '
                    • ', - '
                    • ', - '
                      ', - '
                      Saturation
                      ', - '', - '
                      ', - '
                    • ', - '
                    • ', - '
                      ', - '
                      Blend
                      ', - '', - '
                      ', - '
                    • ', - /* - '
                    • ', - '
                      ', - '
                      Hue
                      ', - '', - '
                      ', - '
                    • ', - '
                    • ', - '
                      ', - '
                      Invert
                      ', - '', - '
                      ', - '
                    • ', - */ - '
                    ' - ].join('\n') + '
                      ', + '
                    • ', + '
                      ', + '
                      Opacity
                      ', + '', + '
                      ', + '
                    • ', + '
                    • ', + '
                      ', + '
                      Brightness
                      ', + '', + '
                      ', + '
                    • ', + '
                    • ', + '
                      ', + '
                      Contrast
                      ', + '', + '
                      ', + '
                    • ', + '
                    • ', + '
                      ', + '
                      Saturation
                      ', + '', + '
                      ', + '
                    • ', + '
                    • ', + '
                      ', + '
                      Blend
                      ', + '', + '
                      ', + '
                    • ', + /* + '
                    • ', + '
                      ', + '
                      Hue
                      ', + '', + '
                      ', + '
                    • ', + '
                    • ', + '
                      ', + '
                      Invert
                      ', + '', + '
                      ', + '
                    • ', + */ + '
                    ' + ].join('\n') break case 'data': currentOpacity = L_.getLayerOpacity(node[i].name) @@ -370,6 +371,7 @@ function interfaceWithMMGIS() { ].join('\n') break case 'model': + case 'query': // prettier-ignore settings = [ '
                      ', @@ -413,8 +415,8 @@ function interfaceWithMMGIS() { // prettier-ignore $('#layersToolList').append( [ - '
                    • ', - '
                      ', + '
                    • ', + '
                      ', '
                      ', '
                      ', '
                      ', @@ -425,13 +427,13 @@ function interfaceWithMMGIS() { '
                      ', '', '
                      ', - (layerExport != '') ? ['
                      ', + (layerExport != '') ? ['
                      ', '', '
                      '].join('\n') : '', - (timeDisplay != '') ? ['
                      ', + (timeDisplay != '') ? ['
                      ', '', '
                      '].join('\n') : '', - '
                      ', + '
                      ', '', '
                      ', '
                      ', From e9b944494e75d9c96385bf8c64d41dca21ba3e59 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 7 Jan 2022 15:28:49 -0800 Subject: [PATCH 76/85] #122 Fix query layer polygon highlighting --- src/essence/Basics/Layers_/Layers_.js | 3 +- .../Tools/Layers/Filtering/ESFilterer.js | 2 +- .../Tools/Layers/Filtering/Filtering.js | 32 +++++++++++-------- .../Tools/Layers/Filtering/LocalFilterer.js | 2 +- 4 files changed, 22 insertions(+), 17 deletions(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 4b083f02..65ecedcd 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -963,7 +963,8 @@ var L_ = { this.layersNamed[key] && (this.layersNamed[key].type == 'point' || (key.toLowerCase().indexOf('draw') == -1 && - this.layersNamed[key].type == 'vector'))) || + (this.layersNamed[key].type === 'vector' || + this.layersNamed[key].type === 'query')))) || (s[0] == 'DrawTool' && !Number.isNaN(onId)) ) { if ( diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index c17bbb9c..8905e4de 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -177,7 +177,7 @@ const ESFilterer = { let must = [] if (filter && filter.values && filter.values.length > 0) { filter.values.forEach((v) => { - if (v.key == null || v.value == null) return + if (v == null || v.key == null || v.value == null) return switch (v.op) { case '=': must.push({ diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 9253dbf6..2588672d 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -92,7 +92,7 @@ const Filtering = { container.append(markup) Filtering.filters[layerName].values.forEach((v) => { - Filtering.addValue(layerName, v) + if (v) Filtering.addValue(layerName, v) }) Filtering.attachEvents(layerName) @@ -323,11 +323,12 @@ const Filtering = { Filtering.filters[layerName].values = Filtering.filters[ layerName ].values.filter((v) => { - $( - `#layersTool_filtering_value_${F_.getSafeName(layerName)}_${ - v.id - }` - ).remove() + if (v) + $( + `#layersTool_filtering_value_${F_.getSafeName( + layerName + )}_${v.id}` + ).remove() return false }) @@ -385,19 +386,21 @@ const Filtering = { $(elmId).on('click', () => { // Clear value filter element - Filtering.filters[layerName].values = Filtering.filters[ - layerName - ].values.filter((v) => { - if (v.id === id) { + for ( + let i = 0; + i < Filtering.filters[layerName].values.length; + i++ + ) { + const vId = Filtering.filters[layerName].values[i].id + if (vId != null && vId === id) { $( `#layersTool_filtering_value_${F_.getSafeName( layerName - )}_${v.id}` + )}_${vId}` ).remove() - return false + Filtering.filters[layerName].values[i] = null } - return true - }) + } Filtering.setSubmitButtonState(true) }) @@ -450,6 +453,7 @@ const Filtering = { const property = Filtering.filters[layerName].aggs[event.value] if (property) { if ( + Filtering.filters[layerName].values[id] && Filtering.filters[layerName].values[id].key !== event.value ) { Filtering.filters[layerName].values[id].key = event.value diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js index e0e149d6..055e3f84 100644 --- a/src/essence/Tools/Layers/Filtering/LocalFilterer.js +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -100,7 +100,7 @@ const LocalFilterer = { let matches = false for (let i = 0; i < filter.values.length; i++) { const v = filter.values[i] - if (v.key != null) { + if (v && v.key != null) { const featureValue = F_.getIn(feature.properties, v.key) let filterValue = v.value if (v.type === 'number') filterValue = parseFloat(filterValue) From 27d3e6423eaf1bd49f8b222c133b4869794d2fb9 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 7 Jan 2022 15:57:05 -0800 Subject: [PATCH 77/85] #122 Bug fixes --- src/essence/Tools/Info/InfoTool.js | 5 +++-- src/essence/Tools/Layers/Filtering/Filtering.js | 8 +++++--- src/essence/Tools/Layers/Filtering/LocalFilterer.js | 4 +++- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/essence/Tools/Info/InfoTool.js b/src/essence/Tools/Info/InfoTool.js index 85b1550e..67126f46 100644 --- a/src/essence/Tools/Info/InfoTool.js +++ b/src/essence/Tools/Info/InfoTool.js @@ -178,7 +178,6 @@ var InfoTool = { ) Dropy.init($('#infoToolSelectedDropdown'), function (idx) { let e = JSON.parse(JSON.stringify(InfoTool.initialEvent)) - Kinds.use( L_.layersNamed[InfoTool.currentLayerName].kind, Map_, @@ -444,7 +443,9 @@ function interfaceWithMMGIS() { InfoTool.variables, null, true, - null + null, + null, + InfoTool.featureLayers ) //Share everything. Don't take things that aren't yours. diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 2588672d..7b257d86 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -57,6 +57,8 @@ const Filtering = { Filtering.getConfig() ) } + const spatialActive = + Filtering.filters[layerName].spatial?.center != null // prettier-ignore const markup = [ @@ -72,8 +74,8 @@ const Filtering = { "
                      ", "
                      ", "
                        ", - "
                          ", - "
                          Place Point
                          ", + `
                            `, + `
                            ${spatialActive ? 'Active' : 'Place Point'}
                            `, "
                            ", "
                            R:
                            ", ``, @@ -476,7 +478,7 @@ const Filtering = { Dropy.construct( [ ``, - ``, + ``, ``, ``, ], diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js index 055e3f84..772940a8 100644 --- a/src/essence/Tools/Layers/Filtering/LocalFilterer.js +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -103,7 +103,8 @@ const LocalFilterer = { if (v && v.key != null) { const featureValue = F_.getIn(feature.properties, v.key) let filterValue = v.value - if (v.type === 'number') filterValue = parseFloat(filterValue) + if (v.type === 'number' && v.op != ',') + filterValue = parseFloat(filterValue) if (featureValue != null) { switch (v.op) { case '=': @@ -111,6 +112,7 @@ const LocalFilterer = { else matches = false break case ',': + console.log(',', filterValue, featureValue) if (filterValue != null) { const stringFilterValue = filterValue + '' const stringFeatureValue = featureValue + '' From ed7f702fb22df1bd252e9556ff3de5ec370178b1 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 7 Jan 2022 16:11:46 -0800 Subject: [PATCH 78/85] #122 Final Touches --- src/essence/Tools/Layers/Filtering/Filtering.js | 5 ++--- src/essence/Tools/Layers/Filtering/LocalFilterer.js | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 7b257d86..12c755f1 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -311,8 +311,6 @@ const Filtering = { if (Filtering.mapSpatialLayer) Filtering.mapSpatialLayer.bringToFront() - - console.log(L_) }) // Clear @@ -452,7 +450,8 @@ const Filtering = { }) $(elmId).on('blur', function (event) { - const property = Filtering.filters[layerName].aggs[event.value] + const property = + Filtering.filters[layerName].aggs[event.value || $(this).val()] if (property) { if ( Filtering.filters[layerName].values[id] && diff --git a/src/essence/Tools/Layers/Filtering/LocalFilterer.js b/src/essence/Tools/Layers/Filtering/LocalFilterer.js index 772940a8..394f2326 100644 --- a/src/essence/Tools/Layers/Filtering/LocalFilterer.js +++ b/src/essence/Tools/Layers/Filtering/LocalFilterer.js @@ -112,7 +112,6 @@ const LocalFilterer = { else matches = false break case ',': - console.log(',', filterValue, featureValue) if (filterValue != null) { const stringFilterValue = filterValue + '' const stringFeatureValue = featureValue + '' From 1010f5907aa110df3a42cb6e6cc399d190f12524 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 7 Jan 2022 16:32:39 -0800 Subject: [PATCH 79/85] #122 Fix fillOpacity setStyle (not per feature) --- src/essence/Basics/Layers_/Layers_.js | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 65ecedcd..4c004949 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -905,12 +905,21 @@ var L_ = { setLayerOpacity: function (name, newOpacity) { newOpacity = parseFloat(newOpacity) if (L_.Globe_) L_.Globe_.litho.setLayerOpacity(name, newOpacity) - var l = L_.layersGroup[name] + let l = L_.layersGroup[name] + + if (l.options.initialFillOpacity == null) + l.options.initialFillOpacity = + L_.layersStyles[name]?.fillOpacity != null + ? parseFloat(L_.layersStyles[name]?.fillOpacity) + : 1 if (l) { try { l.setOpacity(newOpacity) } catch (error) { - l.setStyle({ opacity: newOpacity, fillOpacity: newOpacity }) + l.setStyle({ + opacity: newOpacity, + fillOpacity: newOpacity * l.options.initialFillOpacity, + }) $( `.leafletMarkerShape_${name .replace(/\s/g, '') @@ -918,12 +927,15 @@ var L_ = { ).css({ opacity: newOpacity }) } try { - l.options.fillOpacity = newOpacity + l.options.fillOpacity = + newOpacity * l.options.initialFillOpacity l.options.opacity = newOpacity - l.options.style.fillOpacity = newOpacity + l.options.style.fillOpacity = + newOpacity * l.options.initialFillOpacity l.options.style.opacity = newOpacity } catch (error) { - l.options.fillOpacity = newOpacity + l.options.fillOpacity = + newOpacity * l.options.initialFillOpacity l.options.opacity = newOpacity } } From 605112556e345316f86b9f643f46d7a4c86b63fe Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Fri, 7 Jan 2022 18:07:32 -0800 Subject: [PATCH 80/85] #122 Touch ups 2 --- src/essence/Basics/Layers_/Layers_.js | 3 +++ src/essence/Tools/Info/InfoTool.css | 3 ++- src/essence/Tools/Info/InfoTool.js | 4 +++- .../Tools/Layers/Filtering/ESFilterer.js | 8 +++++++- .../Tools/Layers/Filtering/Filtering.css | 11 +++++++++-- .../Tools/Layers/Filtering/Filtering.js | 19 ++++++------------- src/essence/Tools/Layers/LayersTool.js | 8 +++----- src/external/Dropy/dropy.css | 3 +++ src/external/Dropy/dropy.js | 2 +- 9 files changed, 37 insertions(+), 24 deletions(-) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 4c004949..9e9c4476 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -649,6 +649,9 @@ var L_ = { if (layer._icon) layer._icon.style.filter = `drop-shadow(${color} 2px 0px 0px) drop-shadow(${color} -2px 0px 0px) drop-shadow(${color} 0px 2px 0px) drop-shadow(${color} 0px -2px 0px)` } + try { + layer.bringToFront() + } catch (err) {} }, addArrowToMap: function ( layerId, diff --git a/src/essence/Tools/Info/InfoTool.css b/src/essence/Tools/Info/InfoTool.css index 1003864f..b53d494b 100644 --- a/src/essence/Tools/Info/InfoTool.css +++ b/src/essence/Tools/Info/InfoTool.css @@ -31,7 +31,8 @@ #infoToolEquiv { font-size: 12px; background: var(--color-b); - border-radius: 50%; + border-radius: 3px; + padding: 0px 4px; height: 18px; min-width: 18px; text-align: center; diff --git a/src/essence/Tools/Info/InfoTool.js b/src/essence/Tools/Info/InfoTool.js index 67126f46..87e26a37 100644 --- a/src/essence/Tools/Info/InfoTool.js +++ b/src/essence/Tools/Info/InfoTool.js @@ -140,7 +140,9 @@ var InfoTool = { // Update number of equivalent features if (this.info.length > 1) { - $('#infoToolEquiv').text(`${this.info.length}`) + $('#infoToolEquiv').text( + `${this.activeFeatureI + 1} of ${this.info.length}` + ) $('#infoToolEquiv').css('display', 'block') } else { $('#infoToolEquiv').text(`1`) diff --git a/src/essence/Tools/Layers/Filtering/ESFilterer.js b/src/essence/Tools/Layers/Filtering/ESFilterer.js index 8905e4de..8e7166e2 100644 --- a/src/essence/Tools/Layers/Filtering/ESFilterer.js +++ b/src/essence/Tools/Layers/Filtering/ESFilterer.js @@ -39,7 +39,8 @@ const ESFilterer = { let must = [] if (config.must) must = must.concat(config.must) - must = must.concat(ESFilterer.getFilterMust(filter)) + const filterMust = ESFilterer.getFilterMust(filter) + must = must.concat(filterMust) let query = { query: { @@ -95,6 +96,11 @@ const ESFilterer = { query.query.bool.filter = spatialFilter } + // Ignore results if no filters set + if (spatialFilter == null && filterMust.length === 0) { + query.size = 0 + } + // Format query let body = query if (config.stringifyBody) body = JSON.stringify(body) diff --git a/src/essence/Tools/Layers/Filtering/Filtering.css b/src/essence/Tools/Layers/Filtering/Filtering.css index b92f6624..ba08423a 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.css +++ b/src/essence/Tools/Layers/Filtering/Filtering.css @@ -38,7 +38,7 @@ display: flex; overflow: hidden; white-space: nowrap; - padding-left: 0; + padding-left: 8px; } #layerTool_filtering_filters_spatial_draw > div { line-height: 32px; @@ -61,7 +61,7 @@ #layerTool_filtering_filters_spatial.drawn #layerTool_filtering_filters_spatial_draw > i { - background: white; + background: lime; color: black; } #layerTool_filtering_filters_spatial_draw:hover { @@ -153,6 +153,8 @@ width: 30px; text-align: center; color: #999; + opacity: 0; + transition: opacity 0.2s ease-out; } .layersTool_filtering_value_value_type > i:first-child { color: var(--color-yellow); @@ -161,6 +163,11 @@ color: var(--color-green); } +.layersTool_filtering_value_value_input:hover + + .layersTool_filtering_value_value_type { + opacity: 1; +} + #layersTool_filtering input { background: var(--color-a1); color: #ccc; diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 12c755f1..001eab99 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -107,14 +107,7 @@ const Filtering = { }, destroy: function () { // Clear Spatial Filter - // We save the center because we're not completely clearing it - if (Filtering.filters[Filtering.current.layerName]) { - const savedCenter = - Filtering.filters[Filtering.current.layerName].spatial.center - $('#layerTool_filtering_filters_spatial_clear').click() - Filtering.filters[Filtering.current.layerName].spatial.center = - savedCenter - } + Map_.rmNotNull(Filtering.mapSpatialLayer) $('#layersTool_filtering').remove() }, @@ -365,7 +358,7 @@ const Filtering = { layerName )}_${id}` $(elmId).on('focus', function () { - $(this).parent().css('flex', '2 1') + $(this).parent().css('flex', '2.5 1') }) $(elmId).on('blur', function () { $(this).parent().css('flex', '1 1') @@ -374,7 +367,7 @@ const Filtering = { layerName )}_${id}` $(elmId).on('focus', function () { - $(this).parent().css('flex', '2 1') + $(this).parent().css('flex', '2.5 1') }) $(elmId).on('blur', function () { $(this).parent().css('flex', '1 1') @@ -391,7 +384,7 @@ const Filtering = { i < Filtering.filters[layerName].values.length; i++ ) { - const vId = Filtering.filters[layerName].values[i].id + const vId = Filtering.filters[layerName].values[i]?.id if (vId != null && vId === id) { $( `#layersTool_filtering_value_${F_.getSafeName( @@ -477,7 +470,7 @@ const Filtering = { Dropy.construct( [ ``, - ``, + `
                            in
                            `, ``, ``, ], @@ -511,7 +504,7 @@ const Filtering = { ) $(elmId).autocomplete({ lookup: arrayToSearch, - lookupLimit: 100, + lookupLimit: 150, minChars: 0, transformResult: function (response, originalQuery) { let resultSuggestions = [] diff --git a/src/essence/Tools/Layers/LayersTool.js b/src/essence/Tools/Layers/LayersTool.js index 79ca968f..44b78ddc 100644 --- a/src/essence/Tools/Layers/LayersTool.js +++ b/src/essence/Tools/Layers/LayersTool.js @@ -542,10 +542,8 @@ function interfaceWithMMGIS() { if (!wasOn) li.addClass('gears_on') //Support Filtering 1 - if (!wasOn) { - if (['vector', 'query'].includes(type)) { - Filtering.destroy() - } + if (['vector', 'query'].includes(type)) { + Filtering.destroy() } // Turn layer on if off @@ -576,7 +574,7 @@ function interfaceWithMMGIS() { F_.downloadObject( L_.layersGroup[layerName].toGeoJSON(), layerName, - '.geojson' + '.json' ) }) diff --git a/src/external/Dropy/dropy.css b/src/external/Dropy/dropy.css index bce0e881..3933c833 100644 --- a/src/external/Dropy/dropy.css +++ b/src/external/Dropy/dropy.css @@ -87,6 +87,9 @@ dd { border-radius: 0 0 0.125em 0.125em; } .dropy__content li a { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; display: block; padding: 0.625rem 0.9375em; font-size: 0.875em; diff --git a/src/external/Dropy/dropy.js b/src/external/Dropy/dropy.js index 0894632b..49b68239 100644 --- a/src/external/Dropy/dropy.js +++ b/src/external/Dropy/dropy.js @@ -20,7 +20,7 @@ export default { '
                            ', '', '
                            ', '', From 77c1d11ef97490b49f07aa7302d17aee37fa26ef Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 10 Jan 2022 09:32:43 -0800 Subject: [PATCH 81/85] Bump winston for colors fix --- package-lock.json | 154 +++++++++++++++++----------------------------- package.json | 2 +- 2 files changed, 56 insertions(+), 100 deletions(-) diff --git a/package-lock.json b/package-lock.json index 1ddfd235..0cac81f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -100,7 +100,7 @@ "webpack": "4.42.0", "webpack-dev-server": "^3.11.0", "webpack-manifest-plugin": "2.2.0", - "winston": "^3.3.3", + "winston": "^3.3.4", "workbox-webpack-plugin": "4.3.1" } }, @@ -8914,11 +8914,6 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, "node_modules/fastq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", @@ -8947,9 +8942,9 @@ } }, "node_modules/fecha": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", - "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" }, "node_modules/figgy-pudding": { "version": "3.5.2", @@ -12060,14 +12055,14 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "node_modules/logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.2.tgz", + "integrity": "sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA==", "dependencies": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", + "colors": "1.4.0", "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", "triple-beam": "^1.3.0" } }, @@ -16351,6 +16346,11 @@ "ret": "~0.1.10" } }, + "node_modules/safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -19877,62 +19877,41 @@ } }, "node_modules/winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.4.tgz", + "integrity": "sha512-zWJrfmqE+2IXtVJ125vxpA2m303TjwchLhfRbcnma7c76Qd4pv80JIp37l8uGnWbCoG4X6PMz3vAQeh+vH1CtA==", "dependencies": { "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", + "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.2.0", + "logform": "^2.3.2", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" + "winston-transport": "^4.4.2" }, "engines": { "node": ">= 6.4.0" } }, "node_modules/winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.2.tgz", + "integrity": "sha512-9jmhltAr5ygt5usgUTQbEiw/7RYXpyUbEAFRCSicIacpUzPkrnQsQZSPGEI12aLK9Jth4zNcYJx3Cvznwrl8pw==", "dependencies": { - "readable-stream": "^2.3.7", + "logform": "^2.3.2", + "readable-stream": "^3.4.0", "triple-beam": "^1.2.0" }, "engines": { "node": ">= 6.4.0" } }, - "node_modules/winston-transport/node_modules/readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/winston-transport/node_modules/string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/winston/node_modules/async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "node_modules/winston/node_modules/is-stream": { "version": "2.0.0", @@ -27884,11 +27863,6 @@ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=" }, - "fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, "fastq": { "version": "1.11.0", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.11.0.tgz", @@ -27914,9 +27888,9 @@ } }, "fecha": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.0.tgz", - "integrity": "sha512-aN3pcx/DSmtyoovUudctc8+6Hl4T+hI9GBBHLjA76jdZl7+b1sgh5g4k+u/GL3dTy1/pnYzKp69FpJ0OicE3Wg==" + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/fecha/-/fecha-4.2.1.tgz", + "integrity": "sha512-MMMQ0ludy/nBs1/o0zVOiKTpG7qMbonKUzjJgQFEuvq6INZ1OraKPRAWkBq5vlKLOUMpmNYG1JoN3oDPUQ9m3Q==" }, "figgy-pudding": { "version": "3.5.2", @@ -30448,14 +30422,14 @@ "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=" }, "logform": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/logform/-/logform-2.2.0.tgz", - "integrity": "sha512-N0qPlqfypFx7UHNn4B3lzS/b0uLqt2hmuoa+PpuXNYgozdJYAyauF5Ky0BWVjrxDlMWiT3qN4zPq3vVAfZy7Yg==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/logform/-/logform-2.3.2.tgz", + "integrity": "sha512-V6JiPThZzTsbVRspNO6TmHkR99oqYTs8fivMBYQkjZj6rxW92KxtDCPE6IkAk1DNBnYKNkjm4jYBm6JDUcyhOA==", "requires": { - "colors": "^1.2.1", - "fast-safe-stringify": "^2.0.4", + "colors": "1.4.0", "fecha": "^4.2.0", "ms": "^2.1.1", + "safe-stable-stringify": "^1.1.0", "triple-beam": "^1.3.0" } }, @@ -34005,6 +33979,11 @@ "ret": "~0.1.10" } }, + "safe-stable-stringify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-1.1.1.tgz", + "integrity": "sha512-ERq4hUjKDbJfE4+XtZLFPCDi8Vb1JqaxAPTxWFLBx8XcAlf9Bda/ZJdVezs/NAfsMQScyIlUMx+Yeu7P7rx5jw==" + }, "safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -37043,25 +37022,25 @@ } }, "winston": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.3.tgz", - "integrity": "sha512-oEXTISQnC8VlSAKf1KYSSd7J6IWuRPQqDdo8eoRNaYKLvwSb5+79Z3Yi1lrl6KDpU6/VWaxpakDAtb1oQ4n9aw==", + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/winston/-/winston-3.3.4.tgz", + "integrity": "sha512-zWJrfmqE+2IXtVJ125vxpA2m303TjwchLhfRbcnma7c76Qd4pv80JIp37l8uGnWbCoG4X6PMz3vAQeh+vH1CtA==", "requires": { "@dabh/diagnostics": "^2.0.2", - "async": "^3.1.0", + "async": "^3.2.3", "is-stream": "^2.0.0", - "logform": "^2.2.0", + "logform": "^2.3.2", "one-time": "^1.0.0", "readable-stream": "^3.4.0", "stack-trace": "0.0.x", "triple-beam": "^1.3.0", - "winston-transport": "^4.4.0" + "winston-transport": "^4.4.2" }, "dependencies": { "async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==" + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.3.tgz", + "integrity": "sha512-spZRyzKL5l5BZQrr/6m/SqFdBN0q3OCI0f9rjfBzCMBIP4p75P620rR3gTmaksNOhmzgdxcaxdNfMy6anrbM0g==" }, "is-stream": { "version": "2.0.0", @@ -37071,36 +37050,13 @@ } }, "winston-transport": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.0.tgz", - "integrity": "sha512-Lc7/p3GtqtqPBYYtS6KCN3c77/2QCev51DvcJKbkFPQNoj1sinkGwLGFDxkXY9J6p9+EPnYs+D90uwbnaiURTw==", + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/winston-transport/-/winston-transport-4.4.2.tgz", + "integrity": "sha512-9jmhltAr5ygt5usgUTQbEiw/7RYXpyUbEAFRCSicIacpUzPkrnQsQZSPGEI12aLK9Jth4zNcYJx3Cvznwrl8pw==", "requires": { - "readable-stream": "^2.3.7", + "logform": "^2.3.2", + "readable-stream": "^3.4.0", "triple-beam": "^1.2.0" - }, - "dependencies": { - "readable-stream": { - "version": "2.3.7", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", - "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "requires": { - "safe-buffer": "~5.1.0" - } - } } }, "with": { diff --git a/package.json b/package.json index 5de93c29..f711c93c 100644 --- a/package.json +++ b/package.json @@ -134,7 +134,7 @@ "webpack": "4.42.0", "webpack-dev-server": "^3.11.0", "webpack-manifest-plugin": "2.2.0", - "winston": "^3.3.3", + "winston": "^3.3.4", "workbox-webpack-plugin": "4.3.1" }, "eslintConfig": { From e9450e03e45f6e11464be801836c044933d22afd Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 10 Jan 2022 10:47:16 -0800 Subject: [PATCH 82/85] #122 Add Query Layer docs --- docs/docs.css | 6 + docs/docs.js | 34 ++ docs/pages/markdowns/Data.md | 94 +++++ docs/pages/markdowns/Header.md | 13 + docs/pages/markdowns/Layers_Tab.md | 633 +--------------------------- docs/pages/markdowns/Model.md | 77 ++++ docs/pages/markdowns/Query.md | 122 ++++++ docs/pages/markdowns/Tile.md | 81 ++++ docs/pages/markdowns/Vector.md | 241 +++++++++++ docs/pages/markdowns/Vector_Tile.md | 111 +++++ views/docs.pug | 2 + 11 files changed, 788 insertions(+), 626 deletions(-) create mode 100644 docs/pages/markdowns/Data.md create mode 100644 docs/pages/markdowns/Header.md create mode 100644 docs/pages/markdowns/Model.md create mode 100644 docs/pages/markdowns/Query.md create mode 100644 docs/pages/markdowns/Tile.md create mode 100644 docs/pages/markdowns/Vector.md create mode 100644 docs/pages/markdowns/Vector_Tile.md diff --git a/docs/docs.css b/docs/docs.css index 5fef4607..4d06a925 100644 --- a/docs/docs.css +++ b/docs/docs.css @@ -67,6 +67,7 @@ body { } #nav, #navconfigure, +#navlayers, #navtools { list-style-type: none; padding: 0; @@ -76,6 +77,7 @@ body { } #nav li, #navconfigure li, +#navlayers li, #navtools li { line-height: 28px; text-align: right; @@ -85,17 +87,20 @@ body { } #nav li:hover, #navconfigure li:hover, +#navlayers li:hover, #navtools li:hover { color: white; } #nav li.active, #navconfigure li.active, +#navlayers li.active, #navtools li.active { font-weight: bold; color: white; } #nav li .apiIcon, #navconfigure li .apiIcon, +#navlayers li .apiIcon, #navtools li .apiIcon { color: #ccc; line-height: 27px; @@ -104,6 +109,7 @@ body { } #nav li:hover .apiIcon, #navconfigure li:hover .apiIcon, +#navlayers li:hover .apiIcon, #navtools li:hover .apiIcon { color: white; } diff --git a/docs/docs.js b/docs/docs.js index 419cea10..56a328e5 100644 --- a/docs/docs.js +++ b/docs/docs.js @@ -24,6 +24,15 @@ let configure = [ "Manage_Datasets", "Manage_Geodatasets", ]; +let layers = [ + "Data", + "Header", + "Model", + "Query", + "Tile", + "Vector_Tile", + "Vector", +]; let tools = [ "Chemistry", "Draw", @@ -91,6 +100,31 @@ configure.forEach((v) => { document.getElementById("navconfigure").appendChild(node); }); +layers.forEach((v) => { + let node = document.createElement("li"); + node.setAttribute("id", v); + node.setAttribute("class", "page"); + node.addEventListener( + "click", + (function (page) { + return function () { + let pageElms = document.getElementsByClassName("page"); + for (let i = 0; i < pageElms.length; i++) { + pageElms[i].setAttribute("class", "page"); + } + document.getElementById(page).setAttribute("class", "page active"); + setPage(page); + }; + })(v) + ); + + let text = v.replace(/_/g, " "); + if (text == "README") text = "Home"; + let textnode = document.createTextNode(text); + node.appendChild(textnode); + document.getElementById("navlayers").appendChild(node); +}); + tools.forEach((v) => { let node = document.createElement("li"); node.setAttribute("id", v); diff --git a/docs/pages/markdowns/Data.md b/docs/pages/markdowns/Data.md new file mode 100644 index 00000000..e6723141 --- /dev/null +++ b/docs/pages/markdowns/Data.md @@ -0,0 +1,94 @@ +# Data Layers + +Data layers use WebGL shaders to generate tiles on the fly. + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### URL + +_type:_ string +A relative to the mission directoty or absolute file path to a Digital Elevation Map tileset generated by `auxillary/1bto4b/rasterstotiles1bto4b.py` + +#### Legend + +_type:_ string +An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. + +#### Initial Visibility + +_type:_ bool +Whether the layer is on initially. + +#### Minimum Zoom + +_type:_ integer +The lowest (smallest number) zoom level of the tile set. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Maximum Native Zoom + +_type:_ integer +The highest (largest number) zoom level of the tile set. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Maximum Zoom + +_type:_ integer +The highest (largest number) zoom level to see in MMGIS. This value is at least as high as Maximum Native Zoom. This allows zooms level higher than that of the tileset. Instead of rendering new tile image, it scales them in instead. + +#### Bounding Box + +_type:_ string _optional_ +A comma separated string defining the tileset's `minimumLonDeg,minimumLatDeg,maximumLonDeg,maximumLatDeg`. Setting a bounding box improves performance by limiting requests for tiles to only those that fit the bounds. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Time Enabled + +_type:_ bool +True if the layer is time enabled. URLs that contain `{starttime}` or `{endtime}` will be dynamically replaced by their set values when the layer is fetched. + +#### Time Type + +_type:_ enum [Global, Individual] +Whether the layer should use global time values or function independently with its own time values. + +#### Time Format + +_type:_ string _optional_ +The string format to be used in the URL for `{starttime}` and `{endtime}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. + +#### Raw Variables + +Data layers need a configured `shader` raw variable to be effective. Supported shader types are as follows: + +- "colorize": Allows users to apply and configure dynamic color ramps to the data. Uses the current minimum and maximum viewport data values to adjust color ramps into the most relevant range. + - units: A string to append to user displayed data values. + - noDataValues: Values to exclude from minimum and maximum calculations. + - sigfigs: How many significant figures to round user displayed values. + - ramps: An array of arrays of hex color strings. "transparent" is a special keyword for a fully transparent ramp color. +- "image": (Default) Simply shows the underlying raw data in an image form. Mainly for testing, it can also be useful for development for internal pass-tile-canvas-instead-of-url layers. + +Example: + +```javascript +{ + "shader": { + "type": "colorize", + "units": "m", + "noDataValues": [ + 0 + ], + "sigfigs": 3, + "ramps": [ + [ + "#FF0000", + "transparent", + "#0000FF" + ] + ] + } +} +``` diff --git a/docs/pages/markdowns/Header.md b/docs/pages/markdowns/Header.md new file mode 100644 index 00000000..f98336bf --- /dev/null +++ b/docs/pages/markdowns/Header.md @@ -0,0 +1,13 @@ +# Header + +Header layers contain no content but allows other layers to be grouped underneath it much like a directory. + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### Initial Visibility + +_type:_ bool +Whether the contents of this header are possibly visible initially. diff --git a/docs/pages/markdowns/Layers_Tab.md b/docs/pages/markdowns/Layers_Tab.md index 77909f27..f101472e 100644 --- a/docs/pages/markdowns/Layers_Tab.md +++ b/docs/pages/markdowns/Layers_Tab.md @@ -12,12 +12,6 @@ Add, alter and remove Layers: - [Layer Structure](#layer-structure) - [Configuring Individual Layers](#configuring-individual-layers) - [Layer Types](#layer-types) - - [Header](#header) - - [Tile](#tile) - - [Vector Tile](#vector-tile) - - [Data](#data) - - [Vector](#vector) - - [Model](#model) ## Adding Layers @@ -47,623 +41,10 @@ Add, alter and remove Layers: ## Layer Types -# Header - -Header layers contain no content but allows other layers to be grouped underneath it much like a directory. - -#### Layer Name - -_type:_ string -The unique display name and identifier of the layer. It must be unique and contain no special characters. - -#### Initial Visibility - -_type:_ bool -Whether the contents of this header are possibly visible initially. - -# Tile - -Tile layers are hierarchical raster imagery. - -#### Layer Name - -_type:_ string -The unique display name and identifier of the layer. It must be unique and contain no special characters. - -#### URL - -_type:_ string -A file path that points to a tileset's directory. If the path is relative, it will be relative to the mission's directory. The URL must contain a proper placeholder ending such as: `{z}/{x}/{y}.png`. See the "Tile Format" section below for more details. - -#### DEM Tile URL - -_type:_ string _optional_ -A file path like URL but pointing to a Digital Elevation Map tileset generated by `auxillary/1bto4b/rasterstotiles1bto4b.py` This is responsible for 3D data in the globe. It would be ideal if this tileset can match the extents of its corresponding raster and has either no nodata or has nodata far lower than that of its lowest point. - -#### Legend - -_type:_ string -An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. - -#### Tile Format - -_type:_ enum [TMS, WMTS, WMS] -The format of the tiles. - -- TMS: Tile Map Service tiles are 256x256 sized images hierarchically organized by zoom level and referenced with x and y coordinates. These are the standard format for web tiles and are the format that MMGIS's auxiliary tiling scripts output. Append `/{z}/{x}/{y}.png` to your `URL`. -- WMTS: Web Map Tile Service is the same exact concept as TMS but it has an inverted Y-axis. Just like TMS, append `/{z}/{x}/{y}.png` to your `URL`. -- WMS: Web Map Service tiles are a popular way of publishing maps by professional GIS software. This format is similar to the previous two formats, but more generic and not so well optimized for use in web maps. A WMS image is defined by the coordinates of its corners. A layer (or list of layers) should be provided as an options by appending `?layers=<,another_if_you _want>` to your `URL`. To override WMS parameters append `&=` again to the `URL` after the "layers" parameters. - _Example URL: `http://ows.mundialis.de/services/service?layers=TOPO-WMS,OSM-Overlay-WMS`_ - -#### Initial Visibility - -_type:_ bool -Whether the layer is on initially. - -#### Initial Opacity - -_type:_ float -A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. - -#### Minimum Zoom - -_type:_ integer -The lowest (smallest number) zoom level of the tile set. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Maximum Native Zoom - -_type:_ integer -The highest (largest number) zoom level of the tile set. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Maximum Zoom - -_type:_ integer -The highest (largest number) zoom level to see in MMGIS. This value is at least as high as Maximum Native Zoom. This allows zooms level higher than that of the tileset. Instead of rendering new tile image, it scales them in instead. - -#### Bounding Box - -_type:_ string _optional_ -A comma separated string defining the tileset's `minimumLonDeg,minimumLatDeg,maximumLonDeg,maximumLatDeg`. Setting a bounding box improves performance by limiting requests for tiles to only those that fit the bounds. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Time Enabled - -_type:_ bool -True if the layer is time enabled. URLs that contain `{time}` will be dynamically replaced by their set values when the layer is fetched. - -#### Time Type - -_type:_ enum [Global, Individual] -Whether the layer should use global time values or function independently with its own time values. - -#### Time Format - -_type:_ string _optional_ -The string format to be used in the URL for `{time}`. Defaults to `%Y-%m-%dT%H:%M:%SZ`. - -# Vector Tile - -A mix between Tile and Vector. Useful when rendering tons of features since features are rendered based on viewport instead of all at once at the start. - -#### Layer Name - -_type:_ string -The unique display name and identifier of the layer. It must be unique and contain no special characters. - -#### Kind of Layer - -_type:_ enum -A special kind of interaction for the layer. Please see the Kinds page for more. - -#### URL - -_type:_ string -A file path that points to a vector tileset's directory. If the path is relative, it will be relative to the mission's directory. The URL must contain a proper placeholder ending such as: `{z}/{x}/{y}.png`. Alternatively vector tiles can be generated and served in real time with Geodatasets. Simply go to "Manage Geodatasets" at the bottom left, upload a geojson and link to it in this URL field with "geodatasets:{geodataset*name}" -\_Note: If the vector tile layer contains points, the layer will break. A known workaround is to buffer all points.* - -#### DEM Tile URL - -_type:_ string _optional_ -A file path like URL but pointing to a Digital Elevation Map tileset generated by `auxillary/1bto4b/rasterstotiles1bto4b.py` This is responsible for 3D data in the globe. It would be ideal if this tileset can match the extents of its corresponding raster and has either no nodata or has nodata far lower than that of its lowest point. - -#### Legend - -_type:_ string -An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. - -#### Tile Format - -_type:_ enum [TMS, WMTS, WMS] -The format of the tiles. - -- TMS: Tile Map Service tiles are 256x256 sized images hierarchically organized by zoom level and referenced with x and y coordinates. These are the standard format for web tiles and are the format that MMGIS's auxiliary tiling scripts output. Append `/{z}/{x}/{y}.png` to your `URL`. -- WMTS: Web Map Tile Service is the same exact concept as TMS but it has an inverted Y-axis. Just like TMS, append `/{z}/{x}/{y}.png` to your `URL`. -- WMS: Web Map Service tiles are a popular way of publishing maps by professional GIS software. This format is similar to the previous two formats, but more generic and not so well optimized for use in web maps. A WMS image is defined by the coordinates of its corners. A layer (or list of layers) should be provided as an options by appending `?layers=<,another_if_you _want>` to your `URL`. To override WMS parameters append `&=` again to the `URL` after the "layers" parameters. - _Example URL: `http://ows.mundialis.de/services/service?layers=TOPO-WMS,OSM-Overlay-WMS`_ - -#### Initial Visibility - -_type:_ bool -Whether the layer is on initially. - -#### Initial Opacity - -_type:_ float -A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. - -#### Minimum Zoom - -_type:_ integer -The lowest (smallest number) zoom level of the tile set. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Maximum Native Zoom - -_type:_ integer -The highest (largest number) zoom level of the tile set. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Maximum Zoom - -_type:_ integer -The highest (largest number) zoom level to see in MMGIS. This value is at least as high as Maximum Native Zoom. This allows zooms level higher than that of the tileset. Instead of rendering new tile image, it scales them in instead. - -#### Time Enabled - -_type:_ bool -True if the layer is time enabled. URLs that contain `{time}` will be dynamically replaced by their set values when the layer is fetched. - -#### Time Type - -_type:_ enum [Global, Individual] -Whether the layer should use global time values or function independently with its own time values. - -#### Time Format - -_type:_ string _optional_ -The string format to be used in the URL for `{time}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. - -#### Vector Tile Feature Unique Id Key - -_type:_ string -Each feature of the vector tileset needs a property with a unique value to identify it. This required field is the name of that property. - -#### Use Key as Name - -_type:_ string _optional_ -The property key whose value should be the hover text of each feature. This is the same as the `useKeyAsName` raw variable within Vector layers - -#### Raw Variables - -Vector Tiles are styled differently than Vectors. Raw variables here takes an object that maps internal vector tile layer names to styles. All raw variables are optional. - -Example: - -```javascript -{ - "": { - "color": "#FFFFFF", - "fill": true, - "fillColor": "rgb(0, 125, 200)", - "fillOpacity": 0.5, - "opacity": 1, - "radius": 4, - "weight": 2 - } -} -``` - -# Data - -Data layers use WebGL shaders to generate tiles on the fly. - -#### Layer Name - -_type:_ string -The unique display name and identifier of the layer. It must be unique and contain no special characters. - -#### URL - -_type:_ string -A relative to the mission directoty or absolute file path to a Digital Elevation Map tileset generated by `auxillary/1bto4b/rasterstotiles1bto4b.py` - -#### Legend - -_type:_ string -An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. - -#### Initial Visibility - -_type:_ bool -Whether the layer is on initially. - -#### Minimum Zoom - -_type:_ integer -The lowest (smallest number) zoom level of the tile set. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Maximum Native Zoom - -_type:_ integer -The highest (largest number) zoom level of the tile set. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Maximum Zoom - -_type:_ integer -The highest (largest number) zoom level to see in MMGIS. This value is at least as high as Maximum Native Zoom. This allows zooms level higher than that of the tileset. Instead of rendering new tile image, it scales them in instead. - -#### Bounding Box - -_type:_ string _optional_ -A comma separated string defining the tileset's `minimumLonDeg,minimumLatDeg,maximumLonDeg,maximumLatDeg`. Setting a bounding box improves performance by limiting requests for tiles to only those that fit the bounds. -_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ - -#### Time Enabled - -_type:_ bool -True if the layer is time enabled. URLs that contain `{starttime}` or `{endtime}` will be dynamically replaced by their set values when the layer is fetched. - -#### Time Type - -_type:_ enum [Global, Individual] -Whether the layer should use global time values or function independently with its own time values. - -#### Time Format - -_type:_ string _optional_ -The string format to be used in the URL for `{starttime}` and `{endtime}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. - -#### Raw Variables - -Data layers need a configured `shader` raw variable to be effective. Supported shader types are as follows: - -- "colorize": Allows users to apply and configure dynamic color ramps to the data. Uses the current minimum and maximum viewport data values to adjust color ramps into the most relevant range. - - units: A string to append to user displayed data values. - - noDataValues: Values to exclude from minimum and maximum calculations. - - sigfigs: How many significant figures to round user displayed values. - - ramps: An array of arrays of hex color strings. "transparent" is a special keyword for a fully transparent ramp color. -- "image": (Default) Simply shows the underlying raw data in an image form. Mainly for testing, it can also be useful for development for internal pass-tile-canvas-instead-of-url layers. - -Example: - -```javascript -{ - "shader": { - "type": "colorize", - "units": "m", - "noDataValues": [ - 0 - ], - "sigfigs": 3, - "ramps": [ - [ - "#FF0000", - "transparent", - "#0000FF" - ] - ] - } -} -``` - -# Vector - -A [geojson](https://geojson.org/) layer. - -#### Layer Name - -_type:_ string -The unique display name and identifier of the layer. It must be unique and contain no special characters. - -#### Kind of Layer - -_type:_ enum -A special kind of interaction for the layer. Please see the Kinds page for more. - -#### URL - -_type:_ string -A file path that points to a geojson. If the path is relative, it will be relative to the mission's directory. The URL must contain a proper placeholder ending such as: `{z}/{x}/{y}.png`. Alternatively vectors can be served with Geodatasets. Simply go to "Manage Geodatasets" at the bottom left, upload a geojson and link to it in this URL field with "geodatasets:{geodataset\*name}" - -#### Controlled - -_type:_ bool -Whether the layer can be dynamically updated or not. If true, the layer can be dynamically updated and the URL is not required. - -#### Legend - -_type:_ string -An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. - -#### Initial Visibility - -_type:_ bool -Whether the layer is on initially. - -#### Visibility Cutoff - -_type:_ integer _optional_ -If set, this vector layer will be hidden if the current zoom level is less than or equal to that of the visibility cutoff. `Visibility Cutoff * -1` will invert its visibility condition. This is useful when the dataset is dense, local to a one region, or irrelevant when far away and the desired range of zoom levels is large. - -#### Initial Opacity - -_type:_ float -A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. - -#### Time Enabled - -_type:_ bool -True if the layer is time enabled. URLs that contain `{starttime}` or `{endtime}` will be dynamically replaced by their set values when the layer is fetched. - -#### Time Type - -_type:_ enum [Global, Individual] -Whether the layer should use global time values or function independently with its own time values. - -#### Time Format - -_type:_ string _optional_ -The string format to be used in the URL for `{starttime}` and `{endtime}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. - -#### Stroke Color - -_type:_ CSS color string or a prop _optional_ -The border color of each feature. If the feature is a line, this field is the color of the line. See the Vector Styling page for more. Colors can be as follows: - -- A named color - - crimson, blue, rebeccapurple -- A hex color - - #FFF - - #A58101 -- An rgb color - - rgb(255,89,45) -- An hsl color - - hsl(130, 26%, 34%) -- Based on a feature's color property - - `prop:geojson_property_key` will set the feature's color to the values of `features[i].properties.geojson_property_key` - - If that property is not a valid CSS color and is a string, it will use a random and consistent color based on its hash. - -#### Fill Color - -_type:_ CSS color string or a prop _optional_ -The fill color of each feature. See Stroke Color for color options. See the Vector Styling page for more. - -#### Stroke Weight - -_type:_ positive integer _optional_ -The thickness of the stroke/border in pixels. See the Vector Styling page for more. - -#### Fill Opacity - -_type:_ float _optional_ -A value from 0 to 1 of Fill Color's opacity. 1 is fully opaque. See the Vector Styling page for more. -_Note: It's also possible to set the opacities of colors directly with #CCDDEEFF, rgba() and hsla()._ - -#### Radius - -_type:_ positive integer _optional_ -When a point feature is encountered, this value will be it's radius in pixels. - -#### Raw Variables - -Clicking "Set Default Variables" will add a template of all possible raw variables (without overwriting ones that are already set). All raw variables are optional. - -Example: - -```javascript -{ - "useKeyAsName": "name", - "datasetLinks": [ - { - "prop": "{prop}", - "dataset": "{dataset}", - "column": "{column}", - "type": "{none || images}" - } - ], - "links": [ - { - "name": "example", - "link": "url/?param={prop}" - } - ], - "info": [ - { - "which": "last", - "icon": "material design icon", - "value": "Prop: {prop}" - } - ], - "markerAttachments": { - "bearing": { - "angleProp": "path.to.angle.prop", - "angleUnit": "deg || rad", - "color": "#FFFFFF", - }, - "uncertainty": { - "initialVisibility": true, - "xAxisProp": "path.to.x.prop", - "yAxisProp": "path.to.y.prop", - "axisUnit": "meters || kilometers", - "angleProp": "path.to.angle.prop", - "angleUnit": "deg || rad", - "color": "#888888", - }, - "image": { - "initialVisibility": true, - "path": "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", - "pathProp": "path to image. take priority over path", - "widthMeters": 2.6924, - "widthPixels": 420, - "heightPixels": 600, - "angleProp": "path.to.angle.prop", - "angleUnit": "deg || rad", - "show": "click || always", - }, - "model": { - "path": "path to model (.dae, .glb, .gltf, .obj)", - "pathProp": "path to model. take priority over path", - "mtlPath": "if .obj, path to material file (.mtl)", - "yawProp": "path.to.yaw.prop", - "yawUnit": "deg || rad", - "invertYaw": false, - "pitchProp": "path.to.pitch.prop", - "pitchUnit": "deg || rad", - "invertPitch": true, - "rollProp": "path.to.roll.prop", - "rollUnit": "deg || rad", - "invertRoll": false, - "elevationProp": "path.to.elev.prop", - "scaleProp": "path.to.scale.prop", - "show": "click || always", - "onlyLastN": false - }, - }, - "markerIcon": { //See: https://leafletjs.com/reference-1.7.1.html#icon-l-icon - "iconUrl": "pathToMainIconImage.png", - "shadowUrl": "(opt)pathToShadowImage.png", - "iconSize": [38, 95], // size of the icon - "shadowSize": [50, 64], // size of the shadow - "iconAnchor": [22, 94], // point of the icon which will correspond to marker's location - "shadowAnchor": [4, 62], // the same for the shadow - }. - "search": "(prop1) round(prop2.1) rmunder(prop_3)" -} -``` - -- `useNameAsKey`: The property key whose value should be the hover text of each feature. If left unset, the hover key and value will be the first one listed in the feature's properties. -- `datasetLinks`: Datasets are csvs uploaded from the "Manage Datasets" page accessible on the lower left. Every time a feature from this layer is clicked with datasetLinks configured, it will request the data from the server and include it with it's regular geojson properties. This is especially useful when single features need a lot of metadata to perform a task as it loads it only as needed. - - `prop`: This is a property key already within the features properties. It's value will be searched for in the specified dataset column. - - `dataset`: The name of a dataset to link to. A list of datasets can be found in the "Manage Datasets" page. - - `column`: This is a column/csv header name within the dataset. If the value of the prop key matches the value in this column, the entire row will be return. All rows that match are returned. - - `type`: Unused. -- `links`: Configure deep links to other sites based on the properties on a selected feature. This requires the "Minimalist" option in the Look Tab to be unchecked. Upon clicking a feature, a list of deep links are put into the top bar and can be clicked on to navigate to any other page. - - `name`: The name of the deep link. It should be unique. - - `link`: A url template. Curly brackets are included. On feature click, all `{prop}` are replaced with the corresponding `features[i].properties.prop` value. Multiple `{prop}` are supported as are access to nested props using dot notation `{stores.food.candy}`. -- `info`: Creates an informational record at the top of the page. The first use case was showing the value of the latest sol. Clicking this record pans to the feature specified by `which`. This requires the "Minimalist" option in the Look Tab to be unchecked. This is used on startup and not when a user selects a feature in this layer. - - `which`: This only supports the value `last` at this point. - - `icon`: Any [Material Design Icon](http://materialdesignicons.com/) name - - `value`: A name to display. All `{prop}`s will be replaced by their corresponding `features[which].properties[prop]` value. -- `markerBearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). `{unit}` is either `deg` or `rad` and `{prop}` is the dot notated path to the feature properties that contains the desired rotation angle. Ex. `deg:headings.yaw`. -- `markerAttachments`: An object for attaching dynamic items to point features. - - `bearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). Overrides the layer's shape dropdown value. - - `angleProp`: The dot notated path to the feature properties that contains the desired rotation angle. Ex. `headings.yaw`. - - `angleUnit`: Unit of the value of `angleProp`. Either `deg` or `rad`. - - `color`: A css color for the directional arrow for non-markerIcon bearings. - - `uncertainty`: A sublayer feature that places ellipses about point features to indicate positional uncertainty - - `initialVisibility`: Whether the uncertainty sublayer is initially on. Users can toggle sublayers on and off in the layer settings in the LayersTool. - - `xAxisProp`: Prop path to the x axis radius value of the ellipse. - - `yAxisProp`: Prop path to the y axis radius value of the ellipse. - - `axisUnit`: "meters || kilometers", - - `angleProp`: Prop path to the rotation of the ellipse. - - `angleUnit`: "deg || rad" - - `color`: A css fill color. Will be made more transparent than set. - - `image`: Places a scaled and orientated image under each marker. A sublayer. - - `initialVisibility`: Whether the image sublayer is initially on. Users can toggle sublayers on and off in the layer settings in the LayersTool. - - `path`: A url to a (preferably) top-down north-facing orthographic image. - - `pathProp`: A prop path to an image url. Take priority over path. Useful if the path is feature specific. - - `widthMeters`: Width of image in meters in order to calculate scale. - - `widthPixels`: Image width in pixels. - - `heightPixels`: Image height in pixel. - - `angleProp`: Prop path to the rotation of the image. - - `angleUnit`: "deg || rad" - - `show`: "click || always". If set to "always", overrides the Waypoints Kind (if set) and always renders the image under the marker. "click" just shows the image on click and requires the layer to have the Waypoints Kind. - - `model`: - - `path`: Path to model (.dae, .glb, .gltf, .obj) - - `pathProp`: A prop path to a model. Takes priority over path. Useful if model is feature specific. - - `mtlPath`: If .obj, the path to its material file (.mtl) - - `yawProp`: Prop path to the model's yaw. If this value is a number, uses it directly. - - `yawUnit`: "deg || rad" - - `invertYaw`: Boolean that, if true, multiplies yaw by -1. - - `pitchProp`: Prop path to the model's pitch. If this value is a number, uses it directly. - - `pitchUnit`: "deg || rad" - - `invertPitch`: Boolean that, if true, multiplies pitch by -1. - - `rollProp`: Prop path to the model's roll. If this value is a number, uses it directly. - - `rollUnit`: "deg || rad" - - `invertRoll`: Boolean that, if true, multiplies roll by -1. - - `elevationProp`: Prop path to the model's elevation (in meters). If this value is a number, uses it directly. Default 0. - - `scaleProp`: Prop path to the model's scale. If this value is a number, uses it directly. Default 1. - - `show`: "click || always" - - `onlyLastN`: If false, shows models at all points. If a number, only shows models for the last n points. -- `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. If you're using this as a bearing marker, make sure the base icon is pointing north. -- `search`: This requires the "Minimalist" option in the Look Tab to be unchecked. When set, this layer will become searchable through the search bar at the top. The search will look for and autocomplete on the properties specified. All properties are enclosed by parentheses and space-separated. `round` can be used like a function to round the property beforehand. `rmunder` works similarly but removes all underscores instead. - -# Model - -#### Layer Name - -_type:_ string -The unique display name and identifier of the layer. It must be unique and contain no special characters. - -#### URL - -_type:_ string -A file path that points to a .dae or .obj. If the path is relative, it will be relative to the mission's directory. - -#### Longitude - -_type:_ float -The longitude in decimal degrees at which to place the model. - -#### Latitude - -_type:_ float -The latitude in decimal degrees at which to place the model. - -#### Elevation - -_type:_ float -The elevation in meters at which to place the model. - -#### Rotation X - -_type:_ float _optional_ -An x-axis rotation in radians to orient the model. - -#### Rotation Y - -_type:_ float _optional_ -A y-axis rotation in radians to orient the model. - -#### Rotation Z - -_type:_ float _optional_ -A z-axis rotation in radians to orient the model. - -#### Scale - -_type:_ float _optional_ -A scaling factor to resize the model. - -#### Initial Visibility - -_type:_ bool -Whether the layer is on initially. - -#### Initial Opacity - -_type:_ float -A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. - -#### Time Enabled - -_type:_ bool -True if the layer is time enabled. URLs that contain `{starttime}` or `{endtime}` will be dynamically replaced by their set values when the layer is fetched. - -#### Time Type - -_type:_ enum [Global, Individual] -Whether the layer should use global time values or function independently with its own time values. - -#### Time Format - -_type:_ string _optional_ -The string format to be used in the URL for `{starttime}` and `{endtime}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. - ---- - -_Note:_ Additional vector layer stylings can be found on the [Vector Styling](Vector_Styling) page. +- [Header](?page=Header) +- [Tile](?page=Tile) +- [Vector Tile](?page=Vector_Tile) +- [Data](?page=Data) +- [Query](?page=Query) +- [Vector](?page=Vector) +- [Model](?page=Model) diff --git a/docs/pages/markdowns/Model.md b/docs/pages/markdowns/Model.md new file mode 100644 index 00000000..205d1122 --- /dev/null +++ b/docs/pages/markdowns/Model.md @@ -0,0 +1,77 @@ +# Model Layer + +A 3D Model for the Globe + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### URL + +_type:_ string +A file path that points to a .dae or .obj. If the path is relative, it will be relative to the mission's directory. + +#### Longitude + +_type:_ float +The longitude in decimal degrees at which to place the model. + +#### Latitude + +_type:_ float +The latitude in decimal degrees at which to place the model. + +#### Elevation + +_type:_ float +The elevation in meters at which to place the model. + +#### Rotation X + +_type:_ float _optional_ +An x-axis rotation in radians to orient the model. + +#### Rotation Y + +_type:_ float _optional_ +A y-axis rotation in radians to orient the model. + +#### Rotation Z + +_type:_ float _optional_ +A z-axis rotation in radians to orient the model. + +#### Scale + +_type:_ float _optional_ +A scaling factor to resize the model. + +#### Initial Visibility + +_type:_ bool +Whether the layer is on initially. + +#### Initial Opacity + +_type:_ float +A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. + +#### Time Enabled + +_type:_ bool +True if the layer is time enabled. URLs that contain `{starttime}` or `{endtime}` will be dynamically replaced by their set values when the layer is fetched. + +#### Time Type + +_type:_ enum [Global, Individual] +Whether the layer should use global time values or function independently with its own time values. + +#### Time Format + +_type:_ string _optional_ +The string format to be used in the URL for `{starttime}` and `{endtime}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. + +--- + +_Note:_ Additional vector layer stylings can be found on the [Vector Styling](Vector_Styling) page. diff --git a/docs/pages/markdowns/Query.md b/docs/pages/markdowns/Query.md new file mode 100644 index 00000000..12854f38 --- /dev/null +++ b/docs/pages/markdowns/Query.md @@ -0,0 +1,122 @@ +# Query Layer + +A user queryable layer whose data comes from an external search endpoint. Currently only supports ElasticSearch. + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### Endpoint + +_type:_ string +A file path that points to a search endpoint. Currently only supports ElasticSearch. + +#### Type + +_type:_ enum +Endpoint type. + +#### Stroke Color + +_type:_ CSS color string or a prop _optional_ +The border color of each feature. If the feature is a line, this field is the color of the line. See the Vector Styling page for more. Colors can be as follows: + +- A named color + - crimson, blue, rebeccapurple +- A hex color + - #FFF + - #A58101 +- An rgb color + - rgb(255,89,45) +- An hsl color + - hsl(130, 26%, 34%) +- Based on a feature's color property + - `prop:geojson_property_key` will set the feature's color to the values of `features[i].properties.geojson_property_key` + - If that property is not a valid CSS color and is a string, it will use a random and consistent color based on its hash. + +#### Fill Color + +_type:_ CSS color string or a prop _optional_ +The fill color of each feature. See Stroke Color for color options. See the Vector Styling page for more. + +#### Stroke Weight + +_type:_ positive integer _optional_ +The thickness of the stroke/border in pixels. See the Vector Styling page for more. + +#### Fill Opacity + +_type:_ float _optional_ +A value from 0 to 1 of Fill Color's opacity. 1 is fully opaque. See the Vector Styling page for more. +_Note: It's also possible to set the opacities of colors directly with #CCDDEEFF, rgba() and hsla()._ + +#### Radius + +_type:_ positive integer _optional_ +When a point feature is encountered, this value will be it's radius in pixels. + +#### Raw Variables + +Clicking "Set Default Variables" will add a template of all possible raw variables (without overwriting ones that are already set). All raw variables are optional. + +Example: + +```javascript +{ + "useKeyAsName": "name", + "datasetLinks": [ + { + "prop": "{prop}", + "dataset": "{dataset}", + "column": "{column}", + "type": "{none || images}" + } + ], + "links": [ + { + "name": "example", + "link": "url/?param={prop}" + } + ], + "query": { + "bodyWrapper": "before{BODY}after`, + "stringifyBody": "boolean - should the body be stringified", + "withCredentials": "boolean - send cookie credentials with the request", + "esResponses": + "boolean - is the es responses nested in a responses object", + "headers": { + "Content-Type": "application/x-ndjson", + }, + "fields": { "field1": "max_agg_size_number(0 for no agging)", "field2": 0 }, + "geoshapeProp": "propName of es geoshape field for spatial searches", + "must": [ + { + "match": { + "fieldName": "fieldValue", + }, + }, + ], + "size": 1000, + }; +} +``` + +- `useNameAsKey`: The property key whose value should be the hover text of each feature. If left unset, the hover key and value will be the first one listed in the feature's properties. +- `links`: Configure deep links to other sites based on the properties on a selected feature. This requires the "Minimalist" option in the Look Tab to be unchecked. Upon clicking a feature, a list of deep links are put into the top bar and can be clicked on to navigate to any other page. + - `name`: The name of the deep link. It should be unique. + - `link`: A url template. Curly brackets are included. On feature click, all `{prop}` are replaced with the corresponding `features[i].properties.prop` value. Multiple `{prop}` are supported as are access to nested props using dot notation `{stores.food.candy}`. + - `which`: This only supports the value `last` at this point. + - `icon`: Any [Material Design Icon](http://materialdesignicons.com/) name + - `value`: A name to display. All `{prop}`s will be replaced by their corresponding `features[which].properties[prop]` value. +- `query`: An object detailing how a query should be formed. + - `bodyWrapper`: An optional string to wrapper the request body in. The body replaces `{BODY}` in the string. Use `stringifyBody` if you use `bodyWrapper`. + - `stringifyBody`: Sends the request body as a string. + - `withCredentials`: Sends cookie credentials along with the request. + - `esResponses`: If true, data would be looked for in 'responses.0.data.hits.hits' instead of 'data.hits.hits' + - `headers`: Header object for the requests. + - `fields`: Property fields that we want the user to be able to search upon. + - `geoshapeProp`: The property field of the search result's geoshape feature. + - `must`: A 'must' stanza to always concatenate with the user's own filtered must. + - `size`: Max number of results to show. ES has a default hard limit of 10k. +- _Other high level raw variable fields might still be applicable here but are untested._ diff --git a/docs/pages/markdowns/Tile.md b/docs/pages/markdowns/Tile.md new file mode 100644 index 00000000..22e74454 --- /dev/null +++ b/docs/pages/markdowns/Tile.md @@ -0,0 +1,81 @@ +# Tile Layer + +Tile layers are hierarchical raster imagery. + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### URL + +_type:_ string +A file path that points to a tileset's directory. If the path is relative, it will be relative to the mission's directory. The URL must contain a proper placeholder ending such as: `{z}/{x}/{y}.png`. See the "Tile Format" section below for more details. + +#### DEM Tile URL + +_type:_ string _optional_ +A file path like URL but pointing to a Digital Elevation Map tileset generated by `auxillary/1bto4b/rasterstotiles1bto4b.py` This is responsible for 3D data in the globe. It would be ideal if this tileset can match the extents of its corresponding raster and has either no nodata or has nodata far lower than that of its lowest point. + +#### Legend + +_type:_ string +An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. + +#### Tile Format + +_type:_ enum [TMS, WMTS, WMS] +The format of the tiles. + +- TMS: Tile Map Service tiles are 256x256 sized images hierarchically organized by zoom level and referenced with x and y coordinates. These are the standard format for web tiles and are the format that MMGIS's auxiliary tiling scripts output. Append `/{z}/{x}/{y}.png` to your `URL`. +- WMTS: Web Map Tile Service is the same exact concept as TMS but it has an inverted Y-axis. Just like TMS, append `/{z}/{x}/{y}.png` to your `URL`. +- WMS: Web Map Service tiles are a popular way of publishing maps by professional GIS software. This format is similar to the previous two formats, but more generic and not so well optimized for use in web maps. A WMS image is defined by the coordinates of its corners. A layer (or list of layers) should be provided as an options by appending `?layers=<,another_if_you _want>` to your `URL`. To override WMS parameters append `&=` again to the `URL` after the "layers" parameters. + _Example URL: `http://ows.mundialis.de/services/service?layers=TOPO-WMS,OSM-Overlay-WMS`_ + +#### Initial Visibility + +_type:_ bool +Whether the layer is on initially. + +#### Initial Opacity + +_type:_ float +A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. + +#### Minimum Zoom + +_type:_ integer +The lowest (smallest number) zoom level of the tile set. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Maximum Native Zoom + +_type:_ integer +The highest (largest number) zoom level of the tile set. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Maximum Zoom + +_type:_ integer +The highest (largest number) zoom level to see in MMGIS. This value is at least as high as Maximum Native Zoom. This allows zooms level higher than that of the tileset. Instead of rendering new tile image, it scales them in instead. + +#### Bounding Box + +_type:_ string _optional_ +A comma separated string defining the tileset's `minimumLonDeg,minimumLatDeg,maximumLonDeg,maximumLatDeg`. Setting a bounding box improves performance by limiting requests for tiles to only those that fit the bounds. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Time Enabled + +_type:_ bool +True if the layer is time enabled. URLs that contain `{time}` will be dynamically replaced by their set values when the layer is fetched. + +#### Time Type + +_type:_ enum [Global, Individual] +Whether the layer should use global time values or function independently with its own time values. + +#### Time Format + +_type:_ string _optional_ +The string format to be used in the URL for `{time}`. Defaults to `%Y-%m-%dT%H:%M:%SZ`. diff --git a/docs/pages/markdowns/Vector.md b/docs/pages/markdowns/Vector.md new file mode 100644 index 00000000..52a1c531 --- /dev/null +++ b/docs/pages/markdowns/Vector.md @@ -0,0 +1,241 @@ +# Vector Layer + +A [geojson](https://geojson.org/) layer. + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### Kind of Layer + +_type:_ enum +A special kind of interaction for the layer. Please see the Kinds page for more. + +#### URL + +_type:_ string +A file path that points to a geojson. If the path is relative, it will be relative to the mission's directory. The URL must contain a proper placeholder ending such as: `{z}/{x}/{y}.png`. Alternatively vectors can be served with Geodatasets. Simply go to "Manage Geodatasets" at the bottom left, upload a geojson and link to it in this URL field with "geodatasets:{geodataset\*name}" + +#### Controlled + +_type:_ bool +Whether the layer can be dynamically updated or not. If true, the layer can be dynamically updated and the URL is not required. + +#### Legend + +_type:_ string +An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. + +#### Initial Visibility + +_type:_ bool +Whether the layer is on initially. + +#### Visibility Cutoff + +_type:_ integer _optional_ +If set, this vector layer will be hidden if the current zoom level is less than or equal to that of the visibility cutoff. `Visibility Cutoff * -1` will invert its visibility condition. This is useful when the dataset is dense, local to a one region, or irrelevant when far away and the desired range of zoom levels is large. + +#### Initial Opacity + +_type:_ float +A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. + +#### Time Enabled + +_type:_ bool +True if the layer is time enabled. URLs that contain `{starttime}` or `{endtime}` will be dynamically replaced by their set values when the layer is fetched. + +#### Time Type + +_type:_ enum [Global, Individual] +Whether the layer should use global time values or function independently with its own time values. + +#### Time Format + +_type:_ string _optional_ +The string format to be used in the URL for `{starttime}` and `{endtime}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. + +#### Stroke Color + +_type:_ CSS color string or a prop _optional_ +The border color of each feature. If the feature is a line, this field is the color of the line. See the Vector Styling page for more. Colors can be as follows: + +- A named color + - crimson, blue, rebeccapurple +- A hex color + - #FFF + - #A58101 +- An rgb color + - rgb(255,89,45) +- An hsl color + - hsl(130, 26%, 34%) +- Based on a feature's color property + - `prop:geojson_property_key` will set the feature's color to the values of `features[i].properties.geojson_property_key` + - If that property is not a valid CSS color and is a string, it will use a random and consistent color based on its hash. + +#### Fill Color + +_type:_ CSS color string or a prop _optional_ +The fill color of each feature. See Stroke Color for color options. See the Vector Styling page for more. + +#### Stroke Weight + +_type:_ positive integer _optional_ +The thickness of the stroke/border in pixels. See the Vector Styling page for more. + +#### Fill Opacity + +_type:_ float _optional_ +A value from 0 to 1 of Fill Color's opacity. 1 is fully opaque. See the Vector Styling page for more. +_Note: It's also possible to set the opacities of colors directly with #CCDDEEFF, rgba() and hsla()._ + +#### Radius + +_type:_ positive integer _optional_ +When a point feature is encountered, this value will be it's radius in pixels. + +#### Raw Variables + +Clicking "Set Default Variables" will add a template of all possible raw variables (without overwriting ones that are already set). All raw variables are optional. + +Example: + +```javascript +{ + "useKeyAsName": "name", + "datasetLinks": [ + { + "prop": "{prop}", + "dataset": "{dataset}", + "column": "{column}", + "type": "{none || images}" + } + ], + "links": [ + { + "name": "example", + "link": "url/?param={prop}" + } + ], + "info": [ + { + "which": "last", + "icon": "material design icon", + "value": "Prop: {prop}" + } + ], + "markerAttachments": { + "bearing": { + "angleProp": "path.to.angle.prop", + "angleUnit": "deg || rad", + "color": "#FFFFFF", + }, + "uncertainty": { + "initialVisibility": true, + "xAxisProp": "path.to.x.prop", + "yAxisProp": "path.to.y.prop", + "axisUnit": "meters || kilometers", + "angleProp": "path.to.angle.prop", + "angleUnit": "deg || rad", + "color": "#888888", + }, + "image": { + "initialVisibility": true, + "path": "url to top-down ortho image. ex. public/images/rovers/PerseveranceTopDown.png", + "pathProp": "path to image. take priority over path", + "widthMeters": 2.6924, + "widthPixels": 420, + "heightPixels": 600, + "angleProp": "path.to.angle.prop", + "angleUnit": "deg || rad", + "show": "click || always", + }, + "model": { + "path": "path to model (.dae, .glb, .gltf, .obj)", + "pathProp": "path to model. take priority over path", + "mtlPath": "if .obj, path to material file (.mtl)", + "yawProp": "path.to.yaw.prop", + "yawUnit": "deg || rad", + "invertYaw": false, + "pitchProp": "path.to.pitch.prop", + "pitchUnit": "deg || rad", + "invertPitch": true, + "rollProp": "path.to.roll.prop", + "rollUnit": "deg || rad", + "invertRoll": false, + "elevationProp": "path.to.elev.prop", + "scaleProp": "path.to.scale.prop", + "show": "click || always", + "onlyLastN": false + }, + }, + "markerIcon": { //See: https://leafletjs.com/reference-1.7.1.html#icon-l-icon + "iconUrl": "pathToMainIconImage.png", + "shadowUrl": "(opt)pathToShadowImage.png", + "iconSize": [38, 95], // size of the icon + "shadowSize": [50, 64], // size of the shadow + "iconAnchor": [22, 94], // point of the icon which will correspond to marker's location + "shadowAnchor": [4, 62], // the same for the shadow + }. + "search": "(prop1) round(prop2.1) rmunder(prop_3)" +} +``` + +- `useNameAsKey`: The property key whose value should be the hover text of each feature. If left unset, the hover key and value will be the first one listed in the feature's properties. +- `datasetLinks`: Datasets are csvs uploaded from the "Manage Datasets" page accessible on the lower left. Every time a feature from this layer is clicked with datasetLinks configured, it will request the data from the server and include it with it's regular geojson properties. This is especially useful when single features need a lot of metadata to perform a task as it loads it only as needed. + - `prop`: This is a property key already within the features properties. It's value will be searched for in the specified dataset column. + - `dataset`: The name of a dataset to link to. A list of datasets can be found in the "Manage Datasets" page. + - `column`: This is a column/csv header name within the dataset. If the value of the prop key matches the value in this column, the entire row will be return. All rows that match are returned. + - `type`: Unused. +- `links`: Configure deep links to other sites based on the properties on a selected feature. This requires the "Minimalist" option in the Look Tab to be unchecked. Upon clicking a feature, a list of deep links are put into the top bar and can be clicked on to navigate to any other page. + - `name`: The name of the deep link. It should be unique. + - `link`: A url template. Curly brackets are included. On feature click, all `{prop}` are replaced with the corresponding `features[i].properties.prop` value. Multiple `{prop}` are supported as are access to nested props using dot notation `{stores.food.candy}`. +- `info`: Creates an informational record at the top of the page. The first use case was showing the value of the latest sol. Clicking this record pans to the feature specified by `which`. This requires the "Minimalist" option in the Look Tab to be unchecked. This is used on startup and not when a user selects a feature in this layer. + - `which`: This only supports the value `last` at this point. + - `icon`: Any [Material Design Icon](http://materialdesignicons.com/) name + - `value`: A name to display. All `{prop}`s will be replaced by their corresponding `features[which].properties[prop]` value. +- `markerBearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). `{unit}` is either `deg` or `rad` and `{prop}` is the dot notated path to the feature properties that contains the desired rotation angle. Ex. `deg:headings.yaw`. +- `markerAttachments`: An object for attaching dynamic items to point features. + - `bearing`: Sets the bearing direction of this layer's point markers (or markerIcons if set). Overrides the layer's shape dropdown value. + - `angleProp`: The dot notated path to the feature properties that contains the desired rotation angle. Ex. `headings.yaw`. + - `angleUnit`: Unit of the value of `angleProp`. Either `deg` or `rad`. + - `color`: A css color for the directional arrow for non-markerIcon bearings. + - `uncertainty`: A sublayer feature that places ellipses about point features to indicate positional uncertainty + - `initialVisibility`: Whether the uncertainty sublayer is initially on. Users can toggle sublayers on and off in the layer settings in the LayersTool. + - `xAxisProp`: Prop path to the x axis radius value of the ellipse. + - `yAxisProp`: Prop path to the y axis radius value of the ellipse. + - `axisUnit`: "meters || kilometers", + - `angleProp`: Prop path to the rotation of the ellipse. + - `angleUnit`: "deg || rad" + - `color`: A css fill color. Will be made more transparent than set. + - `image`: Places a scaled and orientated image under each marker. A sublayer. + - `initialVisibility`: Whether the image sublayer is initially on. Users can toggle sublayers on and off in the layer settings in the LayersTool. + - `path`: A url to a (preferably) top-down north-facing orthographic image. + - `pathProp`: A prop path to an image url. Take priority over path. Useful if the path is feature specific. + - `widthMeters`: Width of image in meters in order to calculate scale. + - `widthPixels`: Image width in pixels. + - `heightPixels`: Image height in pixel. + - `angleProp`: Prop path to the rotation of the image. + - `angleUnit`: "deg || rad" + - `show`: "click || always". If set to "always", overrides the Waypoints Kind (if set) and always renders the image under the marker. "click" just shows the image on click and requires the layer to have the Waypoints Kind. + - `model`: + - `path`: Path to model (.dae, .glb, .gltf, .obj) + - `pathProp`: A prop path to a model. Takes priority over path. Useful if model is feature specific. + - `mtlPath`: If .obj, the path to its material file (.mtl) + - `yawProp`: Prop path to the model's yaw. If this value is a number, uses it directly. + - `yawUnit`: "deg || rad" + - `invertYaw`: Boolean that, if true, multiplies yaw by -1. + - `pitchProp`: Prop path to the model's pitch. If this value is a number, uses it directly. + - `pitchUnit`: "deg || rad" + - `invertPitch`: Boolean that, if true, multiplies pitch by -1. + - `rollProp`: Prop path to the model's roll. If this value is a number, uses it directly. + - `rollUnit`: "deg || rad" + - `invertRoll`: Boolean that, if true, multiplies roll by -1. + - `elevationProp`: Prop path to the model's elevation (in meters). If this value is a number, uses it directly. Default 0. + - `scaleProp`: Prop path to the model's scale. If this value is a number, uses it directly. Default 1. + - `show`: "click || always" + - `onlyLastN`: If false, shows models at all points. If a number, only shows models for the last n points. +- `markerIcon`: Uses an icon image instead of an svg for all of the layer's point markers. If you're using this as a bearing marker, make sure the base icon is pointing north. +- `search`: This requires the "Minimalist" option in the Look Tab to be unchecked. When set, this layer will become searchable through the search bar at the top. The search will look for and autocomplete on the properties specified. All properties are enclosed by parentheses and space-separated. `round` can be used like a function to round the property beforehand. `rmunder` works similarly but removes all underscores instead. diff --git a/docs/pages/markdowns/Vector_Tile.md b/docs/pages/markdowns/Vector_Tile.md new file mode 100644 index 00000000..b7b322d3 --- /dev/null +++ b/docs/pages/markdowns/Vector_Tile.md @@ -0,0 +1,111 @@ +# Vector Tile Layer + +A mix between Tile and Vector. Useful when rendering tons of features since features are rendered based on viewport instead of all at once at the start. + +#### Layer Name + +_type:_ string +The unique display name and identifier of the layer. It must be unique and contain no special characters. + +#### Kind of Layer + +_type:_ enum +A special kind of interaction for the layer. Please see the Kinds page for more. + +#### URL + +_type:_ string +A file path that points to a vector tileset's directory. If the path is relative, it will be relative to the mission's directory. The URL must contain a proper placeholder ending such as: `{z}/{x}/{y}.png`. Alternatively vector tiles can be generated and served in real time with Geodatasets. Simply go to "Manage Geodatasets" at the bottom left, upload a geojson and link to it in this URL field with "geodatasets:{geodataset*name}" +\_Note: If the vector tile layer contains points, the layer will break. A known workaround is to buffer all points.* + +#### DEM Tile URL + +_type:_ string _optional_ +A file path like URL but pointing to a Digital Elevation Map tileset generated by `auxillary/1bto4b/rasterstotiles1bto4b.py` This is responsible for 3D data in the globe. It would be ideal if this tileset can match the extents of its corresponding raster and has either no nodata or has nodata far lower than that of its lowest point. + +#### Legend + +_type:_ string +An absolute or relative file path pointing to a `legend.csv` that describes the symbology of the layer. Please see the Legend Tool to see how to form a `legend.csv`. + +#### Tile Format + +_type:_ enum [TMS, WMTS, WMS] +The format of the tiles. + +- TMS: Tile Map Service tiles are 256x256 sized images hierarchically organized by zoom level and referenced with x and y coordinates. These are the standard format for web tiles and are the format that MMGIS's auxiliary tiling scripts output. Append `/{z}/{x}/{y}.png` to your `URL`. +- WMTS: Web Map Tile Service is the same exact concept as TMS but it has an inverted Y-axis. Just like TMS, append `/{z}/{x}/{y}.png` to your `URL`. +- WMS: Web Map Service tiles are a popular way of publishing maps by professional GIS software. This format is similar to the previous two formats, but more generic and not so well optimized for use in web maps. A WMS image is defined by the coordinates of its corners. A layer (or list of layers) should be provided as an options by appending `?layers=<,another_if_you _want>` to your `URL`. To override WMS parameters append `&=` again to the `URL` after the "layers" parameters. + _Example URL: `http://ows.mundialis.de/services/service?layers=TOPO-WMS,OSM-Overlay-WMS`_ + +#### Initial Visibility + +_type:_ bool +Whether the layer is on initially. + +#### Initial Opacity + +_type:_ float +A value from 0 to 1 of the layer's initial opacity. 1 is fully opaque. + +#### Minimum Zoom + +_type:_ integer +The lowest (smallest number) zoom level of the tile set. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Maximum Native Zoom + +_type:_ integer +The highest (largest number) zoom level of the tile set. +_Note: This field can be automatically populate with "Populate from XML". "Populate from XML" uses looks for a `tilemapresource.xml` in the tileset directory specified by the URL field._ + +#### Maximum Zoom + +_type:_ integer +The highest (largest number) zoom level to see in MMGIS. This value is at least as high as Maximum Native Zoom. This allows zooms level higher than that of the tileset. Instead of rendering new tile image, it scales them in instead. + +#### Time Enabled + +_type:_ bool +True if the layer is time enabled. URLs that contain `{time}` will be dynamically replaced by their set values when the layer is fetched. + +#### Time Type + +_type:_ enum [Global, Individual] +Whether the layer should use global time values or function independently with its own time values. + +#### Time Format + +_type:_ string _optional_ +The string format to be used in the URL for `{time}`. Defaults to `YYYY-MM-DDTHH:mm:ssZ`. + +#### Vector Tile Feature Unique Id Key + +_type:_ string +Each feature of the vector tileset needs a property with a unique value to identify it. This required field is the name of that property. + +#### Use Key as Name + +_type:_ string _optional_ +The property key whose value should be the hover text of each feature. This is the same as the `useKeyAsName` raw variable within Vector layers + +#### Raw Variables + +Vector Tiles are styled differently than Vectors. Raw variables here takes an object that maps internal vector tile layer names to styles. All raw variables are optional. + +Example: + +```javascript +{ + "": { + "color": "#FFFFFF", + "fill": true, + "fillColor": "rgb(0, 125, 200)", + "fillOpacity": 0.5, + "opacity": 1, + "radius": 4, + "weight": 2 + } +} +``` diff --git a/views/docs.pug b/views/docs.pug index fb686a9a..71639b9f 100644 --- a/views/docs.pug +++ b/views/docs.pug @@ -18,6 +18,8 @@ head ul#nav #cat CONFIGURE ul#navconfigure + #cat LAYER CONFIGURATIONS + ul#navlayers #cat TOOLS ul#navtools #cat APIS From 679ef60e7239e5e670619fae2506659eb3365ff2 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 10 Jan 2022 10:53:43 -0800 Subject: [PATCH 83/85] #122 Spatial Filter account for current planet radius --- src/essence/Tools/Layers/Filtering/Filtering.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/essence/Tools/Layers/Filtering/Filtering.js b/src/essence/Tools/Layers/Filtering/Filtering.js index 001eab99..059059d7 100644 --- a/src/essence/Tools/Layers/Filtering/Filtering.js +++ b/src/essence/Tools/Layers/Filtering/Filtering.js @@ -179,7 +179,10 @@ const Filtering = { // Buffered Circle const geojson = F_.getBaseGeoJSON() geojson.features.push( - circle([center.lng, center.lat], radius * 0.001) + circle( + [center.lng, center.lat], + radius * 0.001 * F_.getEarthToPlanetRatio() + ) ) Filtering.mapSpatialLayer = L.geoJSON(geojson, { From 6e4f0e5b9114f08a9953885d276de4bd38de4ce5 Mon Sep 17 00:00:00 2001 From: ac-61 Date: Mon, 10 Jan 2022 11:47:05 -0800 Subject: [PATCH 84/85] Update MMGIS API vector layer functions (#123) * Update function parameters for updateVectorLayer function * Rename variables * Seperate editing vector layer functions * Update documentation * Fix documentation * Added extra functions for completeness --- docs/pages/markdowns/JavaScript_API.md | 66 +++++++++++- src/essence/Basics/Layers_/Layers_.js | 144 ++++++++++++++++++++----- src/essence/mmgisAPI/mmgisAPI.js | 27 ++++- 3 files changed, 210 insertions(+), 27 deletions(-) diff --git a/docs/pages/markdowns/JavaScript_API.md b/docs/pages/markdowns/JavaScript_API.md index 2ac0c66b..81c2f1e8 100644 --- a/docs/pages/markdowns/JavaScript_API.md +++ b/docs/pages/markdowns/JavaScript_API.md @@ -18,9 +18,9 @@ The following is an example of how to call the `clearVectorLayer` function: window.mmgisAPI.clearVectorLayer('Waypoints') ``` -### updateVectorLayer(layerName, inputData, keepN) +### updateVectorLayer(layerName, inputData) -This function updates an existing vector layer with a specified name, valid GeoJSON data and keeps the last N number of features after adding the new data +This function updates an existing vector layer with a specified name and valid GeoJSON data #### Function parameters @@ -52,6 +52,68 @@ window.mmgisAPI.updateVectorLayer('Waypoints', { ``` +### trimVectorLayerKeepBeforeTime(layerName, keepBeforeTime, timePropPath) + +This function removes features on a specified layer after a specified time + +#### Function parameters + +- `layerName` - name of layer to update +- `keepBeforeTime` - absolute time in the format of YYYY-MM-DDThh:mm:ssZ; will keep all features before this time +- `timePropPath` - name of time property to compare with the time specified by keepAfterTime + +The following is an example of how to call the `trimVectorLayerKeepBeforeTime` function: + +```javascript +window.mmgisAPI.trimVectorLayerKeepBeforeTime('Waypoints', "2021-12-01T15:10:00.000Z", 'time') +``` + +### trimVectorLayerKeepAfterTime(layerName, keepAfterTime, timePropPath) + +This function removes features on a specified layer before a specified time + +#### Function parameters + +- `layerName` - name of layer to update +- `keepAfterTime` - absolute time in the format of YYYY-MM-DDThh:mm:ssZ; will keep all features after this time +- `timePropPath` - name of time property to compare with the time specified by keepAfterTime + +The following is an example of how to call the `trimVectorLayerKeepAfterTime` function: + +```javascript +window.mmgisAPI.trimVectorLayerKeepAfterTime('Waypoints', "2021-12-01T15:10:00.000Z", 'time') +``` + +### keepFirstN(layerName, keepLastN) + +This function removes features on a specified layer starting from the tail of of the features list to keep the specified number of existing features. This function is not aware of time and will only keep the previous N number of features based on the order the features were added to the layer. + +#### Function parameters + +- `layerName` - name of layer to update +- `keepFirstN` - number of features to keep from the beginning of the features list. A value less than or equal to 0 keeps all previous features + +The following is an example of how to call the `keepFirstN` function: + +```javascript +window.mmgisAPI.keepFirstN('Waypoints', 2) +``` + +### keepLastN(layerName, keepLastN) + +This function removes features on a specified layer starting from the beginning of the features list to keep the specified number of existing features. This function is not aware of time and will only keep the previous N number of features based on the order the features were added to the layer. + +#### Function parameters + +- `layerName` - name of layer to update +- `keepLastN` - number of features to keep from the tail end of the features list. A value less than or equal to 0 keeps all previous features + +The following is an example of how to call the `keepLastN` function: + +```javascript +window.mmgisAPI.keepLastN('Waypoints', 2) +``` + ## Time Control ## toggleTimeUI(visibility) diff --git a/src/essence/Basics/Layers_/Layers_.js b/src/essence/Basics/Layers_/Layers_.js index 9e9c4476..d7555c19 100644 --- a/src/essence/Basics/Layers_/Layers_.js +++ b/src/essence/Basics/Layers_/Layers_.js @@ -1269,20 +1269,135 @@ var L_ = { console.warn('Warning: Unable to clear vector layer: ' + layerName) } }, - updateVectorLayer: function (layerName, inputData, keepN) { - // Validate input for keepN + removeLayerHelper: function (updateLayer, removeLayer) { + // If we remove a layer but its properties are displayed in the InfoTool + // and description (i.e. it was clicked), clear the InfoTool and description + const infoTool = ToolController_.getTool('InfoTool') + if (infoTool.currentLayer === removeLayer) { + L_.clearVectorLayerInfo() + } + + // Remove the layer + updateLayer.removeLayer(removeLayer) + }, + trimVectorLayerKeepBeforeTime: function (layerName, keepBeforeTime, timePropPath) { + L_.trimVectorLayerHelper(layerName, keepBeforeTime, timePropPath, "before") + }, + trimVectorLayerKeepAfterTime: function (layerName, keepAfterTime, timePropPath) { + L_.trimVectorLayerHelper(layerName, keepAfterTime, timePropPath, "after") + }, + trimVectorLayerHelper: function (layerName, keepTime, timePropPath, trimType) { + // Validate input parameters + if (!keepTime) { + console.warn( + 'Warning: The input for keep' + trimType.capitalizeFirstLetter() + 'Time is invalid: ' + keepTime + ) + return + } + + if (!timePropPath) { + console.warn( + 'Warning: The input for timePropPath is invalid: ' + timePropPath + ) + return + } + + if (keepTime) { + const keepAfterAsDate = new Date(keepTime) + if (isNaN(keepAfterAsDate.getTime())) { + console.warn( + 'Warning: The input for keep' + trimType.capitalizeFirstLetter() + 'Time is invalid: ' + keepAfterTime + ) + return + } + } + + if (layerName in L_.layersGroup) { + const updateLayer = L_.layersGroup[layerName] + + if (keepTime) { + const keepTimeAsDate = new Date(keepTime) + + var layers = updateLayer.getLayers() + for (let i = layers.length - 1; i >= 0; i--) { + let layer = layers[i] + if (layer.feature.properties[timePropPath]) { + const layerDate = new Date(layer.feature.properties[timePropPath]) + if (isNaN(layerDate.getTime())) { + console.warn( + 'Warning: The time for the layer is invalid: ' + layer.feature.properties[timePropPath] + ) + continue + } + if (trimType === "after") { + if (layerDate < keepTimeAsDate) { + console.log("if true") + L_.removeLayerHelper(updateLayer, layer) + } + } else if (trimType === "before") { + if (layerDate > keepTimeAsDate) { + console.log("if true") + L_.removeLayerHelper(updateLayer, layer) + } + } + } + } + } + } else { + console.warn( + 'Warning: Unable to trim vector layer as it does not exist: ' + + layerName + ) + } + }, + keepFirstN: function (layerName, keepFirstN) { + L_.keepNHelper(layerName, keepFirstN, "first") + }, + keepLastN: function (layerName, keepLastN) { + L_.keepNHelper(layerName, keepLastN, "last") + }, + keepNHelper: function (layerName, keepN, keepType) { + // Validate input parameter const keepNum = parseInt(keepN) - if (keepN && Number.isNaN(Number(keepNum))) { + if (Number.isNaN(Number(keepNum))) { console.warn( - 'Warning: Unable to update vector layer `' + + 'Warning: Unable to trim vector layer `' + layerName + - '` as keepN == ' + + '` as keep' + keepType.capitalizeFirstLetter() + 'N == ' + keepN + ' and is not a valid integer' ) return } + if (layerName in L_.layersGroup) { + // Keep N elements if greater than 0 else keep all elements + if (keepN && keepN > 0) { + const updateLayer = L_.layersGroup[layerName] + var layers = updateLayer.getLayers() + + if (keepType === "last") { + while (layers.length > keepN) { + const removeLayer = layers[0] + L_.removeLayerHelper(updateLayer, removeLayer) + layers = updateLayer.getLayers() + } + } else if (keepType === "first") { + while (layers.length > keepN) { + const removeLayer = layers[layers.length - 1] + L_.removeLayerHelper(updateLayer, removeLayer) + layers = updateLayer.getLayers() + } + } + } + } else { + console.warn( + 'Warning: Unable to trim vector layer as it does not exist: ' + + layerName + ) + } + }, + updateVectorLayer: function (layerName, inputData) { if (layerName in L_.layersGroup) { const updateLayer = L_.layersGroup[layerName] @@ -1296,25 +1411,6 @@ var L_ = { layerName ) } - - const infoTool = ToolController_.getTool('InfoTool') - - // Keep N elements if greater than 0 else keep all elements - if (keepN && keepNum > 0) { - var layers = updateLayer.getLayers() - while (layers.length > keepNum) { - // If we remove a layer but its properties are displayed in the InfoTool - // and description (i.e. it was clicked), clear the InfoTool and description - const removeLayer = layers[0] - if (infoTool.currentLayer === removeLayer) { - L_.clearVectorLayerInfo() - } - - // Remove the layer - updateLayer.removeLayer(removeLayer) - layers = updateLayer.getLayers() - } - } } else { console.warn( 'Warning: Unable to update vector layer as it does not exist: ' + diff --git a/src/essence/mmgisAPI/mmgisAPI.js b/src/essence/mmgisAPI/mmgisAPI.js index 56f09d7a..9c5cf1f9 100644 --- a/src/essence/mmgisAPI/mmgisAPI.js +++ b/src/essence/mmgisAPI/mmgisAPI.js @@ -202,9 +202,34 @@ var mmgisAPI = { * Updates a specified layer with GeoJSON data * @param {string} - layerName - name of layer to update * @param {GeoJSON} - inputData - valid GeoJSON data - * @param {number} - keepN - number of features to keep. A value less than or equal to 0 keeps all previous features */ updateVectorLayer: L_.updateVectorLayer, + /** + * Remove features on a specified layer before a specified time + * @param {string} - layerName - name of layer to update + * @param {string} - keepAfterTime - absolute time in the format of YYYY-MM-DDThh:mm:ssZ; will keep all features after this time + * @param {number} - timePropPath - name of time property to compare with the time specified by keepAfterTime + */ + trimVectorLayerKeepAfterTime: L_.trimVectorLayerKeepAfterTime, + /** + * Remove features on a specified layer after a specified time + * @param {string} - layerName - name of layer to update + * @param {string} - keepBeforeTime - absolute time in the format of YYYY-MM-DDThh:mm:ssZ; will keep all features before this time + * @param {number} - timePropPath - name of time property to compare with the time specified by keepAfterTime + */ + trimVectorLayerKeepBeforeTime: L_.trimVectorLayerKeepBeforeTime, + /** + * Number of features to keep on a specified layer. Keeps from the tail end of the feature list. + * @param {string} - layerName - name of layer to update + * @param {keepLastN} - keepN - number of features to keep from the tail end of the feature list. A value less than or equal to 0 keeps all previous features + */ + keepLastN: L_.keepLastN, + /** + * Number of features to keep on a specified layer. Keeps features from the beginning of the feature list. + * @param {string} - layerName - name of layer to update + * @param {keepFirstN} - keepN - number of features to keep from the beginning of the feature list. A value less than or equal to 0 keeps all previous features + */ + keepFirstN: L_.keepFirstN, // Time Control API functions From b39f36d18c65319ae824ba5d8a6a810d8a957030 Mon Sep 17 00:00:00 2001 From: Tariq Soliman Date: Mon, 10 Jan 2022 15:04:03 -0800 Subject: [PATCH 85/85] Bump to 2.5.0 --- CHANGELOG.md | 297 +++++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 2 +- 2 files changed, 298 insertions(+), 1 deletion(-) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..3aa1b37d --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,297 @@ +# MMGIS Changelog + +## 2.5.0 + +#### Summary + +This release contains the IsochroneTool, revives the Model layer type and includes a new Query layer type. Each vector layer can now be filtered by the user through the LayersTool, leads in the DrawTool can now draw and publish arrows and annotations, and the MeasureTool finally supports continuous elevation profiles. + +#### Added + +- Isochrone Tool! +- Model layer type! +- Query layer type! +- User filterable layers! +- More mmgisAPI functions +- Deep linking 'centerPin' parameter +- DrawTool lead Map file +- DrawTool text rotation +- Annotation and Arrows are now supported in regular (non-DrawTool) geojson +- Configurable bearings, uncertainty ellipses, models and underlaid images for vector points +- MeasureTool now supports a continuous profile +- MeasureTool csv export includes 3D distance as well +- LayersTool support sublayer visibility toggles within a layer's settings menu +- Python3 version of gdal2customtiles.py +- More Coordinates configurations +- Option in great_circle_calculator to calculate distance between points with Vincenty's formulae +- CHANGELOG.md +- Raw Variables Link has a new 'replace' section for modifying property values before injecting into a url + +#### Changed + +- LithoSphere 1.0.1 => 1.1.0 - [See LithoSphere Releases](https://github.com/NASA-AMMOS/LithoSphere/releases) +- LayersTool, LegendTool and InfoTool panels are wider +- The MMGIS M logo is now an svg +- bulk_tiles.py's colormap is now optional +- DrawTool's compile includes an inward buffer to allow for smaller drawn features to pass checks +- InfoTool now lists all intersected polygons of a layer under a mouse click + +#### Fixed + +- Viewsheds play nicely with polar maps +- Various improvements to the top search bar +- Legend items wrap to new line instead of extending off screen +- `colors` package fix +- `globeLon` deep link not working +- Uses `asHTML` for IdentifierTool again +- `apt-get update` in Dockerfile now uses -y (yes to all) flag + +#### Removed + +- Excess Globe feature highlighting + +## 2.4.0 + +#### Summary + +This release adds in the Viewshed Tool, time enabled layers, [LithoSphere](https://github.com/NASA-AMMOS/LithoSphere), WMS support, data layers, a JavaScript API, and more. + +#### Added + +- The Viewshed Tool! +- Time enabled layers, configurations and a time UI component. +- Full support for WMS layers and projections in 2D and 3D. +- Data layer colorize shader enabling dynamic rendering of data. +- An extensive window.mmgisAPI for interacting with MMGIS through an iframe. +- Configuration for point marker shape. +- Support for serving MMGIS at a subpath with the PUBLIC_URL environment variable. +- bulk_tiles.py auxiliary script. +- Features can be dehighlighted by clicking off on the map. +- Measure Tool supports measurements in kilometers. +- Ability to type in and go to a coordinate. +- Elevation values on mouse over. +- Configurable coordinates. +- Draw Tool features behave like regular layer features when the Draw Tool is closed. + +#### Changed + +- The Globe has been refactored and made standalone in the npm library LithoSphere. +- The Waypoint Kind now uses a top-down image of Perseverance. +- Migrated from Python2 to Python3. + +#### Fixed + +- Documentation uses only relative links for resources now. +- Issue with auth=none not working. +- Draw Tool drawings now work at the meter level. +- Draw Tool drawings now properly respect 0 valued styles. +- Data layer names now support spaces. + +#### Removed + +- All PHP dependencies. + +--- + +## 2.3.1 + +#### Summary + +A point release to address bug fixes. + +#### Fixed + +- WMS layers now work for full polar projections +- Raster layers obey order even if they're initially off +- Draw Tool truly accepts .json files + +--- + +## 2.3.0 + +#### Summary + +The Draw Tool gets its own tag filtering system. The Measure Tool now uses great arcs and is way more accurate and the map now fully supports WMS layers! + +#### Migration Details + +- The DrawTool tagging system change ideally needs more space in the `file_description` column. To increase it and not hit a tag or file description limit in drawing files, back-up the MMGIS database and run the SQL command: + +``` +ALTER TABLE user_files ALTER COLUMN file_description TYPE VARCHAR(10000); +``` + +#### Added + +- Draw Tool files can now be search for by user defined tags/keyword +- Draw Tool file options modal has been upgraded +- Admins can pin preferred tags +- Measure Tool now uses great arcs to compute measurements as well as for rendering lines +- A docker-compose.yml +- Fully functional WMS Map layers + +#### Removed + +#### Changed + +- Draw Tool requires a user to enter a file name before creating a file. (Instead of adding one as "New File") +- Draw Tool now accepts uploads of .json geojson files. (From just .geojson and .shp) +- Tools plugins are captured at build time! (You do not need to run `npm start` before building anymore) +- Info Tool contents are condensed + +#### Fixed + +- Screenshot widget no longer captures the faint bottom bar in its images +- Deep links to selected feature can now activate their info in the Info Tool +- AUTH=local allows users to sign in again +- Measure Tool profile download data is now accurate + +--- + +## 2.0.0 + +#### Migration Details + +- The environment variable `ALLOW_EMBED` has been replaced with `FRAME_ANCESTORS` +- `npm install` is only needed in the root directory and not in the /API directory any more +- Instead of `npm start`, use `npm run build` and then afterwards `npm run start:prod` to run the application. + _You will still need to run `npm start` before building the first time_ + +#### Added + +- Webpack! +- Production level builds +- Babel +- React support +- Icons as markers +- Configurable vector highlight color +- Graticules +- Configure page help buttons to docs + +#### Removed + +- Require.js +- Unused libraries, tools and code +- Swap widget +- FORCE_CONFIGCONFIG environment variable removed + +#### Changed + +- Info Tool upgraded! +- Measure Tool upgraded! +- Top bar search +- The environment variable ALLOW_EMBED has been replaced with FRAME_ANCESTORS +- MMGIS2 splash screen +- Various small UI changes +- Improved configure look tab +- Development logging is friendlier + +#### Fixed + +- Configure save warns of bad json +- Removed unused configure globe projection option +- Configure look tab colors work properly + +--- + +## 1.3.5 + +#### Added + +- ALLOW_EMBED environment variable +- DISABLE_LINK_SHORTENER environment variable + +#### Fixed + +- Tweaked various UI elements +- The Configure page Look tab now correctly reads in any existing `logourl` and `helpurl` +- Configure page now warns of invalid raw variable JSON +- Raw variable `info` values don't break when there's no text to replace in them +- Configuration endpoints no longer assume SQL output is ordered + +--- + +## 1.3.4 + +#### Added: + +- WMS tile support for the Map (does not yet work on the Globe). +- `AUTH` env can be set to "off" to disable user login entirely. +- gdal2customtiles.py for tiling datasets with custom projections. + +--- + +## 1.3.3 + +#### Added: + +- Example docker-compose + +#### Fixed: + +- 3D Globe was rendering layers in depth order instead of breadth order +- Draw Tool publishing sometimes undid the last Lead Map edits +- Draw Tool styling options sometimes hidden in FireFox + +#### Changed: + +- New short URLs are one character longer +- Draw Tool publish overlap tolerance increased + +--- + +## 1.3.2 + +#### Fixed + +- Draw Tool history sql commands assumed rows would be returned in order which could completely break the tool. +- Draw Tool layers would get stuck due to automatic toggling when copying to files or turning the file you're drawing in off. +- The waypoint image links on the Test mission have been fixed. + +--- + +## 1.3.1 + +#### Fixed + +- Additional authorization headers prevented access to the configure login page. + +--- + +## 1.3.0 + +#### New Requirements + +- Node.js >= v10.10 + +#### New Features + +- Export vector layers as geojson from the Layers Tool +- Info Tool uses a JSON viewer +- Users can now split and merge features in the Draw Tool +- Rich application logging +- ENVs that end with \_HOST are pinged at start to test connections +- Ability to configure deep links to other sites based on properties of a selected feature +- Users can upload much larger files in the Draw Tool +- Missions can be configured to use any map projection +- Globe level of detail +- Globe space themed skysphere +- Tools and Backends are included by scanning a directory for setup files instead of editing code +- The Legend Tool supports color scales +- CSV files can be uploaded as datasets and can be queried on feature click +- Early API tokens that allow .csvs to be uploaded programmatically +- An optional top bar with search functionality +- Configurable page name and logo +- On screen Globe controls +- Support both TMS and WMS tilesets +- Layer Kinds for specialized interactions +- Better documentation in /docs +- Resources cache properly + +#### Fixed + +- All tables are properly created with just one start +- Failed layers no longer crash the application +- Infinite login bug +- Vectors disappearing with string weights +- Some endpoint calls began with home slashes that broke certain setups diff --git a/package.json b/package.json index f711c93c..b036c0eb 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mmgis", - "version": "2.4.1", + "version": "2.5.0", "description": "A web-based mapping and localization solution for science operation on planetary missions.", "homepage": "build", "repository": {