Compare commits
2 Commits
3009a11b33
...
9b57ff9e22
| Author | SHA1 | Date | |
|---|---|---|---|
| 9b57ff9e22 | |||
| ef12e4477b |
104
.gitignore
vendored
Normal file
@ -0,0 +1,104 @@
|
||||
# ============================================================================
|
||||
# LUPMIS2 PWA — .gitignore
|
||||
# ============================================================================
|
||||
|
||||
# ----- Node / npm dependencies -----
|
||||
# Re-installable from package-lock.json; never tracked.
|
||||
node_modules/
|
||||
|
||||
# Vite's dependency optimisation cache (lives inside node_modules but listed
|
||||
# explicitly for clarity).
|
||||
node_modules/.vite/
|
||||
.vite/
|
||||
|
||||
# npm / yarn / pnpm logs and debug files
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
pnpm-debug.log*
|
||||
lerna-debug.log*
|
||||
|
||||
# ----- Build artefacts -----
|
||||
# Vite produces these but we do NOT ignore `dist/` because the repo serves
|
||||
# the built output directly. If you switch to a CI-based deploy pipeline
|
||||
# later, uncomment the next two lines.
|
||||
# dist/
|
||||
# dist-ssr/
|
||||
|
||||
# Pre-compressed / source-map sidecar files outside dist/
|
||||
*.tsbuildinfo
|
||||
|
||||
# ----- Local environment & secrets -----
|
||||
.env
|
||||
.env.local
|
||||
.env.*.local
|
||||
*.local
|
||||
|
||||
# ----- IDE / editor configuration -----
|
||||
# BBEdit project / scratchpad state
|
||||
*.bbprojectd/
|
||||
|
||||
# Visual Studio Code (keep recommended-extensions and tasks.json if added)
|
||||
.vscode/*
|
||||
!.vscode/extensions.json
|
||||
!.vscode/tasks.json
|
||||
!.vscode/launch.json
|
||||
|
||||
# JetBrains IDEs (WebStorm, IntelliJ, etc.)
|
||||
.idea/
|
||||
*.iml
|
||||
|
||||
# Zed
|
||||
.zed/
|
||||
|
||||
# Sublime Text
|
||||
*.sublime-workspace
|
||||
*.sublime-project
|
||||
|
||||
# Vim / Emacs swap files
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.#*
|
||||
|
||||
# ----- OS metadata -----
|
||||
# macOS
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
Icon?
|
||||
._*
|
||||
|
||||
# Windows
|
||||
Thumbs.db
|
||||
ehthumbs.db
|
||||
ehthumbs_vista.db
|
||||
Desktop.ini
|
||||
$RECYCLE.BIN/
|
||||
|
||||
# Linux
|
||||
.directory
|
||||
.Trash-*
|
||||
|
||||
# ----- Project-specific -----
|
||||
# Interim Word-document backups produced when iterating on reports
|
||||
# (the *current* report file stays tracked; only versioned snapshots are
|
||||
# excluded).
|
||||
LUPMIS2_Development_Status_Report-v*.docx
|
||||
*-v[0-9].docx
|
||||
*-v[0-9][0-9].docx
|
||||
|
||||
# SQLite databases dropped in the project root for ad-hoc inspection
|
||||
/*.sqlite3
|
||||
/*.sqlite3-journal
|
||||
/*.db
|
||||
|
||||
# Coverage / test output
|
||||
coverage/
|
||||
.nyc_output/
|
||||
|
||||
# Misc caches
|
||||
.eslintcache
|
||||
.parcel-cache/
|
||||
.cache/
|
||||
BIN
LUPMIS2_Development_Status_Report.docx
Normal file
BIN
OpenTopography_Workflow.png
Normal file
|
After Width: | Height: | Size: 319 KiB |
181
OpenTopography_Workflow.svg
Normal file
@ -0,0 +1,181 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 900" font-family="Arial, Helvetica, sans-serif">
|
||||
<!-- ====================================================== -->
|
||||
<!-- OpenTopography ETL Workflow for LUPMIS2 -->
|
||||
<!-- A one-off data pipeline: download → process → serve -->
|
||||
<!-- ====================================================== -->
|
||||
|
||||
<defs>
|
||||
<!-- Arrowhead -->
|
||||
<marker id="arrow" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
|
||||
<path d="M0,0 L10,5 L0,10 z" fill="#4b5563"/>
|
||||
</marker>
|
||||
<!-- Drop shadow -->
|
||||
<filter id="shadow" x="-10%" y="-10%" width="120%" height="120%">
|
||||
<feGaussianBlur in="SourceAlpha" stdDeviation="2"/>
|
||||
<feOffset dx="1" dy="2"/>
|
||||
<feComponentTransfer><feFuncA type="linear" slope="0.18"/></feComponentTransfer>
|
||||
<feMerge><feMergeNode/><feMergeNode in="SourceGraphic"/></feMerge>
|
||||
</filter>
|
||||
</defs>
|
||||
|
||||
<!-- Background -->
|
||||
<rect width="960" height="900" fill="#f9fafb"/>
|
||||
|
||||
<!-- Title -->
|
||||
<text x="480" y="42" text-anchor="middle" font-size="22" font-weight="700" fill="#1e1a4b">
|
||||
OpenTopography → LUPMIS2 Topographic Workflow
|
||||
</text>
|
||||
<text x="480" y="66" text-anchor="middle" font-size="13" fill="#6b7280">
|
||||
One-off ETL pipeline: download DEM → generate products → serve to the PWA
|
||||
</text>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- STAGE 1 — SOURCE (blue) -->
|
||||
<!-- ====================================================== -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="330" y="100" width="300" height="80" rx="10" ry="10" fill="#0ea5e9" stroke="#0369a1" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="480" y="128" text-anchor="middle" font-size="15" font-weight="700" fill="#fff">OpenTopography API</text>
|
||||
<text x="480" y="148" text-anchor="middle" font-size="12" fill="#e0f2fe">SRTM 30m / Copernicus 30m DEM</text>
|
||||
<text x="480" y="166" text-anchor="middle" font-size="11" font-style="italic" fill="#bae6fd">API key required · 50 calls/24h (non-academic)</text>
|
||||
|
||||
<!-- Arrow 1 -->
|
||||
<path d="M480,180 L480,220" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<text x="495" y="205" font-size="11" fill="#6b7280">one-off download · Ghana bbox ≈ 240,000 km²</text>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- STAGE 2 — RAW DATA (grey) -->
|
||||
<!-- ====================================================== -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="340" y="230" width="280" height="70" rx="10" ry="10" fill="#fff" stroke="#6b7280" stroke-width="1.5" stroke-dasharray="4,3"/>
|
||||
</g>
|
||||
<text x="480" y="258" text-anchor="middle" font-size="14" font-weight="700" fill="#1f2937">DEM GeoTIFF</text>
|
||||
<text x="480" y="278" text-anchor="middle" font-size="12" fill="#4b5563">Ghana elevation raster (single file)</text>
|
||||
<text x="480" y="294" text-anchor="middle" font-size="10" font-style="italic" fill="#6b7280">EPSG:4326 · ≈ 1 – 3 GB</text>
|
||||
|
||||
<!-- Split arrows -->
|
||||
<path d="M480,300 L480,340 L230,340 L230,380" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<path d="M480,340 L730,340 L730,380" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<text x="420" y="332" text-anchor="end" font-size="11" fill="#6b7280">contours path</text>
|
||||
<text x="540" y="332" font-size="11" fill="#6b7280">hillshade path</text>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- STAGE 3 — PROCESSING (green) -->
|
||||
<!-- ====================================================== -->
|
||||
<!-- Left: gdal_contour -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="90" y="390" width="280" height="80" rx="10" ry="10" fill="#10b981" stroke="#047857" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="230" y="418" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">gdal_contour</text>
|
||||
<text x="230" y="438" text-anchor="middle" font-size="11" fill="#d1fae5">extract contour polylines at fixed intervals</text>
|
||||
<text x="230" y="456" text-anchor="middle" font-size="10" font-family="Menlo, monospace" fill="#ecfccb">-i 10 (10 m) or -i 20 (20 m)</text>
|
||||
|
||||
<!-- Right: gdaldem hillshade -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="590" y="390" width="280" height="80" rx="10" ry="10" fill="#10b981" stroke="#047857" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="730" y="418" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">gdaldem hillshade</text>
|
||||
<text x="730" y="438" text-anchor="middle" font-size="11" fill="#d1fae5">render shaded relief PNG</text>
|
||||
<text x="730" y="456" text-anchor="middle" font-size="10" font-family="Menlo, monospace" fill="#ecfccb">-z 2 -az 315 -alt 45</text>
|
||||
|
||||
<!-- Arrows 3 → 4 -->
|
||||
<path d="M230,470 L230,510" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<path d="M730,470 L730,510" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- STAGE 4 — DERIVATIVES (orange) -->
|
||||
<!-- ====================================================== -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="90" y="520" width="280" height="70" rx="10" ry="10" fill="#fff" stroke="#f59e0b" stroke-width="2"/>
|
||||
</g>
|
||||
<text x="230" y="548" text-anchor="middle" font-size="14" font-weight="700" fill="#92400e">Contour polylines</text>
|
||||
<text x="230" y="568" text-anchor="middle" font-size="11" fill="#78350f">Shapefile / GeoPackage / GeoJSON</text>
|
||||
<text x="230" y="584" text-anchor="middle" font-size="10" font-style="italic" fill="#b45309">vector</text>
|
||||
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="590" y="520" width="280" height="70" rx="10" ry="10" fill="#fff" stroke="#f59e0b" stroke-width="2"/>
|
||||
</g>
|
||||
<text x="730" y="548" text-anchor="middle" font-size="14" font-weight="700" fill="#92400e">Hillshade raster</text>
|
||||
<text x="730" y="568" text-anchor="middle" font-size="11" fill="#78350f">GeoTIFF / PNG tile pyramid</text>
|
||||
<text x="730" y="584" text-anchor="middle" font-size="10" font-style="italic" fill="#b45309">raster</text>
|
||||
|
||||
<!-- Arrows 4 → 5 -->
|
||||
<path d="M230,590 L230,630" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<path d="M730,590 L730,630" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- STAGE 5 — SERVE (purple) -->
|
||||
<!-- ====================================================== -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="40" y="640" width="180" height="80" rx="10" ry="10" fill="#8b5cf6" stroke="#5b21b6" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="130" y="668" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">GeoServer</text>
|
||||
<text x="130" y="688" text-anchor="middle" font-size="11" fill="#ede9fe">WMS endpoint</text>
|
||||
<text x="130" y="706" text-anchor="middle" font-size="10" font-style="italic" fill="#ddd6fe">on-demand rendering</text>
|
||||
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="240" y="640" width="180" height="80" rx="10" ry="10" fill="#8b5cf6" stroke="#5b21b6" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="330" y="668" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">MBTiles</text>
|
||||
<text x="330" y="688" text-anchor="middle" font-size="11" fill="#ede9fe">XYZ tile server</text>
|
||||
<text x="330" y="706" text-anchor="middle" font-size="10" font-style="italic" fill="#ddd6fe">pre-rendered, fast</text>
|
||||
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="640" y="640" width="180" height="80" rx="10" ry="10" fill="#8b5cf6" stroke="#5b21b6" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="730" y="668" text-anchor="middle" font-size="14" font-weight="700" fill="#fff">Tile pyramid</text>
|
||||
<text x="730" y="688" text-anchor="middle" font-size="11" fill="#ede9fe">XYZ / WMTS</text>
|
||||
<text x="730" y="706" text-anchor="middle" font-size="10" font-style="italic" fill="#ddd6fe">gdal2tiles.py</text>
|
||||
|
||||
<!-- Split arrow from contour derivatives to BOTH GeoServer and MBTiles -->
|
||||
<path d="M180,610 L130,610 L130,640" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<path d="M280,610 L330,610 L330,640" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<path d="M230,590 L230,610" stroke="#4b5563" stroke-width="2" fill="none"/>
|
||||
<line x1="130" y1="610" x2="330" y2="610" stroke="#4b5563" stroke-width="2"/>
|
||||
|
||||
<!-- Label the "OR" on the left side -->
|
||||
<text x="230" y="627" text-anchor="middle" font-size="10" font-weight="700" fill="#6b7280">serve as WMS or XYZ</text>
|
||||
|
||||
<!-- Arrows 5 → 6 — converging to LUPMIS2 -->
|
||||
<path d="M130,720 L130,770 L460,770 L460,800" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
<path d="M330,720 L330,770" stroke="#4b5563" stroke-width="2" fill="none"/>
|
||||
<line x1="330" y1="770" x2="460" y2="770" stroke="#4b5563" stroke-width="2"/>
|
||||
<path d="M730,720 L730,770 L500,770 L500,800" stroke="#4b5563" stroke-width="2" fill="none" marker-end="url(#arrow)"/>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- STAGE 6 — CONSUMER (brand) -->
|
||||
<!-- ====================================================== -->
|
||||
<g filter="url(#shadow)">
|
||||
<rect x="280" y="800" width="400" height="70" rx="10" ry="10" fill="#1e1a4b" stroke="#0f0c2a" stroke-width="1.5"/>
|
||||
</g>
|
||||
<text x="480" y="828" text-anchor="middle" font-size="15" font-weight="700" fill="#fff">LUPMIS2 PWA</text>
|
||||
<text x="480" y="848" text-anchor="middle" font-size="11" fill="#c7d2fe">OpenLayers · addWMSLayer() / addXYZLayer()</text>
|
||||
<text x="480" y="863" text-anchor="middle" font-size="10" font-style="italic" fill="#a5b4fc">"Biophysical Environment" group</text>
|
||||
|
||||
<!-- ====================================================== -->
|
||||
<!-- LEGEND -->
|
||||
<!-- ====================================================== -->
|
||||
<g transform="translate(20,100)">
|
||||
<rect width="140" height="180" rx="6" ry="6" fill="#fff" stroke="#d1d5db" stroke-width="1"/>
|
||||
<text x="70" y="20" text-anchor="middle" font-size="12" font-weight="700" fill="#1f2937">Legend</text>
|
||||
<rect x="10" y="32" width="20" height="14" rx="2" fill="#0ea5e9"/>
|
||||
<text x="36" y="43" font-size="10" fill="#374151">External source</text>
|
||||
<rect x="10" y="54" width="20" height="14" rx="2" fill="#fff" stroke="#6b7280" stroke-dasharray="3,2"/>
|
||||
<text x="36" y="65" font-size="10" fill="#374151">Raw data file</text>
|
||||
<rect x="10" y="76" width="20" height="14" rx="2" fill="#10b981"/>
|
||||
<text x="36" y="87" font-size="10" fill="#374151">Processing step</text>
|
||||
<rect x="10" y="98" width="20" height="14" rx="2" fill="#fff" stroke="#f59e0b" stroke-width="1.5"/>
|
||||
<text x="36" y="109" font-size="10" fill="#374151">Derived product</text>
|
||||
<rect x="10" y="120" width="20" height="14" rx="2" fill="#8b5cf6"/>
|
||||
<text x="36" y="131" font-size="10" fill="#374151">Serving layer</text>
|
||||
<rect x="10" y="142" width="20" height="14" rx="2" fill="#1e1a4b"/>
|
||||
<text x="36" y="153" font-size="10" fill="#374151">Consumer</text>
|
||||
<text x="70" y="172" text-anchor="middle" font-size="9" font-style="italic" fill="#6b7280">Run once · serve forever</text>
|
||||
</g>
|
||||
|
||||
<!-- Footer note -->
|
||||
<text x="480" y="888" text-anchor="middle" font-size="10" font-style="italic" fill="#6b7280">
|
||||
Prepared for LUSPA · April 2026 · One-off ETL job — no runtime OpenTopography API calls from the PWA
|
||||
</text>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 11 KiB |
BIN
Topographic_Background_Layers_for_LUPMIS2.docx
Normal file
23
dist/assets/html2canvas.esm-B0tyYwQk.js
vendored
Normal file
1
dist/assets/html2canvas.esm-B0tyYwQk.js.map
vendored
Normal file
393
dist/assets/index-2WHoRhxp.js
vendored
1
dist/assets/index-2WHoRhxp.js.map
vendored
636
dist/assets/index-B4XzHtZX.js
vendored
Normal file
1
dist/assets/index-B4XzHtZX.js.map
vendored
Normal file
19
dist/assets/index.es-CRPDPo17.js
vendored
Normal file
1
dist/assets/index.es-CRPDPo17.js.map
vendored
Normal file
172
dist/assets/jspdf-Cu-2SCgw.js
vendored
Normal file
1
dist/assets/jspdf-Cu-2SCgw.js.map
vendored
Normal file
2
dist/assets/ol-ext-CSk2UikI.js
vendored
Normal file
1
dist/assets/ol-ext-CSk2UikI.js.map
vendored
Normal file
2
dist/assets/ol-ext-DytxBANR.js
vendored
1
dist/assets/ol-ext-DytxBANR.js.map
vendored
573
dist/assets/openlayers-CUDtI0S3.js
vendored
Normal file
1
dist/assets/openlayers-CUDtI0S3.js.map
vendored
Normal file
573
dist/assets/openlayers-D2I-bVN2.js
vendored
1
dist/assets/openlayers-D2I-bVN2.js.map
vendored
2
dist/assets/pdf-export-Vpiz8VA4.js
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
import{E as f,a as b}from"./jspdf-Cu-2SCgw.js";import"./openlayers-CUDtI0S3.js";b(f);let s=null;async function x(){if(s)return s;try{const e=new Image;e.crossOrigin="anonymous",await new Promise((r,i)=>{e.onload=r,e.onerror=i,e.src="./icons/luspa-pdf.jpg"});const n=document.createElement("canvas");n.width=e.naturalWidth,n.height=e.naturalHeight;const t=n.getContext("2d");return t.fillStyle="#ffffff",t.fillRect(0,0,n.width,n.height),t.drawImage(e,0,0),s=n.toDataURL("image/jpeg",.92),s}catch(e){return console.warn("[PDF] Could not load logo:",e),null}}async function v({title:e,rows:n}){const t=new f({orientation:"portrait",unit:"mm",format:"a4"}),r=t.internal.pageSize.getWidth(),i=[30,26,75],g=await x(),c=28,a=14;let o=14;g&&t.addImage(g,"JPEG",a,o,c,c);const m=a+c+6;t.setFont("helvetica","bold"),t.setFontSize(18),t.setTextColor(...i),t.text("LUPMIS",m,o+11),t.setFont("helvetica","normal"),t.setFontSize(12),t.text(e,m,o+19);const d=new Date,h=d.toLocaleDateString(void 0,{year:"numeric",month:"long",day:"numeric"}),y=d.toLocaleTimeString([],{hour:"2-digit",minute:"2-digit"});t.setFontSize(9),t.setTextColor(120,120,120),t.text(`${h} ${y}`,r-a,o+11,{align:"right"}),o+=c+6,t.setDrawColor(...i),t.setLineWidth(.5),t.line(a,o,r-a,o),o+=6;const S=n.map(l=>[l.label,l.value]);t.autoTable({startY:o,head:[["Property","Value"]],body:S,margin:{left:a,right:a},styles:{font:"helvetica",fontSize:10,cellPadding:4},headStyles:{fillColor:i,textColor:[255,255,255],fontStyle:"bold"},alternateRowStyles:{fillColor:[245,245,250]},columnStyles:{0:{fontStyle:"bold",cellWidth:50}}});const p=t.lastAutoTable.finalY+10;t.setFontSize(8),t.setTextColor(160,160,160),t.text("Generated by LUPMIS2 Land Use Planning & Management Information System",a,p);const w=t.output("blob"),u=URL.createObjectURL(w);if(!window.open(u,"_blank")){const l=document.createElement("a");l.href=u,l.download=`${e.replace(/\s+/g,"_")}_${d.toISOString().slice(0,10)}.pdf`,document.body.appendChild(l),l.click(),document.body.removeChild(l)}}export{v as exportAnalysisPDF};
|
||||
//# sourceMappingURL=pdf-export-Vpiz8VA4.js.map
|
||||
1
dist/assets/pdf-export-Vpiz8VA4.js.map
vendored
Normal file
3
dist/assets/purify.es-BgtpMKW3.js
vendored
Normal file
1
dist/assets/purify.es-BgtpMKW3.js.map
vendored
Normal file
5
dist/assets/shpjs-CNrRgkgn.js
vendored
Normal file
1
dist/assets/shpjs-CNrRgkgn.js.map
vendored
Normal file
BIN
dist/fonts/bebas-neue-latin-ext.woff2
vendored
Normal file
BIN
dist/fonts/bebas-neue-latin.woff2
vendored
Normal file
BIN
dist/fonts/exo-latin-ext.woff2
vendored
Normal file
BIN
dist/fonts/exo-latin.woff2
vendored
Normal file
BIN
dist/fonts/exo-vietnamese.woff2
vendored
Normal file
1
dist/icons/README.txt
vendored
@ -1 +0,0 @@
|
||||
Place PWA icons here (icon-72.png, icon-96.png, icon-128.png, icon-144.png, icon-152.png, icon-192.png, icon-384.png, icon-512.png)
|
||||
BIN
dist/icons/luspa-128x128.png
vendored
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
dist/icons/luspa-144x144.png
vendored
Normal file
|
After Width: | Height: | Size: 36 KiB |
BIN
dist/icons/luspa-152x152.png
vendored
Normal file
|
After Width: | Height: | Size: 40 KiB |
BIN
dist/icons/luspa-384x384.png
vendored
Normal file
|
After Width: | Height: | Size: 170 KiB |
BIN
dist/icons/luspa-72x72.png
vendored
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
dist/icons/luspa-96x96.png
vendored
Normal file
|
After Width: | Height: | Size: 18 KiB |
BIN
dist/icons/luspa-pdf.jpg
vendored
Normal file
|
After Width: | Height: | Size: 47 KiB |
745
dist/index.html
vendored
@ -2,19 +2,64 @@
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#005eb8">
|
||||
<meta name="description" content="LUPMIS2 Drawing Tools">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="apple-touch-icon" href="/icons/luspa.icon">
|
||||
<link rel="icon" href="/icons/luspa.icon">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="icons/luspa-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/luspa-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="icons/luspa-16x16.png">
|
||||
|
||||
<!-- LUSPA Design System Fonts: Bebas Neue (display) + Exo (body) -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Exo:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<!-- LUSPA Design System Fonts: Bebas Neue (display) + Exo (body) — self-hosted -->
|
||||
<style>
|
||||
/* Bebas Neue 400 — latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Bebas Neue';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/bebas-neue-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* Bebas Neue 400 — latin */
|
||||
@font-face {
|
||||
font-family: 'Bebas Neue';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/bebas-neue-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* Exo 300-800 — vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Exo';
|
||||
font-style: normal;
|
||||
font-weight: 300 800;
|
||||
font-display: swap;
|
||||
src: url('/fonts/exo-vietnamese.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* Exo 300-800 — latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Exo';
|
||||
font-style: normal;
|
||||
font-weight: 300 800;
|
||||
font-display: swap;
|
||||
src: url('/fonts/exo-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* Exo 300-800 — latin */
|
||||
@font-face {
|
||||
font-family: 'Exo';
|
||||
font-style: normal;
|
||||
font-weight: 300 800;
|
||||
font-display: swap;
|
||||
src: url('/fonts/exo-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>LUPMIS2 Drawing Tools</title>
|
||||
|
||||
@ -106,6 +151,295 @@
|
||||
--radius-2xl: 1rem;
|
||||
}
|
||||
|
||||
/* ─── Fieldwork Mode ─── high-contrast + larger touch targets ─── */
|
||||
.fieldwork-mode {
|
||||
--foreground: #000;
|
||||
--background: #fff;
|
||||
--card: #fff;
|
||||
--card-foreground: #000;
|
||||
--primary: #0044aa;
|
||||
--primary-foreground: #fff;
|
||||
--primary-hover: #003080;
|
||||
--muted: #e0e0e0;
|
||||
--muted-foreground: #333;
|
||||
--accent: #cce0ff;
|
||||
--accent-foreground: #000;
|
||||
--border: rgba(0,0,0,0.25);
|
||||
--success: #005a00;
|
||||
--success-foreground: #fff;
|
||||
--warning: #b36b00;
|
||||
--warning-foreground: #000;
|
||||
--destructive: #b80000;
|
||||
--destructive-foreground: #fff;
|
||||
--ring: #0044aa;
|
||||
--bs-body-color: #000;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger dock buttons */
|
||||
.fieldwork-mode .dock-btn {
|
||||
min-width: 72px;
|
||||
min-height: 58px;
|
||||
font-size: 1.6rem;
|
||||
border-width: 2px;
|
||||
}
|
||||
.fieldwork-mode .dock-btn-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Fieldwork: bolder navbar */
|
||||
.fieldwork-mode .navbar {
|
||||
border-bottom-width: 4px;
|
||||
}
|
||||
.fieldwork-mode .navbar .navbar-brand {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger offcanvas toggle buttons */
|
||||
.fieldwork-mode .offcanvas-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: thicker bottom dock border */
|
||||
.fieldwork-mode .bottom-dock {
|
||||
border-top-width: 4px;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger text in cards / lists */
|
||||
.fieldwork-mode .card-header h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.fieldwork-mode .list-group-item {
|
||||
font-size: 0.95rem;
|
||||
padding: 0.65rem 1rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger buttons globally */
|
||||
.fieldwork-mode .btn {
|
||||
font-size: 0.95rem;
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fieldwork-mode .btn-sm {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.4rem 0.75rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: stronger borders on inputs / form controls */
|
||||
.fieldwork-mode .form-control,
|
||||
.fieldwork-mode .form-select {
|
||||
border-width: 2px;
|
||||
border-color: #555;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: bolder map controls (ol-ext) */
|
||||
.fieldwork-mode .ol-control button {
|
||||
font-size: 1.3rem;
|
||||
width: 2.2em;
|
||||
height: 2.2em;
|
||||
}
|
||||
|
||||
/* Fieldwork: scale bar text legibility */
|
||||
.fieldwork-mode .ol-scale-bar .ol-scale-step-text,
|
||||
.fieldwork-mode .ol-scale-bar .ol-scale-text {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 0 4px #fff, 0 0 8px #fff;
|
||||
}
|
||||
|
||||
/* ─── Dark Mode ─── reversed colour scheme ─── */
|
||||
.dark-mode {
|
||||
--foreground: #e0dff0;
|
||||
--background: #131325;
|
||||
--card: #1e1e38;
|
||||
--card-foreground: #e0dff0;
|
||||
--primary: #4d9de6;
|
||||
--primary-foreground: #fff;
|
||||
--primary-hover: #6fb3f0;
|
||||
--muted: #272745;
|
||||
--muted-foreground: #9594a8;
|
||||
--accent: #1e3a5f;
|
||||
--accent-foreground: #e0dff0;
|
||||
--border: rgba(255,255,255,0.12);
|
||||
--ring: #4d9de6;
|
||||
--success: #2dd46a;
|
||||
--success-foreground: #131325;
|
||||
--warning: #ffb84d;
|
||||
--warning-foreground: #131325;
|
||||
--destructive: #f04040;
|
||||
--destructive-foreground: #fff;
|
||||
--bs-body-color: #e0dff0;
|
||||
--bs-body-bg: #131325;
|
||||
--bs-tertiary-bg: #1e1e38;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
/* Dark: navbar */
|
||||
.dark-mode .navbar {
|
||||
background-color: #1a1a30 !important;
|
||||
box-shadow: 0 1px 6px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
/* Dark: bottom dock */
|
||||
.dark-mode .bottom-dock {
|
||||
background-color: #1a1a30;
|
||||
box-shadow: 0 -2px 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
.dark-mode .dock-btn {
|
||||
border-color: var(--primary);
|
||||
color: var(--foreground);
|
||||
}
|
||||
.dark-mode .dock-btn:hover {
|
||||
background-color: var(--muted);
|
||||
}
|
||||
.dark-mode .dock-btn.active {
|
||||
background-color: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
|
||||
/* Dark: offcanvas panels */
|
||||
.dark-mode .offcanvas {
|
||||
background-color: var(--background) !important;
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
.dark-mode .offcanvas-header {
|
||||
border-bottom-color: var(--border) !important;
|
||||
}
|
||||
.dark-mode .btn-close {
|
||||
filter: invert(1) grayscale(100%) brightness(200%);
|
||||
}
|
||||
|
||||
/* Dark: cards */
|
||||
.dark-mode .card {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--card-foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
/* Dark: offcanvas toggle buttons */
|
||||
.dark-mode .offcanvas-toggle {
|
||||
background-color: var(--card);
|
||||
color: var(--foreground);
|
||||
border-color: var(--border);
|
||||
}
|
||||
.dark-mode .offcanvas-toggle:hover {
|
||||
background-color: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
|
||||
/* Dark: form controls */
|
||||
.dark-mode .form-control,
|
||||
.dark-mode .form-select {
|
||||
background-color: var(--muted) !important;
|
||||
color: var(--foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
.dark-mode .form-check-input {
|
||||
background-color: var(--muted);
|
||||
border-color: var(--muted-foreground);
|
||||
}
|
||||
.dark-mode .form-check-input:checked {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
/* Dark: list groups */
|
||||
.dark-mode .list-group-item {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--card-foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
/* Dark: buttons */
|
||||
.dark-mode .btn-outline-primary {
|
||||
color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.dark-mode .btn-outline-danger {
|
||||
color: var(--destructive);
|
||||
border-color: var(--destructive);
|
||||
}
|
||||
|
||||
/* Dark: text utilities */
|
||||
.dark-mode .text-muted {
|
||||
color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* Dark: measurement tooltips */
|
||||
.dark-mode .measure-tooltip {
|
||||
background: rgba(30, 30, 56, 0.95);
|
||||
color: var(--foreground);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.dark-mode .measure-tooltip::before {
|
||||
border-right-color: var(--primary);
|
||||
}
|
||||
|
||||
/* Dark: OL controls */
|
||||
.dark-mode .ol-control button {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
.dark-mode .ol-control button:hover {
|
||||
background-color: var(--primary) !important;
|
||||
color: var(--primary-foreground) !important;
|
||||
}
|
||||
.dark-mode .ol-attribution,
|
||||
.dark-mode .ol-attribution a {
|
||||
color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* Dark: scale bar */
|
||||
.dark-mode .ol-scale-bar .ol-scale-step-text,
|
||||
.dark-mode .ol-scale-bar .ol-scale-text {
|
||||
color: #fff !important;
|
||||
text-shadow: 0 0 4px #000, 0 0 8px #000 !important;
|
||||
}
|
||||
.dark-mode .ol-scale-bar .ol-scale-singlebar-even {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
.dark-mode .ol-scale-bar .ol-scale-singlebar-odd {
|
||||
background-color: #999 !important;
|
||||
}
|
||||
|
||||
/* Dark: map drop overlay */
|
||||
.dark-mode .map-drop-overlay {
|
||||
background: rgba(19, 19, 37, 0.85);
|
||||
border-color: var(--primary);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* Dark: ol-ext LayerSwitcher */
|
||||
.dark-mode .ol-layerswitcher {
|
||||
background-color: var(--card) !important;
|
||||
}
|
||||
.dark-mode .ol-layerswitcher .panel {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
.dark-mode .ol-layerswitcher .panel li {
|
||||
color: var(--foreground);
|
||||
}
|
||||
.dark-mode .ol-layerswitcher .ol-switchertopdiv,
|
||||
.dark-mode .ol-layerswitcher .ol-switcherbottomdiv {
|
||||
background: var(--card) !important;
|
||||
}
|
||||
|
||||
/* Dark: alert boxes */
|
||||
.dark-mode .alert-danger {
|
||||
background-color: rgba(240, 64, 64, 0.15) !important;
|
||||
color: var(--destructive) !important;
|
||||
border-color: var(--destructive) !important;
|
||||
}
|
||||
.dark-mode .alert-success {
|
||||
background-color: rgba(45, 212, 106, 0.15) !important;
|
||||
color: var(--success) !important;
|
||||
border-color: var(--success) !important;
|
||||
}
|
||||
|
||||
/* Full height layout */
|
||||
html, body {
|
||||
height: 100%;
|
||||
@ -214,9 +548,12 @@
|
||||
font-family: var(--font-body);
|
||||
}
|
||||
|
||||
/* Main container - full height */
|
||||
/* Main container - full height.
|
||||
100dvh accounts for mobile browser chrome and OS nav bars.
|
||||
Falls back to 100vh for older browsers. */
|
||||
.app-container {
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -244,6 +581,35 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Drag-and-drop overlay shown when files are dragged over the map */
|
||||
.map-drop-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 94, 184, 0.15);
|
||||
border: 3px dashed var(--primary, #005eb8);
|
||||
border-radius: 8px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
.map-container.drag-over .map-drop-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
.map-drop-overlay span {
|
||||
font-family: var(--font-body, 'Exo', sans-serif);
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary, #005eb8);
|
||||
background: var(--card, #fff);
|
||||
padding: 0.6rem 1.4rem;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
/* Offline indicator */
|
||||
#offline-indicator {
|
||||
display: none;
|
||||
@ -301,9 +667,14 @@
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
/* Fix ol-ext LayerSwitcher z-index */
|
||||
.ol-layerswitcher {
|
||||
z-index: 100;
|
||||
/* OL controls stacking context fix — OpenLayers sets z-index:0 on
|
||||
.ol-overlaycontainer-stopevent, trapping all controls below the
|
||||
offcanvas-toggle buttons (z-index:500). Raising the container
|
||||
to 501 lets the LayerSwitcher dropdown render above the toggles.
|
||||
pointer-events:none on the container still lets clicks through
|
||||
to the toggle buttons underneath. */
|
||||
.ol-overlaycontainer-stopevent {
|
||||
z-index: 501 !important;
|
||||
}
|
||||
|
||||
/* Alert hint box */
|
||||
@ -419,7 +790,7 @@
|
||||
}
|
||||
|
||||
.offcanvas-toggle-bottom {
|
||||
bottom: 80px; /* Above the dock */
|
||||
bottom: calc(80px + env(safe-area-inset-bottom, 0px)); /* Above the dock */
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
@ -432,7 +803,10 @@
|
||||
transform: translateX(-50%) scale(0.95);
|
||||
}
|
||||
|
||||
/* Bottom Dock — white card style with blue-strong accent */
|
||||
/* Bottom Dock — white card style with blue-strong accent.
|
||||
env(safe-area-inset-bottom) adds padding on devices with a
|
||||
home indicator / gesture bar (e.g. iPhone notch models).
|
||||
The value is 0 on devices without an inset. */
|
||||
.bottom-dock {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
@ -441,7 +815,7 @@
|
||||
z-index: 600;
|
||||
background-color: var(--card);
|
||||
border-top: 3px solid var(--primary);
|
||||
padding: 8px 16px;
|
||||
padding: 8px 16px calc(8px + env(safe-area-inset-bottom, 0px));
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
@ -503,6 +877,13 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Snap-guides toggle — highlighted when active */
|
||||
.ol-snap-toggle.ol-active button {
|
||||
background: var(--primary) !important;
|
||||
color: var(--primary-foreground, #fff) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Touch-friendly improvements for forms and buttons */
|
||||
.form-control, .form-select {
|
||||
min-height: 44px;
|
||||
@ -541,6 +922,18 @@
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* Message log in the right panel */
|
||||
.message-log {
|
||||
max-height: 260px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.message-log-entry {
|
||||
font-size: 0.82rem;
|
||||
border-color: var(--border, #eee) !important;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* ol-ext GeolocationButton styling */
|
||||
.ol-geobt {
|
||||
top: auto !important;
|
||||
@ -830,6 +1223,7 @@
|
||||
/* Locations list in offcanvas - can be taller now without form */
|
||||
.offcanvas-end .locations-list {
|
||||
max-height: calc(100vh - 280px);
|
||||
max-height: calc(100dvh - 280px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@ -921,17 +1315,32 @@
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* ScaleLine - position above the bottom dock */
|
||||
.ol-scale-line {
|
||||
bottom: 76px !important;
|
||||
/* ScaleBar - position above the bottom dock with 4px gap */
|
||||
.ol-scale-bar {
|
||||
bottom: calc(85px + env(safe-area-inset-bottom, 0px)) !important;
|
||||
left: 10px !important;
|
||||
}
|
||||
|
||||
.ol-scale-line-inner {
|
||||
border-color: var(--foreground) !important;
|
||||
.ol-scale-bar .ol-scale-step-text {
|
||||
color: var(--foreground) !important;
|
||||
font-family: var(--font-body) !important;
|
||||
font-size: 11px !important;
|
||||
text-shadow: 0 0 3px var(--background), 0 0 6px var(--background) !important;
|
||||
}
|
||||
|
||||
.ol-scale-bar .ol-scale-text {
|
||||
color: var(--foreground) !important;
|
||||
font-family: var(--font-body) !important;
|
||||
font-size: 11px !important;
|
||||
text-shadow: 0 0 3px var(--background), 0 0 6px var(--background) !important;
|
||||
}
|
||||
|
||||
.ol-scale-bar .ol-scale-singlebar-even {
|
||||
background-color: var(--foreground) !important;
|
||||
}
|
||||
|
||||
.ol-scale-bar .ol-scale-singlebar-odd {
|
||||
background-color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* ol-ext Bar overrides */
|
||||
@ -950,12 +1359,12 @@
|
||||
gap: 2px;
|
||||
}
|
||||
</style>
|
||||
<script type="module" crossorigin src="/assets/index-2WHoRhxp.js"></script>
|
||||
<script type="module" crossorigin src="/assets/index-B4XzHtZX.js"></script>
|
||||
<link rel="modulepreload" crossorigin href="/assets/openlayers-CUDtI0S3.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/bootstrap-D1-uvFxm.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/openlayers-D2I-bVN2.js">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ol-ext-DytxBANR.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/bootstrap-BtmJYOxZ.css">
|
||||
<link rel="modulepreload" crossorigin href="/assets/ol-ext-CSk2UikI.js">
|
||||
<link rel="stylesheet" crossorigin href="/assets/openlayers-BtPuoxOl.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/bootstrap-BtmJYOxZ.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/ol-ext-BgKrOIxx.css">
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BnwqsTiD.css">
|
||||
</head>
|
||||
@ -988,6 +1397,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div id="map"></div>
|
||||
<div class="map-drop-overlay"><span><i class="bi bi-file-earmark-arrow-up me-2"></i>Drop file to import (.shp .geojson .kml)</span></div>
|
||||
|
||||
<!-- Offcanvas toggle buttons -->
|
||||
<button class="offcanvas-toggle offcanvas-toggle-left"
|
||||
@ -1112,17 +1522,40 @@
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="local-data-btn">
|
||||
<i class="bi bi-database me-2"></i>Local Data
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="import-shp-btn">
|
||||
<i class="bi bi-file-earmark-arrow-up me-2"></i>Import .shp
|
||||
</button>
|
||||
<input type="file" id="shp-file-input" accept=".zip,.shp,.dbf,.shx,.prj" multiple class="d-none">
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="import-geojson-btn">
|
||||
<i class="bi bi-file-earmark-arrow-up me-2"></i>Import GeoJSON
|
||||
</button>
|
||||
<input type="file" id="geojson-file-input" accept=".geojson,.json" class="d-none">
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="import-kml-btn">
|
||||
<i class="bi bi-file-earmark-arrow-up me-2"></i>Import KML
|
||||
</button>
|
||||
<input type="file" id="kml-file-input" accept=".kml,.kmz" class="d-none">
|
||||
<div id="file-import-alert" class="alert alert-danger alert-dismissible fade show d-none mb-3" role="alert">
|
||||
<small class="message-text"></small>
|
||||
<button type="button" class="btn-close btn-close-sm" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<div id="imported-layers-info" class="d-none mb-3"></div>
|
||||
<div id="local-data-stats" class="d-none">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary py-2">
|
||||
<div class="card-header bg-primary py-2 d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0"><i class="bi bi-database me-2"></i>Local Database Tables</h6>
|
||||
<button type="button" class="btn btn-sm btn-outline-light"
|
||||
id="clear-all-cached-btn"
|
||||
title="Delete all cached map layers. They will be re-downloaded on next app start.">
|
||||
<i class="bi bi-arrow-clockwise me-1"></i>Refresh cached layers
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ps-3">Table</th>
|
||||
<th class="text-end pe-3">Records</th>
|
||||
<th class="text-end">Records</th>
|
||||
<th class="text-end pe-3" style="width:3rem;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="local-data-tbody">
|
||||
@ -1150,6 +1583,10 @@
|
||||
<span class="message-text"></span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<div id="warning-message" class="alert alert-warning alert-dismissible fade show d-none" role="alert">
|
||||
<span class="message-text"></span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<!-- Tip -->
|
||||
<div class="alert alert-light border-start border-4 border-primary py-2 mb-3" role="alert">
|
||||
@ -1189,20 +1626,268 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Log -->
|
||||
<div class="card mt-3" id="message-log-card">
|
||||
<div class="card-header bg-transparent py-2 d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0" style="font-family:var(--font-body);font-weight:700;"><i class="bi bi-journal-text me-1"></i> Messages</h6>
|
||||
<button class="btn btn-sm btn-link text-muted p-0" id="clear-message-log" title="Clear messages">
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div id="message-log" class="message-log list-group list-group-flush">
|
||||
<div class="text-center text-muted py-3">
|
||||
<small>No messages yet.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Offcanvas -->
|
||||
<div class="offcanvas offcanvas-bottom" tabindex="-1" id="offcanvasBottom" aria-labelledby="offcanvasBottomLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="offcanvasBottomLabel"><i class="bi bi-chevron-down me-2"></i>Bottom Panel</h5>
|
||||
<h5 class="offcanvas-title" id="offcanvasBottomLabel"><i class="bi bi-gear me-2"></i>Settings</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<p>This is the bottom offcanvas panel.</p>
|
||||
<p>You can add a data table, charts, or other wide content here.</p>
|
||||
<div class="row g-3">
|
||||
<!-- Fieldwork Mode -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Fieldwork Mode</h6>
|
||||
<small class="text-muted">High-contrast colours and larger touch targets for bright sunlight and field conditions.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch ms-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="fieldwork-mode-toggle" style="width:3rem;height:1.5rem;cursor:pointer;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Dark Mode -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Dark Mode</h6>
|
||||
<small class="text-muted">Reduce glare and save battery with a dark colour scheme.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch ms-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="dark-mode-toggle" style="width:3rem;height:1.5rem;cursor:pointer;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Measurement System -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Measurement System</h6>
|
||||
<small class="text-muted">Switch between Metric (m, km) and Imperial (ft, mi, acres) units.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch ms-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="measurement-system-toggle" style="width:3rem;height:1.5rem;cursor:pointer;">
|
||||
<label class="form-check-label ms-1" id="measurement-system-label" for="measurement-system-toggle" style="font-size:0.8rem;font-weight:600;min-width:55px;">Metric</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Default Base Map -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div style="flex:1;min-width:0;">
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Default Base Map</h6>
|
||||
<small class="text-muted">Base map shown on app start. Saved on this device.</small>
|
||||
</div>
|
||||
<div class="ms-3" style="min-width:140px;">
|
||||
<select class="form-select form-select-sm" id="default-basemap-select" aria-label="Default base map">
|
||||
<option value="topo">Topographic</option>
|
||||
<option value="osm">OpenStreetMap</option>
|
||||
<option value="satellite">Satellite</option>
|
||||
<option value="googlesat">Google Sat</option>
|
||||
<option value="carto-light">Carto Light</option>
|
||||
<option value="carto-dark">Carto Dark</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Offline Map Tiles -->
|
||||
<div class="col-12 col-md-6 col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between mb-2">
|
||||
<div style="flex:1;min-width:0;">
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">
|
||||
<i class="bi bi-map me-1"></i>Offline Map Tiles
|
||||
</h6>
|
||||
<small class="text-muted">
|
||||
Map tiles you've already viewed are cached on this device so they work offline.
|
||||
Tiles are cached automatically as you browse, or you can pre-download a region.
|
||||
</small>
|
||||
</div>
|
||||
<div class="ms-3 d-flex gap-2 flex-shrink-0">
|
||||
<button type="button" class="btn btn-sm btn-primary"
|
||||
id="download-tiles-btn" style="white-space:nowrap;">
|
||||
<i class="bi bi-cloud-download me-1"></i>Download offline map
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger"
|
||||
id="clear-tiles-btn" style="white-space:nowrap;">
|
||||
<i class="bi bi-trash3 me-1"></i>Clear cached tiles
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tile-cache-stats" class="small">
|
||||
<div class="text-muted fst-italic">Loading…</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download Offline Map modal -->
|
||||
<div class="modal fade" id="offline-download-modal" tabindex="-1" aria-labelledby="offline-download-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="offline-download-title">
|
||||
<i class="bi bi-cloud-download me-2"></i>Download Offline Map
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" id="offline-download-close-btn"></button>
|
||||
</div>
|
||||
|
||||
<!-- Form view (shown until Start is clicked) -->
|
||||
<div class="modal-body" id="offline-download-form-view">
|
||||
<p class="text-muted small mb-3">
|
||||
Pre-fetch map tiles so they're available when you're offline.
|
||||
Only the OpenStreetMap and Topographic base maps can be downloaded;
|
||||
other providers don't permit bulk caching.
|
||||
</p>
|
||||
|
||||
<!-- Base map -->
|
||||
<div class="mb-3">
|
||||
<label for="offline-basemap-select" class="form-label fw-bold">Base map</label>
|
||||
<select class="form-select form-select-sm" id="offline-basemap-select">
|
||||
<option value="topo">Topographic</option>
|
||||
<option value="osm">OpenStreetMap</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Area -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold mb-1">Area to download</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="offline-area" id="offline-area-view" value="view" checked>
|
||||
<label class="form-check-label" for="offline-area-view">
|
||||
Current map view
|
||||
<span class="text-muted small" id="offline-area-view-info"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="offline-area" id="offline-area-district" value="district">
|
||||
<label class="form-check-label" for="offline-area-district">
|
||||
District boundary
|
||||
<span class="text-muted small" id="offline-area-district-info"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="offline-area" id="offline-area-ghana" value="ghana">
|
||||
<label class="form-check-label" for="offline-area-ghana">
|
||||
Entire Ghana <span class="text-muted small">(very large — only attempt over fast Wi-Fi)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zoom range -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold mb-1">Zoom levels</label>
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-auto"><label for="offline-min-zoom" class="form-label small mb-0">Min</label></div>
|
||||
<div class="col-auto">
|
||||
<input type="number" class="form-control form-control-sm" id="offline-min-zoom" min="6" max="19" value="10" style="width:5em;">
|
||||
</div>
|
||||
<div class="col-auto"><label for="offline-max-zoom" class="form-label small mb-0">Max</label></div>
|
||||
<div class="col-auto">
|
||||
<input type="number" class="form-control form-control-sm" id="offline-max-zoom" min="6" max="19" value="15" style="width:5em;">
|
||||
</div>
|
||||
<div class="col text-muted small">10 = regional · 13 = neighbourhood · 16 = building</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Estimate -->
|
||||
<div class="alert alert-info py-2 px-3 mb-3" id="offline-estimate" style="font-size:0.9em;">
|
||||
<strong>Estimated download:</strong>
|
||||
<span id="offline-estimate-detail">Calculating…</span>
|
||||
</div>
|
||||
|
||||
<!-- Acknowledgement -->
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="offline-ack-check">
|
||||
<label class="form-check-label small" for="offline-ack-check">
|
||||
I understand this counts against the tile provider's usage quota
|
||||
and will use mobile data if I'm not on Wi-Fi.
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progress view (shown during download) -->
|
||||
<div class="modal-body d-none" id="offline-download-progress-view">
|
||||
<div class="text-center mb-3">
|
||||
<div class="fs-5 fw-bold" id="offline-progress-percent">0%</div>
|
||||
<div class="small text-muted" id="offline-progress-counts">0 of 0 tiles</div>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height:1.25em;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar" id="offline-progress-bar"
|
||||
aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div>
|
||||
</div>
|
||||
<div class="row text-center small text-muted">
|
||||
<div class="col"><div class="fw-bold text-body" id="offline-progress-ok">0</div>fetched</div>
|
||||
<div class="col"><div class="fw-bold text-body" id="offline-progress-failed">0</div>failed</div>
|
||||
<div class="col"><div class="fw-bold text-body" id="offline-progress-eta">—</div>remaining</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Done view (shown after completion) -->
|
||||
<div class="modal-body d-none" id="offline-download-done-view">
|
||||
<div class="text-center py-3">
|
||||
<i class="bi bi-check-circle-fill text-success" style="font-size:3rem;"></i>
|
||||
<div class="fs-5 fw-bold mt-2" id="offline-done-title">Download complete</div>
|
||||
<div class="text-muted" id="offline-done-detail"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="offline-download-cancel-btn">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="offline-download-start-btn" disabled>
|
||||
<i class="bi bi-cloud-download me-1"></i>Start download
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary d-none" id="offline-download-close-done-btn" data-bs-dismiss="modal">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Polyfill crypto.randomUUID for non-secure contexts (HTTP) -->
|
||||
<!-- Must run before module imports (SQLocal/coincident require it) -->
|
||||
|
||||
22
dist/manifest.json
vendored
@ -1,58 +1,58 @@
|
||||
{
|
||||
"name": "LUPMIS2 Drawing Tools",
|
||||
"short_name": "LUPMIS",
|
||||
"short_name": "LUPMIS2",
|
||||
"description": "Map and GIS functions for Land Use Planning in Ghana",
|
||||
"start_url": "/",
|
||||
"scope": "/",
|
||||
"start_url": "./",
|
||||
"scope": "./",
|
||||
"display": "standalone",
|
||||
"background_color": "#ffffff",
|
||||
"theme_color": "#005eb8",
|
||||
"orientation": "any",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/icons/icon-72.png",
|
||||
"src": "./icons/luspa-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-96.png",
|
||||
"src": "./icons/luspa-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-128.png",
|
||||
"src": "./icons/luspa-128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-144.png",
|
||||
"src": "./icons/luspa-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-152.png",
|
||||
"src": "./icons/luspa-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icons/luspa-192x192.png",
|
||||
"src": "./icons/luspa-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
},
|
||||
{
|
||||
"src": "/icons/icon-384.png",
|
||||
"src": "./icons/luspa-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png",
|
||||
"purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icons/luspa-512x512.png",
|
||||
"src": "./icons/luspa-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "any maskable"
|
||||
|
||||
367
dist/sw.js
vendored
@ -1,29 +1,81 @@
|
||||
/**
|
||||
* Service Worker
|
||||
*
|
||||
*
|
||||
* Handles caching of:
|
||||
* - App shell (HTML, CSS, JS)
|
||||
* - Map tiles (runtime caching)
|
||||
* - Map tiles (passive runtime caching, per-host buckets)
|
||||
* - API responses (network-first)
|
||||
*
|
||||
*
|
||||
* Note: Database operations are handled by the SharedWorker (shared-db-worker.js),
|
||||
* NOT by this service worker. They serve different purposes:
|
||||
* - Service Worker: Caching, offline asset serving, push notifications
|
||||
* - SharedWorker: Shared database connection across tabs
|
||||
*/
|
||||
|
||||
const CACHE_VERSION = 'v1';
|
||||
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
||||
const TILES_CACHE = `tiles-${CACHE_VERSION}`;
|
||||
// v3: lower per-cache limits (5000 → 1500) and counter-based eviction to
|
||||
// prevent Safari memory-pressure reloads.
|
||||
// v4: raise OSM and Topographic limits to 8000 to support active offline
|
||||
// downloads (Phase 2). Other providers stay at 1500.
|
||||
const CACHE_VERSION = 'v4';
|
||||
const SHELL_CACHE = `shell-${CACHE_VERSION}`;
|
||||
const MODULES_CACHE = `modules-${CACHE_VERSION}`;
|
||||
const API_CACHE = `api-${CACHE_VERSION}`;
|
||||
const API_CACHE = `api-${CACHE_VERSION}`;
|
||||
|
||||
// Maximum number of tiles to cache
|
||||
const MAX_TILES = 500;
|
||||
// ----------------------------------------------------------------------------
|
||||
// Tile caches — one per provider so users can clear them independently.
|
||||
// Limits are per-cache (not global). 5 000 tiles ≈ ~150 MB at ~30 KB/tile,
|
||||
// which covers a Ghana district at zoom 10–15 (typical field-work range).
|
||||
// ----------------------------------------------------------------------------
|
||||
const TILES_OSM = `tiles-osm-${CACHE_VERSION}`;
|
||||
const TILES_TOPO = `tiles-topo-${CACHE_VERSION}`;
|
||||
const TILES_SATELLITE = `tiles-satellite-${CACHE_VERSION}`;
|
||||
const TILES_CARTO_LIGHT = `tiles-carto-light-${CACHE_VERSION}`;
|
||||
const TILES_CARTO_DARK = `tiles-carto-dark-${CACHE_VERSION}`;
|
||||
|
||||
// App shell assets - precached on install
|
||||
// Vite will generate hashed filenames, so we cache the entry points
|
||||
// and let the browser handle the hashed assets
|
||||
// Per-provider tile limits.
|
||||
// • OSM and Topographic are the providers offered for active offline
|
||||
// download (Phase 2 dialog), so they get a higher cap (~240 MB each at
|
||||
// ~30 KB/tile) — enough for a typical Ghana district at zoom 10–15.
|
||||
// • The other providers serve passive caching only (whatever the user has
|
||||
// already viewed), so 1 500 tiles ≈ 45 MB is plenty.
|
||||
//
|
||||
// Total max ≈ 5 × ~150 MB = ~750 MB on disk in the worst case, but only the
|
||||
// two downloadable buckets are likely to fill. Eviction sweeps run every 100
|
||||
// inserts (see EVICTION_CHECK_INTERVAL) so memory pressure stays bounded.
|
||||
const TILE_LIMITS = {
|
||||
[TILES_OSM]: 8000,
|
||||
[TILES_TOPO]: 8000,
|
||||
[TILES_SATELLITE]: 1500,
|
||||
[TILES_CARTO_LIGHT]: 1500,
|
||||
[TILES_CARTO_DARK]: 1500,
|
||||
};
|
||||
|
||||
// Per-cache running insert counter, in memory. Avoids calling cache.keys()
|
||||
// (which materialises every Request object in the cache) on every put — that
|
||||
// was the cause of the Safari "reloaded due to memory pressure" failures.
|
||||
//
|
||||
// We only run a real eviction sweep every EVICTION_CHECK_INTERVAL inserts.
|
||||
const _tileInsertCounters = new Map(); // cacheName → number of inserts since last eviction
|
||||
const EVICTION_CHECK_INTERVAL = 100;
|
||||
|
||||
// Friendly name shown in the UI (matches Settings card labels)
|
||||
const TILE_CACHE_LABELS = {
|
||||
[TILES_OSM]: 'OpenStreetMap',
|
||||
[TILES_TOPO]: 'Topographic',
|
||||
[TILES_SATELLITE]: 'Satellite',
|
||||
[TILES_CARTO_LIGHT]: 'Carto Light',
|
||||
[TILES_CARTO_DARK]: 'Carto Dark',
|
||||
};
|
||||
|
||||
const ALL_TILE_CACHES = Object.keys(TILE_LIMITS);
|
||||
|
||||
// Approximate average tile size — used for storage estimation.
|
||||
// Real measurements: PNG tiles range 5–80 KB; 30 KB is a good middle ground.
|
||||
const AVG_TILE_BYTES = 30 * 1024;
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// App shell assets — precached on install.
|
||||
// ----------------------------------------------------------------------------
|
||||
const SHELL_ASSETS = [
|
||||
'/',
|
||||
'/index.html',
|
||||
@ -37,7 +89,7 @@ const SHELL_ASSETS = [
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
console.log('[SW] Installing...');
|
||||
|
||||
|
||||
event.waitUntil(
|
||||
caches.open(SHELL_CACHE)
|
||||
.then((cache) => {
|
||||
@ -54,18 +106,26 @@ self.addEventListener('install', (event) => {
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
console.log('[SW] Activating...');
|
||||
|
||||
|
||||
event.waitUntil(
|
||||
caches.keys()
|
||||
.then((cacheNames) => {
|
||||
// Build the set of caches that should remain
|
||||
const keep = new Set([SHELL_CACHE, MODULES_CACHE, API_CACHE, ...ALL_TILE_CACHES]);
|
||||
|
||||
return Promise.all(
|
||||
cacheNames
|
||||
// Delete anything that:
|
||||
// • belongs to one of our managed cache prefixes (shell-, tiles-, modules-, api-)
|
||||
// • but is NOT in the current keep set
|
||||
// This includes the legacy "tiles-v1" single bucket.
|
||||
.filter((name) => {
|
||||
// Delete old version caches
|
||||
return (name.startsWith('shell-') && name !== SHELL_CACHE) ||
|
||||
(name.startsWith('tiles-') && name !== TILES_CACHE) ||
|
||||
(name.startsWith('modules-') && name !== MODULES_CACHE) ||
|
||||
(name.startsWith('api-') && name !== API_CACHE);
|
||||
const isOurs =
|
||||
name.startsWith('shell-') ||
|
||||
name.startsWith('tiles-') ||
|
||||
name.startsWith('modules-') ||
|
||||
name.startsWith('api-');
|
||||
return isOurs && !keep.has(name);
|
||||
})
|
||||
.map((name) => {
|
||||
console.log('[SW] Deleting old cache:', name);
|
||||
@ -84,17 +144,28 @@ self.addEventListener('activate', (event) => {
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const request = event.request;
|
||||
const url = new URL(request.url);
|
||||
|
||||
|
||||
// Only handle GET requests
|
||||
if (request.method !== 'GET') return;
|
||||
|
||||
|
||||
// Skip chrome-extension and other non-http(s) requests
|
||||
if (!url.protocol.startsWith('http')) return;
|
||||
|
||||
// Route to appropriate caching strategy
|
||||
if (isMapTile(url)) {
|
||||
event.respondWith(cacheThenNetwork(request, TILES_CACHE, MAX_TILES));
|
||||
} else if (isApiRequest(url)) {
|
||||
|
||||
// Skip worker files and Vite dev-server node_modules requests —
|
||||
// intercepting these breaks module workers (e.g. SQLocal/SQLite).
|
||||
if (url.pathname.includes('node_modules') ||
|
||||
url.search.includes('worker_file') ||
|
||||
request.destination === 'worker') return;
|
||||
|
||||
// ----- TILE REQUESTS — passive cache-then-network (per-host bucket) -----
|
||||
const tileCache = getTileCacheName(url);
|
||||
if (tileCache) {
|
||||
event.respondWith(tileCacheThenNetwork(request, tileCache));
|
||||
return;
|
||||
}
|
||||
|
||||
// ----- OTHER ROUTES (unchanged) -----
|
||||
if (isApiRequest(url)) {
|
||||
event.respondWith(networkFirst(request, API_CACHE));
|
||||
} else if (isModuleAsset(url)) {
|
||||
event.respondWith(staleWhileRevalidate(request, MODULES_CACHE));
|
||||
@ -108,15 +179,36 @@ self.addEventListener('fetch', (event) => {
|
||||
// URL CLASSIFICATION
|
||||
// ============================================================================
|
||||
|
||||
function isMapTile(url) {
|
||||
// Common tile server patterns for all our base maps
|
||||
return url.hostname.includes('tile.openstreetmap.org') ||
|
||||
url.hostname.includes('opentopomap.org') ||
|
||||
url.hostname.includes('arcgisonline.com') ||
|
||||
url.hostname.includes('basemaps.cartocdn.com') ||
|
||||
url.hostname.includes('tiles.') ||
|
||||
url.pathname.match(/\/\d+\/\d+\/\d+\.(png|jpg|pbf)$/) ||
|
||||
url.pathname.match(/\/tile\/\d+\/\d+\/\d+/);
|
||||
/**
|
||||
* Classify a URL into the appropriate tile cache.
|
||||
* Returns `null` for non-tile requests, or for tile providers we deliberately
|
||||
* do NOT cache (e.g. Google — caching is forbidden by their ToS).
|
||||
*/
|
||||
function getTileCacheName(url) {
|
||||
const host = url.hostname;
|
||||
|
||||
// OpenStreetMap — tile.openstreetmap.org and a/b/c subdomains
|
||||
if (host.endsWith('tile.openstreetmap.org')) return TILES_OSM;
|
||||
|
||||
// OpenTopoMap — a/b/c.tile.opentopomap.org
|
||||
if (host.endsWith('tile.opentopomap.org') || host.endsWith('opentopomap.org')) return TILES_TOPO;
|
||||
|
||||
// Carto Basemaps — light_all / dark_all distinguished by path
|
||||
if (host.endsWith('basemaps.cartocdn.com')) {
|
||||
if (url.pathname.includes('/light_all/')) return TILES_CARTO_LIGHT;
|
||||
if (url.pathname.includes('/dark_all/')) return TILES_CARTO_DARK;
|
||||
return null; // unknown Carto style
|
||||
}
|
||||
|
||||
// Esri — server.arcgisonline.com
|
||||
if (host.endsWith('arcgisonline.com')) return TILES_SATELLITE;
|
||||
|
||||
// Google — caching forbidden by ToS, do not store
|
||||
if (host.endsWith('google.com') || host.endsWith('googleapis.com')) return null;
|
||||
|
||||
// Other tile providers (WMS endpoints, OWS, custom) — not cached at this layer
|
||||
// (the user's "online only" toast handles those).
|
||||
return null;
|
||||
}
|
||||
|
||||
function isApiRequest(url) {
|
||||
@ -129,7 +221,6 @@ function isModuleAsset(url) {
|
||||
}
|
||||
|
||||
function isAppAsset(url) {
|
||||
// Same origin, common asset extensions
|
||||
return url.origin === self.location.origin &&
|
||||
(url.pathname.endsWith('.html') ||
|
||||
url.pathname.endsWith('.css') ||
|
||||
@ -144,13 +235,13 @@ function isAppAsset(url) {
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Cache First - Use cache, fallback to network
|
||||
* Best for: App shell, static assets
|
||||
* Cache First — Use cache, fallback to network.
|
||||
* Best for: App shell, static assets.
|
||||
*/
|
||||
async function cacheFirst(request, cacheName) {
|
||||
const cached = await caches.match(request);
|
||||
if (cached) return cached;
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(request);
|
||||
if (response.ok) {
|
||||
@ -159,7 +250,6 @@ async function cacheFirst(request, cacheName) {
|
||||
}
|
||||
return response;
|
||||
} catch (error) {
|
||||
// Return offline page for navigation requests
|
||||
if (request.mode === 'navigate') {
|
||||
return caches.match('/offline.html');
|
||||
}
|
||||
@ -168,8 +258,8 @@ async function cacheFirst(request, cacheName) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Network First - Try network, fallback to cache
|
||||
* Best for: API requests, dynamic content
|
||||
* Network First — Try network, fallback to cache.
|
||||
* Best for: API requests, dynamic content.
|
||||
*/
|
||||
async function networkFirst(request, cacheName) {
|
||||
try {
|
||||
@ -187,89 +277,141 @@ async function networkFirst(request, cacheName) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Stale While Revalidate - Return cache immediately, update in background
|
||||
* Best for: Module assets, frequently updated content
|
||||
* Stale While Revalidate — Return cache immediately, update in background.
|
||||
* Best for: Module assets, frequently updated content.
|
||||
*/
|
||||
async function staleWhileRevalidate(request, cacheName) {
|
||||
const cache = await caches.open(cacheName);
|
||||
const cached = await cache.match(request);
|
||||
|
||||
|
||||
const fetchPromise = fetch(request).then((response) => {
|
||||
if (response.ok) {
|
||||
cache.put(request, response.clone());
|
||||
}
|
||||
return response;
|
||||
}).catch(() => cached);
|
||||
|
||||
|
||||
return cached || fetchPromise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache Then Network with limit - Cache tiles with size limit
|
||||
* Best for: Map tiles
|
||||
* Tile Cache then Network — Per-host bucket with size limit.
|
||||
* Cache first; on miss, fetch from network and store.
|
||||
*
|
||||
* Memory-conservative eviction:
|
||||
* • Increments an in-memory counter on every successful insert
|
||||
* • Only calls cache.keys() (which materialises all Request objects) every
|
||||
* EVICTION_CHECK_INTERVAL inserts — so the cost is amortised
|
||||
* • Eviction drops the oldest 10 % when over the per-host limit
|
||||
*
|
||||
* On network failure (offline), serves a 408 so the map renders a blank tile
|
||||
* rather than throwing.
|
||||
*/
|
||||
async function cacheThenNetwork(request, cacheName, maxItems) {
|
||||
async function tileCacheThenNetwork(request, cacheName) {
|
||||
const cache = await caches.open(cacheName);
|
||||
const cached = await cache.match(request);
|
||||
|
||||
if (cached) return cached;
|
||||
|
||||
|
||||
try {
|
||||
const response = await fetch(request);
|
||||
|
||||
|
||||
if (response.ok) {
|
||||
// Check cache size and trim if needed
|
||||
const keys = await cache.keys();
|
||||
if (keys.length >= maxItems) {
|
||||
// Remove oldest entries (first 10%)
|
||||
const toDelete = keys.slice(0, Math.ceil(maxItems * 0.1));
|
||||
await Promise.all(toDelete.map(key => cache.delete(key)));
|
||||
// Bump the counter; periodically run a real eviction sweep
|
||||
const count = (_tileInsertCounters.get(cacheName) || 0) + 1;
|
||||
_tileInsertCounters.set(cacheName, count);
|
||||
|
||||
if (count % EVICTION_CHECK_INTERVAL === 0) {
|
||||
// Reset the counter — next sweep is another EVICTION_CHECK_INTERVAL away
|
||||
_tileInsertCounters.set(cacheName, 0);
|
||||
await maybeEvict(cache, cacheName);
|
||||
}
|
||||
|
||||
cache.put(request, response.clone());
|
||||
|
||||
// Don't await put() — it can run after we return the response, keeping
|
||||
// the fetch hot path lightweight.
|
||||
cache.put(request, response.clone()).catch((err) => {
|
||||
// QuotaExceededError → run an immediate eviction sweep and retry once
|
||||
if (err && err.name === 'QuotaExceededError') {
|
||||
maybeEvict(cache, cacheName, /* force */ true).catch(() => {});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
return response;
|
||||
} catch (error) {
|
||||
// For tiles, just fail silently - map will show blank tile
|
||||
// Offline — let the map renderer show a blank tile
|
||||
return new Response('', { status: 408, statusText: 'Offline' });
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Run an eviction sweep on a cache, dropping the oldest 10 % of entries
|
||||
* when over the per-cache limit. Heavy: only call periodically.
|
||||
*/
|
||||
async function maybeEvict(cache, cacheName, force = false) {
|
||||
try {
|
||||
const limit = TILE_LIMITS[cacheName] || 1500;
|
||||
const keys = await cache.keys();
|
||||
if (force || keys.length >= limit) {
|
||||
const drop = Math.max(1, Math.ceil(limit * 0.1));
|
||||
const toDelete = keys.slice(0, drop);
|
||||
await Promise.all(toDelete.map((k) => cache.delete(k)));
|
||||
}
|
||||
} catch (err) {
|
||||
console.warn('[SW] eviction sweep failed for', cacheName, err);
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// MESSAGE HANDLING
|
||||
// ============================================================================
|
||||
|
||||
self.addEventListener('message', (event) => {
|
||||
const { type, payload } = event.data || {};
|
||||
|
||||
|
||||
switch (type) {
|
||||
case 'SKIP_WAITING':
|
||||
self.skipWaiting();
|
||||
break;
|
||||
|
||||
|
||||
case 'CACHE_MODULES':
|
||||
cacheModules(payload.modules);
|
||||
break;
|
||||
|
||||
|
||||
case 'CLEAR_USER_CACHE':
|
||||
clearUserCaches();
|
||||
break;
|
||||
|
||||
|
||||
case 'GET_CACHE_STATUS':
|
||||
getCacheStatus().then(status => {
|
||||
getCacheStatus().then((status) => {
|
||||
event.source.postMessage({ type: 'CACHE_STATUS', status });
|
||||
});
|
||||
break;
|
||||
|
||||
// ----- Tile-cache management (Phase 1 offline maps) -----
|
||||
case 'GET_TILE_STATS':
|
||||
getTileStats().then((stats) => {
|
||||
event.source.postMessage({ type: 'TILE_STATS', stats });
|
||||
});
|
||||
break;
|
||||
|
||||
case 'CLEAR_TILE_CACHES':
|
||||
clearTileCaches().then(() => {
|
||||
event.source.postMessage({ type: 'TILE_CACHES_CLEARED' });
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
// ============================================================================
|
||||
// HELPER FUNCTIONS
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Cache specific modules on demand
|
||||
* Cache specific modules on demand.
|
||||
*/
|
||||
async function cacheModules(moduleNames) {
|
||||
const cache = await caches.open(MODULES_CACHE);
|
||||
|
||||
|
||||
for (const moduleName of moduleNames) {
|
||||
try {
|
||||
const moduleAssets = [
|
||||
@ -277,9 +419,8 @@ async function cacheModules(moduleNames) {
|
||||
`/modules/${moduleName}/index.css`,
|
||||
`/modules/${moduleName}/index.html`
|
||||
];
|
||||
|
||||
|
||||
await cache.addAll(moduleAssets.filter(async (url) => {
|
||||
// Only cache assets that exist
|
||||
try {
|
||||
const response = await fetch(url, { method: 'HEAD' });
|
||||
return response.ok;
|
||||
@ -287,7 +428,7 @@ async function cacheModules(moduleNames) {
|
||||
return false;
|
||||
}
|
||||
}));
|
||||
|
||||
|
||||
console.log('[SW] Cached module:', moduleName);
|
||||
} catch (error) {
|
||||
console.warn('[SW] Failed to cache module:', moduleName, error);
|
||||
@ -296,7 +437,8 @@ async function cacheModules(moduleNames) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear user-specific caches (call on logout)
|
||||
* Clear user-specific caches (call on logout).
|
||||
* Tile caches are NOT cleared here — those belong to the device, not the user.
|
||||
*/
|
||||
async function clearUserCaches() {
|
||||
await caches.delete(API_CACHE);
|
||||
@ -305,17 +447,90 @@ async function clearUserCaches() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache status information
|
||||
* Get summary status of all caches (count of entries in each).
|
||||
*/
|
||||
async function getCacheStatus() {
|
||||
const cacheNames = await caches.keys();
|
||||
const status = {};
|
||||
|
||||
|
||||
for (const name of cacheNames) {
|
||||
const cache = await caches.open(name);
|
||||
const keys = await cache.keys();
|
||||
status[name] = keys.length;
|
||||
}
|
||||
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get per-provider tile cache statistics.
|
||||
*
|
||||
* Returns shape:
|
||||
* {
|
||||
* totals: { count, estBytes },
|
||||
* byProvider: [{ key, label, count, limit, estBytes }, ...]
|
||||
* }
|
||||
*
|
||||
* estBytes is an approximation (count × AVG_TILE_BYTES). For an exact size,
|
||||
* the caller can use navigator.storage.estimate() on the page side.
|
||||
*
|
||||
* Result is cached for STATS_TTL_MS so rapid re-queries (e.g. multiple
|
||||
* Settings opens) don't re-enumerate every cache.
|
||||
*/
|
||||
const STATS_TTL_MS = 10 * 1000;
|
||||
let _cachedStats = null;
|
||||
let _cachedStatsAt = 0;
|
||||
|
||||
async function getTileStats({ force = false } = {}) {
|
||||
const now = Date.now();
|
||||
if (!force && _cachedStats && (now - _cachedStatsAt) < STATS_TTL_MS) {
|
||||
return _cachedStats;
|
||||
}
|
||||
|
||||
const byProvider = [];
|
||||
let totalCount = 0;
|
||||
|
||||
for (const cacheName of ALL_TILE_CACHES) {
|
||||
let count = 0;
|
||||
if (await caches.has(cacheName)) {
|
||||
const cache = await caches.open(cacheName);
|
||||
// matchAll returns a smaller payload than keys() on Safari, but neither
|
||||
// is free. Done at most once per STATS_TTL_MS thanks to the cache above.
|
||||
const keys = await cache.keys();
|
||||
count = keys.length;
|
||||
}
|
||||
byProvider.push({
|
||||
key: cacheName,
|
||||
label: TILE_CACHE_LABELS[cacheName] || cacheName,
|
||||
count,
|
||||
limit: TILE_LIMITS[cacheName] || 0,
|
||||
estBytes: count * AVG_TILE_BYTES,
|
||||
});
|
||||
totalCount += count;
|
||||
}
|
||||
|
||||
_cachedStats = {
|
||||
totals: {
|
||||
count: totalCount,
|
||||
estBytes: totalCount * AVG_TILE_BYTES,
|
||||
},
|
||||
byProvider,
|
||||
};
|
||||
_cachedStatsAt = now;
|
||||
return _cachedStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete every tile cache. Frees the device storage used by cached map tiles.
|
||||
* Does not affect app-shell, modules, or API caches.
|
||||
*/
|
||||
async function clearTileCaches() {
|
||||
const results = await Promise.all(
|
||||
ALL_TILE_CACHES.map((name) => caches.delete(name))
|
||||
);
|
||||
// Reset counters and invalidate stats cache
|
||||
_tileInsertCounters.clear();
|
||||
_cachedStats = null;
|
||||
_cachedStatsAt = 0;
|
||||
console.log('[SW] Cleared tile caches:', ALL_TILE_CACHES.filter((_, i) => results[i]));
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 217 KiB After Width: | Height: | Size: 217 KiB |
737
index.html
@ -2,19 +2,64 @@
|
||||
<html lang="en" data-bs-theme="light">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||
<meta name="theme-color" content="#005eb8">
|
||||
<meta name="description" content="LUPMIS2 Drawing Tools">
|
||||
|
||||
<!-- PWA Manifest -->
|
||||
<link rel="manifest" href="/manifest.json">
|
||||
<link rel="apple-touch-icon" href="/icons/luspa.icon">
|
||||
<link rel="icon" href="/icons/luspa.icon">
|
||||
<link rel="manifest" href="manifest.json">
|
||||
<link rel="apple-touch-icon" sizes="192x192" href="icons/luspa-192x192.png">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="icons/luspa-32x32.png">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="icons/luspa-16x16.png">
|
||||
|
||||
<!-- LUSPA Design System Fonts: Bebas Neue (display) + Exo (body) -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
<link href="https://fonts.googleapis.com/css2?family=Bebas+Neue&family=Exo:wght@300;400;500;600;700;800&display=swap" rel="stylesheet">
|
||||
<!-- LUSPA Design System Fonts: Bebas Neue (display) + Exo (body) — self-hosted -->
|
||||
<style>
|
||||
/* Bebas Neue 400 — latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Bebas Neue';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/bebas-neue-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* Bebas Neue 400 — latin */
|
||||
@font-face {
|
||||
font-family: 'Bebas Neue';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
font-display: swap;
|
||||
src: url('/fonts/bebas-neue-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
/* Exo 300-800 — vietnamese */
|
||||
@font-face {
|
||||
font-family: 'Exo';
|
||||
font-style: normal;
|
||||
font-weight: 300 800;
|
||||
font-display: swap;
|
||||
src: url('/fonts/exo-vietnamese.woff2') format('woff2');
|
||||
unicode-range: U+0102-0103, U+0110-0111, U+0128-0129, U+0168-0169, U+01A0-01A1, U+01AF-01B0, U+0300-0301, U+0303-0304, U+0308-0309, U+0323, U+0329, U+1EA0-1EF9, U+20AB;
|
||||
}
|
||||
/* Exo 300-800 — latin-ext */
|
||||
@font-face {
|
||||
font-family: 'Exo';
|
||||
font-style: normal;
|
||||
font-weight: 300 800;
|
||||
font-display: swap;
|
||||
src: url('/fonts/exo-latin-ext.woff2') format('woff2');
|
||||
unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
|
||||
}
|
||||
/* Exo 300-800 — latin */
|
||||
@font-face {
|
||||
font-family: 'Exo';
|
||||
font-style: normal;
|
||||
font-weight: 300 800;
|
||||
font-display: swap;
|
||||
src: url('/fonts/exo-latin.woff2') format('woff2');
|
||||
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
|
||||
}
|
||||
</style>
|
||||
|
||||
<title>LUPMIS2 Drawing Tools</title>
|
||||
|
||||
@ -106,6 +151,295 @@
|
||||
--radius-2xl: 1rem;
|
||||
}
|
||||
|
||||
/* ─── Fieldwork Mode ─── high-contrast + larger touch targets ─── */
|
||||
.fieldwork-mode {
|
||||
--foreground: #000;
|
||||
--background: #fff;
|
||||
--card: #fff;
|
||||
--card-foreground: #000;
|
||||
--primary: #0044aa;
|
||||
--primary-foreground: #fff;
|
||||
--primary-hover: #003080;
|
||||
--muted: #e0e0e0;
|
||||
--muted-foreground: #333;
|
||||
--accent: #cce0ff;
|
||||
--accent-foreground: #000;
|
||||
--border: rgba(0,0,0,0.25);
|
||||
--success: #005a00;
|
||||
--success-foreground: #fff;
|
||||
--warning: #b36b00;
|
||||
--warning-foreground: #000;
|
||||
--destructive: #b80000;
|
||||
--destructive-foreground: #fff;
|
||||
--ring: #0044aa;
|
||||
--bs-body-color: #000;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger dock buttons */
|
||||
.fieldwork-mode .dock-btn {
|
||||
min-width: 72px;
|
||||
min-height: 58px;
|
||||
font-size: 1.6rem;
|
||||
border-width: 2px;
|
||||
}
|
||||
.fieldwork-mode .dock-btn-label {
|
||||
font-size: 0.75rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
/* Fieldwork: bolder navbar */
|
||||
.fieldwork-mode .navbar {
|
||||
border-bottom-width: 4px;
|
||||
}
|
||||
.fieldwork-mode .navbar .navbar-brand {
|
||||
font-size: 1.6rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger offcanvas toggle buttons */
|
||||
.fieldwork-mode .offcanvas-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
font-size: 1.2rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: thicker bottom dock border */
|
||||
.fieldwork-mode .bottom-dock {
|
||||
border-top-width: 4px;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger text in cards / lists */
|
||||
.fieldwork-mode .card-header h6 {
|
||||
font-size: 1rem;
|
||||
}
|
||||
.fieldwork-mode .list-group-item {
|
||||
font-size: 0.95rem;
|
||||
padding: 0.65rem 1rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: larger buttons globally */
|
||||
.fieldwork-mode .btn {
|
||||
font-size: 0.95rem;
|
||||
padding: 0.5rem 1rem;
|
||||
font-weight: 600;
|
||||
}
|
||||
.fieldwork-mode .btn-sm {
|
||||
font-size: 0.85rem;
|
||||
padding: 0.4rem 0.75rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: stronger borders on inputs / form controls */
|
||||
.fieldwork-mode .form-control,
|
||||
.fieldwork-mode .form-select {
|
||||
border-width: 2px;
|
||||
border-color: #555;
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
/* Fieldwork: bolder map controls (ol-ext) */
|
||||
.fieldwork-mode .ol-control button {
|
||||
font-size: 1.3rem;
|
||||
width: 2.2em;
|
||||
height: 2.2em;
|
||||
}
|
||||
|
||||
/* Fieldwork: scale bar text legibility */
|
||||
.fieldwork-mode .ol-scale-bar .ol-scale-step-text,
|
||||
.fieldwork-mode .ol-scale-bar .ol-scale-text {
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
text-shadow: 0 0 4px #fff, 0 0 8px #fff;
|
||||
}
|
||||
|
||||
/* ─── Dark Mode ─── reversed colour scheme ─── */
|
||||
.dark-mode {
|
||||
--foreground: #e0dff0;
|
||||
--background: #131325;
|
||||
--card: #1e1e38;
|
||||
--card-foreground: #e0dff0;
|
||||
--primary: #4d9de6;
|
||||
--primary-foreground: #fff;
|
||||
--primary-hover: #6fb3f0;
|
||||
--muted: #272745;
|
||||
--muted-foreground: #9594a8;
|
||||
--accent: #1e3a5f;
|
||||
--accent-foreground: #e0dff0;
|
||||
--border: rgba(255,255,255,0.12);
|
||||
--ring: #4d9de6;
|
||||
--success: #2dd46a;
|
||||
--success-foreground: #131325;
|
||||
--warning: #ffb84d;
|
||||
--warning-foreground: #131325;
|
||||
--destructive: #f04040;
|
||||
--destructive-foreground: #fff;
|
||||
--bs-body-color: #e0dff0;
|
||||
--bs-body-bg: #131325;
|
||||
--bs-tertiary-bg: #1e1e38;
|
||||
color-scheme: dark;
|
||||
}
|
||||
|
||||
/* Dark: navbar */
|
||||
.dark-mode .navbar {
|
||||
background-color: #1a1a30 !important;
|
||||
box-shadow: 0 1px 6px rgba(0,0,0,0.4);
|
||||
}
|
||||
|
||||
/* Dark: bottom dock */
|
||||
.dark-mode .bottom-dock {
|
||||
background-color: #1a1a30;
|
||||
box-shadow: 0 -2px 10px rgba(0,0,0,0.3);
|
||||
}
|
||||
.dark-mode .dock-btn {
|
||||
border-color: var(--primary);
|
||||
color: var(--foreground);
|
||||
}
|
||||
.dark-mode .dock-btn:hover {
|
||||
background-color: var(--muted);
|
||||
}
|
||||
.dark-mode .dock-btn.active {
|
||||
background-color: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
|
||||
/* Dark: offcanvas panels */
|
||||
.dark-mode .offcanvas {
|
||||
background-color: var(--background) !important;
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
.dark-mode .offcanvas-header {
|
||||
border-bottom-color: var(--border) !important;
|
||||
}
|
||||
.dark-mode .btn-close {
|
||||
filter: invert(1) grayscale(100%) brightness(200%);
|
||||
}
|
||||
|
||||
/* Dark: cards */
|
||||
.dark-mode .card {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--card-foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
/* Dark: offcanvas toggle buttons */
|
||||
.dark-mode .offcanvas-toggle {
|
||||
background-color: var(--card);
|
||||
color: var(--foreground);
|
||||
border-color: var(--border);
|
||||
}
|
||||
.dark-mode .offcanvas-toggle:hover {
|
||||
background-color: var(--primary);
|
||||
color: var(--primary-foreground);
|
||||
}
|
||||
|
||||
/* Dark: form controls */
|
||||
.dark-mode .form-control,
|
||||
.dark-mode .form-select {
|
||||
background-color: var(--muted) !important;
|
||||
color: var(--foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
.dark-mode .form-check-input {
|
||||
background-color: var(--muted);
|
||||
border-color: var(--muted-foreground);
|
||||
}
|
||||
.dark-mode .form-check-input:checked {
|
||||
background-color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
/* Dark: list groups */
|
||||
.dark-mode .list-group-item {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--card-foreground) !important;
|
||||
border-color: var(--border) !important;
|
||||
}
|
||||
|
||||
/* Dark: buttons */
|
||||
.dark-mode .btn-outline-primary {
|
||||
color: var(--primary);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.dark-mode .btn-outline-danger {
|
||||
color: var(--destructive);
|
||||
border-color: var(--destructive);
|
||||
}
|
||||
|
||||
/* Dark: text utilities */
|
||||
.dark-mode .text-muted {
|
||||
color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* Dark: measurement tooltips */
|
||||
.dark-mode .measure-tooltip {
|
||||
background: rgba(30, 30, 56, 0.95);
|
||||
color: var(--foreground);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
.dark-mode .measure-tooltip::before {
|
||||
border-right-color: var(--primary);
|
||||
}
|
||||
|
||||
/* Dark: OL controls */
|
||||
.dark-mode .ol-control button {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
.dark-mode .ol-control button:hover {
|
||||
background-color: var(--primary) !important;
|
||||
color: var(--primary-foreground) !important;
|
||||
}
|
||||
.dark-mode .ol-attribution,
|
||||
.dark-mode .ol-attribution a {
|
||||
color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* Dark: scale bar */
|
||||
.dark-mode .ol-scale-bar .ol-scale-step-text,
|
||||
.dark-mode .ol-scale-bar .ol-scale-text {
|
||||
color: #fff !important;
|
||||
text-shadow: 0 0 4px #000, 0 0 8px #000 !important;
|
||||
}
|
||||
.dark-mode .ol-scale-bar .ol-scale-singlebar-even {
|
||||
background-color: #fff !important;
|
||||
}
|
||||
.dark-mode .ol-scale-bar .ol-scale-singlebar-odd {
|
||||
background-color: #999 !important;
|
||||
}
|
||||
|
||||
/* Dark: map drop overlay */
|
||||
.dark-mode .map-drop-overlay {
|
||||
background: rgba(19, 19, 37, 0.85);
|
||||
border-color: var(--primary);
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* Dark: ol-ext LayerSwitcher */
|
||||
.dark-mode .ol-layerswitcher {
|
||||
background-color: var(--card) !important;
|
||||
}
|
||||
.dark-mode .ol-layerswitcher .panel {
|
||||
background-color: var(--card) !important;
|
||||
color: var(--foreground) !important;
|
||||
}
|
||||
.dark-mode .ol-layerswitcher .panel li {
|
||||
color: var(--foreground);
|
||||
}
|
||||
.dark-mode .ol-layerswitcher .ol-switchertopdiv,
|
||||
.dark-mode .ol-layerswitcher .ol-switcherbottomdiv {
|
||||
background: var(--card) !important;
|
||||
}
|
||||
|
||||
/* Dark: alert boxes */
|
||||
.dark-mode .alert-danger {
|
||||
background-color: rgba(240, 64, 64, 0.15) !important;
|
||||
color: var(--destructive) !important;
|
||||
border-color: var(--destructive) !important;
|
||||
}
|
||||
.dark-mode .alert-success {
|
||||
background-color: rgba(45, 212, 106, 0.15) !important;
|
||||
color: var(--success) !important;
|
||||
border-color: var(--success) !important;
|
||||
}
|
||||
|
||||
/* Full height layout */
|
||||
html, body {
|
||||
height: 100%;
|
||||
@ -214,9 +548,12 @@
|
||||
font-family: var(--font-body);
|
||||
}
|
||||
|
||||
/* Main container - full height */
|
||||
/* Main container - full height.
|
||||
100dvh accounts for mobile browser chrome and OS nav bars.
|
||||
Falls back to 100vh for older browsers. */
|
||||
.app-container {
|
||||
height: 100vh;
|
||||
height: 100dvh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
@ -244,6 +581,35 @@
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Drag-and-drop overlay shown when files are dragged over the map */
|
||||
.map-drop-overlay {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background: rgba(0, 94, 184, 0.15);
|
||||
border: 3px dashed var(--primary, #005eb8);
|
||||
border-radius: 8px;
|
||||
pointer-events: none;
|
||||
opacity: 0;
|
||||
transition: opacity 0.15s ease;
|
||||
}
|
||||
.map-container.drag-over .map-drop-overlay {
|
||||
opacity: 1;
|
||||
}
|
||||
.map-drop-overlay span {
|
||||
font-family: var(--font-body, 'Exo', sans-serif);
|
||||
font-size: 1.15rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary, #005eb8);
|
||||
background: var(--card, #fff);
|
||||
padding: 0.6rem 1.4rem;
|
||||
border-radius: 6px;
|
||||
box-shadow: 0 2px 8px rgba(0,0,0,0.12);
|
||||
}
|
||||
|
||||
/* Offline indicator */
|
||||
#offline-indicator {
|
||||
display: none;
|
||||
@ -301,9 +667,14 @@
|
||||
z-index: 1050;
|
||||
}
|
||||
|
||||
/* Fix ol-ext LayerSwitcher z-index */
|
||||
.ol-layerswitcher {
|
||||
z-index: 100;
|
||||
/* OL controls stacking context fix — OpenLayers sets z-index:0 on
|
||||
.ol-overlaycontainer-stopevent, trapping all controls below the
|
||||
offcanvas-toggle buttons (z-index:500). Raising the container
|
||||
to 501 lets the LayerSwitcher dropdown render above the toggles.
|
||||
pointer-events:none on the container still lets clicks through
|
||||
to the toggle buttons underneath. */
|
||||
.ol-overlaycontainer-stopevent {
|
||||
z-index: 501 !important;
|
||||
}
|
||||
|
||||
/* Alert hint box */
|
||||
@ -419,7 +790,7 @@
|
||||
}
|
||||
|
||||
.offcanvas-toggle-bottom {
|
||||
bottom: 80px; /* Above the dock */
|
||||
bottom: calc(80px + env(safe-area-inset-bottom, 0px)); /* Above the dock */
|
||||
left: 50%;
|
||||
transform: translateX(-50%);
|
||||
}
|
||||
@ -432,7 +803,10 @@
|
||||
transform: translateX(-50%) scale(0.95);
|
||||
}
|
||||
|
||||
/* Bottom Dock — white card style with blue-strong accent */
|
||||
/* Bottom Dock — white card style with blue-strong accent.
|
||||
env(safe-area-inset-bottom) adds padding on devices with a
|
||||
home indicator / gesture bar (e.g. iPhone notch models).
|
||||
The value is 0 on devices without an inset. */
|
||||
.bottom-dock {
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
@ -441,7 +815,7 @@
|
||||
z-index: 600;
|
||||
background-color: var(--card);
|
||||
border-top: 3px solid var(--primary);
|
||||
padding: 8px 16px;
|
||||
padding: 8px 16px calc(8px + env(safe-area-inset-bottom, 0px));
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
align-items: center;
|
||||
@ -503,6 +877,13 @@
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
/* Snap-guides toggle — highlighted when active */
|
||||
.ol-snap-toggle.ol-active button {
|
||||
background: var(--primary) !important;
|
||||
color: var(--primary-foreground, #fff) !important;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
/* Touch-friendly improvements for forms and buttons */
|
||||
.form-control, .form-select {
|
||||
min-height: 44px;
|
||||
@ -541,6 +922,18 @@
|
||||
color: var(--foreground);
|
||||
}
|
||||
|
||||
/* Message log in the right panel */
|
||||
.message-log {
|
||||
max-height: 260px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
.message-log-entry {
|
||||
font-size: 0.82rem;
|
||||
border-color: var(--border, #eee) !important;
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
/* ol-ext GeolocationButton styling */
|
||||
.ol-geobt {
|
||||
top: auto !important;
|
||||
@ -830,6 +1223,7 @@
|
||||
/* Locations list in offcanvas - can be taller now without form */
|
||||
.offcanvas-end .locations-list {
|
||||
max-height: calc(100vh - 280px);
|
||||
max-height: calc(100dvh - 280px);
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@ -921,17 +1315,32 @@
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
/* ScaleLine - position above the bottom dock */
|
||||
.ol-scale-line {
|
||||
bottom: 76px !important;
|
||||
/* ScaleBar - position above the bottom dock with 4px gap */
|
||||
.ol-scale-bar {
|
||||
bottom: calc(85px + env(safe-area-inset-bottom, 0px)) !important;
|
||||
left: 10px !important;
|
||||
}
|
||||
|
||||
.ol-scale-line-inner {
|
||||
border-color: var(--foreground) !important;
|
||||
.ol-scale-bar .ol-scale-step-text {
|
||||
color: var(--foreground) !important;
|
||||
font-family: var(--font-body) !important;
|
||||
font-size: 11px !important;
|
||||
text-shadow: 0 0 3px var(--background), 0 0 6px var(--background) !important;
|
||||
}
|
||||
|
||||
.ol-scale-bar .ol-scale-text {
|
||||
color: var(--foreground) !important;
|
||||
font-family: var(--font-body) !important;
|
||||
font-size: 11px !important;
|
||||
text-shadow: 0 0 3px var(--background), 0 0 6px var(--background) !important;
|
||||
}
|
||||
|
||||
.ol-scale-bar .ol-scale-singlebar-even {
|
||||
background-color: var(--foreground) !important;
|
||||
}
|
||||
|
||||
.ol-scale-bar .ol-scale-singlebar-odd {
|
||||
background-color: var(--muted-foreground) !important;
|
||||
}
|
||||
|
||||
/* ol-ext Bar overrides */
|
||||
@ -980,6 +1389,7 @@
|
||||
</span>
|
||||
</div>
|
||||
<div id="map"></div>
|
||||
<div class="map-drop-overlay"><span><i class="bi bi-file-earmark-arrow-up me-2"></i>Drop file to import (.shp .geojson .kml)</span></div>
|
||||
|
||||
<!-- Offcanvas toggle buttons -->
|
||||
<button class="offcanvas-toggle offcanvas-toggle-left"
|
||||
@ -1104,17 +1514,40 @@
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="local-data-btn">
|
||||
<i class="bi bi-database me-2"></i>Local Data
|
||||
</button>
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="import-shp-btn">
|
||||
<i class="bi bi-file-earmark-arrow-up me-2"></i>Import .shp
|
||||
</button>
|
||||
<input type="file" id="shp-file-input" accept=".zip,.shp,.dbf,.shx,.prj" multiple class="d-none">
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="import-geojson-btn">
|
||||
<i class="bi bi-file-earmark-arrow-up me-2"></i>Import GeoJSON
|
||||
</button>
|
||||
<input type="file" id="geojson-file-input" accept=".geojson,.json" class="d-none">
|
||||
<button type="button" class="btn btn-outline-primary w-100 mb-3" id="import-kml-btn">
|
||||
<i class="bi bi-file-earmark-arrow-up me-2"></i>Import KML
|
||||
</button>
|
||||
<input type="file" id="kml-file-input" accept=".kml,.kmz" class="d-none">
|
||||
<div id="file-import-alert" class="alert alert-danger alert-dismissible fade show d-none mb-3" role="alert">
|
||||
<small class="message-text"></small>
|
||||
<button type="button" class="btn-close btn-close-sm" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<div id="imported-layers-info" class="d-none mb-3"></div>
|
||||
<div id="local-data-stats" class="d-none">
|
||||
<div class="card">
|
||||
<div class="card-header bg-primary py-2">
|
||||
<div class="card-header bg-primary py-2 d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0"><i class="bi bi-database me-2"></i>Local Database Tables</h6>
|
||||
<button type="button" class="btn btn-sm btn-outline-light"
|
||||
id="clear-all-cached-btn"
|
||||
title="Delete all cached map layers. They will be re-downloaded on next app start.">
|
||||
<i class="bi bi-arrow-clockwise me-1"></i>Refresh cached layers
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<table class="table table-sm table-striped mb-0">
|
||||
<thead>
|
||||
<tr>
|
||||
<th class="ps-3">Table</th>
|
||||
<th class="text-end pe-3">Records</th>
|
||||
<th class="text-end">Records</th>
|
||||
<th class="text-end pe-3" style="width:3rem;"></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody id="local-data-tbody">
|
||||
@ -1142,6 +1575,10 @@
|
||||
<span class="message-text"></span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
<div id="warning-message" class="alert alert-warning alert-dismissible fade show d-none" role="alert">
|
||||
<span class="message-text"></span>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
|
||||
</div>
|
||||
|
||||
<!-- Tip -->
|
||||
<div class="alert alert-light border-start border-4 border-primary py-2 mb-3" role="alert">
|
||||
@ -1181,20 +1618,268 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Message Log -->
|
||||
<div class="card mt-3" id="message-log-card">
|
||||
<div class="card-header bg-transparent py-2 d-flex justify-content-between align-items-center">
|
||||
<h6 class="mb-0" style="font-family:var(--font-body);font-weight:700;"><i class="bi bi-journal-text me-1"></i> Messages</h6>
|
||||
<button class="btn btn-sm btn-link text-muted p-0" id="clear-message-log" title="Clear messages">
|
||||
<i class="bi bi-trash3"></i>
|
||||
</button>
|
||||
</div>
|
||||
<div class="card-body p-0">
|
||||
<div id="message-log" class="message-log list-group list-group-flush">
|
||||
<div class="text-center text-muted py-3">
|
||||
<small>No messages yet.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bottom Offcanvas -->
|
||||
<div class="offcanvas offcanvas-bottom" tabindex="-1" id="offcanvasBottom" aria-labelledby="offcanvasBottomLabel">
|
||||
<div class="offcanvas-header">
|
||||
<h5 class="offcanvas-title" id="offcanvasBottomLabel"><i class="bi bi-chevron-down me-2"></i>Bottom Panel</h5>
|
||||
<h5 class="offcanvas-title" id="offcanvasBottomLabel"><i class="bi bi-gear me-2"></i>Settings</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="offcanvas-body">
|
||||
<p>This is the bottom offcanvas panel.</p>
|
||||
<p>You can add a data table, charts, or other wide content here.</p>
|
||||
<div class="row g-3">
|
||||
<!-- Fieldwork Mode -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Fieldwork Mode</h6>
|
||||
<small class="text-muted">High-contrast colours and larger touch targets for bright sunlight and field conditions.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch ms-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="fieldwork-mode-toggle" style="width:3rem;height:1.5rem;cursor:pointer;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Dark Mode -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Dark Mode</h6>
|
||||
<small class="text-muted">Reduce glare and save battery with a dark colour scheme.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch ms-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="dark-mode-toggle" style="width:3rem;height:1.5rem;cursor:pointer;">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Measurement System -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div>
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Measurement System</h6>
|
||||
<small class="text-muted">Switch between Metric (m, km) and Imperial (ft, mi, acres) units.</small>
|
||||
</div>
|
||||
<div class="form-check form-switch ms-3">
|
||||
<input class="form-check-input" type="checkbox" role="switch" id="measurement-system-toggle" style="width:3rem;height:1.5rem;cursor:pointer;">
|
||||
<label class="form-check-label ms-1" id="measurement-system-label" for="measurement-system-toggle" style="font-size:0.8rem;font-weight:600;min-width:55px;">Metric</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Default Base Map -->
|
||||
<div class="col-12 col-md-6 col-lg-4">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-center justify-content-between">
|
||||
<div style="flex:1;min-width:0;">
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">Default Base Map</h6>
|
||||
<small class="text-muted">Base map shown on app start. Saved on this device.</small>
|
||||
</div>
|
||||
<div class="ms-3" style="min-width:140px;">
|
||||
<select class="form-select form-select-sm" id="default-basemap-select" aria-label="Default base map">
|
||||
<option value="topo">Topographic</option>
|
||||
<option value="osm">OpenStreetMap</option>
|
||||
<option value="satellite">Satellite</option>
|
||||
<option value="googlesat">Google Sat</option>
|
||||
<option value="carto-light">Carto Light</option>
|
||||
<option value="carto-dark">Carto Dark</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Offline Map Tiles -->
|
||||
<div class="col-12 col-md-6 col-lg-8">
|
||||
<div class="card">
|
||||
<div class="card-body">
|
||||
<div class="d-flex align-items-start justify-content-between mb-2">
|
||||
<div style="flex:1;min-width:0;">
|
||||
<h6 class="mb-1" style="font-family:var(--font-body);font-weight:700;">
|
||||
<i class="bi bi-map me-1"></i>Offline Map Tiles
|
||||
</h6>
|
||||
<small class="text-muted">
|
||||
Map tiles you've already viewed are cached on this device so they work offline.
|
||||
Tiles are cached automatically as you browse, or you can pre-download a region.
|
||||
</small>
|
||||
</div>
|
||||
<div class="ms-3 d-flex gap-2 flex-shrink-0">
|
||||
<button type="button" class="btn btn-sm btn-primary"
|
||||
id="download-tiles-btn" style="white-space:nowrap;">
|
||||
<i class="bi bi-cloud-download me-1"></i>Download offline map
|
||||
</button>
|
||||
<button type="button" class="btn btn-sm btn-outline-danger"
|
||||
id="clear-tiles-btn" style="white-space:nowrap;">
|
||||
<i class="bi bi-trash3 me-1"></i>Clear cached tiles
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="tile-cache-stats" class="small">
|
||||
<div class="text-muted fst-italic">Loading…</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Download Offline Map modal -->
|
||||
<div class="modal fade" id="offline-download-modal" tabindex="-1" aria-labelledby="offline-download-title" aria-hidden="true">
|
||||
<div class="modal-dialog modal-dialog-centered modal-lg">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="offline-download-title">
|
||||
<i class="bi bi-cloud-download me-2"></i>Download Offline Map
|
||||
</h5>
|
||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close" id="offline-download-close-btn"></button>
|
||||
</div>
|
||||
|
||||
<!-- Form view (shown until Start is clicked) -->
|
||||
<div class="modal-body" id="offline-download-form-view">
|
||||
<p class="text-muted small mb-3">
|
||||
Pre-fetch map tiles so they're available when you're offline.
|
||||
Only the OpenStreetMap and Topographic base maps can be downloaded;
|
||||
other providers don't permit bulk caching.
|
||||
</p>
|
||||
|
||||
<!-- Base map -->
|
||||
<div class="mb-3">
|
||||
<label for="offline-basemap-select" class="form-label fw-bold">Base map</label>
|
||||
<select class="form-select form-select-sm" id="offline-basemap-select">
|
||||
<option value="topo">Topographic</option>
|
||||
<option value="osm">OpenStreetMap</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<!-- Area -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold mb-1">Area to download</label>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="offline-area" id="offline-area-view" value="view" checked>
|
||||
<label class="form-check-label" for="offline-area-view">
|
||||
Current map view
|
||||
<span class="text-muted small" id="offline-area-view-info"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="offline-area" id="offline-area-district" value="district">
|
||||
<label class="form-check-label" for="offline-area-district">
|
||||
District boundary
|
||||
<span class="text-muted small" id="offline-area-district-info"></span>
|
||||
</label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="radio" name="offline-area" id="offline-area-ghana" value="ghana">
|
||||
<label class="form-check-label" for="offline-area-ghana">
|
||||
Entire Ghana <span class="text-muted small">(very large — only attempt over fast Wi-Fi)</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Zoom range -->
|
||||
<div class="mb-3">
|
||||
<label class="form-label fw-bold mb-1">Zoom levels</label>
|
||||
<div class="row g-2 align-items-center">
|
||||
<div class="col-auto"><label for="offline-min-zoom" class="form-label small mb-0">Min</label></div>
|
||||
<div class="col-auto">
|
||||
<input type="number" class="form-control form-control-sm" id="offline-min-zoom" min="6" max="19" value="10" style="width:5em;">
|
||||
</div>
|
||||
<div class="col-auto"><label for="offline-max-zoom" class="form-label small mb-0">Max</label></div>
|
||||
<div class="col-auto">
|
||||
<input type="number" class="form-control form-control-sm" id="offline-max-zoom" min="6" max="19" value="15" style="width:5em;">
|
||||
</div>
|
||||
<div class="col text-muted small">10 = regional · 13 = neighbourhood · 16 = building</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Estimate -->
|
||||
<div class="alert alert-info py-2 px-3 mb-3" id="offline-estimate" style="font-size:0.9em;">
|
||||
<strong>Estimated download:</strong>
|
||||
<span id="offline-estimate-detail">Calculating…</span>
|
||||
</div>
|
||||
|
||||
<!-- Acknowledgement -->
|
||||
<div class="form-check mb-2">
|
||||
<input class="form-check-input" type="checkbox" id="offline-ack-check">
|
||||
<label class="form-check-label small" for="offline-ack-check">
|
||||
I understand this counts against the tile provider's usage quota
|
||||
and will use mobile data if I'm not on Wi-Fi.
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Progress view (shown during download) -->
|
||||
<div class="modal-body d-none" id="offline-download-progress-view">
|
||||
<div class="text-center mb-3">
|
||||
<div class="fs-5 fw-bold" id="offline-progress-percent">0%</div>
|
||||
<div class="small text-muted" id="offline-progress-counts">0 of 0 tiles</div>
|
||||
</div>
|
||||
<div class="progress mb-3" style="height:1.25em;">
|
||||
<div class="progress-bar progress-bar-striped progress-bar-animated"
|
||||
role="progressbar" id="offline-progress-bar"
|
||||
aria-valuemin="0" aria-valuemax="100" style="width:0%;"></div>
|
||||
</div>
|
||||
<div class="row text-center small text-muted">
|
||||
<div class="col"><div class="fw-bold text-body" id="offline-progress-ok">0</div>fetched</div>
|
||||
<div class="col"><div class="fw-bold text-body" id="offline-progress-failed">0</div>failed</div>
|
||||
<div class="col"><div class="fw-bold text-body" id="offline-progress-eta">—</div>remaining</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Done view (shown after completion) -->
|
||||
<div class="modal-body d-none" id="offline-download-done-view">
|
||||
<div class="text-center py-3">
|
||||
<i class="bi bi-check-circle-fill text-success" style="font-size:3rem;"></i>
|
||||
<div class="fs-5 fw-bold mt-2" id="offline-done-title">Download complete</div>
|
||||
<div class="text-muted" id="offline-done-detail"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" id="offline-download-cancel-btn">
|
||||
Cancel
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary" id="offline-download-start-btn" disabled>
|
||||
<i class="bi bi-cloud-download me-1"></i>Start download
|
||||
</button>
|
||||
<button type="button" class="btn btn-primary d-none" id="offline-download-close-done-btn" data-bs-dismiss="modal">
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Polyfill crypto.randomUUID for non-secure contexts (HTTP) -->
|
||||
<!-- Must run before module imports (SQLocal/coincident require it) -->
|
||||
|
||||
1
node_modules/.bin/esbuild
generated
vendored
@ -1 +0,0 @@
|
||||
../esbuild/bin/esbuild
|
||||
1
node_modules/.bin/nanoid
generated
vendored
@ -1 +0,0 @@
|
||||
../nanoid/bin/nanoid.cjs
|
||||
1
node_modules/.bin/pbf
generated
vendored
@ -1 +0,0 @@
|
||||
../pbf/bin/pbf
|
||||
1
node_modules/.bin/rollup
generated
vendored
@ -1 +0,0 @@
|
||||
../rollup/dist/bin/rollup
|
||||
1
node_modules/.bin/sqlite-wasm
generated
vendored
@ -1 +0,0 @@
|
||||
../@sqlite.org/sqlite-wasm/bin/index.js
|
||||
1
node_modules/.bin/vite
generated
vendored
@ -1 +0,0 @@
|
||||
../vite/bin/vite.js
|
||||
643
node_modules/.package-lock.json
generated
vendored
@ -1,643 +0,0 @@
|
||||
{
|
||||
"name": "lupmis-pwa",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.12.tgz",
|
||||
"integrity": "sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@petamoriken/float16": {
|
||||
"version": "3.9.3",
|
||||
"resolved": "https://registry.npmjs.org/@petamoriken/float16/-/float16-3.9.3.tgz",
|
||||
"integrity": "sha512-8awtpHXCx/bNpFt4mt2xdkgtgVvKqty8VbjHI/WWWQuEw+KLzFot3f4+LkQY9YmOtq7A5GdOnqoIC8Pdygjk2g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@popperjs/core": {
|
||||
"version": "2.11.8",
|
||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
|
||||
"integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/popperjs"
|
||||
}
|
||||
},
|
||||
"node_modules/@rollup/rollup-darwin-arm64": {
|
||||
"version": "4.55.3",
|
||||
"resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.55.3.tgz",
|
||||
"integrity": "sha512-1ht2SpGIjEl2igJ9AbNpPIKzb1B5goXOcmtD0RFxnwNuMxqkR6AUaaErZz+4o+FKmzxcSNBOLrzsICZVNYa1Rw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@sqlite.org/sqlite-wasm": {
|
||||
"version": "3.50.4-build1",
|
||||
"resolved": "https://registry.npmjs.org/@sqlite.org/sqlite-wasm/-/sqlite-wasm-3.50.4-build1.tgz",
|
||||
"integrity": "sha512-Qig2Wso7gPkU1PtXwFzndh+CTRzrIFxVGqv6eCetjU7YqxlHItj+GvQYwYTppCRgAPawtRN/4AJcEgB9xDHGug==",
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"sqlite-wasm": "bin/index.js"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/estree": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
|
||||
"integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
|
||||
"devOptional": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/rbush": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/rbush/-/rbush-4.0.0.tgz",
|
||||
"integrity": "sha512-+N+2H39P8X+Hy1I5mC6awlTX54k3FhiUmvt7HWzGJZvF+syUAAxP/stwppS8JE84YHqFgRMv6fCy31202CMFxQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@ungap/structured-clone": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.0.tgz",
|
||||
"integrity": "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/@ungap/with-resolvers": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@ungap/with-resolvers/-/with-resolvers-0.1.0.tgz",
|
||||
"integrity": "sha512-g7f0IkJdPW2xhY7H4iE72DAsIyfuwEFc6JWc2tYFwKDMWWAF699vGjrM348cwQuOXgHpe1gWFe+Eiyjx/ewvvw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/bootstrap": {
|
||||
"version": "5.3.8",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.8.tgz",
|
||||
"integrity": "sha512-HP1SZDqaLDPwsNiqRqi5NcP0SSXciX2s9E+RyqJIIqGo+vJeN5AJVM98CXmW/Wux0nQ5L7jeWUdplCEf0Ee+tg==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"@popperjs/core": "^2.11.8"
|
||||
}
|
||||
},
|
||||
"node_modules/bootstrap-icons": {
|
||||
"version": "1.13.1",
|
||||
"resolved": "https://registry.npmjs.org/bootstrap-icons/-/bootstrap-icons-1.13.1.tgz",
|
||||
"integrity": "sha512-ijombt4v6bv5CLeXvRWKy7CuM3TRTuPEuGaGKvTV5cz65rQSY8RQ2JcHt6b90cBBAC7s8fsf2EkQDldzCoXUjw==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/twbs"
|
||||
},
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/bootstrap"
|
||||
}
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/coincident": {
|
||||
"version": "1.2.3",
|
||||
"resolved": "https://registry.npmjs.org/coincident/-/coincident-1.2.3.tgz",
|
||||
"integrity": "sha512-Uxz3BMTWIslzeWjuQnizGWVg0j6khbvHUQ8+5BdM7WuJEm4ALXwq3wluYoB+uF68uPBz/oUOeJnYURKyfjexlA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@ungap/structured-clone": "^1.2.0",
|
||||
"@ungap/with-resolvers": "^0.1.0",
|
||||
"gc-hook": "^0.3.1",
|
||||
"proxy-target": "^3.0.2"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"ws": "^8.16.0"
|
||||
}
|
||||
},
|
||||
"node_modules/earcut": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/earcut/-/earcut-3.0.2.tgz",
|
||||
"integrity": "sha512-X7hshQbLyMJ/3RPhyObLARM2sNxxmRALLKx1+NVFFnQ9gKzmCrxm9+uLIAdBcvc8FNLpctqlQ2V6AE92Ol9UDQ==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.12",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.12.tgz",
|
||||
"integrity": "sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==",
|
||||
"devOptional": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"esbuild": "bin/esbuild"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.25.12",
|
||||
"@esbuild/android-arm": "0.25.12",
|
||||
"@esbuild/android-arm64": "0.25.12",
|
||||
"@esbuild/android-x64": "0.25.12",
|
||||
"@esbuild/darwin-arm64": "0.25.12",
|
||||
"@esbuild/darwin-x64": "0.25.12",
|
||||
"@esbuild/freebsd-arm64": "0.25.12",
|
||||
"@esbuild/freebsd-x64": "0.25.12",
|
||||
"@esbuild/linux-arm": "0.25.12",
|
||||
"@esbuild/linux-arm64": "0.25.12",
|
||||
"@esbuild/linux-ia32": "0.25.12",
|
||||
"@esbuild/linux-loong64": "0.25.12",
|
||||
"@esbuild/linux-mips64el": "0.25.12",
|
||||
"@esbuild/linux-ppc64": "0.25.12",
|
||||
"@esbuild/linux-riscv64": "0.25.12",
|
||||
"@esbuild/linux-s390x": "0.25.12",
|
||||
"@esbuild/linux-x64": "0.25.12",
|
||||
"@esbuild/netbsd-arm64": "0.25.12",
|
||||
"@esbuild/netbsd-x64": "0.25.12",
|
||||
"@esbuild/openbsd-arm64": "0.25.12",
|
||||
"@esbuild/openbsd-x64": "0.25.12",
|
||||
"@esbuild/openharmony-arm64": "0.25.12",
|
||||
"@esbuild/sunos-x64": "0.25.12",
|
||||
"@esbuild/win32-arm64": "0.25.12",
|
||||
"@esbuild/win32-ia32": "0.25.12",
|
||||
"@esbuild/win32-x64": "0.25.12"
|
||||
}
|
||||
},
|
||||
"node_modules/fdir": {
|
||||
"version": "6.5.0",
|
||||
"resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz",
|
||||
"integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"picomatch": "^3 || ^4"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"picomatch": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "2.3.3",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
|
||||
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/gc-hook": {
|
||||
"version": "0.3.1",
|
||||
"resolved": "https://registry.npmjs.org/gc-hook/-/gc-hook-0.3.1.tgz",
|
||||
"integrity": "sha512-E5M+O/h2o7eZzGhzRZGex6hbB3k4NWqO0eA+OzLRLXxhdbYPajZnynPwAtphnh+cRHPwsj5Z80dqZlfI4eK55A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/geotiff": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/geotiff/-/geotiff-2.1.3.tgz",
|
||||
"integrity": "sha512-PT6uoF5a1+kbC3tHmZSUsLHBp2QJlHasxxxxPW47QIY1VBKpFB+FcDvX+MxER6UzgLQZ0xDzJ9s48B9JbOCTqA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@petamoriken/float16": "^3.4.7",
|
||||
"lerc": "^3.0.0",
|
||||
"pako": "^2.0.4",
|
||||
"parse-headers": "^2.0.2",
|
||||
"quick-lru": "^6.1.1",
|
||||
"web-worker": "^1.2.0",
|
||||
"xml-utils": "^1.0.2",
|
||||
"zstddec": "^0.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10.19"
|
||||
}
|
||||
},
|
||||
"node_modules/lerc": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lerc/-/lerc-3.0.0.tgz",
|
||||
"integrity": "sha512-Rm4J/WaHhRa93nCN2mwWDZFoRVF18G1f47C+kvQWyHGEZxFpTUi73p7lMVSAndyxGt6lJ2/CFbOcf9ra5p8aww==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.11",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz",
|
||||
"integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==",
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ol": {
|
||||
"version": "10.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ol/-/ol-10.7.0.tgz",
|
||||
"integrity": "sha512-122U5gamPqNgLpLOkogFJhgpywvd/5en2kETIDW+Ubfi9lPnZ0G9HWRdG+CX0oP8od2d6u6ky3eewIYYlrVczw==",
|
||||
"license": "BSD-2-Clause",
|
||||
"dependencies": {
|
||||
"@types/rbush": "4.0.0",
|
||||
"earcut": "^3.0.0",
|
||||
"geotiff": "^2.1.3",
|
||||
"pbf": "4.0.1",
|
||||
"rbush": "^4.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/openlayers"
|
||||
}
|
||||
},
|
||||
"node_modules/ol-ext": {
|
||||
"version": "4.0.37",
|
||||
"resolved": "https://registry.npmjs.org/ol-ext/-/ol-ext-4.0.37.tgz",
|
||||
"integrity": "sha512-RxzdgMWnNBDP9VZCza3oS3rl1+OCl+1SJLMjt7ATyDDLZl/zzrsQELfJ25WAL6HIWgjkQ2vYDh3nnHFupxOH4w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"peerDependencies": {
|
||||
"ol": ">= 5.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz",
|
||||
"integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==",
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parse-headers": {
|
||||
"version": "2.0.6",
|
||||
"resolved": "https://registry.npmjs.org/parse-headers/-/parse-headers-2.0.6.tgz",
|
||||
"integrity": "sha512-Tz11t3uKztEW5FEVZnj1ox8GKblWn+PvHY9TmJV5Mll2uHEwRdR/5Li1OlXoECjLYkApdhWy44ocONwXLiKO5A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pbf": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/pbf/-/pbf-4.0.1.tgz",
|
||||
"integrity": "sha512-SuLdBvS42z33m8ejRbInMapQe8n0D3vN/Xd5fmWM3tufNgRQFBpaW2YVJxQZV4iPNqb0vEFvssMEo5w9c6BTIA==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"resolve-protobuf-schema": "^2.1.0"
|
||||
},
|
||||
"bin": {
|
||||
"pbf": "bin/pbf"
|
||||
}
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||
"devOptional": true,
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/picomatch": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.3.tgz",
|
||||
"integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss": {
|
||||
"version": "8.5.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
|
||||
"integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
|
||||
"devOptional": true,
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/postcss/"
|
||||
},
|
||||
{
|
||||
"type": "tidelift",
|
||||
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||
},
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.3.11",
|
||||
"picocolors": "^1.1.1",
|
||||
"source-map-js": "^1.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/protocol-buffers-schema": {
|
||||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/protocol-buffers-schema/-/protocol-buffers-schema-3.6.0.tgz",
|
||||
"integrity": "sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/proxy-target": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/proxy-target/-/proxy-target-3.0.2.tgz",
|
||||
"integrity": "sha512-FFE1XNwXX/FNC3/P8HiKaJSy/Qk68RitG/QEcLy/bVnTAPlgTAWPZKh0pARLAnpfXQPKyalBhk009NRTgsk8vQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/quick-lru": {
|
||||
"version": "6.1.2",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-6.1.2.tgz",
|
||||
"integrity": "sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/quickselect": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/quickselect/-/quickselect-3.0.0.tgz",
|
||||
"integrity": "sha512-XdjUArbK4Bm5fLLvlm5KpTFOiOThgfWWI4axAZDWg4E/0mKdZyI9tNEfds27qCi1ze/vwTR16kvmmGhRra3c2g==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/rbush": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/rbush/-/rbush-4.0.1.tgz",
|
||||
"integrity": "sha512-IP0UpfeWQujYC8Jg162rMNc01Rf0gWMMAb2Uxus/Q0qOFw4lCcq6ZnQEZwUoJqWyUGJ9th7JjwI4yIWo+uvoAQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"quickselect": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/resolve-protobuf-schema": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-protobuf-schema/-/resolve-protobuf-schema-2.1.0.tgz",
|
||||
"integrity": "sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"protocol-buffers-schema": "^3.3.1"
|
||||
}
|
||||
},
|
||||
"node_modules/rollup": {
|
||||
"version": "4.55.3",
|
||||
"resolved": "https://registry.npmjs.org/rollup/-/rollup-4.55.3.tgz",
|
||||
"integrity": "sha512-y9yUpfQvetAjiDLtNMf1hL9NXchIJgWt6zIKeoB+tCd3npX08Eqfzg60V9DhIGVMtQ0AlMkFw5xa+AQ37zxnAA==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "1.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"rollup": "dist/bin/rollup"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.0.0",
|
||||
"npm": ">=8.0.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@rollup/rollup-android-arm-eabi": "4.55.3",
|
||||
"@rollup/rollup-android-arm64": "4.55.3",
|
||||
"@rollup/rollup-darwin-arm64": "4.55.3",
|
||||
"@rollup/rollup-darwin-x64": "4.55.3",
|
||||
"@rollup/rollup-freebsd-arm64": "4.55.3",
|
||||
"@rollup/rollup-freebsd-x64": "4.55.3",
|
||||
"@rollup/rollup-linux-arm-gnueabihf": "4.55.3",
|
||||
"@rollup/rollup-linux-arm-musleabihf": "4.55.3",
|
||||
"@rollup/rollup-linux-arm64-gnu": "4.55.3",
|
||||
"@rollup/rollup-linux-arm64-musl": "4.55.3",
|
||||
"@rollup/rollup-linux-loong64-gnu": "4.55.3",
|
||||
"@rollup/rollup-linux-loong64-musl": "4.55.3",
|
||||
"@rollup/rollup-linux-ppc64-gnu": "4.55.3",
|
||||
"@rollup/rollup-linux-ppc64-musl": "4.55.3",
|
||||
"@rollup/rollup-linux-riscv64-gnu": "4.55.3",
|
||||
"@rollup/rollup-linux-riscv64-musl": "4.55.3",
|
||||
"@rollup/rollup-linux-s390x-gnu": "4.55.3",
|
||||
"@rollup/rollup-linux-x64-gnu": "4.55.3",
|
||||
"@rollup/rollup-linux-x64-musl": "4.55.3",
|
||||
"@rollup/rollup-openbsd-x64": "4.55.3",
|
||||
"@rollup/rollup-openharmony-arm64": "4.55.3",
|
||||
"@rollup/rollup-win32-arm64-msvc": "4.55.3",
|
||||
"@rollup/rollup-win32-ia32-msvc": "4.55.3",
|
||||
"@rollup/rollup-win32-x64-gnu": "4.55.3",
|
||||
"@rollup/rollup-win32-x64-msvc": "4.55.3",
|
||||
"fsevents": "~2.3.2"
|
||||
}
|
||||
},
|
||||
"node_modules/source-map-js": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||
"devOptional": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/sqlocal": {
|
||||
"version": "0.16.0",
|
||||
"resolved": "https://registry.npmjs.org/sqlocal/-/sqlocal-0.16.0.tgz",
|
||||
"integrity": "sha512-iK9IAnPGW+98Pw0dWvhPZlapEZ9NaAKMEhRsbY1XlXPpAnRXblF6hP3NGtfLcW2dErWRJ79xzX3tAVZ2jNwqCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@sqlite.org/sqlite-wasm": "^3.50.4-build1",
|
||||
"coincident": "^1.2.3"
|
||||
},
|
||||
"funding": {
|
||||
"type": "paypal",
|
||||
"url": "https://www.paypal.com/biz/fund?id=U3ZNM2Q26WJY8"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@angular/core": ">=17.0.0",
|
||||
"drizzle-orm": "*",
|
||||
"kysely": "*",
|
||||
"react": ">=18.0.0",
|
||||
"vite": ">=4.0.0",
|
||||
"vue": ">=3.0.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@angular/core": {
|
||||
"optional": true
|
||||
},
|
||||
"drizzle-orm": {
|
||||
"optional": true
|
||||
},
|
||||
"kysely": {
|
||||
"optional": true
|
||||
},
|
||||
"react": {
|
||||
"optional": true
|
||||
},
|
||||
"vite": {
|
||||
"optional": true
|
||||
},
|
||||
"vue": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/tinyglobby": {
|
||||
"version": "0.2.15",
|
||||
"resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz",
|
||||
"integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"fdir": "^6.5.0",
|
||||
"picomatch": "^4.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/SuperchupuDev"
|
||||
}
|
||||
},
|
||||
"node_modules/vite": {
|
||||
"version": "6.4.1",
|
||||
"resolved": "https://registry.npmjs.org/vite/-/vite-6.4.1.tgz",
|
||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||
"devOptional": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"esbuild": "^0.25.0",
|
||||
"fdir": "^6.4.4",
|
||||
"picomatch": "^4.0.2",
|
||||
"postcss": "^8.5.3",
|
||||
"rollup": "^4.34.9",
|
||||
"tinyglobby": "^0.2.13"
|
||||
},
|
||||
"bin": {
|
||||
"vite": "bin/vite.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^18.0.0 || ^20.0.0 || >=22.0.0"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/vitejs/vite?sponsor=1"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"fsevents": "~2.3.3"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0",
|
||||
"jiti": ">=1.21.0",
|
||||
"less": "*",
|
||||
"lightningcss": "^1.21.0",
|
||||
"sass": "*",
|
||||
"sass-embedded": "*",
|
||||
"stylus": "*",
|
||||
"sugarss": "*",
|
||||
"terser": "^5.16.0",
|
||||
"tsx": "^4.8.1",
|
||||
"yaml": "^2.4.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@types/node": {
|
||||
"optional": true
|
||||
},
|
||||
"jiti": {
|
||||
"optional": true
|
||||
},
|
||||
"less": {
|
||||
"optional": true
|
||||
},
|
||||
"lightningcss": {
|
||||
"optional": true
|
||||
},
|
||||
"sass": {
|
||||
"optional": true
|
||||
},
|
||||
"sass-embedded": {
|
||||
"optional": true
|
||||
},
|
||||
"stylus": {
|
||||
"optional": true
|
||||
},
|
||||
"sugarss": {
|
||||
"optional": true
|
||||
},
|
||||
"terser": {
|
||||
"optional": true
|
||||
},
|
||||
"tsx": {
|
||||
"optional": true
|
||||
},
|
||||
"yaml": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/web-worker": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/web-worker/-/web-worker-1.5.0.tgz",
|
||||
"integrity": "sha512-RiMReJrTAiA+mBjGONMnjVDP2u3p9R1vkcGz6gDIrOMT3oGuYwX2WRMYI9ipkphSuE5XKEhydbhNEJh4NY9mlw==",
|
||||
"license": "Apache-2.0"
|
||||
},
|
||||
"node_modules/ws": {
|
||||
"version": "8.19.0",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-8.19.0.tgz",
|
||||
"integrity": "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"engines": {
|
||||
"node": ">=10.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"utf-8-validate": ">=5.0.2"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"bufferutil": {
|
||||
"optional": true
|
||||
},
|
||||
"utf-8-validate": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/xml-utils": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/xml-utils/-/xml-utils-1.10.2.tgz",
|
||||
"integrity": "sha512-RqM+2o1RYs6T8+3DzDSoTRAUfrvaejbVHcp3+thnAtDKo8LskR+HomLajEy5UjTz24rpka7AxVBRR3g2wTUkJA==",
|
||||
"license": "CC0-1.0"
|
||||
},
|
||||
"node_modules/zstddec": {
|
||||
"version": "0.1.0",
|
||||
"resolved": "https://registry.npmjs.org/zstddec/-/zstddec-0.1.0.tgz",
|
||||
"integrity": "sha512-w2NTI8+3l3eeltKAdK8QpiLo/flRAr2p8AGeakfMZOXBxOg9HIu4LVDxBi81sYgVhFhdJjv1OrB5ssI8uFPoLg==",
|
||||
"license": "MIT AND BSD-3-Clause"
|
||||
}
|
||||
}
|
||||
}
|
||||
439
node_modules/.vite/deps/_metadata.json
generated
vendored
@ -1,439 +0,0 @@
|
||||
{
|
||||
"hash": "5fa9d27f",
|
||||
"configHash": "cab165a2",
|
||||
"lockfileHash": "c2087766",
|
||||
"browserHash": "c156faea",
|
||||
"optimized": {
|
||||
"bootstrap": {
|
||||
"src": "../../bootstrap/dist/js/bootstrap.esm.js",
|
||||
"file": "bootstrap.js",
|
||||
"fileHash": "fd6ceaaa",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/Map": {
|
||||
"src": "../../ol/Map.js",
|
||||
"file": "ol_Map.js",
|
||||
"fileHash": "b0e367b7",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/View": {
|
||||
"src": "../../ol/View.js",
|
||||
"file": "ol_View.js",
|
||||
"fileHash": "355ac42e",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/Overlay": {
|
||||
"src": "../../ol/Overlay.js",
|
||||
"file": "ol_Overlay.js",
|
||||
"fileHash": "fe4fef22",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/layer/Tile": {
|
||||
"src": "../../ol/layer/Tile.js",
|
||||
"file": "ol_layer_Tile.js",
|
||||
"fileHash": "e6defa38",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/layer/Group": {
|
||||
"src": "../../ol/layer/Group.js",
|
||||
"file": "ol_layer_Group.js",
|
||||
"fileHash": "b538c107",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/layer/Vector": {
|
||||
"src": "../../ol/layer/Vector.js",
|
||||
"file": "ol_layer_Vector.js",
|
||||
"fileHash": "88b2fe3b",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/source/Vector": {
|
||||
"src": "../../ol/source/Vector.js",
|
||||
"file": "ol_source_Vector.js",
|
||||
"fileHash": "f625949b",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/source/OSM": {
|
||||
"src": "../../ol/source/OSM.js",
|
||||
"file": "ol_source_OSM.js",
|
||||
"fileHash": "3b97b715",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/source/XYZ": {
|
||||
"src": "../../ol/source/XYZ.js",
|
||||
"file": "ol_source_XYZ.js",
|
||||
"fileHash": "7d8f852b",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/proj": {
|
||||
"src": "../../ol/proj.js",
|
||||
"file": "ol_proj.js",
|
||||
"fileHash": "bde13aba",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/geom": {
|
||||
"src": "../../ol/geom.js",
|
||||
"file": "ol_geom.js",
|
||||
"fileHash": "e4ded8a3",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/Feature": {
|
||||
"src": "../../ol/Feature.js",
|
||||
"file": "ol_Feature.js",
|
||||
"fileHash": "8ad86d7d",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/style": {
|
||||
"src": "../../ol/style.js",
|
||||
"file": "ol_style.js",
|
||||
"fileHash": "6029528e",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/LayerSwitcher": {
|
||||
"src": "../../ol-ext/control/LayerSwitcher.js",
|
||||
"file": "ol-ext_control_LayerSwitcher.js",
|
||||
"fileHash": "ba3fcba4",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/GeolocationButton": {
|
||||
"src": "../../ol-ext/control/GeolocationButton.js",
|
||||
"file": "ol-ext_control_GeolocationButton.js",
|
||||
"fileHash": "6e1e8c81",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/SearchNominatim": {
|
||||
"src": "../../ol-ext/control/SearchNominatim.js",
|
||||
"file": "ol-ext_control_SearchNominatim.js",
|
||||
"fileHash": "49a8e3f6",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/interaction": {
|
||||
"src": "../../ol/interaction.js",
|
||||
"file": "ol_interaction.js",
|
||||
"fileHash": "3b0cba52",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/layer": {
|
||||
"src": "../../ol/layer.js",
|
||||
"file": "ol_layer.js",
|
||||
"fileHash": "2f7ece85",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/source": {
|
||||
"src": "../../ol/source.js",
|
||||
"file": "ol_source.js",
|
||||
"fileHash": "55b243b7",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/sphere": {
|
||||
"src": "../../ol/sphere.js",
|
||||
"file": "ol_sphere.js",
|
||||
"fileHash": "17c5b65f",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/Observable": {
|
||||
"src": "../../ol/Observable.js",
|
||||
"file": "ol_Observable.js",
|
||||
"fileHash": "a1d95e20",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/Bar": {
|
||||
"src": "../../ol-ext/control/Bar.js",
|
||||
"file": "ol-ext_control_Bar.js",
|
||||
"fileHash": "9961a97b",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/Toggle": {
|
||||
"src": "../../ol-ext/control/Toggle.js",
|
||||
"file": "ol-ext_control_Toggle.js",
|
||||
"fileHash": "3716a205",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/Button": {
|
||||
"src": "../../ol-ext/control/Button.js",
|
||||
"file": "ol-ext_control_Button.js",
|
||||
"fileHash": "94db9999",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/format/GeoJSON": {
|
||||
"src": "../../ol/format/GeoJSON.js",
|
||||
"file": "ol_format_GeoJSON.js",
|
||||
"fileHash": "6ca0d734",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/control/EditBar": {
|
||||
"src": "../../ol-ext/control/EditBar.js",
|
||||
"file": "ol-ext_control_EditBar.js",
|
||||
"fileHash": "eaa0bfea",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/interaction/TouchCursor": {
|
||||
"src": "../../ol-ext/interaction/TouchCursor.js",
|
||||
"file": "ol-ext_interaction_TouchCursor.js",
|
||||
"fileHash": "a53deca0",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/interaction/ModifyFeature": {
|
||||
"src": "../../ol-ext/interaction/ModifyFeature.js",
|
||||
"file": "ol-ext_interaction_ModifyFeature.js",
|
||||
"fileHash": "50e7de35",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/interaction/Select": {
|
||||
"src": "../../ol/interaction/Select.js",
|
||||
"file": "ol_interaction_Select.js",
|
||||
"fileHash": "e3c3f813",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/events/condition": {
|
||||
"src": "../../ol/events/condition.js",
|
||||
"file": "ol_events_condition.js",
|
||||
"fileHash": "bdeed76d",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol-ext/interaction/UndoRedo": {
|
||||
"src": "../../ol-ext/interaction/UndoRedo.js",
|
||||
"file": "ol-ext_interaction_UndoRedo.js",
|
||||
"fileHash": "906faad5",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/geom/Polygon": {
|
||||
"src": "../../ol/geom/Polygon.js",
|
||||
"file": "ol_geom_Polygon.js",
|
||||
"fileHash": "c61e8553",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/control/ScaleLine": {
|
||||
"src": "../../ol/control/ScaleLine.js",
|
||||
"file": "ol_control_ScaleLine.js",
|
||||
"fileHash": "8cff3002",
|
||||
"needsInterop": false
|
||||
},
|
||||
"ol/format/WKT": {
|
||||
"src": "../../ol/format/WKT.js",
|
||||
"file": "ol_format_WKT.js",
|
||||
"fileHash": "c6bcdd8f",
|
||||
"needsInterop": false
|
||||
}
|
||||
},
|
||||
"chunks": {
|
||||
"lerc-YJMC4I3X": {
|
||||
"file": "lerc-YJMC4I3X.js"
|
||||
},
|
||||
"webimage-T4PTOJUP": {
|
||||
"file": "webimage-T4PTOJUP.js"
|
||||
},
|
||||
"decoder-FUDNTCPN": {
|
||||
"file": "decoder-FUDNTCPN.js"
|
||||
},
|
||||
"raw-UKC26CDE": {
|
||||
"file": "raw-UKC26CDE.js"
|
||||
},
|
||||
"lzw-7DRJSDK5": {
|
||||
"file": "lzw-7DRJSDK5.js"
|
||||
},
|
||||
"jpeg-HGEGG7HT": {
|
||||
"file": "jpeg-HGEGG7HT.js"
|
||||
},
|
||||
"deflate-IME5YE3D": {
|
||||
"file": "deflate-IME5YE3D.js"
|
||||
},
|
||||
"chunk-OVHVPML2": {
|
||||
"file": "chunk-OVHVPML2.js"
|
||||
},
|
||||
"packbits-F6QMWCFA": {
|
||||
"file": "packbits-F6QMWCFA.js"
|
||||
},
|
||||
"chunk-YNX27GDF": {
|
||||
"file": "chunk-YNX27GDF.js"
|
||||
},
|
||||
"chunk-3UNEODO2": {
|
||||
"file": "chunk-3UNEODO2.js"
|
||||
},
|
||||
"chunk-MEQVYVYE": {
|
||||
"file": "chunk-MEQVYVYE.js"
|
||||
},
|
||||
"chunk-6DXBPPKF": {
|
||||
"file": "chunk-6DXBPPKF.js"
|
||||
},
|
||||
"chunk-NNBJMTCH": {
|
||||
"file": "chunk-NNBJMTCH.js"
|
||||
},
|
||||
"chunk-QTABLK4X": {
|
||||
"file": "chunk-QTABLK4X.js"
|
||||
},
|
||||
"chunk-C5KGH6RQ": {
|
||||
"file": "chunk-C5KGH6RQ.js"
|
||||
},
|
||||
"chunk-3TN6D4MD": {
|
||||
"file": "chunk-3TN6D4MD.js"
|
||||
},
|
||||
"chunk-VCBXDRBT": {
|
||||
"file": "chunk-VCBXDRBT.js"
|
||||
},
|
||||
"chunk-NMUIRNIP": {
|
||||
"file": "chunk-NMUIRNIP.js"
|
||||
},
|
||||
"chunk-43GYE2V5": {
|
||||
"file": "chunk-43GYE2V5.js"
|
||||
},
|
||||
"chunk-PD2E5XZ4": {
|
||||
"file": "chunk-PD2E5XZ4.js"
|
||||
},
|
||||
"chunk-YUMATXXX": {
|
||||
"file": "chunk-YUMATXXX.js"
|
||||
},
|
||||
"chunk-E7S7Q7VV": {
|
||||
"file": "chunk-E7S7Q7VV.js"
|
||||
},
|
||||
"chunk-S3QBQTEW": {
|
||||
"file": "chunk-S3QBQTEW.js"
|
||||
},
|
||||
"chunk-V7WRBSQ6": {
|
||||
"file": "chunk-V7WRBSQ6.js"
|
||||
},
|
||||
"chunk-56VFHHUN": {
|
||||
"file": "chunk-56VFHHUN.js"
|
||||
},
|
||||
"chunk-W7BDJOQY": {
|
||||
"file": "chunk-W7BDJOQY.js"
|
||||
},
|
||||
"chunk-7JXPN73Q": {
|
||||
"file": "chunk-7JXPN73Q.js"
|
||||
},
|
||||
"chunk-E53S5GN6": {
|
||||
"file": "chunk-E53S5GN6.js"
|
||||
},
|
||||
"chunk-UNDFRJ2M": {
|
||||
"file": "chunk-UNDFRJ2M.js"
|
||||
},
|
||||
"chunk-T3TT2KJN": {
|
||||
"file": "chunk-T3TT2KJN.js"
|
||||
},
|
||||
"chunk-HM3IY3H4": {
|
||||
"file": "chunk-HM3IY3H4.js"
|
||||
},
|
||||
"chunk-JFXZSSOM": {
|
||||
"file": "chunk-JFXZSSOM.js"
|
||||
},
|
||||
"chunk-ZUI5NXIU": {
|
||||
"file": "chunk-ZUI5NXIU.js"
|
||||
},
|
||||
"chunk-I4Q72WOW": {
|
||||
"file": "chunk-I4Q72WOW.js"
|
||||
},
|
||||
"chunk-RTVPCGIJ": {
|
||||
"file": "chunk-RTVPCGIJ.js"
|
||||
},
|
||||
"chunk-MSWSBYBR": {
|
||||
"file": "chunk-MSWSBYBR.js"
|
||||
},
|
||||
"chunk-QCJTGAWF": {
|
||||
"file": "chunk-QCJTGAWF.js"
|
||||
},
|
||||
"chunk-CAVOO5JW": {
|
||||
"file": "chunk-CAVOO5JW.js"
|
||||
},
|
||||
"chunk-VRTURNK3": {
|
||||
"file": "chunk-VRTURNK3.js"
|
||||
},
|
||||
"chunk-2C73OZ6M": {
|
||||
"file": "chunk-2C73OZ6M.js"
|
||||
},
|
||||
"chunk-M5TTSD4C": {
|
||||
"file": "chunk-M5TTSD4C.js"
|
||||
},
|
||||
"chunk-ZCRXKB7J": {
|
||||
"file": "chunk-ZCRXKB7J.js"
|
||||
},
|
||||
"chunk-RW3V7S4F": {
|
||||
"file": "chunk-RW3V7S4F.js"
|
||||
},
|
||||
"chunk-PAB2HIXK": {
|
||||
"file": "chunk-PAB2HIXK.js"
|
||||
},
|
||||
"chunk-I6K7MRGV": {
|
||||
"file": "chunk-I6K7MRGV.js"
|
||||
},
|
||||
"chunk-PGWX4545": {
|
||||
"file": "chunk-PGWX4545.js"
|
||||
},
|
||||
"chunk-AYBYZSAV": {
|
||||
"file": "chunk-AYBYZSAV.js"
|
||||
},
|
||||
"chunk-YLJGUH5Z": {
|
||||
"file": "chunk-YLJGUH5Z.js"
|
||||
},
|
||||
"chunk-AZGMK675": {
|
||||
"file": "chunk-AZGMK675.js"
|
||||
},
|
||||
"chunk-C6SRSVJF": {
|
||||
"file": "chunk-C6SRSVJF.js"
|
||||
},
|
||||
"chunk-BHVDQB66": {
|
||||
"file": "chunk-BHVDQB66.js"
|
||||
},
|
||||
"chunk-6EWLK2BW": {
|
||||
"file": "chunk-6EWLK2BW.js"
|
||||
},
|
||||
"chunk-3ZDRPUXW": {
|
||||
"file": "chunk-3ZDRPUXW.js"
|
||||
},
|
||||
"chunk-6Y7C6NBJ": {
|
||||
"file": "chunk-6Y7C6NBJ.js"
|
||||
},
|
||||
"chunk-7XMWB3J4": {
|
||||
"file": "chunk-7XMWB3J4.js"
|
||||
},
|
||||
"chunk-5D2XPBR2": {
|
||||
"file": "chunk-5D2XPBR2.js"
|
||||
},
|
||||
"chunk-SHUBVYN4": {
|
||||
"file": "chunk-SHUBVYN4.js"
|
||||
},
|
||||
"chunk-FM44FOIC": {
|
||||
"file": "chunk-FM44FOIC.js"
|
||||
},
|
||||
"chunk-LMC3RO5P": {
|
||||
"file": "chunk-LMC3RO5P.js"
|
||||
},
|
||||
"chunk-X52LGBOS": {
|
||||
"file": "chunk-X52LGBOS.js"
|
||||
},
|
||||
"chunk-QFCIXVZ3": {
|
||||
"file": "chunk-QFCIXVZ3.js"
|
||||
},
|
||||
"chunk-A3RXLHYB": {
|
||||
"file": "chunk-A3RXLHYB.js"
|
||||
},
|
||||
"chunk-ZLPTRF2L": {
|
||||
"file": "chunk-ZLPTRF2L.js"
|
||||
},
|
||||
"chunk-54BTDBAD": {
|
||||
"file": "chunk-54BTDBAD.js"
|
||||
},
|
||||
"chunk-UPTVWZ45": {
|
||||
"file": "chunk-UPTVWZ45.js"
|
||||
},
|
||||
"chunk-5XHD7RSF": {
|
||||
"file": "chunk-5XHD7RSF.js"
|
||||
},
|
||||
"chunk-Q5ZULJHM": {
|
||||
"file": "chunk-Q5ZULJHM.js"
|
||||
},
|
||||
"chunk-NGFXCWUF": {
|
||||
"file": "chunk-NGFXCWUF.js"
|
||||
},
|
||||
"chunk-K25ZO44T": {
|
||||
"file": "chunk-K25ZO44T.js"
|
||||
},
|
||||
"chunk-SRXHWJOY": {
|
||||
"file": "chunk-SRXHWJOY.js"
|
||||
},
|
||||
"chunk-5RHQVMYD": {
|
||||
"file": "chunk-5RHQVMYD.js"
|
||||
},
|
||||
"chunk-DC5AMYBS": {
|
||||
"file": "chunk-DC5AMYBS.js"
|
||||
}
|
||||
}
|
||||
}
|
||||
5186
node_modules/.vite/deps/bootstrap.js
generated
vendored
7
node_modules/.vite/deps/bootstrap.js.map
generated
vendored
297
node_modules/.vite/deps/chunk-2C73OZ6M.js
generated
vendored
@ -1,297 +0,0 @@
|
||||
import {
|
||||
CollectionEventType_default,
|
||||
Collection_default
|
||||
} from "./chunk-M5TTSD4C.js";
|
||||
import {
|
||||
Base_default
|
||||
} from "./chunk-AYBYZSAV.js";
|
||||
import {
|
||||
assert
|
||||
} from "./chunk-QFCIXVZ3.js";
|
||||
import {
|
||||
ObjectEventType_default,
|
||||
getUid
|
||||
} from "./chunk-Q5ZULJHM.js";
|
||||
import {
|
||||
Event_default,
|
||||
listen,
|
||||
unlistenByKey
|
||||
} from "./chunk-NGFXCWUF.js";
|
||||
import {
|
||||
EventType_default
|
||||
} from "./chunk-K25ZO44T.js";
|
||||
import {
|
||||
getIntersection
|
||||
} from "./chunk-SRXHWJOY.js";
|
||||
import {
|
||||
clear
|
||||
} from "./chunk-5RHQVMYD.js";
|
||||
|
||||
// node_modules/ol/layer/Group.js
|
||||
var GroupEventType = {
|
||||
/**
|
||||
* Triggered when a layer is added
|
||||
* @event GroupEvent#addlayer
|
||||
* @api
|
||||
*/
|
||||
ADDLAYER: "addlayer",
|
||||
/**
|
||||
* Triggered when a layer is removed
|
||||
* @event GroupEvent#removelayer
|
||||
* @api
|
||||
*/
|
||||
REMOVELAYER: "removelayer"
|
||||
};
|
||||
var GroupEvent = class extends Event_default {
|
||||
/**
|
||||
* @param {GroupEventType} type The event type.
|
||||
* @param {BaseLayer} layer The layer.
|
||||
*/
|
||||
constructor(type, layer) {
|
||||
super(type);
|
||||
this.layer = layer;
|
||||
}
|
||||
};
|
||||
var Property = {
|
||||
LAYERS: "layers"
|
||||
};
|
||||
var LayerGroup = class _LayerGroup extends Base_default {
|
||||
/**
|
||||
* @param {Options} [options] Layer options.
|
||||
*/
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
const baseOptions = (
|
||||
/** @type {Options} */
|
||||
Object.assign({}, options)
|
||||
);
|
||||
delete baseOptions.layers;
|
||||
let layers = options.layers;
|
||||
super(baseOptions);
|
||||
this.on;
|
||||
this.once;
|
||||
this.un;
|
||||
this.layersListenerKeys_ = [];
|
||||
this.listenerKeys_ = {};
|
||||
this.addChangeListener(Property.LAYERS, this.handleLayersChanged_);
|
||||
if (layers) {
|
||||
if (Array.isArray(layers)) {
|
||||
layers = new Collection_default(layers.slice(), { unique: true });
|
||||
} else {
|
||||
assert(
|
||||
typeof /** @type {?} */
|
||||
layers.getArray === "function",
|
||||
"Expected `layers` to be an array or a `Collection`"
|
||||
);
|
||||
}
|
||||
} else {
|
||||
layers = new Collection_default(void 0, { unique: true });
|
||||
}
|
||||
this.setLayers(layers);
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleLayerChange_() {
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
handleLayersChanged_() {
|
||||
this.layersListenerKeys_.forEach(unlistenByKey);
|
||||
this.layersListenerKeys_.length = 0;
|
||||
const layers = this.getLayers();
|
||||
this.layersListenerKeys_.push(
|
||||
listen(layers, CollectionEventType_default.ADD, this.handleLayersAdd_, this),
|
||||
listen(
|
||||
layers,
|
||||
CollectionEventType_default.REMOVE,
|
||||
this.handleLayersRemove_,
|
||||
this
|
||||
)
|
||||
);
|
||||
for (const id in this.listenerKeys_) {
|
||||
this.listenerKeys_[id].forEach(unlistenByKey);
|
||||
}
|
||||
clear(this.listenerKeys_);
|
||||
const layersArray = layers.getArray();
|
||||
for (let i = 0, ii = layersArray.length; i < ii; i++) {
|
||||
const layer = layersArray[i];
|
||||
this.registerLayerListeners_(layer);
|
||||
this.dispatchEvent(new GroupEvent(GroupEventType.ADDLAYER, layer));
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* @param {BaseLayer} layer The layer.
|
||||
*/
|
||||
registerLayerListeners_(layer) {
|
||||
const listenerKeys = [
|
||||
listen(
|
||||
layer,
|
||||
ObjectEventType_default.PROPERTYCHANGE,
|
||||
this.handleLayerChange_,
|
||||
this
|
||||
),
|
||||
listen(layer, EventType_default.CHANGE, this.handleLayerChange_, this)
|
||||
];
|
||||
if (layer instanceof _LayerGroup) {
|
||||
listenerKeys.push(
|
||||
listen(layer, GroupEventType.ADDLAYER, this.handleLayerGroupAdd_, this),
|
||||
listen(
|
||||
layer,
|
||||
GroupEventType.REMOVELAYER,
|
||||
this.handleLayerGroupRemove_,
|
||||
this
|
||||
)
|
||||
);
|
||||
}
|
||||
this.listenerKeys_[getUid(layer)] = listenerKeys;
|
||||
}
|
||||
/**
|
||||
* @param {GroupEvent} event The layer group event.
|
||||
*/
|
||||
handleLayerGroupAdd_(event) {
|
||||
this.dispatchEvent(new GroupEvent(GroupEventType.ADDLAYER, event.layer));
|
||||
}
|
||||
/**
|
||||
* @param {GroupEvent} event The layer group event.
|
||||
*/
|
||||
handleLayerGroupRemove_(event) {
|
||||
this.dispatchEvent(new GroupEvent(GroupEventType.REMOVELAYER, event.layer));
|
||||
}
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
|
||||
* @private
|
||||
*/
|
||||
handleLayersAdd_(collectionEvent) {
|
||||
const layer = collectionEvent.element;
|
||||
this.registerLayerListeners_(layer);
|
||||
this.dispatchEvent(new GroupEvent(GroupEventType.ADDLAYER, layer));
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent<import("./Base.js").default>} collectionEvent CollectionEvent.
|
||||
* @private
|
||||
*/
|
||||
handleLayersRemove_(collectionEvent) {
|
||||
const layer = collectionEvent.element;
|
||||
const key = getUid(layer);
|
||||
this.listenerKeys_[key].forEach(unlistenByKey);
|
||||
delete this.listenerKeys_[key];
|
||||
this.dispatchEvent(new GroupEvent(GroupEventType.REMOVELAYER, layer));
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* Returns the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
||||
* in this group.
|
||||
* @return {!Collection<import("./Base.js").default>} Collection of
|
||||
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getLayers() {
|
||||
return (
|
||||
/** @type {!Collection<import("./Base.js").default>} */
|
||||
this.get(Property.LAYERS)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Set the {@link module:ol/Collection~Collection collection} of {@link module:ol/layer/Layer~Layer layers}
|
||||
* in this group.
|
||||
* @param {!Collection<import("./Base.js").default>} layers Collection of
|
||||
* {@link module:ol/layer/Base~BaseLayer layers} that are part of this group.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setLayers(layers) {
|
||||
const collection = this.getLayers();
|
||||
if (collection) {
|
||||
const currentLayers = collection.getArray();
|
||||
for (let i = 0, ii = currentLayers.length; i < ii; ++i) {
|
||||
this.dispatchEvent(
|
||||
new GroupEvent(GroupEventType.REMOVELAYER, currentLayers[i])
|
||||
);
|
||||
}
|
||||
}
|
||||
this.set(Property.LAYERS, layers);
|
||||
}
|
||||
/**
|
||||
* @param {Array<import("./Layer.js").default>} [array] Array of layers (to be modified in place).
|
||||
* @return {Array<import("./Layer.js").default>} Array of layers.
|
||||
* @override
|
||||
*/
|
||||
getLayersArray(array) {
|
||||
array = array !== void 0 ? array : [];
|
||||
this.getLayers().forEach(function(layer) {
|
||||
layer.getLayersArray(array);
|
||||
});
|
||||
return array;
|
||||
}
|
||||
/**
|
||||
* Get the layer states list and use this groups z-index as the default
|
||||
* for all layers in this and nested groups, if it is unset at this point.
|
||||
* If dest is not provided and this group's z-index is undefined
|
||||
* 0 is used a the default z-index.
|
||||
* @param {Array<import("./Layer.js").State>} [dest] Optional list
|
||||
* of layer states (to be modified in place).
|
||||
* @return {Array<import("./Layer.js").State>} List of layer states.
|
||||
* @override
|
||||
*/
|
||||
getLayerStatesArray(dest) {
|
||||
const states = dest !== void 0 ? dest : [];
|
||||
const pos = states.length;
|
||||
this.getLayers().forEach(function(layer) {
|
||||
layer.getLayerStatesArray(states);
|
||||
});
|
||||
const ownLayerState = this.getLayerState();
|
||||
let defaultZIndex = ownLayerState.zIndex;
|
||||
if (!dest && ownLayerState.zIndex === void 0) {
|
||||
defaultZIndex = 0;
|
||||
}
|
||||
for (let i = pos, ii = states.length; i < ii; i++) {
|
||||
const layerState = states[i];
|
||||
layerState.opacity *= ownLayerState.opacity;
|
||||
layerState.visible = layerState.visible && ownLayerState.visible;
|
||||
layerState.maxResolution = Math.min(
|
||||
layerState.maxResolution,
|
||||
ownLayerState.maxResolution
|
||||
);
|
||||
layerState.minResolution = Math.max(
|
||||
layerState.minResolution,
|
||||
ownLayerState.minResolution
|
||||
);
|
||||
layerState.minZoom = Math.max(layerState.minZoom, ownLayerState.minZoom);
|
||||
layerState.maxZoom = Math.min(layerState.maxZoom, ownLayerState.maxZoom);
|
||||
if (ownLayerState.extent !== void 0) {
|
||||
if (layerState.extent !== void 0) {
|
||||
layerState.extent = getIntersection(
|
||||
layerState.extent,
|
||||
ownLayerState.extent
|
||||
);
|
||||
} else {
|
||||
layerState.extent = ownLayerState.extent;
|
||||
}
|
||||
}
|
||||
if (layerState.zIndex === void 0) {
|
||||
layerState.zIndex = defaultZIndex;
|
||||
}
|
||||
}
|
||||
return states;
|
||||
}
|
||||
/**
|
||||
* @return {import("../source/Source.js").State} Source state.
|
||||
* @override
|
||||
*/
|
||||
getSourceState() {
|
||||
return "ready";
|
||||
}
|
||||
};
|
||||
var Group_default = LayerGroup;
|
||||
|
||||
export {
|
||||
GroupEvent,
|
||||
Group_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-2C73OZ6M.js.map
|
||||
7
node_modules/.vite/deps/chunk-2C73OZ6M.js.map
generated
vendored
77
node_modules/.vite/deps/chunk-3TN6D4MD.js
generated
vendored
@ -1,77 +0,0 @@
|
||||
import {
|
||||
ImageState_default,
|
||||
Image_default
|
||||
} from "./chunk-SHUBVYN4.js";
|
||||
|
||||
// node_modules/ol/ImageCanvas.js
|
||||
var ImageCanvas = class extends Image_default {
|
||||
/**
|
||||
* @param {import("./extent.js").Extent} extent Extent.
|
||||
* @param {number} resolution Resolution.
|
||||
* @param {number} pixelRatio Pixel ratio.
|
||||
* @param {HTMLCanvasElement|OffscreenCanvas} canvas Canvas.
|
||||
* @param {Loader} [loader] Optional loader function to
|
||||
* support asynchronous canvas drawing.
|
||||
*/
|
||||
constructor(extent, resolution, pixelRatio, canvas, loader) {
|
||||
const state = loader !== void 0 ? ImageState_default.IDLE : ImageState_default.LOADED;
|
||||
super(extent, resolution, pixelRatio, state);
|
||||
this.loader_ = loader !== void 0 ? loader : null;
|
||||
this.canvas_ = canvas;
|
||||
this.error_ = null;
|
||||
}
|
||||
/**
|
||||
* Get any error associated with asynchronous rendering.
|
||||
* @return {?Error} Any error that occurred during rendering.
|
||||
*/
|
||||
getError() {
|
||||
return this.error_;
|
||||
}
|
||||
/**
|
||||
* Handle async drawing complete.
|
||||
* @param {Error} [err] Any error during drawing.
|
||||
* @private
|
||||
*/
|
||||
handleLoad_(err) {
|
||||
if (err) {
|
||||
this.error_ = err;
|
||||
this.state = ImageState_default.ERROR;
|
||||
} else {
|
||||
this.state = ImageState_default.LOADED;
|
||||
}
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* Load not yet loaded URI.
|
||||
* @override
|
||||
*/
|
||||
load() {
|
||||
if (this.state == ImageState_default.IDLE) {
|
||||
this.state = ImageState_default.LOADING;
|
||||
this.changed();
|
||||
this.loader_(this.handleLoad_.bind(this));
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @return {HTMLCanvasElement|OffscreenCanvas} Canvas element.
|
||||
* @override
|
||||
*/
|
||||
getImage() {
|
||||
return this.canvas_;
|
||||
}
|
||||
};
|
||||
var ImageCanvas_default = ImageCanvas;
|
||||
|
||||
// node_modules/ol/resolution.js
|
||||
function fromResolutionLike(resolution) {
|
||||
if (Array.isArray(resolution)) {
|
||||
return Math.min(...resolution);
|
||||
}
|
||||
return resolution;
|
||||
}
|
||||
|
||||
export {
|
||||
ImageCanvas_default,
|
||||
fromResolutionLike
|
||||
};
|
||||
//# sourceMappingURL=chunk-3TN6D4MD.js.map
|
||||
7
node_modules/.vite/deps/chunk-3TN6D4MD.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/ImageCanvas.js", "../../ol/resolution.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/ImageCanvas\n */\nimport ImageWrapper from './Image.js';\nimport ImageState from './ImageState.js';\n\n/**\n * A function that is called to trigger asynchronous canvas drawing. It is\n * called with a \"done\" callback that should be called when drawing is done.\n * If any error occurs during drawing, the \"done\" callback should be called with\n * that error.\n *\n * @typedef {function(function(Error=): void): void} Loader\n */\n\nclass ImageCanvas extends ImageWrapper {\n /**\n * @param {import(\"./extent.js\").Extent} extent Extent.\n * @param {number} resolution Resolution.\n * @param {number} pixelRatio Pixel ratio.\n * @param {HTMLCanvasElement|OffscreenCanvas} canvas Canvas.\n * @param {Loader} [loader] Optional loader function to\n * support asynchronous canvas drawing.\n */\n constructor(extent, resolution, pixelRatio, canvas, loader) {\n const state = loader !== undefined ? ImageState.IDLE : ImageState.LOADED;\n\n super(extent, resolution, pixelRatio, state);\n\n /**\n * Optional canvas loader function.\n * @type {?Loader}\n * @private\n */\n this.loader_ = loader !== undefined ? loader : null;\n\n /**\n * @private\n * @type {HTMLCanvasElement|OffscreenCanvas}\n */\n this.canvas_ = canvas;\n\n /**\n * @private\n * @type {?Error}\n */\n this.error_ = null;\n }\n\n /**\n * Get any error associated with asynchronous rendering.\n * @return {?Error} Any error that occurred during rendering.\n */\n getError() {\n return this.error_;\n }\n\n /**\n * Handle async drawing complete.\n * @param {Error} [err] Any error during drawing.\n * @private\n */\n handleLoad_(err) {\n if (err) {\n this.error_ = err;\n this.state = ImageState.ERROR;\n } else {\n this.state = ImageState.LOADED;\n }\n this.changed();\n }\n\n /**\n * Load not yet loaded URI.\n * @override\n */\n load() {\n if (this.state == ImageState.IDLE) {\n this.state = ImageState.LOADING;\n this.changed();\n this.loader_(this.handleLoad_.bind(this));\n }\n }\n\n /**\n * @return {HTMLCanvasElement|OffscreenCanvas} Canvas element.\n * @override\n */\n getImage() {\n return this.canvas_;\n }\n}\n\nexport default ImageCanvas;\n", "/**\n * @module ol/resolution\n */\n\n/**\n * @typedef {number|Array<number>} ResolutionLike\n */\n\n/**\n * @param {ResolutionLike} resolution Resolution.\n * @return {number} Resolution.\n */\nexport function fromResolutionLike(resolution) {\n if (Array.isArray(resolution)) {\n return Math.min(...resolution);\n }\n return resolution;\n}\n"],
|
||||
"mappings": ";;;;;;AAeA,IAAM,cAAN,cAA0B,cAAa;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASrC,YAAY,QAAQ,YAAY,YAAY,QAAQ,QAAQ;AAC1D,UAAM,QAAQ,WAAW,SAAY,mBAAW,OAAO,mBAAW;AAElE,UAAM,QAAQ,YAAY,YAAY,KAAK;AAO3C,SAAK,UAAU,WAAW,SAAY,SAAS;AAM/C,SAAK,UAAU;AAMf,SAAK,SAAS;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW;AACT,WAAO,KAAK;AAAA,EACd;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,YAAY,KAAK;AACf,QAAI,KAAK;AACP,WAAK,SAAS;AACd,WAAK,QAAQ,mBAAW;AAAA,IAC1B,OAAO;AACL,WAAK,QAAQ,mBAAW;AAAA,IAC1B;AACA,SAAK,QAAQ;AAAA,EACf;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,OAAO;AACL,QAAI,KAAK,SAAS,mBAAW,MAAM;AACjC,WAAK,QAAQ,mBAAW;AACxB,WAAK,QAAQ;AACb,WAAK,QAAQ,KAAK,YAAY,KAAK,IAAI,CAAC;AAAA,IAC1C;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,WAAW;AACT,WAAO,KAAK;AAAA,EACd;AACF;AAEA,IAAO,sBAAQ;;;ACjFR,SAAS,mBAAmB,YAAY;AAC7C,MAAI,MAAM,QAAQ,UAAU,GAAG;AAC7B,WAAO,KAAK,IAAI,GAAG,UAAU;AAAA,EAC/B;AACA,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
270
node_modules/.vite/deps/chunk-3UNEODO2.js
generated
vendored
@ -1,270 +0,0 @@
|
||||
import {
|
||||
Circle_default,
|
||||
LineString_default,
|
||||
MultiLineString_default,
|
||||
MultiPolygon_default
|
||||
} from "./chunk-7JXPN73Q.js";
|
||||
import {
|
||||
Polygon_default
|
||||
} from "./chunk-AZGMK675.js";
|
||||
import {
|
||||
buffer
|
||||
} from "./chunk-SRXHWJOY.js";
|
||||
|
||||
// node_modules/ol-ext/geom/GeomUtils.js
|
||||
var ol_coordinate_dist2d = function(p1, p2) {
|
||||
var dx = p1[0] - p2[0];
|
||||
var dy = p1[1] - p2[1];
|
||||
return Math.sqrt(dx * dx + dy * dy);
|
||||
};
|
||||
var ol_coordinate_equal = function(p1, p2) {
|
||||
return p1[0] == p2[0] && p1[1] == p2[1];
|
||||
};
|
||||
var ol_coordinate_offsetCoords = function(coords, offset) {
|
||||
var path = [];
|
||||
var N = coords.length - 1;
|
||||
var max = N;
|
||||
var mi, mi1, li, li1, ri, ri1, si, si1, Xi1, Yi1;
|
||||
var p0, p1, p2;
|
||||
var isClosed = ol_coordinate_equal(coords[0], coords[N]);
|
||||
if (!isClosed) {
|
||||
p0 = coords[0];
|
||||
p1 = coords[1];
|
||||
p2 = [
|
||||
p0[0] + (p1[1] - p0[1]) / ol_coordinate_dist2d(p0, p1) * offset,
|
||||
p0[1] - (p1[0] - p0[0]) / ol_coordinate_dist2d(p0, p1) * offset
|
||||
];
|
||||
path.push(p2);
|
||||
coords.push(coords[N]);
|
||||
N++;
|
||||
max--;
|
||||
}
|
||||
for (var i = 0; i < max; i++) {
|
||||
p0 = coords[i];
|
||||
p1 = coords[(i + 1) % N];
|
||||
p2 = coords[(i + 2) % N];
|
||||
mi = (p1[1] - p0[1]) / (p1[0] - p0[0]);
|
||||
mi1 = (p2[1] - p1[1]) / (p2[0] - p1[0]);
|
||||
if (Math.abs(mi - mi1) > 1e-10) {
|
||||
li = Math.sqrt((p1[0] - p0[0]) * (p1[0] - p0[0]) + (p1[1] - p0[1]) * (p1[1] - p0[1]));
|
||||
li1 = Math.sqrt((p2[0] - p1[0]) * (p2[0] - p1[0]) + (p2[1] - p1[1]) * (p2[1] - p1[1]));
|
||||
ri = p0[0] + offset * (p1[1] - p0[1]) / li;
|
||||
ri1 = p1[0] + offset * (p2[1] - p1[1]) / li1;
|
||||
si = p0[1] - offset * (p1[0] - p0[0]) / li;
|
||||
si1 = p1[1] - offset * (p2[0] - p1[0]) / li1;
|
||||
Xi1 = (mi1 * ri1 - mi * ri + si - si1) / (mi1 - mi);
|
||||
Yi1 = (mi * mi1 * (ri1 - ri) + mi1 * si - mi * si1) / (mi1 - mi);
|
||||
if (p1[0] - p0[0] == 0) {
|
||||
Xi1 = p1[0] + offset * (p1[1] - p0[1]) / Math.abs(p1[1] - p0[1]);
|
||||
Yi1 = mi1 * Xi1 - mi1 * ri1 + si1;
|
||||
}
|
||||
if (p2[0] - p1[0] == 0) {
|
||||
Xi1 = p2[0] + offset * (p2[1] - p1[1]) / Math.abs(p2[1] - p1[1]);
|
||||
Yi1 = mi * Xi1 - mi * ri + si;
|
||||
}
|
||||
path.push([Xi1, Yi1]);
|
||||
}
|
||||
}
|
||||
if (isClosed) {
|
||||
path.push(path[0]);
|
||||
} else {
|
||||
coords.pop();
|
||||
p0 = coords[coords.length - 1];
|
||||
p1 = coords[coords.length - 2];
|
||||
p2 = [
|
||||
p0[0] - (p1[1] - p0[1]) / ol_coordinate_dist2d(p0, p1) * offset,
|
||||
p0[1] + (p1[0] - p0[0]) / ol_coordinate_dist2d(p0, p1) * offset
|
||||
];
|
||||
path.push(p2);
|
||||
}
|
||||
return path;
|
||||
};
|
||||
var ol_coordinate_findSegment = function(pt, coords) {
|
||||
for (var i = 0; i < coords.length - 1; i++) {
|
||||
var p0 = coords[i];
|
||||
var p1 = coords[i + 1];
|
||||
if (ol_coordinate_equal(pt, p0) || ol_coordinate_equal(pt, p1)) {
|
||||
return { index: 1, segment: [p0, p1] };
|
||||
} else {
|
||||
var d0 = ol_coordinate_dist2d(p0, p1);
|
||||
var v0 = [(p1[0] - p0[0]) / d0, (p1[1] - p0[1]) / d0];
|
||||
var d1 = ol_coordinate_dist2d(p0, pt);
|
||||
var v1 = [(pt[0] - p0[0]) / d1, (pt[1] - p0[1]) / d1];
|
||||
if (Math.abs(v0[0] * v1[1] - v0[1] * v1[0]) < 1e-10) {
|
||||
return { index: 1, segment: [p0, p1] };
|
||||
}
|
||||
}
|
||||
}
|
||||
return { index: -1 };
|
||||
};
|
||||
var ol_extent_intersection;
|
||||
(function() {
|
||||
function splitX(pts, x) {
|
||||
var pt;
|
||||
for (let i = pts.length - 1; i > 0; i--) {
|
||||
if (pts[i][0] > x && pts[i - 1][0] < x || pts[i][0] < x && pts[i - 1][0] > x) {
|
||||
pt = [x, (x - pts[i][0]) / (pts[i - 1][0] - pts[i][0]) * (pts[i - 1][1] - pts[i][1]) + pts[i][1]];
|
||||
pts.splice(i, 0, pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
function splitY(pts, y) {
|
||||
var pt;
|
||||
for (let i = pts.length - 1; i > 0; i--) {
|
||||
if (pts[i][1] > y && pts[i - 1][1] < y || pts[i][1] < y && pts[i - 1][1] > y) {
|
||||
pt = [(y - pts[i][1]) / (pts[i - 1][1] - pts[i][1]) * (pts[i - 1][0] - pts[i][0]) + pts[i][0], y];
|
||||
pts.splice(i, 0, pt);
|
||||
}
|
||||
}
|
||||
}
|
||||
ol_extent_intersection = function(extent, polygon) {
|
||||
var poly = polygon.getType() === "Polygon";
|
||||
if (!poly && polygon.getType() !== "MultiPolygon") return null;
|
||||
var geom = polygon.getCoordinates();
|
||||
if (poly) geom = [geom];
|
||||
geom.forEach(function(g) {
|
||||
g.forEach(function(c) {
|
||||
splitX(c, extent[0]);
|
||||
splitX(c, extent[2]);
|
||||
splitY(c, extent[1]);
|
||||
splitY(c, extent[3]);
|
||||
});
|
||||
});
|
||||
geom.forEach(function(g) {
|
||||
g.forEach(function(c) {
|
||||
c.forEach(function(p) {
|
||||
if (p[0] < extent[0]) p[0] = extent[0];
|
||||
else if (p[0] > extent[2]) p[0] = extent[2];
|
||||
if (p[1] < extent[1]) p[1] = extent[1];
|
||||
else if (p[1] > extent[3]) p[1] = extent[3];
|
||||
});
|
||||
});
|
||||
});
|
||||
if (poly) {
|
||||
return new Polygon_default(geom[0]);
|
||||
} else {
|
||||
return new MultiPolygon_default(geom);
|
||||
}
|
||||
};
|
||||
})();
|
||||
var ol_coordinate_sampleAt = function(p1, p2, d, start) {
|
||||
var pts = [];
|
||||
if (start !== false) pts.push(p1);
|
||||
var dl = ol_coordinate_dist2d(p1, p2);
|
||||
if (dl) {
|
||||
var nb = Math.round(dl / d);
|
||||
if (nb > 1) {
|
||||
var dx = (p2[0] - p1[0]) / nb;
|
||||
var dy = (p2[1] - p1[1]) / nb;
|
||||
for (var i = 1; i < nb; i++) {
|
||||
pts.push([p1[0] + dx * i, p1[1] + dy * i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
pts.push(p2);
|
||||
return pts;
|
||||
};
|
||||
LineString_default.prototype.sampleAt = function(d) {
|
||||
var line = this.getCoordinates();
|
||||
var result = [];
|
||||
for (var i = 1; i < line.length; i++) {
|
||||
result = result.concat(ol_coordinate_sampleAt(line[i - 1], line[i], d, i === 1));
|
||||
}
|
||||
return new LineString_default(result);
|
||||
};
|
||||
MultiLineString_default.prototype.sampleAt = function(d) {
|
||||
var lines = this.getCoordinates();
|
||||
var result = [];
|
||||
lines.forEach(function(p) {
|
||||
var l = [];
|
||||
for (var i = 1; i < p.length; i++) {
|
||||
l = l.concat(ol_coordinate_sampleAt(p[i - 1], p[i], d, i === 1));
|
||||
}
|
||||
result.push(l);
|
||||
});
|
||||
return new MultiLineString_default(result);
|
||||
};
|
||||
Polygon_default.prototype.sampleAt = function(res) {
|
||||
var poly = this.getCoordinates();
|
||||
var result = [];
|
||||
poly.forEach(function(p) {
|
||||
var l = [];
|
||||
for (var i = 1; i < p.length; i++) {
|
||||
l = l.concat(ol_coordinate_sampleAt(p[i - 1], p[i], res, i === 1));
|
||||
}
|
||||
result.push(l);
|
||||
});
|
||||
return new Polygon_default(result);
|
||||
};
|
||||
MultiPolygon_default.prototype.sampleAt = function(res) {
|
||||
var mpoly = this.getCoordinates();
|
||||
var result = [];
|
||||
mpoly.forEach(function(poly) {
|
||||
var a = [];
|
||||
result.push(a);
|
||||
poly.forEach(function(p) {
|
||||
var l = [];
|
||||
for (var i = 1; i < p.length; i++) {
|
||||
l = l.concat(ol_coordinate_sampleAt(p[i - 1], p[i], res, i === 1));
|
||||
}
|
||||
a.push(l);
|
||||
});
|
||||
});
|
||||
return new MultiPolygon_default(result);
|
||||
};
|
||||
Circle_default.prototype.intersection = function(geom, resolution) {
|
||||
if (geom.sampleAt) {
|
||||
var ext = buffer(this.getCenter().concat(this.getCenter()), this.getRadius());
|
||||
geom = ol_extent_intersection(ext, geom);
|
||||
geom = geom.simplify(resolution);
|
||||
var c = this.getCenter();
|
||||
var r = this.getRadius();
|
||||
var g = geom.sampleAt(resolution).getCoordinates();
|
||||
switch (geom.getType()) {
|
||||
case "Polygon":
|
||||
g = [g];
|
||||
// fallthrough
|
||||
case "MultiPolygon": {
|
||||
var hasout = false;
|
||||
var result = [];
|
||||
g.forEach(function(poly) {
|
||||
var a = [];
|
||||
result.push(a);
|
||||
poly.forEach(function(ring) {
|
||||
var l = [];
|
||||
a.push(l);
|
||||
ring.forEach(function(p) {
|
||||
var d = ol_coordinate_dist2d(c, p);
|
||||
if (d > r) {
|
||||
hasout = true;
|
||||
l.push([
|
||||
c[0] + r / d * (p[0] - c[0]),
|
||||
c[1] + r / d * (p[1] - c[1])
|
||||
]);
|
||||
} else {
|
||||
l.push(p);
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
if (!hasout) return geom;
|
||||
if (geom.getType() === "Polygon") {
|
||||
return new Polygon_default(result[0]);
|
||||
} else {
|
||||
return new MultiPolygon_default(result);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.warn("[ol/geom/Circle~intersection] Unsupported geometry type: " + geom.getType());
|
||||
}
|
||||
return geom;
|
||||
};
|
||||
|
||||
export {
|
||||
ol_coordinate_dist2d,
|
||||
ol_coordinate_equal,
|
||||
ol_coordinate_offsetCoords,
|
||||
ol_coordinate_findSegment
|
||||
};
|
||||
//# sourceMappingURL=chunk-3UNEODO2.js.map
|
||||
7
node_modules/.vite/deps/chunk-3UNEODO2.js.map
generated
vendored
1408
node_modules/.vite/deps/chunk-3ZDRPUXW.js
generated
vendored
7
node_modules/.vite/deps/chunk-3ZDRPUXW.js.map
generated
vendored
59
node_modules/.vite/deps/chunk-43GYE2V5.js
generated
vendored
@ -1,59 +0,0 @@
|
||||
import {
|
||||
XYZ_default,
|
||||
defaultTileLoadFunction
|
||||
} from "./chunk-3ZDRPUXW.js";
|
||||
import {
|
||||
WORKER_OFFSCREEN_CANVAS
|
||||
} from "./chunk-5XHD7RSF.js";
|
||||
|
||||
// node_modules/ol/source/OSM.js
|
||||
var ATTRIBUTION = '© <a href="https://www.openstreetmap.org/copyright" target="_blank">OpenStreetMap</a> contributors.';
|
||||
var OSM = class extends XYZ_default {
|
||||
/**
|
||||
* @param {Options} [options] Open Street Map options.
|
||||
*/
|
||||
constructor(options) {
|
||||
options = options || {};
|
||||
let attributions;
|
||||
if (options.attributions !== void 0) {
|
||||
attributions = options.attributions;
|
||||
} else {
|
||||
attributions = [ATTRIBUTION];
|
||||
}
|
||||
const crossOrigin = options.crossOrigin !== void 0 ? options.crossOrigin : "anonymous";
|
||||
const url = options.url !== void 0 ? options.url : "https://tile.openstreetmap.org/{z}/{x}/{y}.png";
|
||||
super({
|
||||
attributions,
|
||||
attributionsCollapsible: false,
|
||||
cacheSize: options.cacheSize,
|
||||
crossOrigin,
|
||||
interpolate: options.interpolate,
|
||||
maxZoom: options.maxZoom !== void 0 ? options.maxZoom : 19,
|
||||
reprojectionErrorThreshold: options.reprojectionErrorThreshold,
|
||||
tileLoadFunction: (
|
||||
/**
|
||||
* @param {import("../ImageTile.js").default} tile Image tile
|
||||
* @param {string} src Image src
|
||||
*/
|
||||
(tile, src) => {
|
||||
const image = tile.getImage();
|
||||
if (!WORKER_OFFSCREEN_CANVAS && image instanceof HTMLImageElement) {
|
||||
image.referrerPolicy = "origin-when-cross-origin";
|
||||
}
|
||||
(options.tileLoadFunction || defaultTileLoadFunction)(tile, src);
|
||||
}
|
||||
),
|
||||
transition: options.transition,
|
||||
url,
|
||||
wrapX: options.wrapX,
|
||||
zDirection: options.zDirection
|
||||
});
|
||||
}
|
||||
};
|
||||
var OSM_default = OSM;
|
||||
|
||||
export {
|
||||
ATTRIBUTION,
|
||||
OSM_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-43GYE2V5.js.map
|
||||
7
node_modules/.vite/deps/chunk-43GYE2V5.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/source/OSM.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/source/OSM\n */\n\nimport {WORKER_OFFSCREEN_CANVAS} from '../has.js';\nimport {defaultTileLoadFunction} from './TileImage.js';\nimport XYZ from './XYZ.js';\n\n/**\n * The attribution containing a link to the OpenStreetMap Copyright and License\n * page.\n * @const\n * @type {string}\n * @api\n */\nexport const ATTRIBUTION =\n '© ' +\n '<a href=\"https://www.openstreetmap.org/copyright\" target=\"_blank\">OpenStreetMap</a> ' +\n 'contributors.';\n\n/**\n * @typedef {Object} Options\n * @property {import(\"./Source.js\").AttributionLike} [attributions] Attributions.\n * @property {number} [cacheSize] Deprecated. Use the cacheSize option on the layer instead.\n * @property {null|string} [crossOrigin='anonymous'] The `crossOrigin` attribute for loaded images. Note that\n * you must provide a `crossOrigin` value if you want to access pixel data with the Canvas renderer.\n * See https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image for more detail.\n * @property {boolean} [interpolate=true] Use interpolated values when resampling. By default,\n * linear interpolation is used when resampling. Set to false to use the nearest neighbor instead.\n * @property {number} [maxZoom=19] Max zoom.\n * @property {number} [reprojectionErrorThreshold=0.5] Maximum allowed reprojection error (in pixels).\n * Higher values can increase reprojection performance, but decrease precision.\n * @property {import(\"../Tile.js\").LoadFunction} [tileLoadFunction] Optional function to load a tile given a URL. The default is\n * ```js\n * function(imageTile, src) {\n * imageTile.getImage().src = src;\n * };\n * ```\n * @property {number} [transition=250] Duration of the opacity transition for rendering.\n * To disable the opacity transition, pass `transition: 0`.\n * @property {string} [url='https://tile.openstreetmap.org/{z}/{x}/{y}.png'] URL template.\n * Must include `{x}`, `{y}` or `{-y}`, and `{z}` placeholders.\n * @property {boolean} [wrapX=true] Whether to wrap the world horizontally.\n * @property {number|import(\"../array.js\").NearestDirectionFunction} [zDirection=0]\n * Choose whether to use tiles with a higher or lower zoom level when between integer\n * zoom levels. See {@link module:ol/tilegrid/TileGrid~TileGrid#getZForResolution}.\n */\n\n/**\n * @classdesc\n * Layer source for the OpenStreetMap tile server.\n * @api\n */\nclass OSM extends XYZ {\n /**\n * @param {Options} [options] Open Street Map options.\n */\n constructor(options) {\n options = options || {};\n\n let attributions;\n if (options.attributions !== undefined) {\n attributions = options.attributions;\n } else {\n attributions = [ATTRIBUTION];\n }\n\n const crossOrigin =\n options.crossOrigin !== undefined ? options.crossOrigin : 'anonymous';\n\n const url =\n options.url !== undefined\n ? options.url\n : 'https://tile.openstreetmap.org/{z}/{x}/{y}.png';\n\n super({\n attributions: attributions,\n attributionsCollapsible: false,\n cacheSize: options.cacheSize,\n crossOrigin: crossOrigin,\n interpolate: options.interpolate,\n maxZoom: options.maxZoom !== undefined ? options.maxZoom : 19,\n reprojectionErrorThreshold: options.reprojectionErrorThreshold,\n tileLoadFunction:\n /**\n * @param {import(\"../ImageTile.js\").default} tile Image tile\n * @param {string} src Image src\n */\n (tile, src) => {\n const image = tile.getImage();\n // FIXME referrer policy for worker fetch requests\n if (!WORKER_OFFSCREEN_CANVAS && image instanceof HTMLImageElement) {\n image.referrerPolicy = 'origin-when-cross-origin';\n }\n (options.tileLoadFunction || defaultTileLoadFunction)(tile, src);\n },\n transition: options.transition,\n url: url,\n wrapX: options.wrapX,\n zDirection: options.zDirection,\n });\n }\n}\n\nexport default OSM;\n"],
|
||||
"mappings": ";;;;;;;;;AAeO,IAAM,cACX;AAqCF,IAAM,MAAN,cAAkB,YAAI;AAAA;AAAA;AAAA;AAAA,EAIpB,YAAY,SAAS;AACnB,cAAU,WAAW,CAAC;AAEtB,QAAI;AACJ,QAAI,QAAQ,iBAAiB,QAAW;AACtC,qBAAe,QAAQ;AAAA,IACzB,OAAO;AACL,qBAAe,CAAC,WAAW;AAAA,IAC7B;AAEA,UAAM,cACJ,QAAQ,gBAAgB,SAAY,QAAQ,cAAc;AAE5D,UAAM,MACJ,QAAQ,QAAQ,SACZ,QAAQ,MACR;AAEN,UAAM;AAAA,MACJ;AAAA,MACA,yBAAyB;AAAA,MACzB,WAAW,QAAQ;AAAA,MACnB;AAAA,MACA,aAAa,QAAQ;AAAA,MACrB,SAAS,QAAQ,YAAY,SAAY,QAAQ,UAAU;AAAA,MAC3D,4BAA4B,QAAQ;AAAA,MACpC;AAAA;AAAA;AAAA;AAAA;AAAA,QAKE,CAAC,MAAM,QAAQ;AACb,gBAAM,QAAQ,KAAK,SAAS;AAE5B,cAAI,CAAC,2BAA2B,iBAAiB,kBAAkB;AACjE,kBAAM,iBAAiB;AAAA,UACzB;AACA,WAAC,QAAQ,oBAAoB,yBAAyB,MAAM,GAAG;AAAA,QACjE;AAAA;AAAA,MACF,YAAY,QAAQ;AAAA,MACpB;AAAA,MACA,OAAO,QAAQ;AAAA,MACf,YAAY,QAAQ;AAAA,IACtB,CAAC;AAAA,EACH;AACF;AAEA,IAAO,cAAQ;",
|
||||
"names": []
|
||||
}
|
||||
112
node_modules/.vite/deps/chunk-54BTDBAD.js
generated
vendored
@ -1,112 +0,0 @@
|
||||
// node_modules/ol/math.js
|
||||
function clamp(value, min, max) {
|
||||
return Math.min(Math.max(value, min), max);
|
||||
}
|
||||
function squaredSegmentDistance(x, y, x1, y1, x2, y2) {
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
if (dx !== 0 || dy !== 0) {
|
||||
const t = ((x - x1) * dx + (y - y1) * dy) / (dx * dx + dy * dy);
|
||||
if (t > 1) {
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
} else if (t > 0) {
|
||||
x1 += dx * t;
|
||||
y1 += dy * t;
|
||||
}
|
||||
}
|
||||
return squaredDistance(x, y, x1, y1);
|
||||
}
|
||||
function squaredDistance(x1, y1, x2, y2) {
|
||||
const dx = x2 - x1;
|
||||
const dy = y2 - y1;
|
||||
return dx * dx + dy * dy;
|
||||
}
|
||||
function solveLinearSystem(mat) {
|
||||
const n = mat.length;
|
||||
for (let i = 0; i < n; i++) {
|
||||
let maxRow = i;
|
||||
let maxEl = Math.abs(mat[i][i]);
|
||||
for (let r = i + 1; r < n; r++) {
|
||||
const absValue = Math.abs(mat[r][i]);
|
||||
if (absValue > maxEl) {
|
||||
maxEl = absValue;
|
||||
maxRow = r;
|
||||
}
|
||||
}
|
||||
if (maxEl === 0) {
|
||||
return null;
|
||||
}
|
||||
const tmp = mat[maxRow];
|
||||
mat[maxRow] = mat[i];
|
||||
mat[i] = tmp;
|
||||
for (let j = i + 1; j < n; j++) {
|
||||
const coef = -mat[j][i] / mat[i][i];
|
||||
for (let k = i; k < n + 1; k++) {
|
||||
if (i == k) {
|
||||
mat[j][k] = 0;
|
||||
} else {
|
||||
mat[j][k] += coef * mat[i][k];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const x = new Array(n);
|
||||
for (let l = n - 1; l >= 0; l--) {
|
||||
x[l] = mat[l][n] / mat[l][l];
|
||||
for (let m = l - 1; m >= 0; m--) {
|
||||
mat[m][n] -= mat[m][l] * x[l];
|
||||
}
|
||||
}
|
||||
return x;
|
||||
}
|
||||
function toDegrees(angleInRadians) {
|
||||
return angleInRadians * 180 / Math.PI;
|
||||
}
|
||||
function toRadians(angleInDegrees) {
|
||||
return angleInDegrees * Math.PI / 180;
|
||||
}
|
||||
function modulo(a, b) {
|
||||
const r = a % b;
|
||||
return r * b < 0 ? r + b : r;
|
||||
}
|
||||
function lerp(a, b, x) {
|
||||
return a + x * (b - a);
|
||||
}
|
||||
function toFixed(n, decimals) {
|
||||
const factor = Math.pow(10, decimals);
|
||||
return Math.round(n * factor) / factor;
|
||||
}
|
||||
function round(n, decimals) {
|
||||
return Math.round(toFixed(n, decimals));
|
||||
}
|
||||
function floor(n, decimals) {
|
||||
return Math.floor(toFixed(n, decimals));
|
||||
}
|
||||
function ceil(n, decimals) {
|
||||
return Math.ceil(toFixed(n, decimals));
|
||||
}
|
||||
function wrap(n, min, max) {
|
||||
if (n >= min && n < max) {
|
||||
return n;
|
||||
}
|
||||
const range = max - min;
|
||||
return ((n - min) % range + range) % range + min;
|
||||
}
|
||||
|
||||
export {
|
||||
clamp,
|
||||
squaredSegmentDistance,
|
||||
squaredDistance,
|
||||
solveLinearSystem,
|
||||
toDegrees,
|
||||
toRadians,
|
||||
modulo,
|
||||
lerp,
|
||||
toFixed,
|
||||
round,
|
||||
floor,
|
||||
ceil,
|
||||
wrap
|
||||
};
|
||||
//# sourceMappingURL=chunk-54BTDBAD.js.map
|
||||
7
node_modules/.vite/deps/chunk-54BTDBAD.js.map
generated
vendored
276
node_modules/.vite/deps/chunk-56VFHHUN.js
generated
vendored
@ -1,276 +0,0 @@
|
||||
import {
|
||||
Feature_default as Feature_default2
|
||||
} from "./chunk-W7BDJOQY.js";
|
||||
import {
|
||||
GeometryCollection_default,
|
||||
LineString_default,
|
||||
MultiLineString_default,
|
||||
MultiPoint_default,
|
||||
MultiPolygon_default
|
||||
} from "./chunk-7JXPN73Q.js";
|
||||
import {
|
||||
Feature_default
|
||||
} from "./chunk-E53S5GN6.js";
|
||||
import {
|
||||
Point_default,
|
||||
Polygon_default,
|
||||
linearRingsAreOriented,
|
||||
linearRingssAreOriented,
|
||||
orientLinearRings,
|
||||
orientLinearRingsArray
|
||||
} from "./chunk-AZGMK675.js";
|
||||
import {
|
||||
equivalent,
|
||||
get,
|
||||
getTransform
|
||||
} from "./chunk-A3RXLHYB.js";
|
||||
import {
|
||||
abstract
|
||||
} from "./chunk-Q5ZULJHM.js";
|
||||
|
||||
// node_modules/ol/format/Feature.js
|
||||
var FeatureFormat = class {
|
||||
constructor() {
|
||||
this.dataProjection = void 0;
|
||||
this.defaultFeatureProjection = void 0;
|
||||
this.featureClass = /** @type {FeatureToFeatureClass<FeatureType>} */
|
||||
Feature_default;
|
||||
this.supportedMediaTypes = null;
|
||||
}
|
||||
/**
|
||||
* Adds the data projection to the read options.
|
||||
* @param {Document|Element|Object|string} source Source.
|
||||
* @param {ReadOptions} [options] Options.
|
||||
* @return {ReadOptions|undefined} Options.
|
||||
* @protected
|
||||
*/
|
||||
getReadOptions(source, options) {
|
||||
if (options) {
|
||||
let dataProjection = options.dataProjection ? get(options.dataProjection) : this.readProjection(source);
|
||||
if (options.extent && dataProjection && dataProjection.getUnits() === "tile-pixels") {
|
||||
dataProjection = get(dataProjection);
|
||||
dataProjection.setWorldExtent(options.extent);
|
||||
}
|
||||
options = {
|
||||
dataProjection,
|
||||
featureProjection: options.featureProjection
|
||||
};
|
||||
}
|
||||
return this.adaptOptions(options);
|
||||
}
|
||||
/**
|
||||
* Sets the `dataProjection` on the options, if no `dataProjection`
|
||||
* is set.
|
||||
* @param {WriteOptions|ReadOptions|undefined} options
|
||||
* Options.
|
||||
* @protected
|
||||
* @return {WriteOptions|ReadOptions|undefined}
|
||||
* Updated options.
|
||||
*/
|
||||
adaptOptions(options) {
|
||||
return Object.assign(
|
||||
{
|
||||
dataProjection: this.dataProjection,
|
||||
featureProjection: this.defaultFeatureProjection,
|
||||
featureClass: this.featureClass
|
||||
},
|
||||
options
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @abstract
|
||||
* @return {Type} The format type.
|
||||
*/
|
||||
getType() {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Read a single feature from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Element|Object|string} source Source.
|
||||
* @param {ReadOptions} [options] Read options.
|
||||
* @return {FeatureType|Array<FeatureType>} Feature.
|
||||
*/
|
||||
readFeature(source, options) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Read all features from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Element|ArrayBuffer|Object|string} source Source.
|
||||
* @param {ReadOptions} [options] Read options.
|
||||
* @return {Array<FeatureType>} Features.
|
||||
*/
|
||||
readFeatures(source, options) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Read a single geometry from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Element|Object|string} source Source.
|
||||
* @param {ReadOptions} [options] Read options.
|
||||
* @return {import("../geom/Geometry.js").default} Geometry.
|
||||
*/
|
||||
readGeometry(source, options) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Read the projection from a source.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Document|Element|Object|string} source Source.
|
||||
* @return {import("../proj/Projection.js").default|undefined} Projection.
|
||||
*/
|
||||
readProjection(source) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Encode a feature in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Feature} feature Feature.
|
||||
* @param {WriteOptions} [options] Write options.
|
||||
* @return {string|ArrayBuffer} Result.
|
||||
*/
|
||||
writeFeature(feature, options) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Encode an array of features in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {Array<Feature>} features Features.
|
||||
* @param {WriteOptions} [options] Write options.
|
||||
* @return {string|ArrayBuffer} Result.
|
||||
*/
|
||||
writeFeatures(features, options) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Write a single geometry in this format.
|
||||
*
|
||||
* @abstract
|
||||
* @param {import("../geom/Geometry.js").default} geometry Geometry.
|
||||
* @param {WriteOptions} [options] Write options.
|
||||
* @return {string|ArrayBuffer} Result.
|
||||
*/
|
||||
writeGeometry(geometry, options) {
|
||||
return abstract();
|
||||
}
|
||||
};
|
||||
var Feature_default3 = FeatureFormat;
|
||||
function transformGeometryWithOptions(geometry, write, options) {
|
||||
const featureProjection = options ? get(options.featureProjection) : null;
|
||||
const dataProjection = options ? get(options.dataProjection) : null;
|
||||
let transformed = geometry;
|
||||
if (featureProjection && dataProjection && !equivalent(featureProjection, dataProjection)) {
|
||||
if (write) {
|
||||
transformed = /** @type {T} */
|
||||
geometry.clone();
|
||||
}
|
||||
const fromProjection = write ? featureProjection : dataProjection;
|
||||
const toProjection = write ? dataProjection : featureProjection;
|
||||
if (fromProjection.getUnits() === "tile-pixels") {
|
||||
transformed.transform(fromProjection, toProjection);
|
||||
} else {
|
||||
transformed.applyTransform(getTransform(fromProjection, toProjection));
|
||||
}
|
||||
}
|
||||
if (write && options && /** @type {WriteOptions} */
|
||||
options.decimals !== void 0) {
|
||||
const power = Math.pow(
|
||||
10,
|
||||
/** @type {WriteOptions} */
|
||||
options.decimals
|
||||
);
|
||||
const transform = function(coordinates) {
|
||||
for (let i = 0, ii = coordinates.length; i < ii; ++i) {
|
||||
coordinates[i] = Math.round(coordinates[i] * power) / power;
|
||||
}
|
||||
return coordinates;
|
||||
};
|
||||
if (transformed === geometry) {
|
||||
transformed = /** @type {T} */
|
||||
geometry.clone();
|
||||
}
|
||||
transformed.applyTransform(transform);
|
||||
}
|
||||
return transformed;
|
||||
}
|
||||
var GeometryConstructor = {
|
||||
Point: Point_default,
|
||||
LineString: LineString_default,
|
||||
Polygon: Polygon_default,
|
||||
MultiPoint: MultiPoint_default,
|
||||
MultiLineString: MultiLineString_default,
|
||||
MultiPolygon: MultiPolygon_default
|
||||
};
|
||||
function orientFlatCoordinates(flatCoordinates, ends, stride) {
|
||||
if (Array.isArray(ends[0])) {
|
||||
if (!linearRingssAreOriented(flatCoordinates, 0, ends, stride)) {
|
||||
flatCoordinates = flatCoordinates.slice();
|
||||
orientLinearRingsArray(flatCoordinates, 0, ends, stride);
|
||||
}
|
||||
return flatCoordinates;
|
||||
}
|
||||
if (!linearRingsAreOriented(flatCoordinates, 0, ends, stride)) {
|
||||
flatCoordinates = flatCoordinates.slice();
|
||||
orientLinearRings(flatCoordinates, 0, ends, stride);
|
||||
}
|
||||
return flatCoordinates;
|
||||
}
|
||||
function createRenderFeature(object, options) {
|
||||
var _a;
|
||||
const geometry = object.geometry;
|
||||
if (!geometry) {
|
||||
return [];
|
||||
}
|
||||
if (Array.isArray(geometry)) {
|
||||
return geometry.map((geometry2) => createRenderFeature({ ...object, geometry: geometry2 })).flat();
|
||||
}
|
||||
const geometryType = geometry.type === "MultiPolygon" ? "Polygon" : geometry.type;
|
||||
if (geometryType === "GeometryCollection" || geometryType === "Circle") {
|
||||
throw new Error("Unsupported geometry type: " + geometryType);
|
||||
}
|
||||
const stride = geometry.layout.length;
|
||||
return transformGeometryWithOptions(
|
||||
new Feature_default2(
|
||||
geometryType,
|
||||
geometryType === "Polygon" ? orientFlatCoordinates(geometry.flatCoordinates, geometry.ends, stride) : geometry.flatCoordinates,
|
||||
(_a = geometry.ends) == null ? void 0 : _a.flat(),
|
||||
stride,
|
||||
object.properties || {},
|
||||
object.id
|
||||
).enableSimplifyTransformed(),
|
||||
false,
|
||||
options
|
||||
);
|
||||
}
|
||||
function createGeometry(object, options) {
|
||||
if (!object) {
|
||||
return null;
|
||||
}
|
||||
if (Array.isArray(object)) {
|
||||
const geometries = object.map(
|
||||
(geometry) => createGeometry(geometry, options)
|
||||
);
|
||||
return new GeometryCollection_default(geometries);
|
||||
}
|
||||
const Geometry = GeometryConstructor[object.type];
|
||||
return transformGeometryWithOptions(
|
||||
new Geometry(object.flatCoordinates, object.layout || "XY", object.ends),
|
||||
false,
|
||||
options
|
||||
);
|
||||
}
|
||||
|
||||
export {
|
||||
Feature_default3 as Feature_default,
|
||||
transformGeometryWithOptions,
|
||||
createRenderFeature,
|
||||
createGeometry
|
||||
};
|
||||
//# sourceMappingURL=chunk-56VFHHUN.js.map
|
||||
7
node_modules/.vite/deps/chunk-56VFHHUN.js.map
generated
vendored
17
node_modules/.vite/deps/chunk-5D2XPBR2.js
generated
vendored
@ -1,17 +0,0 @@
|
||||
// node_modules/ol/TileState.js
|
||||
var TileState_default = {
|
||||
IDLE: 0,
|
||||
LOADING: 1,
|
||||
LOADED: 2,
|
||||
/**
|
||||
* Indicates that tile loading failed
|
||||
* @type {number}
|
||||
*/
|
||||
ERROR: 3,
|
||||
EMPTY: 4
|
||||
};
|
||||
|
||||
export {
|
||||
TileState_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-5D2XPBR2.js.map
|
||||
7
node_modules/.vite/deps/chunk-5D2XPBR2.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/TileState.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/TileState\n */\n\n/**\n * @enum {number}\n */\nexport default {\n IDLE: 0,\n LOADING: 1,\n LOADED: 2,\n /**\n * Indicates that tile loading failed\n * @type {number}\n */\n ERROR: 3,\n EMPTY: 4,\n};\n"],
|
||||
"mappings": ";AAOA,IAAO,oBAAQ;AAAA,EACb,MAAM;AAAA,EACN,SAAS;AAAA,EACT,QAAQ;AAAA;AAAA;AAAA;AAAA;AAAA,EAKR,OAAO;AAAA,EACP,OAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
19
node_modules/.vite/deps/chunk-5RHQVMYD.js
generated
vendored
@ -1,19 +0,0 @@
|
||||
// node_modules/ol/obj.js
|
||||
function clear(object) {
|
||||
for (const property in object) {
|
||||
delete object[property];
|
||||
}
|
||||
}
|
||||
function isEmpty(object) {
|
||||
let property;
|
||||
for (property in object) {
|
||||
return false;
|
||||
}
|
||||
return !property;
|
||||
}
|
||||
|
||||
export {
|
||||
clear,
|
||||
isEmpty
|
||||
};
|
||||
//# sourceMappingURL=chunk-5RHQVMYD.js.map
|
||||
7
node_modules/.vite/deps/chunk-5RHQVMYD.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/obj.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/obj\n */\n\n/**\n * Removes all properties from an object.\n * @param {Object<string, unknown>} object The object to clear.\n */\nexport function clear(object) {\n for (const property in object) {\n delete object[property];\n }\n}\n\n/**\n * Determine if an object has any properties.\n * @param {Object} object The object to check.\n * @return {boolean} The object is empty.\n */\nexport function isEmpty(object) {\n let property;\n for (property in object) {\n return false;\n }\n return !property;\n}\n"],
|
||||
"mappings": ";AAQO,SAAS,MAAM,QAAQ;AAC5B,aAAW,YAAY,QAAQ;AAC7B,WAAO,OAAO,QAAQ;AAAA,EACxB;AACF;AAOO,SAAS,QAAQ,QAAQ;AAC9B,MAAI;AACJ,OAAK,YAAY,QAAQ;AACvB,WAAO;AAAA,EACT;AACA,SAAO,CAAC;AACV;",
|
||||
"names": []
|
||||
}
|
||||
36
node_modules/.vite/deps/chunk-5XHD7RSF.js
generated
vendored
@ -1,36 +0,0 @@
|
||||
// node_modules/ol/has.js
|
||||
var ua = typeof navigator !== "undefined" && typeof navigator.userAgent !== "undefined" ? navigator.userAgent.toLowerCase() : "";
|
||||
var SAFARI = ua.includes("safari") && !ua.includes("chrom");
|
||||
var SAFARI_BUG_237906 = SAFARI && (ua.includes("version/15.4") || /cpu (os|iphone os) 15_4 like mac os x/.test(ua));
|
||||
var WEBKIT = ua.includes("webkit") && !ua.includes("edge");
|
||||
var MAC = ua.includes("macintosh");
|
||||
var DEVICE_PIXEL_RATIO = typeof devicePixelRatio !== "undefined" ? devicePixelRatio : 1;
|
||||
var WORKER_OFFSCREEN_CANVAS = typeof WorkerGlobalScope !== "undefined" && typeof OffscreenCanvas !== "undefined" && self instanceof WorkerGlobalScope;
|
||||
var IMAGE_DECODE = typeof Image !== "undefined" && Image.prototype.decode;
|
||||
var CREATE_IMAGE_BITMAP = typeof createImageBitmap === "function";
|
||||
var PASSIVE_EVENT_LISTENERS = (function() {
|
||||
let passive = false;
|
||||
try {
|
||||
const options = Object.defineProperty({}, "passive", {
|
||||
get: function() {
|
||||
passive = true;
|
||||
}
|
||||
});
|
||||
window.addEventListener("_", null, options);
|
||||
window.removeEventListener("_", null, options);
|
||||
} catch {
|
||||
}
|
||||
return passive;
|
||||
})();
|
||||
|
||||
export {
|
||||
SAFARI_BUG_237906,
|
||||
WEBKIT,
|
||||
MAC,
|
||||
DEVICE_PIXEL_RATIO,
|
||||
WORKER_OFFSCREEN_CANVAS,
|
||||
IMAGE_DECODE,
|
||||
CREATE_IMAGE_BITMAP,
|
||||
PASSIVE_EVENT_LISTENERS
|
||||
};
|
||||
//# sourceMappingURL=chunk-5XHD7RSF.js.map
|
||||
7
node_modules/.vite/deps/chunk-5XHD7RSF.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/has.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/has\n */\n\nconst ua =\n typeof navigator !== 'undefined' && typeof navigator.userAgent !== 'undefined'\n ? navigator.userAgent.toLowerCase()\n : '';\n\n/**\n * User agent string says we are dealing with Safari as browser.\n * @type {boolean}\n */\nexport const SAFARI = ua.includes('safari') && !ua.includes('chrom');\n\n/**\n * https://bugs.webkit.org/show_bug.cgi?id=237906\n * @type {boolean}\n */\nexport const SAFARI_BUG_237906 =\n SAFARI &&\n (ua.includes('version/15.4') ||\n /cpu (os|iphone os) 15_4 like mac os x/.test(ua));\n\n/**\n * User agent string says we are dealing with a WebKit engine.\n * @type {boolean}\n */\nexport const WEBKIT = ua.includes('webkit') && !ua.includes('edge');\n\n/**\n * User agent string says we are dealing with a Mac as platform.\n * @type {boolean}\n */\nexport const MAC = ua.includes('macintosh');\n\n/**\n * The ratio between physical pixels and device-independent pixels\n * (dips) on the device (`window.devicePixelRatio`).\n * @const\n * @type {number}\n * @api\n */\nexport const DEVICE_PIXEL_RATIO =\n typeof devicePixelRatio !== 'undefined' ? devicePixelRatio : 1;\n\n/**\n * The execution context is a worker with OffscreenCanvas available.\n * @const\n * @type {boolean}\n */\nexport const WORKER_OFFSCREEN_CANVAS =\n typeof WorkerGlobalScope !== 'undefined' &&\n typeof OffscreenCanvas !== 'undefined' &&\n self instanceof WorkerGlobalScope; //eslint-disable-line\n\n/**\n * Image.prototype.decode() is supported.\n * @type {boolean}\n */\nexport const IMAGE_DECODE =\n typeof Image !== 'undefined' && Image.prototype.decode;\n\n/**\n * createImageBitmap() is supported.\n * @type {boolean}\n */\nexport const CREATE_IMAGE_BITMAP = typeof createImageBitmap === 'function';\n\n/**\n * @type {boolean}\n */\nexport const PASSIVE_EVENT_LISTENERS = (function () {\n let passive = false;\n try {\n const options = Object.defineProperty({}, 'passive', {\n get: function () {\n passive = true;\n },\n });\n\n // @ts-ignore Ignore invalid event type '_'\n window.addEventListener('_', null, options);\n // @ts-ignore Ignore invalid event type '_'\n window.removeEventListener('_', null, options);\n } catch {\n // passive not supported\n }\n return passive;\n})();\n"],
|
||||
"mappings": ";AAIA,IAAM,KACJ,OAAO,cAAc,eAAe,OAAO,UAAU,cAAc,cAC/D,UAAU,UAAU,YAAY,IAChC;AAMC,IAAM,SAAS,GAAG,SAAS,QAAQ,KAAK,CAAC,GAAG,SAAS,OAAO;AAM5D,IAAM,oBACX,WACC,GAAG,SAAS,cAAc,KACzB,wCAAwC,KAAK,EAAE;AAM5C,IAAM,SAAS,GAAG,SAAS,QAAQ,KAAK,CAAC,GAAG,SAAS,MAAM;AAM3D,IAAM,MAAM,GAAG,SAAS,WAAW;AASnC,IAAM,qBACX,OAAO,qBAAqB,cAAc,mBAAmB;AAOxD,IAAM,0BACX,OAAO,sBAAsB,eAC7B,OAAO,oBAAoB,eAC3B,gBAAgB;AAMX,IAAM,eACX,OAAO,UAAU,eAAe,MAAM,UAAU;AAM3C,IAAM,sBAAsB,OAAO,sBAAsB;AAKzD,IAAM,2BAA2B,WAAY;AAClD,MAAI,UAAU;AACd,MAAI;AACF,UAAM,UAAU,OAAO,eAAe,CAAC,GAAG,WAAW;AAAA,MACnD,KAAK,WAAY;AACf,kBAAU;AAAA,MACZ;AAAA,IACF,CAAC;AAGD,WAAO,iBAAiB,KAAK,MAAM,OAAO;AAE1C,WAAO,oBAAoB,KAAK,MAAM,OAAO;AAAA,EAC/C,QAAQ;AAAA,EAER;AACA,SAAO;AACT,GAAG;",
|
||||
"names": []
|
||||
}
|
||||
465
node_modules/.vite/deps/chunk-6DXBPPKF.js
generated
vendored
@ -1,465 +0,0 @@
|
||||
import {
|
||||
Feature_default
|
||||
} from "./chunk-E53S5GN6.js";
|
||||
import {
|
||||
Vector_default
|
||||
} from "./chunk-T3TT2KJN.js";
|
||||
import {
|
||||
Interaction_default
|
||||
} from "./chunk-MSWSBYBR.js";
|
||||
import {
|
||||
never,
|
||||
shiftKeyOnly,
|
||||
singleClick
|
||||
} from "./chunk-QCJTGAWF.js";
|
||||
import {
|
||||
CollectionEventType_default,
|
||||
Collection_default
|
||||
} from "./chunk-M5TTSD4C.js";
|
||||
import {
|
||||
createEditingStyle
|
||||
} from "./chunk-PAB2HIXK.js";
|
||||
import {
|
||||
getUid
|
||||
} from "./chunk-Q5ZULJHM.js";
|
||||
import {
|
||||
Event_default
|
||||
} from "./chunk-NGFXCWUF.js";
|
||||
import {
|
||||
TRUE,
|
||||
extend
|
||||
} from "./chunk-K25ZO44T.js";
|
||||
import {
|
||||
clear
|
||||
} from "./chunk-5RHQVMYD.js";
|
||||
|
||||
// node_modules/ol/interaction/Select.js
|
||||
var SelectEventType = {
|
||||
/**
|
||||
* Triggered when feature(s) has been (de)selected.
|
||||
* @event SelectEvent#select
|
||||
* @api
|
||||
*/
|
||||
SELECT: "select"
|
||||
};
|
||||
var SelectEvent = class extends Event_default {
|
||||
/**
|
||||
* @param {SelectEventType} type The event type.
|
||||
* @param {Array<import("../Feature.js").default>} selected Selected features.
|
||||
* @param {Array<import("../Feature.js").default>} deselected Deselected features.
|
||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Associated
|
||||
* {@link module:ol/MapBrowserEvent~MapBrowserEvent}.
|
||||
*/
|
||||
constructor(type, selected, deselected, mapBrowserEvent) {
|
||||
super(type);
|
||||
this.selected = selected;
|
||||
this.deselected = deselected;
|
||||
this.mapBrowserEvent = mapBrowserEvent;
|
||||
}
|
||||
};
|
||||
var originalFeatureStyles = {};
|
||||
var Select = class _Select extends Interaction_default {
|
||||
/**
|
||||
* @param {Options} [options] Options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
this.on;
|
||||
this.once;
|
||||
this.un;
|
||||
options = options ? options : {};
|
||||
this.boundAddFeature_ = this.addFeature_.bind(this);
|
||||
this.boundRemoveFeature_ = this.removeFeature_.bind(this);
|
||||
this.condition_ = options.condition ? options.condition : singleClick;
|
||||
this.addCondition_ = options.addCondition ? options.addCondition : never;
|
||||
this.removeCondition_ = options.removeCondition ? options.removeCondition : never;
|
||||
this.toggleCondition_ = options.toggleCondition ? options.toggleCondition : shiftKeyOnly;
|
||||
this.multi_ = options.multi ? options.multi : false;
|
||||
this.filter_ = options.filter ? options.filter : TRUE;
|
||||
this.hitTolerance_ = options.hitTolerance ? options.hitTolerance : 0;
|
||||
this.style_ = options.style !== void 0 ? options.style : getDefaultStyleFunction();
|
||||
this.features_ = options.features || new Collection_default();
|
||||
let layerFilter;
|
||||
if (options.layers) {
|
||||
if (typeof options.layers === "function") {
|
||||
layerFilter = options.layers;
|
||||
} else {
|
||||
const layers = options.layers;
|
||||
layerFilter = function(layer) {
|
||||
return layers.includes(layer);
|
||||
};
|
||||
}
|
||||
} else {
|
||||
layerFilter = TRUE;
|
||||
}
|
||||
this.layerFilter_ = layerFilter;
|
||||
this.featureLayerAssociation_ = {};
|
||||
}
|
||||
/**
|
||||
* @param {import("../Feature.js").default} feature Feature.
|
||||
* @param {import("../layer/Layer.js").default} layer Layer.
|
||||
* @private
|
||||
*/
|
||||
addFeatureLayerAssociation_(feature, layer) {
|
||||
this.featureLayerAssociation_[getUid(feature)] = layer;
|
||||
}
|
||||
/**
|
||||
* Get the selected features.
|
||||
* @return {Collection<Feature>} Features collection.
|
||||
* @api
|
||||
*/
|
||||
getFeatures() {
|
||||
return this.features_;
|
||||
}
|
||||
/**
|
||||
* Returns the Hit-detection tolerance.
|
||||
* @return {number} Hit tolerance in pixels.
|
||||
* @api
|
||||
*/
|
||||
getHitTolerance() {
|
||||
return this.hitTolerance_;
|
||||
}
|
||||
/**
|
||||
* Returns the associated {@link module:ol/layer/Vector~VectorLayer vector layer} of
|
||||
* a selected feature.
|
||||
* @param {import("../Feature.js").default} feature Feature
|
||||
* @return {import('../layer/Vector.js').default} Layer.
|
||||
* @api
|
||||
*/
|
||||
getLayer(feature) {
|
||||
return (
|
||||
/** @type {import('../layer/Vector.js').default} */
|
||||
this.featureLayerAssociation_[getUid(feature)]
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Hit-detection tolerance. Pixels inside the radius around the given position
|
||||
* will be checked for features.
|
||||
* @param {number} hitTolerance Hit tolerance in pixels.
|
||||
* @api
|
||||
*/
|
||||
setHitTolerance(hitTolerance) {
|
||||
this.hitTolerance_ = hitTolerance;
|
||||
}
|
||||
/**
|
||||
* Remove the interaction from its current map, if any, and attach it to a new
|
||||
* map, if any. Pass `null` to just remove the interaction from the current map.
|
||||
* @param {import("../Map.js").default|null} map Map.
|
||||
* @api
|
||||
* @override
|
||||
*/
|
||||
setMap(map) {
|
||||
const currentMap = this.getMap();
|
||||
if (currentMap && this.style_) {
|
||||
this.features_.forEach(this.restorePreviousStyle_.bind(this));
|
||||
}
|
||||
super.setMap(map);
|
||||
if (map) {
|
||||
this.features_.addEventListener(
|
||||
CollectionEventType_default.ADD,
|
||||
this.boundAddFeature_
|
||||
);
|
||||
this.features_.addEventListener(
|
||||
CollectionEventType_default.REMOVE,
|
||||
this.boundRemoveFeature_
|
||||
);
|
||||
if (this.style_) {
|
||||
this.features_.forEach(this.applySelectedStyle_.bind(this));
|
||||
}
|
||||
} else {
|
||||
this.features_.removeEventListener(
|
||||
CollectionEventType_default.ADD,
|
||||
this.boundAddFeature_
|
||||
);
|
||||
this.features_.removeEventListener(
|
||||
CollectionEventType_default.REMOVE,
|
||||
this.boundRemoveFeature_
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
addFeature_(evt) {
|
||||
const feature = evt.element;
|
||||
if (this.style_) {
|
||||
this.applySelectedStyle_(feature);
|
||||
}
|
||||
if (!this.getLayer(feature)) {
|
||||
const layer = this.findLayerOfFeature_(feature);
|
||||
if (layer) {
|
||||
this.addFeatureLayerAssociation_(feature, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {import("../Collection.js").CollectionEvent<Feature>} evt Event.
|
||||
* @private
|
||||
*/
|
||||
removeFeature_(evt) {
|
||||
if (this.style_) {
|
||||
this.restorePreviousStyle_(evt.element);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @param {Feature} feature Feature of which to get the layer
|
||||
* @return {VectorLayer} layer, if one was found.
|
||||
* @private
|
||||
*/
|
||||
findLayerOfFeature_(feature) {
|
||||
const layer = (
|
||||
/** @type {VectorLayer} */
|
||||
this.getMap().getAllLayers().find(function(layer2) {
|
||||
if (layer2 instanceof Vector_default && layer2.getSource() && layer2.getSource().hasFeature(feature)) {
|
||||
return layer2;
|
||||
}
|
||||
})
|
||||
);
|
||||
return layer;
|
||||
}
|
||||
/**
|
||||
* @return {import("../style/Style.js").StyleLike|null} Select style.
|
||||
*/
|
||||
getStyle() {
|
||||
return this.style_;
|
||||
}
|
||||
/**
|
||||
* @param {Feature} feature Feature
|
||||
* @private
|
||||
*/
|
||||
applySelectedStyle_(feature) {
|
||||
const key = getUid(feature);
|
||||
if (!(key in originalFeatureStyles)) {
|
||||
originalFeatureStyles[key] = feature.getStyle();
|
||||
}
|
||||
feature.setStyle(this.style_);
|
||||
}
|
||||
/**
|
||||
* @param {Feature} feature Feature
|
||||
* @private
|
||||
*/
|
||||
restorePreviousStyle_(feature) {
|
||||
const interactions = this.getMap().getInteractions().getArray();
|
||||
for (let i = interactions.length - 1; i >= 0; --i) {
|
||||
const interaction = interactions[i];
|
||||
if (interaction !== this && interaction instanceof _Select && interaction.getStyle() && interaction.getFeatures().getArray().lastIndexOf(feature) !== -1) {
|
||||
feature.setStyle(interaction.getStyle());
|
||||
return;
|
||||
}
|
||||
}
|
||||
const key = getUid(feature);
|
||||
feature.setStyle(originalFeatureStyles[key]);
|
||||
delete originalFeatureStyles[key];
|
||||
}
|
||||
/**
|
||||
* @param {Feature} feature Feature.
|
||||
* @private
|
||||
*/
|
||||
removeFeatureLayerAssociation_(feature) {
|
||||
delete this.featureLayerAssociation_[getUid(feature)];
|
||||
}
|
||||
/**
|
||||
* @param {import("../Feature.js").FeatureLike} feature The feature to select
|
||||
* @param {import("../layer/Layer.js").default} layer Optional layer containing this feature
|
||||
* @param {Array<Feature>} [selected] optional array to which selected features will be added
|
||||
* @return {Feature|undefined} The feature, if it got selected.
|
||||
* @private
|
||||
*/
|
||||
selectFeatureInternal_(feature, layer, selected) {
|
||||
if (!(feature instanceof Feature_default)) {
|
||||
return;
|
||||
}
|
||||
if (!this.filter_(feature, layer)) {
|
||||
return;
|
||||
}
|
||||
const features = this.getFeatures();
|
||||
if (!features.getArray().includes(feature)) {
|
||||
this.addFeatureLayerAssociation_(feature, layer);
|
||||
features.push(feature);
|
||||
selected == null ? void 0 : selected.push(feature);
|
||||
}
|
||||
return feature;
|
||||
}
|
||||
/**
|
||||
* Try to select a feature as if it was clicked and `addCondition` evaluated to True.
|
||||
* Unlike modifying `select.getFeatures()` directly, this respects the `filter` and `layers` options (except `multi`, which is ignored).
|
||||
* The {@link module:ol/interaction/Select~SelectEvent} fired by this won't have a mapBrowserEvent property
|
||||
* @param {Feature} feature The feature to select
|
||||
* @return {boolean} True if the feature was selected
|
||||
*/
|
||||
selectFeature(feature) {
|
||||
const layer = this.findLayerOfFeature_(feature);
|
||||
if (!this.layerFilter_(layer)) {
|
||||
return false;
|
||||
}
|
||||
const selected = this.selectFeatureInternal_(feature, layer);
|
||||
if (selected) {
|
||||
this.dispatchEvent(
|
||||
new SelectEvent(SelectEventType.SELECT, [selected], [], void 0)
|
||||
);
|
||||
}
|
||||
return !!selected;
|
||||
}
|
||||
/**
|
||||
* Deselects a feature if it was previously selected. Also removes layer association.
|
||||
* @param {import("../Feature.js").FeatureLike} feature The feature to deselect
|
||||
* @param {Array<Feature>} [deselected] optional array to which deselected features will be added
|
||||
* @return {Feature|undefined} The feature, if it was previously selected.
|
||||
* @private
|
||||
*/
|
||||
removeFeatureInternal_(feature, deselected) {
|
||||
const features = this.getFeatures();
|
||||
if (!(feature instanceof Feature_default) || !features.getArray().includes(feature)) {
|
||||
return;
|
||||
}
|
||||
features.remove(feature);
|
||||
this.removeFeatureLayerAssociation_(feature);
|
||||
deselected == null ? void 0 : deselected.push(feature);
|
||||
return feature;
|
||||
}
|
||||
/**
|
||||
* Try to deselect a feature as if it was clicked.
|
||||
* Compared to `select.getFeatures().remove(feature)` this causes a SelectEvent.
|
||||
* The {@link module:ol/interaction/Select~SelectEvent} fired by this won't have a mapBrowserEvent property
|
||||
* @param {Feature} feature The feature to deselect
|
||||
* @return {boolean} True if the feature was deselected
|
||||
*/
|
||||
deselectFeature(feature) {
|
||||
const deselected = this.removeFeatureInternal_(feature);
|
||||
if (deselected) {
|
||||
this.dispatchEvent(
|
||||
new SelectEvent(SelectEventType.SELECT, [], [deselected], void 0)
|
||||
);
|
||||
}
|
||||
return !!deselected;
|
||||
}
|
||||
/**
|
||||
* Try to toggle a feature as if it was clicked and `toggleCondition` was True.
|
||||
* Unlike modifying `select.getFeatures()` directly, this respects the `filter` and `layers` options (except `multi`, which is ignored).
|
||||
* The {@link module:ol/interaction/Select~SelectEvent} fired by this won't have a mapBrowserEvent property
|
||||
* @param {Feature} feature The feature to deselect
|
||||
*/
|
||||
toggleFeature(feature) {
|
||||
if (!this.deselectFeature(feature)) {
|
||||
this.selectFeature(feature);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Deselect all features as if a user deselected them.
|
||||
* Compared to `select.getFeatures().clear()` this causes a SelectEvent.
|
||||
* The {@link module:ol/interaction/Select~SelectEvent} fired by this won't have a mapBrowserEvent property
|
||||
*/
|
||||
clearSelection() {
|
||||
clear(this.featureLayerAssociation_);
|
||||
const features = this.getFeatures();
|
||||
const deselected = features.getArray().slice();
|
||||
features.clear();
|
||||
if (deselected.length !== 0) {
|
||||
this.dispatchEvent(
|
||||
new SelectEvent(SelectEventType.SELECT, [], deselected, void 0)
|
||||
);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles the {@link module:ol/MapBrowserEvent~MapBrowserEvent map browser event} and may change the
|
||||
* selected state of features.
|
||||
* @param {import("../MapBrowserEvent.js").default} mapBrowserEvent Map browser event.
|
||||
* @return {boolean} `false` to stop event propagation.
|
||||
* @override
|
||||
*/
|
||||
handleEvent(mapBrowserEvent) {
|
||||
if (!this.condition_(mapBrowserEvent)) {
|
||||
return true;
|
||||
}
|
||||
const add = this.addCondition_(mapBrowserEvent);
|
||||
const remove = this.removeCondition_(mapBrowserEvent);
|
||||
const toggle = this.toggleCondition_(mapBrowserEvent);
|
||||
const set = !add && !remove && !toggle;
|
||||
const map = mapBrowserEvent.map;
|
||||
const features = this.getFeatures();
|
||||
const deselected = [];
|
||||
const selected = [];
|
||||
if (set) {
|
||||
let foundAtCursor = false;
|
||||
map.forEachFeatureAtPixel(
|
||||
mapBrowserEvent.pixel,
|
||||
(feature, layer) => {
|
||||
foundAtCursor = true;
|
||||
if (!this.selectFeatureInternal_(feature, layer, selected)) {
|
||||
return;
|
||||
}
|
||||
return !this.multi_;
|
||||
},
|
||||
{
|
||||
layerFilter: this.layerFilter_,
|
||||
hitTolerance: this.hitTolerance_
|
||||
}
|
||||
);
|
||||
for (let i = features.getLength() - 1; i >= 0; --i) {
|
||||
const feature = features.item(i);
|
||||
if (
|
||||
// remove all but selected, if there were any selected
|
||||
selected.length > 0 && !selected.includes(feature) || // remove all, if click outside of layer
|
||||
!foundAtCursor
|
||||
) {
|
||||
this.removeFeatureInternal_(feature, deselected);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
map.forEachFeatureAtPixel(
|
||||
mapBrowserEvent.pixel,
|
||||
(feature, layer) => {
|
||||
let modifiedFeature;
|
||||
if (remove || toggle) {
|
||||
modifiedFeature = this.removeFeatureInternal_(feature, deselected);
|
||||
}
|
||||
if ((add || toggle) && !modifiedFeature) {
|
||||
modifiedFeature = this.selectFeatureInternal_(
|
||||
feature,
|
||||
layer,
|
||||
selected
|
||||
);
|
||||
}
|
||||
if (!modifiedFeature) {
|
||||
return;
|
||||
}
|
||||
return !this.multi_;
|
||||
},
|
||||
{
|
||||
layerFilter: this.layerFilter_,
|
||||
hitTolerance: this.hitTolerance_
|
||||
}
|
||||
);
|
||||
}
|
||||
if (selected.length > 0 || deselected.length > 0) {
|
||||
this.dispatchEvent(
|
||||
new SelectEvent(
|
||||
SelectEventType.SELECT,
|
||||
selected,
|
||||
deselected,
|
||||
mapBrowserEvent
|
||||
)
|
||||
);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
function getDefaultStyleFunction() {
|
||||
const styles = createEditingStyle();
|
||||
extend(styles["Polygon"], styles["LineString"]);
|
||||
extend(styles["GeometryCollection"], styles["LineString"]);
|
||||
return function(feature) {
|
||||
if (!feature.getGeometry()) {
|
||||
return null;
|
||||
}
|
||||
return styles[feature.getGeometry().getType()];
|
||||
};
|
||||
}
|
||||
var Select_default = Select;
|
||||
|
||||
export {
|
||||
SelectEvent,
|
||||
Select_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-6DXBPPKF.js.map
|
||||
7
node_modules/.vite/deps/chunk-6DXBPPKF.js.map
generated
vendored
68
node_modules/.vite/deps/chunk-6EWLK2BW.js
generated
vendored
@ -1,68 +0,0 @@
|
||||
// node_modules/ol/css.js
|
||||
var CLASS_HIDDEN = "ol-hidden";
|
||||
var CLASS_SELECTABLE = "ol-selectable";
|
||||
var CLASS_UNSELECTABLE = "ol-unselectable";
|
||||
var CLASS_CONTROL = "ol-control";
|
||||
var CLASS_COLLAPSED = "ol-collapsed";
|
||||
var fontRegEx = new RegExp(
|
||||
[
|
||||
"^\\s*(?=(?:(?:[-a-z]+\\s*){0,2}(italic|oblique))?)",
|
||||
"(?=(?:(?:[-a-z]+\\s*){0,2}(small-caps))?)",
|
||||
"(?=(?:(?:[-a-z]+\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)",
|
||||
"(?:(?:normal|\\1|\\2|\\3)\\s*){0,3}((?:xx?-)?",
|
||||
"(?:small|large)|medium|smaller|larger|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx]))",
|
||||
"(?:\\s*\\/\\s*(normal|[\\.\\d]+(?:\\%|in|[cem]m|ex|p[ctx])?))",
|
||||
`?\\s*([-,\\"\\'\\sa-z0-9]+?)\\s*$`
|
||||
].join(""),
|
||||
"i"
|
||||
);
|
||||
var fontRegExMatchIndex = [
|
||||
"style",
|
||||
"variant",
|
||||
"weight",
|
||||
"size",
|
||||
"lineHeight",
|
||||
"family"
|
||||
];
|
||||
var fontWeights = {
|
||||
normal: 400,
|
||||
bold: 700
|
||||
};
|
||||
var getFontParameters = function(fontSpec) {
|
||||
const match = fontSpec.match(fontRegEx);
|
||||
if (!match) {
|
||||
return null;
|
||||
}
|
||||
const style = (
|
||||
/** @type {FontParameters} */
|
||||
{
|
||||
lineHeight: "normal",
|
||||
size: "1.2em",
|
||||
style: "normal",
|
||||
weight: "400",
|
||||
variant: "normal"
|
||||
}
|
||||
);
|
||||
for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {
|
||||
const value = match[i + 1];
|
||||
if (value !== void 0) {
|
||||
style[fontRegExMatchIndex[i]] = typeof value === "string" ? value.trim() : value;
|
||||
}
|
||||
}
|
||||
if (isNaN(Number(style.weight)) && style.weight in fontWeights) {
|
||||
style.weight = fontWeights[style.weight];
|
||||
}
|
||||
style.families = style.family.split(/,\s?/).map((f) => f.trim().replace(/^['"]|['"]$/g, ""));
|
||||
return style;
|
||||
};
|
||||
|
||||
export {
|
||||
CLASS_HIDDEN,
|
||||
CLASS_SELECTABLE,
|
||||
CLASS_UNSELECTABLE,
|
||||
CLASS_CONTROL,
|
||||
CLASS_COLLAPSED,
|
||||
fontWeights,
|
||||
getFontParameters
|
||||
};
|
||||
//# sourceMappingURL=chunk-6EWLK2BW.js.map
|
||||
7
node_modules/.vite/deps/chunk-6EWLK2BW.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/css.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/css\n */\n\n/**\n * @typedef {Object} FontParameters\n * @property {string} style Style.\n * @property {string} variant Variant.\n * @property {string} weight Weight.\n * @property {string} size Size.\n * @property {string} lineHeight LineHeight.\n * @property {string} family Family.\n * @property {Array<string>} families Families.\n */\n\n/**\n * The CSS class for hidden feature.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_HIDDEN = 'ol-hidden';\n\n/**\n * The CSS class that we'll give the DOM elements to have them selectable.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_SELECTABLE = 'ol-selectable';\n\n/**\n * The CSS class that we'll give the DOM elements to have them unselectable.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_UNSELECTABLE = 'ol-unselectable';\n\n/**\n * The CSS class for unsupported feature.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_UNSUPPORTED = 'ol-unsupported';\n\n/**\n * The CSS class for controls.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_CONTROL = 'ol-control';\n\n/**\n * The CSS class that we'll give the DOM elements that are collapsed, i.e.\n * to those elements which usually can be expanded.\n *\n * @const\n * @type {string}\n */\nexport const CLASS_COLLAPSED = 'ol-collapsed';\n\n/**\n * From https://stackoverflow.com/questions/10135697/regex-to-parse-any-css-font\n * @type {RegExp}\n */\nconst fontRegEx = new RegExp(\n [\n '^\\\\s*(?=(?:(?:[-a-z]+\\\\s*){0,2}(italic|oblique))?)',\n '(?=(?:(?:[-a-z]+\\\\s*){0,2}(small-caps))?)',\n '(?=(?:(?:[-a-z]+\\\\s*){0,2}(bold(?:er)?|lighter|[1-9]00 ))?)',\n '(?:(?:normal|\\\\1|\\\\2|\\\\3)\\\\s*){0,3}((?:xx?-)?',\n '(?:small|large)|medium|smaller|larger|[\\\\.\\\\d]+(?:\\\\%|in|[cem]m|ex|p[ctx]))',\n '(?:\\\\s*\\\\/\\\\s*(normal|[\\\\.\\\\d]+(?:\\\\%|in|[cem]m|ex|p[ctx])?))',\n '?\\\\s*([-,\\\\\"\\\\\\'\\\\sa-z0-9]+?)\\\\s*$',\n ].join(''),\n 'i',\n);\n/** @type {Array<'style'|'variant'|'weight'|'size'|'lineHeight'|'family'>} */\nconst fontRegExMatchIndex = [\n 'style',\n 'variant',\n 'weight',\n 'size',\n 'lineHeight',\n 'family',\n];\n\n/** @type {Object<string|number, number>} */\nexport const fontWeights = {\n normal: 400,\n bold: 700,\n};\n\n/**\n * Get the list of font families from a font spec. Note that this doesn't work\n * for font families that have commas in them.\n * @param {string} fontSpec The CSS font property.\n * @return {FontParameters|null} The font parameters (or null if the input spec is invalid).\n */\nexport const getFontParameters = function (fontSpec) {\n const match = fontSpec.match(fontRegEx);\n if (!match) {\n return null;\n }\n const style = /** @type {FontParameters} */ ({\n lineHeight: 'normal',\n size: '1.2em',\n style: 'normal',\n weight: '400',\n variant: 'normal',\n });\n for (let i = 0, ii = fontRegExMatchIndex.length; i < ii; ++i) {\n const value = match[i + 1];\n if (value !== undefined) {\n style[fontRegExMatchIndex[i]] =\n typeof value === 'string' ? value.trim() : value;\n }\n }\n if (isNaN(Number(style.weight)) && style.weight in fontWeights) {\n style.weight = fontWeights[style.weight];\n }\n style.families = style.family\n .split(/,\\s?/)\n .map((f) => f.trim().replace(/^['\"]|['\"]$/g, ''));\n return style;\n};\n"],
|
||||
"mappings": ";AAqBO,IAAM,eAAe;AAQrB,IAAM,mBAAmB;AAQzB,IAAM,qBAAqB;AAgB3B,IAAM,gBAAgB;AAStB,IAAM,kBAAkB;AAM/B,IAAM,YAAY,IAAI;AAAA,EACpB;AAAA,IACE;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACF,EAAE,KAAK,EAAE;AAAA,EACT;AACF;AAEA,IAAM,sBAAsB;AAAA,EAC1B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGO,IAAM,cAAc;AAAA,EACzB,QAAQ;AAAA,EACR,MAAM;AACR;AAQO,IAAM,oBAAoB,SAAU,UAAU;AACnD,QAAM,QAAQ,SAAS,MAAM,SAAS;AACtC,MAAI,CAAC,OAAO;AACV,WAAO;AAAA,EACT;AACA,QAAM;AAAA;AAAA,IAAuC;AAAA,MAC3C,YAAY;AAAA,MACZ,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ;AAAA,MACR,SAAS;AAAA,IACX;AAAA;AACA,WAAS,IAAI,GAAG,KAAK,oBAAoB,QAAQ,IAAI,IAAI,EAAE,GAAG;AAC5D,UAAM,QAAQ,MAAM,IAAI,CAAC;AACzB,QAAI,UAAU,QAAW;AACvB,YAAM,oBAAoB,CAAC,CAAC,IAC1B,OAAO,UAAU,WAAW,MAAM,KAAK,IAAI;AAAA,IAC/C;AAAA,EACF;AACA,MAAI,MAAM,OAAO,MAAM,MAAM,CAAC,KAAK,MAAM,UAAU,aAAa;AAC9D,UAAM,SAAS,YAAY,MAAM,MAAM;AAAA,EACzC;AACA,QAAM,WAAW,MAAM,OACpB,MAAM,MAAM,EACZ,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,QAAQ,gBAAgB,EAAE,CAAC;AAClD,SAAO;AACT;",
|
||||
"names": []
|
||||
}
|
||||
130
node_modules/.vite/deps/chunk-6Y7C6NBJ.js
generated
vendored
@ -1,130 +0,0 @@
|
||||
import {
|
||||
get
|
||||
} from "./chunk-A3RXLHYB.js";
|
||||
import {
|
||||
Object_default
|
||||
} from "./chunk-Q5ZULJHM.js";
|
||||
|
||||
// node_modules/ol/source/Source.js
|
||||
var Source = class extends Object_default {
|
||||
/**
|
||||
* @param {Options} options Source options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
this.projection = get(options.projection);
|
||||
this.attributions_ = adaptAttributions(options.attributions);
|
||||
this.attributionsCollapsible_ = options.attributionsCollapsible ?? true;
|
||||
this.loading = false;
|
||||
this.state_ = options.state !== void 0 ? options.state : "ready";
|
||||
this.wrapX_ = options.wrapX !== void 0 ? options.wrapX : false;
|
||||
this.interpolate_ = !!options.interpolate;
|
||||
this.viewResolver = null;
|
||||
this.viewRejector = null;
|
||||
const self = this;
|
||||
this.viewPromise_ = new Promise(function(resolve, reject) {
|
||||
self.viewResolver = resolve;
|
||||
self.viewRejector = reject;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Get the attribution function for the source.
|
||||
* @return {?Attribution} Attribution function.
|
||||
* @api
|
||||
*/
|
||||
getAttributions() {
|
||||
return this.attributions_;
|
||||
}
|
||||
/**
|
||||
* @return {boolean} Attributions are collapsible.
|
||||
* @api
|
||||
*/
|
||||
getAttributionsCollapsible() {
|
||||
return this.attributionsCollapsible_;
|
||||
}
|
||||
/**
|
||||
* Get the projection of the source.
|
||||
* @return {import("../proj/Projection.js").default|null} Projection.
|
||||
* @api
|
||||
*/
|
||||
getProjection() {
|
||||
return this.projection;
|
||||
}
|
||||
/**
|
||||
* @param {import("../proj/Projection").default} [projection] Projection.
|
||||
* @return {Array<number>|null} Resolutions.
|
||||
*/
|
||||
getResolutions(projection) {
|
||||
return null;
|
||||
}
|
||||
/**
|
||||
* @return {Promise<import("../View.js").ViewOptions>} A promise for view-related properties.
|
||||
*/
|
||||
getView() {
|
||||
return this.viewPromise_;
|
||||
}
|
||||
/**
|
||||
* Get the state of the source, see {@link import("./Source.js").State} for possible states.
|
||||
* @return {import("./Source.js").State} State.
|
||||
* @api
|
||||
*/
|
||||
getState() {
|
||||
return this.state_;
|
||||
}
|
||||
/**
|
||||
* @return {boolean|undefined} Wrap X.
|
||||
*/
|
||||
getWrapX() {
|
||||
return this.wrapX_;
|
||||
}
|
||||
/**
|
||||
* @return {boolean} Use linear interpolation when resampling.
|
||||
*/
|
||||
getInterpolate() {
|
||||
return this.interpolate_;
|
||||
}
|
||||
/**
|
||||
* Refreshes the source. The source will be cleared, and data from the server will be reloaded.
|
||||
* @api
|
||||
*/
|
||||
refresh() {
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* Set the attributions of the source.
|
||||
* @param {AttributionLike|undefined} attributions Attributions.
|
||||
* Can be passed as `string`, `Array<string>`, {@link module:ol/source/Source~Attribution},
|
||||
* or `undefined`.
|
||||
* @api
|
||||
*/
|
||||
setAttributions(attributions) {
|
||||
this.attributions_ = adaptAttributions(attributions);
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* Set the state of the source.
|
||||
* @param {import("./Source.js").State} state State.
|
||||
*/
|
||||
setState(state) {
|
||||
this.state_ = state;
|
||||
this.changed();
|
||||
}
|
||||
};
|
||||
function adaptAttributions(attributionLike) {
|
||||
if (!attributionLike) {
|
||||
return null;
|
||||
}
|
||||
if (typeof attributionLike === "function") {
|
||||
return attributionLike;
|
||||
}
|
||||
if (!Array.isArray(attributionLike)) {
|
||||
attributionLike = [attributionLike];
|
||||
}
|
||||
return (frameState) => attributionLike;
|
||||
}
|
||||
var Source_default = Source;
|
||||
|
||||
export {
|
||||
Source_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-6Y7C6NBJ.js.map
|
||||
7
node_modules/.vite/deps/chunk-6Y7C6NBJ.js.map
generated
vendored
1907
node_modules/.vite/deps/chunk-7JXPN73Q.js
generated
vendored
7
node_modules/.vite/deps/chunk-7JXPN73Q.js.map
generated
vendored
1357
node_modules/.vite/deps/chunk-7XMWB3J4.js
generated
vendored
7
node_modules/.vite/deps/chunk-7XMWB3J4.js.map
generated
vendored
1089
node_modules/.vite/deps/chunk-A3RXLHYB.js
generated
vendored
7
node_modules/.vite/deps/chunk-A3RXLHYB.js.map
generated
vendored
329
node_modules/.vite/deps/chunk-AYBYZSAV.js
generated
vendored
@ -1,329 +0,0 @@
|
||||
import {
|
||||
assert
|
||||
} from "./chunk-QFCIXVZ3.js";
|
||||
import {
|
||||
clamp
|
||||
} from "./chunk-54BTDBAD.js";
|
||||
import {
|
||||
Object_default,
|
||||
abstract
|
||||
} from "./chunk-Q5ZULJHM.js";
|
||||
|
||||
// node_modules/ol/layer/Property.js
|
||||
var Property_default = {
|
||||
OPACITY: "opacity",
|
||||
VISIBLE: "visible",
|
||||
EXTENT: "extent",
|
||||
Z_INDEX: "zIndex",
|
||||
MAX_RESOLUTION: "maxResolution",
|
||||
MIN_RESOLUTION: "minResolution",
|
||||
MAX_ZOOM: "maxZoom",
|
||||
MIN_ZOOM: "minZoom",
|
||||
SOURCE: "source",
|
||||
MAP: "map"
|
||||
};
|
||||
|
||||
// node_modules/ol/layer/Base.js
|
||||
var BaseLayer = class extends Object_default {
|
||||
/**
|
||||
* @param {Options} options Layer options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
this.on;
|
||||
this.once;
|
||||
this.un;
|
||||
this.background_ = options.background;
|
||||
const properties = Object.assign({}, options);
|
||||
if (typeof options.properties === "object") {
|
||||
delete properties.properties;
|
||||
Object.assign(properties, options.properties);
|
||||
}
|
||||
properties[Property_default.OPACITY] = options.opacity !== void 0 ? options.opacity : 1;
|
||||
assert(
|
||||
typeof properties[Property_default.OPACITY] === "number",
|
||||
"Layer opacity must be a number"
|
||||
);
|
||||
properties[Property_default.VISIBLE] = options.visible !== void 0 ? options.visible : true;
|
||||
properties[Property_default.Z_INDEX] = options.zIndex;
|
||||
properties[Property_default.MAX_RESOLUTION] = options.maxResolution !== void 0 ? options.maxResolution : Infinity;
|
||||
properties[Property_default.MIN_RESOLUTION] = options.minResolution !== void 0 ? options.minResolution : 0;
|
||||
properties[Property_default.MIN_ZOOM] = options.minZoom !== void 0 ? options.minZoom : -Infinity;
|
||||
properties[Property_default.MAX_ZOOM] = options.maxZoom !== void 0 ? options.maxZoom : Infinity;
|
||||
this.className_ = properties.className !== void 0 ? properties.className : "ol-layer";
|
||||
delete properties.className;
|
||||
this.setProperties(properties);
|
||||
this.state_ = null;
|
||||
}
|
||||
/**
|
||||
* Get the background for this layer.
|
||||
* @return {BackgroundColor|false} Layer background.
|
||||
*/
|
||||
getBackground() {
|
||||
return this.background_;
|
||||
}
|
||||
/**
|
||||
* @return {string} CSS class name.
|
||||
*/
|
||||
getClassName() {
|
||||
return this.className_;
|
||||
}
|
||||
/**
|
||||
* This method is not meant to be called by layers or layer renderers because the state
|
||||
* is incorrect if the layer is included in a layer group.
|
||||
*
|
||||
* @param {boolean} [managed] Layer is managed.
|
||||
* @return {import("./Layer.js").State} Layer state.
|
||||
*/
|
||||
getLayerState(managed) {
|
||||
const state = this.state_ || /** @type {?} */
|
||||
{
|
||||
layer: this,
|
||||
managed: managed === void 0 ? true : managed
|
||||
};
|
||||
const zIndex = this.getZIndex();
|
||||
state.opacity = clamp(Math.round(this.getOpacity() * 100) / 100, 0, 1);
|
||||
state.visible = this.getVisible();
|
||||
state.extent = this.getExtent();
|
||||
state.zIndex = zIndex === void 0 && !state.managed ? Infinity : zIndex;
|
||||
state.maxResolution = this.getMaxResolution();
|
||||
state.minResolution = Math.max(this.getMinResolution(), 0);
|
||||
state.minZoom = this.getMinZoom();
|
||||
state.maxZoom = this.getMaxZoom();
|
||||
this.state_ = state;
|
||||
return state;
|
||||
}
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Array<import("./Layer.js").default>} [array] Array of layers (to be
|
||||
* modified in place).
|
||||
* @return {Array<import("./Layer.js").default>} Array of layers.
|
||||
*/
|
||||
getLayersArray(array) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* @abstract
|
||||
* @param {Array<import("./Layer.js").State>} [states] Optional list of layer
|
||||
* states (to be modified in place).
|
||||
* @return {Array<import("./Layer.js").State>} List of layer states.
|
||||
*/
|
||||
getLayerStatesArray(states) {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Return the {@link module:ol/extent~Extent extent} of the layer or `undefined` if it
|
||||
* will be visible regardless of extent.
|
||||
* @return {import("../extent.js").Extent|undefined} The layer extent.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getExtent() {
|
||||
return (
|
||||
/** @type {import("../extent.js").Extent|undefined} */
|
||||
this.get(Property_default.EXTENT)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Return the maximum resolution of the layer. Returns Infinity if
|
||||
* the layer has no maximum resolution set.
|
||||
* @return {number} The maximum resolution of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getMaxResolution() {
|
||||
return (
|
||||
/** @type {number} */
|
||||
this.get(Property_default.MAX_RESOLUTION)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Return the minimum resolution of the layer. Returns 0 if
|
||||
* the layer has no minimum resolution set.
|
||||
* @return {number} The minimum resolution of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getMinResolution() {
|
||||
return (
|
||||
/** @type {number} */
|
||||
this.get(Property_default.MIN_RESOLUTION)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Return the minimum zoom level of the layer. Returns -Infinity if
|
||||
* the layer has no minimum zoom set.
|
||||
* @return {number} The minimum zoom level of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getMinZoom() {
|
||||
return (
|
||||
/** @type {number} */
|
||||
this.get(Property_default.MIN_ZOOM)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Return the maximum zoom level of the layer. Returns Infinity if
|
||||
* the layer has no maximum zoom set.
|
||||
* @return {number} The maximum zoom level of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getMaxZoom() {
|
||||
return (
|
||||
/** @type {number} */
|
||||
this.get(Property_default.MAX_ZOOM)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Return the opacity of the layer (between 0 and 1).
|
||||
* @return {number} The opacity of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getOpacity() {
|
||||
return (
|
||||
/** @type {number} */
|
||||
this.get(Property_default.OPACITY)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @abstract
|
||||
* @return {import("../source/Source.js").State} Source state.
|
||||
*/
|
||||
getSourceState() {
|
||||
return abstract();
|
||||
}
|
||||
/**
|
||||
* Return the value of this layer's `visible` property. To find out whether the layer
|
||||
* is visible on a map, use `isVisible()` instead.
|
||||
* @return {boolean} The value of the `visible` property of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getVisible() {
|
||||
return (
|
||||
/** @type {boolean} */
|
||||
this.get(Property_default.VISIBLE)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Return the Z-index of the layer, which is used to order layers before
|
||||
* rendering. Returns undefined if the layer is unmanaged.
|
||||
* @return {number|undefined} The Z-index of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getZIndex() {
|
||||
return (
|
||||
/** @type {number|undefined} */
|
||||
this.get(Property_default.Z_INDEX)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Sets the background color.
|
||||
* @param {BackgroundColor} [background] Background color.
|
||||
*/
|
||||
setBackground(background) {
|
||||
this.background_ = background;
|
||||
this.changed();
|
||||
}
|
||||
/**
|
||||
* Set the extent at which the layer is visible. If `undefined`, the layer
|
||||
* will be visible at all extents.
|
||||
* @param {import("../extent.js").Extent|undefined} extent The extent of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setExtent(extent) {
|
||||
this.set(Property_default.EXTENT, extent);
|
||||
}
|
||||
/**
|
||||
* Set the maximum resolution at which the layer is visible.
|
||||
* @param {number} maxResolution The maximum resolution of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setMaxResolution(maxResolution) {
|
||||
this.set(Property_default.MAX_RESOLUTION, maxResolution);
|
||||
}
|
||||
/**
|
||||
* Set the minimum resolution at which the layer is visible.
|
||||
* @param {number} minResolution The minimum resolution of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setMinResolution(minResolution) {
|
||||
this.set(Property_default.MIN_RESOLUTION, minResolution);
|
||||
}
|
||||
/**
|
||||
* Set the maximum zoom (exclusive) at which the layer is visible.
|
||||
* Note that the zoom levels for layer visibility are based on the
|
||||
* view zoom level, which may be different from a tile source zoom level.
|
||||
* @param {number} maxZoom The maximum zoom of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setMaxZoom(maxZoom) {
|
||||
this.set(Property_default.MAX_ZOOM, maxZoom);
|
||||
}
|
||||
/**
|
||||
* Set the minimum zoom (inclusive) at which the layer is visible.
|
||||
* Note that the zoom levels for layer visibility are based on the
|
||||
* view zoom level, which may be different from a tile source zoom level.
|
||||
* @param {number} minZoom The minimum zoom of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setMinZoom(minZoom) {
|
||||
this.set(Property_default.MIN_ZOOM, minZoom);
|
||||
}
|
||||
/**
|
||||
* Set the opacity of the layer, allowed values range from 0 to 1.
|
||||
* @param {number} opacity The opacity of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setOpacity(opacity) {
|
||||
assert(typeof opacity === "number", "Layer opacity must be a number");
|
||||
this.set(Property_default.OPACITY, opacity);
|
||||
}
|
||||
/**
|
||||
* Set the visibility of the layer (`true` or `false`).
|
||||
* @param {boolean} visible The visibility of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setVisible(visible) {
|
||||
this.set(Property_default.VISIBLE, visible);
|
||||
}
|
||||
/**
|
||||
* Set Z-index of the layer, which is used to order layers before rendering.
|
||||
* The default Z-index is 0.
|
||||
* @param {number} zindex The z-index of the layer.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setZIndex(zindex) {
|
||||
this.set(Property_default.Z_INDEX, zindex);
|
||||
}
|
||||
/**
|
||||
* Clean up.
|
||||
* @override
|
||||
*/
|
||||
disposeInternal() {
|
||||
if (this.state_) {
|
||||
this.state_.layer = null;
|
||||
this.state_ = null;
|
||||
}
|
||||
super.disposeInternal();
|
||||
}
|
||||
};
|
||||
var Base_default = BaseLayer;
|
||||
|
||||
export {
|
||||
Property_default,
|
||||
Base_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-AYBYZSAV.js.map
|
||||
7
node_modules/.vite/deps/chunk-AYBYZSAV.js.map
generated
vendored
2010
node_modules/.vite/deps/chunk-AZGMK675.js
generated
vendored
7
node_modules/.vite/deps/chunk-AZGMK675.js.map
generated
vendored
38
node_modules/.vite/deps/chunk-BHVDQB66.js
generated
vendored
@ -1,38 +0,0 @@
|
||||
// node_modules/ol/MapEventType.js
|
||||
var MapEventType_default = {
|
||||
/**
|
||||
* Triggered after a map frame is rendered.
|
||||
* @event module:ol/MapEvent~MapEvent#postrender
|
||||
* @api
|
||||
*/
|
||||
POSTRENDER: "postrender",
|
||||
/**
|
||||
* Triggered when the map starts moving.
|
||||
* @event module:ol/MapEvent~MapEvent#movestart
|
||||
* @api
|
||||
*/
|
||||
MOVESTART: "movestart",
|
||||
/**
|
||||
* Triggered after the map is moved.
|
||||
* @event module:ol/MapEvent~MapEvent#moveend
|
||||
* @api
|
||||
*/
|
||||
MOVEEND: "moveend",
|
||||
/**
|
||||
* Triggered when loading of additional map data (tiles, images, features) starts.
|
||||
* @event module:ol/MapEvent~MapEvent#loadstart
|
||||
* @api
|
||||
*/
|
||||
LOADSTART: "loadstart",
|
||||
/**
|
||||
* Triggered when loading of additional map data has completed.
|
||||
* @event module:ol/MapEvent~MapEvent#loadend
|
||||
* @api
|
||||
*/
|
||||
LOADEND: "loadend"
|
||||
};
|
||||
|
||||
export {
|
||||
MapEventType_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-BHVDQB66.js.map
|
||||
7
node_modules/.vite/deps/chunk-BHVDQB66.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../ol/MapEventType.js"],
|
||||
"sourcesContent": ["/**\n * @module ol/MapEventType\n */\n\n/**\n * @enum {string}\n */\nexport default {\n /**\n * Triggered after a map frame is rendered.\n * @event module:ol/MapEvent~MapEvent#postrender\n * @api\n */\n POSTRENDER: 'postrender',\n\n /**\n * Triggered when the map starts moving.\n * @event module:ol/MapEvent~MapEvent#movestart\n * @api\n */\n MOVESTART: 'movestart',\n\n /**\n * Triggered after the map is moved.\n * @event module:ol/MapEvent~MapEvent#moveend\n * @api\n */\n MOVEEND: 'moveend',\n\n /**\n * Triggered when loading of additional map data (tiles, images, features) starts.\n * @event module:ol/MapEvent~MapEvent#loadstart\n * @api\n */\n LOADSTART: 'loadstart',\n\n /**\n * Triggered when loading of additional map data has completed.\n * @event module:ol/MapEvent~MapEvent#loadend\n * @api\n */\n LOADEND: 'loadend',\n};\n\n/***\n * @typedef {'postrender'|'movestart'|'moveend'|'loadstart'|'loadend'} Types\n */\n"],
|
||||
"mappings": ";AAOA,IAAO,uBAAQ;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMb,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOZ,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOX,SAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOX,SAAS;AACX;",
|
||||
"names": []
|
||||
}
|
||||
114
node_modules/.vite/deps/chunk-C5KGH6RQ.js
generated
vendored
@ -1,114 +0,0 @@
|
||||
// node_modules/geotiff/dist-module/predictor.js
|
||||
function decodeRowAcc(row, stride) {
|
||||
let length = row.length - stride;
|
||||
let offset = 0;
|
||||
do {
|
||||
for (let i = stride; i > 0; i--) {
|
||||
row[offset + stride] += row[offset];
|
||||
offset++;
|
||||
}
|
||||
length -= stride;
|
||||
} while (length > 0);
|
||||
}
|
||||
function decodeRowFloatingPoint(row, stride, bytesPerSample) {
|
||||
let index = 0;
|
||||
let count = row.length;
|
||||
const wc = count / bytesPerSample;
|
||||
while (count > stride) {
|
||||
for (let i = stride; i > 0; --i) {
|
||||
row[index + stride] += row[index];
|
||||
++index;
|
||||
}
|
||||
count -= stride;
|
||||
}
|
||||
const copy = row.slice();
|
||||
for (let i = 0; i < wc; ++i) {
|
||||
for (let b = 0; b < bytesPerSample; ++b) {
|
||||
row[bytesPerSample * i + b] = copy[(bytesPerSample - b - 1) * wc + i];
|
||||
}
|
||||
}
|
||||
}
|
||||
function applyPredictor(block, predictor, width, height, bitsPerSample, planarConfiguration) {
|
||||
if (!predictor || predictor === 1) {
|
||||
return block;
|
||||
}
|
||||
for (let i = 0; i < bitsPerSample.length; ++i) {
|
||||
if (bitsPerSample[i] % 8 !== 0) {
|
||||
throw new Error("When decoding with predictor, only multiple of 8 bits are supported.");
|
||||
}
|
||||
if (bitsPerSample[i] !== bitsPerSample[0]) {
|
||||
throw new Error("When decoding with predictor, all samples must have the same size.");
|
||||
}
|
||||
}
|
||||
const bytesPerSample = bitsPerSample[0] / 8;
|
||||
const stride = planarConfiguration === 2 ? 1 : bitsPerSample.length;
|
||||
for (let i = 0; i < height; ++i) {
|
||||
if (i * stride * width * bytesPerSample >= block.byteLength) {
|
||||
break;
|
||||
}
|
||||
let row;
|
||||
if (predictor === 2) {
|
||||
switch (bitsPerSample[0]) {
|
||||
case 8:
|
||||
row = new Uint8Array(
|
||||
block,
|
||||
i * stride * width * bytesPerSample,
|
||||
stride * width * bytesPerSample
|
||||
);
|
||||
break;
|
||||
case 16:
|
||||
row = new Uint16Array(
|
||||
block,
|
||||
i * stride * width * bytesPerSample,
|
||||
stride * width * bytesPerSample / 2
|
||||
);
|
||||
break;
|
||||
case 32:
|
||||
row = new Uint32Array(
|
||||
block,
|
||||
i * stride * width * bytesPerSample,
|
||||
stride * width * bytesPerSample / 4
|
||||
);
|
||||
break;
|
||||
default:
|
||||
throw new Error(`Predictor 2 not allowed with ${bitsPerSample[0]} bits per sample.`);
|
||||
}
|
||||
decodeRowAcc(row, stride, bytesPerSample);
|
||||
} else if (predictor === 3) {
|
||||
row = new Uint8Array(
|
||||
block,
|
||||
i * stride * width * bytesPerSample,
|
||||
stride * width * bytesPerSample
|
||||
);
|
||||
decodeRowFloatingPoint(row, stride, bytesPerSample);
|
||||
}
|
||||
}
|
||||
return block;
|
||||
}
|
||||
|
||||
// node_modules/geotiff/dist-module/compression/basedecoder.js
|
||||
var BaseDecoder = class {
|
||||
async decode(fileDirectory, buffer) {
|
||||
const decoded = await this.decodeBlock(buffer);
|
||||
const predictor = fileDirectory.Predictor || 1;
|
||||
if (predictor !== 1) {
|
||||
const isTiled = !fileDirectory.StripOffsets;
|
||||
const tileWidth = isTiled ? fileDirectory.TileWidth : fileDirectory.ImageWidth;
|
||||
const tileHeight = isTiled ? fileDirectory.TileLength : fileDirectory.RowsPerStrip || fileDirectory.ImageLength;
|
||||
return applyPredictor(
|
||||
decoded,
|
||||
predictor,
|
||||
tileWidth,
|
||||
tileHeight,
|
||||
fileDirectory.BitsPerSample,
|
||||
fileDirectory.PlanarConfiguration
|
||||
);
|
||||
}
|
||||
return decoded;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
BaseDecoder
|
||||
};
|
||||
//# sourceMappingURL=chunk-C5KGH6RQ.js.map
|
||||
7
node_modules/.vite/deps/chunk-C5KGH6RQ.js.map
generated
vendored
@ -1,7 +0,0 @@
|
||||
{
|
||||
"version": 3,
|
||||
"sources": ["../../geotiff/dist-module/predictor.js", "../../geotiff/dist-module/compression/basedecoder.js"],
|
||||
"sourcesContent": ["function decodeRowAcc(row, stride) {\n let length = row.length - stride;\n let offset = 0;\n do {\n for (let i = stride; i > 0; i--) {\n row[offset + stride] += row[offset];\n offset++;\n }\n\n length -= stride;\n } while (length > 0);\n}\n\nfunction decodeRowFloatingPoint(row, stride, bytesPerSample) {\n let index = 0;\n let count = row.length;\n const wc = count / bytesPerSample;\n\n while (count > stride) {\n for (let i = stride; i > 0; --i) {\n row[index + stride] += row[index];\n ++index;\n }\n count -= stride;\n }\n\n const copy = row.slice();\n for (let i = 0; i < wc; ++i) {\n for (let b = 0; b < bytesPerSample; ++b) {\n row[(bytesPerSample * i) + b] = copy[((bytesPerSample - b - 1) * wc) + i];\n }\n }\n}\n\nexport function applyPredictor(block, predictor, width, height, bitsPerSample,\n planarConfiguration) {\n if (!predictor || predictor === 1) {\n return block;\n }\n\n for (let i = 0; i < bitsPerSample.length; ++i) {\n if (bitsPerSample[i] % 8 !== 0) {\n throw new Error('When decoding with predictor, only multiple of 8 bits are supported.');\n }\n if (bitsPerSample[i] !== bitsPerSample[0]) {\n throw new Error('When decoding with predictor, all samples must have the same size.');\n }\n }\n\n const bytesPerSample = bitsPerSample[0] / 8;\n const stride = planarConfiguration === 2 ? 1 : bitsPerSample.length;\n\n for (let i = 0; i < height; ++i) {\n // Last strip will be truncated if height % stripHeight != 0\n if (i * stride * width * bytesPerSample >= block.byteLength) {\n break;\n }\n let row;\n if (predictor === 2) { // horizontal prediction\n switch (bitsPerSample[0]) {\n case 8:\n row = new Uint8Array(\n block, i * stride * width * bytesPerSample, stride * width * bytesPerSample,\n );\n break;\n case 16:\n row = new Uint16Array(\n block, i * stride * width * bytesPerSample, stride * width * bytesPerSample / 2,\n );\n break;\n case 32:\n row = new Uint32Array(\n block, i * stride * width * bytesPerSample, stride * width * bytesPerSample / 4,\n );\n break;\n default:\n throw new Error(`Predictor 2 not allowed with ${bitsPerSample[0]} bits per sample.`);\n }\n decodeRowAcc(row, stride, bytesPerSample);\n } else if (predictor === 3) { // horizontal floating point\n row = new Uint8Array(\n block, i * stride * width * bytesPerSample, stride * width * bytesPerSample,\n );\n decodeRowFloatingPoint(row, stride, bytesPerSample);\n }\n }\n return block;\n}\n", "import { applyPredictor } from '../predictor.js';\n\nexport default class BaseDecoder {\n async decode(fileDirectory, buffer) {\n const decoded = await this.decodeBlock(buffer);\n const predictor = fileDirectory.Predictor || 1;\n if (predictor !== 1) {\n const isTiled = !fileDirectory.StripOffsets;\n const tileWidth = isTiled ? fileDirectory.TileWidth : fileDirectory.ImageWidth;\n const tileHeight = isTiled ? fileDirectory.TileLength : (\n fileDirectory.RowsPerStrip || fileDirectory.ImageLength\n );\n return applyPredictor(\n decoded, predictor, tileWidth, tileHeight, fileDirectory.BitsPerSample,\n fileDirectory.PlanarConfiguration,\n );\n }\n return decoded;\n }\n}\n"],
|
||||
"mappings": ";AAAA,SAAS,aAAa,KAAK,QAAQ;AACjC,MAAI,SAAS,IAAI,SAAS;AAC1B,MAAI,SAAS;AACb,KAAG;AACD,aAAS,IAAI,QAAQ,IAAI,GAAG,KAAK;AAC/B,UAAI,SAAS,MAAM,KAAK,IAAI,MAAM;AAClC;AAAA,IACF;AAEA,cAAU;AAAA,EACZ,SAAS,SAAS;AACpB;AAEA,SAAS,uBAAuB,KAAK,QAAQ,gBAAgB;AAC3D,MAAI,QAAQ;AACZ,MAAI,QAAQ,IAAI;AAChB,QAAM,KAAK,QAAQ;AAEnB,SAAO,QAAQ,QAAQ;AACrB,aAAS,IAAI,QAAQ,IAAI,GAAG,EAAE,GAAG;AAC/B,UAAI,QAAQ,MAAM,KAAK,IAAI,KAAK;AAChC,QAAE;AAAA,IACJ;AACA,aAAS;AAAA,EACX;AAEA,QAAM,OAAO,IAAI,MAAM;AACvB,WAAS,IAAI,GAAG,IAAI,IAAI,EAAE,GAAG;AAC3B,aAAS,IAAI,GAAG,IAAI,gBAAgB,EAAE,GAAG;AACvC,UAAK,iBAAiB,IAAK,CAAC,IAAI,MAAO,iBAAiB,IAAI,KAAK,KAAM,CAAC;AAAA,IAC1E;AAAA,EACF;AACF;AAEO,SAAS,eAAe,OAAO,WAAW,OAAO,QAAQ,eAC9D,qBAAqB;AACrB,MAAI,CAAC,aAAa,cAAc,GAAG;AACjC,WAAO;AAAA,EACT;AAEA,WAAS,IAAI,GAAG,IAAI,cAAc,QAAQ,EAAE,GAAG;AAC7C,QAAI,cAAc,CAAC,IAAI,MAAM,GAAG;AAC9B,YAAM,IAAI,MAAM,sEAAsE;AAAA,IACxF;AACA,QAAI,cAAc,CAAC,MAAM,cAAc,CAAC,GAAG;AACzC,YAAM,IAAI,MAAM,oEAAoE;AAAA,IACtF;AAAA,EACF;AAEA,QAAM,iBAAiB,cAAc,CAAC,IAAI;AAC1C,QAAM,SAAS,wBAAwB,IAAI,IAAI,cAAc;AAE7D,WAAS,IAAI,GAAG,IAAI,QAAQ,EAAE,GAAG;AAE/B,QAAI,IAAI,SAAS,QAAQ,kBAAkB,MAAM,YAAY;AAC3D;AAAA,IACF;AACA,QAAI;AACJ,QAAI,cAAc,GAAG;AACnB,cAAQ,cAAc,CAAC,GAAG;AAAA,QACxB,KAAK;AACH,gBAAM,IAAI;AAAA,YACR;AAAA,YAAO,IAAI,SAAS,QAAQ;AAAA,YAAgB,SAAS,QAAQ;AAAA,UAC/D;AACA;AAAA,QACF,KAAK;AACH,gBAAM,IAAI;AAAA,YACR;AAAA,YAAO,IAAI,SAAS,QAAQ;AAAA,YAAgB,SAAS,QAAQ,iBAAiB;AAAA,UAChF;AACA;AAAA,QACF,KAAK;AACH,gBAAM,IAAI;AAAA,YACR;AAAA,YAAO,IAAI,SAAS,QAAQ;AAAA,YAAgB,SAAS,QAAQ,iBAAiB;AAAA,UAChF;AACA;AAAA,QACF;AACE,gBAAM,IAAI,MAAM,gCAAgC,cAAc,CAAC,CAAC,mBAAmB;AAAA,MACvF;AACA,mBAAa,KAAK,QAAQ,cAAc;AAAA,IAC1C,WAAW,cAAc,GAAG;AAC1B,YAAM,IAAI;AAAA,QACR;AAAA,QAAO,IAAI,SAAS,QAAQ;AAAA,QAAgB,SAAS,QAAQ;AAAA,MAC/D;AACA,6BAAuB,KAAK,QAAQ,cAAc;AAAA,IACpD;AAAA,EACF;AACA,SAAO;AACT;;;ACrFA,IAAqB,cAArB,MAAiC;AAAA,EAC/B,MAAM,OAAO,eAAe,QAAQ;AAClC,UAAM,UAAU,MAAM,KAAK,YAAY,MAAM;AAC7C,UAAM,YAAY,cAAc,aAAa;AAC7C,QAAI,cAAc,GAAG;AACnB,YAAM,UAAU,CAAC,cAAc;AAC/B,YAAM,YAAY,UAAU,cAAc,YAAY,cAAc;AACpE,YAAM,aAAa,UAAU,cAAc,aACzC,cAAc,gBAAgB,cAAc;AAE9C,aAAO;AAAA,QACL;AAAA,QAAS;AAAA,QAAW;AAAA,QAAW;AAAA,QAAY,cAAc;AAAA,QACzD,cAAc;AAAA,MAChB;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACF;",
|
||||
"names": []
|
||||
}
|
||||
397
node_modules/.vite/deps/chunk-C6SRSVJF.js
generated
vendored
@ -1,397 +0,0 @@
|
||||
import {
|
||||
MapEventType_default
|
||||
} from "./chunk-BHVDQB66.js";
|
||||
import {
|
||||
CLASS_SELECTABLE
|
||||
} from "./chunk-6EWLK2BW.js";
|
||||
import {
|
||||
outerHeight,
|
||||
outerWidth,
|
||||
removeChildren
|
||||
} from "./chunk-UPTVWZ45.js";
|
||||
import {
|
||||
Object_default
|
||||
} from "./chunk-Q5ZULJHM.js";
|
||||
import {
|
||||
listen,
|
||||
unlistenByKey
|
||||
} from "./chunk-NGFXCWUF.js";
|
||||
import {
|
||||
containsExtent
|
||||
} from "./chunk-SRXHWJOY.js";
|
||||
|
||||
// node_modules/ol/Overlay.js
|
||||
var Property = {
|
||||
ELEMENT: "element",
|
||||
MAP: "map",
|
||||
OFFSET: "offset",
|
||||
POSITION: "position",
|
||||
POSITIONING: "positioning"
|
||||
};
|
||||
var Overlay = class extends Object_default {
|
||||
/**
|
||||
* @param {Options} options Overlay options.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
this.on;
|
||||
this.once;
|
||||
this.un;
|
||||
this.options = options;
|
||||
this.id = options.id;
|
||||
this.insertFirst = options.insertFirst !== void 0 ? options.insertFirst : true;
|
||||
this.stopEvent = options.stopEvent !== void 0 ? options.stopEvent : true;
|
||||
this.element = document.createElement("div");
|
||||
this.element.className = options.className !== void 0 ? options.className : "ol-overlay-container " + CLASS_SELECTABLE;
|
||||
this.element.style.position = "absolute";
|
||||
this.element.style.pointerEvents = "auto";
|
||||
this.autoPan = options.autoPan === true ? {} : options.autoPan || void 0;
|
||||
this.rendered = {
|
||||
transform_: "",
|
||||
visible: true
|
||||
};
|
||||
this.mapPostrenderListenerKey = null;
|
||||
this.addChangeListener(Property.ELEMENT, this.handleElementChanged);
|
||||
this.addChangeListener(Property.MAP, this.handleMapChanged);
|
||||
this.addChangeListener(Property.OFFSET, this.handleOffsetChanged);
|
||||
this.addChangeListener(Property.POSITION, this.handlePositionChanged);
|
||||
this.addChangeListener(Property.POSITIONING, this.handlePositioningChanged);
|
||||
if (options.element !== void 0) {
|
||||
this.setElement(options.element);
|
||||
}
|
||||
this.setOffset(options.offset !== void 0 ? options.offset : [0, 0]);
|
||||
this.setPositioning(options.positioning || "top-left");
|
||||
if (options.position !== void 0) {
|
||||
this.setPosition(options.position);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the DOM element of this overlay.
|
||||
* @return {HTMLElement|undefined} The Element containing the overlay.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getElement() {
|
||||
return (
|
||||
/** @type {HTMLElement|undefined} */
|
||||
this.get(Property.ELEMENT)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Get the overlay identifier which is set on constructor.
|
||||
* @return {number|string|undefined} Id.
|
||||
* @api
|
||||
*/
|
||||
getId() {
|
||||
return this.id;
|
||||
}
|
||||
/**
|
||||
* Get the map associated with this overlay.
|
||||
* @return {import("./Map.js").default|null} The map that the
|
||||
* overlay is part of.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getMap() {
|
||||
return (
|
||||
/** @type {import("./Map.js").default|null} */
|
||||
this.get(Property.MAP) || null
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Get the offset of this overlay.
|
||||
* @return {Array<number>} The offset.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getOffset() {
|
||||
return (
|
||||
/** @type {Array<number>} */
|
||||
this.get(Property.OFFSET)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Get the current position of this overlay.
|
||||
* @return {import("./coordinate.js").Coordinate|undefined} The spatial point that the overlay is
|
||||
* anchored at.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getPosition() {
|
||||
return (
|
||||
/** @type {import("./coordinate.js").Coordinate|undefined} */
|
||||
this.get(Property.POSITION)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* Get the current positioning of this overlay.
|
||||
* @return {Positioning} How the overlay is positioned
|
||||
* relative to its point on the map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
getPositioning() {
|
||||
return (
|
||||
/** @type {Positioning} */
|
||||
this.get(Property.POSITIONING)
|
||||
);
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleElementChanged() {
|
||||
removeChildren(this.element);
|
||||
const element = this.getElement();
|
||||
if (element) {
|
||||
this.element.appendChild(element);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleMapChanged() {
|
||||
var _a;
|
||||
if (this.mapPostrenderListenerKey) {
|
||||
(_a = this.element) == null ? void 0 : _a.remove();
|
||||
unlistenByKey(this.mapPostrenderListenerKey);
|
||||
this.mapPostrenderListenerKey = null;
|
||||
}
|
||||
const map = this.getMap();
|
||||
if (map) {
|
||||
this.mapPostrenderListenerKey = listen(
|
||||
map,
|
||||
MapEventType_default.POSTRENDER,
|
||||
this.render,
|
||||
this
|
||||
);
|
||||
this.updatePixelPosition();
|
||||
const container = this.stopEvent ? map.getOverlayContainerStopEvent() : map.getOverlayContainer();
|
||||
if (this.insertFirst) {
|
||||
container.insertBefore(this.element, container.childNodes[0] || null);
|
||||
} else {
|
||||
container.appendChild(this.element);
|
||||
}
|
||||
this.performAutoPan();
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
render() {
|
||||
this.updatePixelPosition();
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handleOffsetChanged() {
|
||||
this.updatePixelPosition();
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handlePositionChanged() {
|
||||
this.updatePixelPosition();
|
||||
this.performAutoPan();
|
||||
}
|
||||
/**
|
||||
* @protected
|
||||
*/
|
||||
handlePositioningChanged() {
|
||||
this.updatePixelPosition();
|
||||
}
|
||||
/**
|
||||
* Set the DOM element to be associated with this overlay.
|
||||
* @param {HTMLElement|undefined} element The Element containing the overlay.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setElement(element) {
|
||||
this.set(Property.ELEMENT, element);
|
||||
}
|
||||
/**
|
||||
* Set the map to be associated with this overlay.
|
||||
* @param {import("./Map.js").default|null} map The map that the
|
||||
* overlay is part of. Pass `null` to just remove the overlay from the current map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setMap(map) {
|
||||
this.set(Property.MAP, map);
|
||||
}
|
||||
/**
|
||||
* Set the offset for this overlay.
|
||||
* @param {Array<number>} offset Offset.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setOffset(offset) {
|
||||
this.set(Property.OFFSET, offset);
|
||||
}
|
||||
/**
|
||||
* Set the position for this overlay. If the position is `undefined` the
|
||||
* overlay is hidden.
|
||||
* @param {import("./coordinate.js").Coordinate|undefined} position The spatial point that the overlay
|
||||
* is anchored at.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setPosition(position) {
|
||||
this.set(Property.POSITION, position);
|
||||
}
|
||||
/**
|
||||
* Pan the map so that the overlay is entirely visible in the current viewport
|
||||
* (if necessary) using the configured autoPan parameters
|
||||
* @protected
|
||||
*/
|
||||
performAutoPan() {
|
||||
if (this.autoPan) {
|
||||
this.panIntoView(this.autoPan);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Pan the map so that the overlay is entirely visible in the current viewport
|
||||
* (if necessary).
|
||||
* @param {PanIntoViewOptions} [panIntoViewOptions] Options for the pan action
|
||||
* @api
|
||||
*/
|
||||
panIntoView(panIntoViewOptions) {
|
||||
const map = this.getMap();
|
||||
if (!map || !map.getTargetElement() || !this.get(Property.POSITION)) {
|
||||
return;
|
||||
}
|
||||
const mapRect = this.getRect(map.getTargetElement(), map.getSize());
|
||||
const element = this.getElement();
|
||||
const overlayRect = this.getRect(element, [
|
||||
outerWidth(element),
|
||||
outerHeight(element)
|
||||
]);
|
||||
panIntoViewOptions = panIntoViewOptions || {};
|
||||
const myMargin = panIntoViewOptions.margin === void 0 ? 20 : panIntoViewOptions.margin;
|
||||
if (!containsExtent(mapRect, overlayRect)) {
|
||||
const offsetLeft = overlayRect[0] - mapRect[0];
|
||||
const offsetRight = mapRect[2] - overlayRect[2];
|
||||
const offsetTop = overlayRect[1] - mapRect[1];
|
||||
const offsetBottom = mapRect[3] - overlayRect[3];
|
||||
const delta = [0, 0];
|
||||
if (offsetLeft < 0) {
|
||||
delta[0] = offsetLeft - myMargin;
|
||||
} else if (offsetRight < 0) {
|
||||
delta[0] = Math.abs(offsetRight) + myMargin;
|
||||
}
|
||||
if (offsetTop < 0) {
|
||||
delta[1] = offsetTop - myMargin;
|
||||
} else if (offsetBottom < 0) {
|
||||
delta[1] = Math.abs(offsetBottom) + myMargin;
|
||||
}
|
||||
if (delta[0] !== 0 || delta[1] !== 0) {
|
||||
const center = (
|
||||
/** @type {import("./coordinate.js").Coordinate} */
|
||||
map.getView().getCenterInternal()
|
||||
);
|
||||
const centerPx = map.getPixelFromCoordinateInternal(center);
|
||||
if (!centerPx) {
|
||||
return;
|
||||
}
|
||||
const newCenterPx = [centerPx[0] + delta[0], centerPx[1] + delta[1]];
|
||||
const panOptions = panIntoViewOptions.animation || {};
|
||||
map.getView().animateInternal({
|
||||
center: map.getCoordinateFromPixelInternal(newCenterPx),
|
||||
duration: panOptions.duration,
|
||||
easing: panOptions.easing
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Get the extent of an element relative to the document
|
||||
* @param {HTMLElement} element The element.
|
||||
* @param {import("./size.js").Size} size The size of the element.
|
||||
* @return {import("./extent.js").Extent} The extent.
|
||||
* @protected
|
||||
*/
|
||||
getRect(element, size) {
|
||||
const box = element.getBoundingClientRect();
|
||||
const offsetX = box.left + window.pageXOffset;
|
||||
const offsetY = box.top + window.pageYOffset;
|
||||
return [offsetX, offsetY, offsetX + size[0], offsetY + size[1]];
|
||||
}
|
||||
/**
|
||||
* Set the positioning for this overlay.
|
||||
* @param {Positioning} positioning how the overlay is
|
||||
* positioned relative to its point on the map.
|
||||
* @observable
|
||||
* @api
|
||||
*/
|
||||
setPositioning(positioning) {
|
||||
this.set(Property.POSITIONING, positioning);
|
||||
}
|
||||
/**
|
||||
* Modify the visibility of the element.
|
||||
* @param {boolean} visible Element visibility.
|
||||
* @protected
|
||||
*/
|
||||
setVisible(visible) {
|
||||
if (this.rendered.visible !== visible) {
|
||||
this.element.style.display = visible ? "" : "none";
|
||||
this.rendered.visible = visible;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Update pixel position.
|
||||
* @protected
|
||||
*/
|
||||
updatePixelPosition() {
|
||||
const map = this.getMap();
|
||||
const position = this.getPosition();
|
||||
if (!map || !map.isRendered() || !position) {
|
||||
this.setVisible(false);
|
||||
return;
|
||||
}
|
||||
const pixel = map.getPixelFromCoordinate(position);
|
||||
const mapSize = map.getSize();
|
||||
this.updateRenderedPosition(pixel, mapSize);
|
||||
}
|
||||
/**
|
||||
* @param {import("./pixel.js").Pixel} pixel The pixel location.
|
||||
* @param {import("./size.js").Size|undefined} mapSize The map size.
|
||||
* @protected
|
||||
*/
|
||||
updateRenderedPosition(pixel, mapSize) {
|
||||
const style = this.element.style;
|
||||
const offset = this.getOffset();
|
||||
const positioning = this.getPositioning();
|
||||
this.setVisible(true);
|
||||
const x = `${pixel[0] + offset[0]}px`;
|
||||
const y = `${pixel[1] + offset[1]}px`;
|
||||
let posX = "0%";
|
||||
let posY = "0%";
|
||||
if (positioning == "bottom-right" || positioning == "center-right" || positioning == "top-right") {
|
||||
posX = "-100%";
|
||||
} else if (positioning == "bottom-center" || positioning == "center-center" || positioning == "top-center") {
|
||||
posX = "-50%";
|
||||
}
|
||||
if (positioning == "bottom-left" || positioning == "bottom-center" || positioning == "bottom-right") {
|
||||
posY = "-100%";
|
||||
} else if (positioning == "center-left" || positioning == "center-center" || positioning == "center-right") {
|
||||
posY = "-50%";
|
||||
}
|
||||
const transform = `translate(${posX}, ${posY}) translate(${x}, ${y})`;
|
||||
if (this.rendered.transform_ != transform) {
|
||||
this.rendered.transform_ = transform;
|
||||
style.transform = transform;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* returns the options this Overlay has been created with
|
||||
* @return {Options} overlay options
|
||||
*/
|
||||
getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
};
|
||||
var Overlay_default = Overlay;
|
||||
|
||||
export {
|
||||
Overlay_default
|
||||
};
|
||||
//# sourceMappingURL=chunk-C6SRSVJF.js.map
|
||||