|
6 | 6 | import { useProjectionNames } from "@/composables/SrProjections"; |
7 | 7 | import { srProjections } from "@/composables/SrProjections"; |
8 | 8 | import proj4 from 'proj4'; |
9 | | - import { register } from 'ol/proj/proj4'; |
| 9 | + import { register } from 'ol/proj/proj4.js'; |
10 | 10 | import 'ol-geocoder/dist/ol-geocoder.min.css'; |
11 | 11 | import { useMapStore } from "@/stores/mapStore"; |
12 | 12 | import { useGeoCoderStore } from '@/stores/geoCoderStore'; |
13 | 13 | import { get as getProjection } from 'ol/proj.js'; |
14 | 14 | import { addLayersForCurrentView } from "@/composables/SrLayers"; |
15 | | - import { Layer } from 'ol/layer'; |
| 15 | + import { Layer } from 'ol/layer.js'; |
16 | 16 | import { useWmsCap } from "@/composables/useWmsCap"; |
17 | | - import { Feature } from 'ol'; |
18 | | - import type { FeatureLike } from 'ol/Feature'; |
19 | | - import type Geometry from 'ol/geom/Geometry'; |
20 | | - import { Polygon as OlPolygon } from 'ol/geom'; |
21 | | - import { DragBox as DragBoxType } from 'ol/interaction'; |
22 | | - import { Draw as DrawType } from 'ol/interaction'; |
23 | | - import { Vector as VectorSource } from 'ol/source'; |
24 | | - import { fromExtent } from 'ol/geom/Polygon'; |
25 | | - import { Stroke, Style, Fill } from 'ol/style'; |
| 17 | + import Feature from 'ol/Feature.js'; |
| 18 | + import type { FeatureLike } from 'ol/Feature.js'; |
| 19 | + import type Geometry from 'ol/geom/Geometry.js'; |
| 20 | + import DragBox from 'ol/interaction/DragBox.js'; |
| 21 | + import Draw from 'ol/interaction/Draw.js'; |
| 22 | + import VectorSource from 'ol/source/Vector.js'; |
| 23 | + import { Stroke, Style, Fill } from 'ol/style.js'; |
26 | 24 | import { clearPolyCoords, clearReqGeoJsonData, drawGeoJson, enableTagDisplay, disableTagDisplay, saveMapZoomState, renderRequestPolygon, canRestoreZoomCenter, assignStyleFunctionToPinLayer } from "@/utils/SrMapUtils"; |
27 | 25 | import { onActivated } from "vue"; |
28 | 26 | import { onDeactivated } from "vue"; |
29 | 27 | import type { Ref } from "vue"; |
30 | 28 | import { checkAreaOfConvexHullWarning,updateSrViewName,renderReqPin } from "@/utils/SrMapUtils"; |
31 | | - import { toLonLat } from 'ol/proj'; |
| 29 | + import { toLonLat } from 'ol/proj.js'; |
32 | 30 | import { useReqParamsStore } from "@/stores/reqParamsStore"; |
33 | 31 | import { convexHull, isClockwise } from "@/composables/SrTurfUtils"; |
34 | | - import { type Coordinate } from "ol/coordinate"; |
| 32 | + import { type Coordinate } from "ol/coordinate.js"; |
35 | 33 | import { hullColor, type SrRegion } from '@/types/SrTypes' |
36 | | - import { format } from 'ol/coordinate'; |
| 34 | + import { format } from 'ol/coordinate.js'; |
37 | 35 | import SrViewControl from "./SrViewControl.vue"; |
38 | 36 | import SrBaseLayerControl from "./SrBaseLayerControl.vue"; |
39 | 37 | import SrDrawControl from "@/components/SrDrawControl.vue"; |
40 | 38 | import { Map, MapControls } from "vue3-openlayers"; |
41 | 39 | import { useRequestsStore } from "@/stores/requestsStore"; |
42 | | - import VectorLayer from "ol/layer/Vector"; |
| 40 | + import VectorLayer from "ol/layer/Vector.js"; |
43 | 41 | import { useDebugStore } from "@/stores/debugStore"; |
44 | 42 | import { updateMapView } from "@/utils/SrMapUtils"; |
45 | 43 | import { renderSvrReqPoly,renderSvrReqRegionMask,zoomOutToFullMap,renderSvrReqPin} from "@/utils/SrMapUtils"; |
46 | 44 | import router from '@/router/index.js'; |
47 | 45 | import { useRecTreeStore } from "@/stores/recTreeStore"; |
48 | 46 | import SrFeatureMenuOverlay from "@/components/SrFeatureMenuOverlay.vue"; |
49 | | - import type { Source } from 'ol/source'; |
50 | | - import type LayerRenderer from 'ol/renderer/Layer'; |
| 47 | + import type { Source } from 'ol/source.js'; |
| 48 | + import type LayerRenderer from 'ol/renderer/Layer.js'; |
51 | 49 | import SrCustomTooltip from "@/components//SrCustomTooltip.vue"; |
52 | 50 | import SrDropPinControl from "@/components//SrDropPinControl.vue"; |
53 | 51 | import SrUploadRegionControl from "@/components/SrUploadRegionControl.vue"; |
54 | | - import Point from 'ol/geom/Point'; |
| 52 | + import Point from 'ol/geom/Point.js'; |
55 | 53 | import { readShapefileToOlFeatures } from "@/composables/useReadShapefiles"; |
56 | 54 | import { useGeoJsonStore } from "@/stores/geoJsonStore"; |
57 | | - |
| 55 | + import OlOverlay from 'ol/Overlay.js'; |
| 56 | + import type Overlay from 'ol/Overlay'; |
| 57 | + import { getArea as geodesicArea } from 'ol/sphere.js'; |
| 58 | + import Polygon, { fromExtent as polygonFromExtent } from 'ol/geom/Polygon.js'; |
| 59 | + import { unByKey } from 'ol/Observable.js'; |
| 60 | +
|
| 61 | +
|
| 62 | +
|
| 63 | + const dragAreaEl = document.createElement('div'); |
| 64 | + dragAreaEl.className = 'ol-measure-hud'; |
| 65 | + const dragAreaOverlay = ref<Overlay | null>(null); |
| 66 | + let polyGeomChangeKey: any = null; |
| 67 | +
|
| 68 | + function formatArea(m2: number): string { |
| 69 | + if (!isFinite(m2)) return ''; |
| 70 | + if (m2 < 1e6) return `${m2.toFixed(0)} m²`; |
| 71 | + const km2 = m2 / 1e6; |
| 72 | + return `${km2.toFixed(km2 < 10 ? 2 : 1)} km²`; |
| 73 | + } |
| 74 | +
|
58 | 75 | const defaultBathymetryFeatures: Ref<Feature<Geometry>[] | null> = ref(null); |
59 | 76 | const showBathymetryFeatures = computed(() => { |
60 | 77 | return ((reqParamsStore.missionValue === 'ICESat-2') && (reqParamsStore.iceSat2SelectedAPI === 'atl24x')); |
|
103 | 120 | const mapStore = useMapStore(); |
104 | 121 | const controls = ref([]); |
105 | 122 | const toast = useToast(); |
106 | | - const dragBox = new DragBoxType(); |
| 123 | + const dragBox = new DragBox(); |
107 | 124 | const drawVectorSource = new VectorSource({wrapX: false}); |
108 | 125 | const drawVectorLayer = new VectorLayer({ |
109 | 126 | source: drawVectorSource, |
|
135 | 152 | }); |
136 | 153 |
|
137 | 154 | // Set a custom property, like 'name' |
138 | | - const drawPolygon = new DrawType({ |
| 155 | + const drawPolygon = new Draw({ |
139 | 156 | source: drawVectorSource, |
140 | 157 | type: 'Polygon', |
141 | 158 | style: new Style({ |
|
199 | 216 | }), |
200 | 217 | }); |
201 | 218 |
|
| 219 | + dragBox.on('boxstart', () => { |
| 220 | + // show empty HUD near the starting corner |
| 221 | + const geom = dragBox.getGeometry(); |
| 222 | + if (!geom) return; |
| 223 | + const extent = geom.getExtent(); |
| 224 | + // position at the current top-right corner |
| 225 | + const pos: [number, number] = [extent[2], extent[3]]; |
| 226 | + dragAreaEl.textContent = ''; |
| 227 | + dragAreaOverlay.value?.setPosition(pos); |
| 228 | + }); |
| 229 | +
|
| 230 | + dragBox.on('boxdrag', () => { |
| 231 | + const map = mapRef.value?.map; |
| 232 | + const geom = dragBox.getGeometry(); |
| 233 | + if (!map || !geom) return; |
| 234 | +
|
| 235 | + // 1) Current extent |
| 236 | + const extent = geom.getExtent(); |
| 237 | +
|
| 238 | + // 2) Build a polygon from the extent in the *map’s projection* |
| 239 | + //const poly = Polygon.fromExtent(extent); |
| 240 | + const poly = polygonFromExtent(extent); |
| 241 | +
|
| 242 | + // 3) Geodesic area (meters²), sphere-corrected using the map projection |
| 243 | + const m2 = geodesicArea(poly, { projection: map.getView().getProjection() }); |
| 244 | + dragAreaEl.textContent = formatArea(Math.abs(m2)); |
| 245 | +
|
| 246 | + // 4) Move HUD to the box’s top-right corner so it stays out of the box |
| 247 | + const pos: [number, number] = [extent[2], extent[3]]; |
| 248 | + dragAreaOverlay.value?.setPosition(pos); |
| 249 | + }); |
| 250 | +
|
| 251 | + |
| 252 | + // your existing code… |
| 253 | + // … |
| 254 | + // hide the HUD now that the final tag is drawn via your existing path |
| 255 | + |
| 256 | +
|
202 | 257 | dragBox.on('boxend', function() { |
203 | 258 | //console.log("dragBox.on boxend"); |
204 | 259 | isDrawing.value = true; |
|
251 | 306 | const vectorSource = vectorLayer?.getSource(); |
252 | 307 | if(vectorSource){ |
253 | 308 | // Create a rectangle feature using the extent |
254 | | - let boxFeature = new Feature(fromExtent(extent)); |
| 309 | + //let boxFeature = new Feature(fromExtent(extent)); |
| 310 | + let boxFeature = new Feature(polygonFromExtent(extent)); |
255 | 311 | // Apply the style to the feature |
256 | 312 | boxFeature.setStyle(boxStyle); |
257 | 313 | //console.log("dragBox.on boxend boxFeature tag:",tag); |
|
284 | 340 | if (srDrawControlRef.value) { |
285 | 341 | srDrawControlRef.value.resetPicked(); |
286 | 342 | } |
| 343 | + dragAreaOverlay.value?.setPosition(undefined); |
287 | 344 | }); |
288 | 345 |
|
289 | 346 | // Function to toggle the Draw interaction. |
|
310 | 367 | map?.addInteraction(drawPolygon); |
311 | 368 | //console.log("enableDrawPolygon"); |
312 | 369 | } |
| 370 | + // Show live area while drawing a polygon |
| 371 | + drawPolygon.on('drawstart', (evt) => { |
| 372 | + const map = mapRef.value?.map; |
| 373 | + const feature = evt.feature; |
| 374 | +
|
| 375 | + // clear + show HUD |
| 376 | + dragAreaEl.textContent = ''; |
| 377 | + dragAreaOverlay.value?.setPosition(undefined); |
| 378 | +
|
| 379 | + polyGeomChangeKey = feature.getGeometry()?.on('change', () => { |
| 380 | + const geom = feature.getGeometry() as Polygon; |
| 381 | + if (!map || !geom) return; |
| 382 | +
|
| 383 | + // geodesic area in m² using current view projection |
| 384 | + const m2 = Math.abs(geodesicArea(geom, { projection: map.getView().getProjection() })); |
| 385 | + dragAreaEl.textContent = formatArea(m2); |
| 386 | +
|
| 387 | + // position HUD near the latest vertex (fallback: interior of polygon) |
| 388 | + const rings = geom.getCoordinates(); |
| 389 | + const last = rings?.[0]?.[rings[0].length - 1]; |
| 390 | + const pos = last ?? geom.getInteriorPoint().getCoordinates(); |
| 391 | + dragAreaOverlay.value?.setPosition(pos as [number, number]); |
| 392 | + }); |
| 393 | + }); |
313 | 394 |
|
314 | 395 | drawPolygon.on('drawend', function(event) { |
315 | 396 | //console.log("drawend:", event); |
|
325 | 406 | feature.setStyle(polygonStyle); |
326 | 407 | //console.log("feature:", feature); |
327 | 408 | // Get the geometry of the feature |
328 | | - const geometry = feature.getGeometry() as OlPolygon; |
| 409 | + const geometry = feature.getGeometry() as Polygon; |
329 | 410 | //console.log("geometry:", geometry); |
330 | 411 | // Check if the geometry is a polygon |
331 | 412 | if (geometry && geometry.getType() === 'Polygon') { |
|
423 | 504 | } else { |
424 | 505 | console.error("Error:vectorLayer is null"); |
425 | 506 | } |
| 507 | +
|
| 508 | + // stop listening + hide HUD (your existing tagging UI will take over) |
| 509 | + if (polyGeomChangeKey) { |
| 510 | + unByKey(polyGeomChangeKey); |
| 511 | + polyGeomChangeKey = null; |
| 512 | + } |
| 513 | + dragAreaOverlay.value?.setPosition(undefined); |
| 514 | +
|
426 | 515 | isDrawing.value = false; |
427 | 516 | const records = getLayerByName("Records Layer"); |
428 | 517 | if (map && records && wasRecordsLayerVisible.value) { |
|
673 | 762 | // const plink = mapStore.plink as any; |
674 | 763 | // map.addControl(plink); |
675 | 764 | // } |
| 765 | +
|
| 766 | + dragAreaOverlay.value = new OlOverlay({ |
| 767 | + element: dragAreaEl, |
| 768 | + offset: [8, -8], |
| 769 | + positioning: 'bottom-left', |
| 770 | + stopEvent: false, |
| 771 | + }); |
| 772 | + map.addOverlay(dragAreaOverlay.value as unknown as import('ol/Overlay').default); |
676 | 773 | await updateReqMapView("SrMap onMounted",canRestoreZoomCenter(map)); |
677 | 774 | map.getView().on('change:resolution', () => { |
678 | 775 | //const zoom = map.getView().getZoom(); |
|
1443 | 1540 | padding: 0.25rem; |
1444 | 1541 | } |
1445 | 1542 |
|
| 1543 | +:deep(.ol-measure-hud) { |
| 1544 | + font: 700 0.9rem/1.4 var(--p-font-family, system-ui, sans-serif); |
| 1545 | + padding: 0.35rem 0.6rem; |
| 1546 | + background: rgba(0,0,0,0.85); |
| 1547 | + color: #ffeb3b; |
| 1548 | + border: 2px solid #fff; |
| 1549 | + border-radius: 6px; |
| 1550 | + white-space: nowrap; |
| 1551 | + pointer-events: none; |
| 1552 | + box-shadow: 0 2px 4px rgba(0,0,0,0.4); |
| 1553 | + /* if something upstream sets opacity, force full */ |
| 1554 | + opacity: 1; |
| 1555 | +} |
| 1556 | +
|
1446 | 1557 |
|
1447 | 1558 |
|
1448 | 1559 |
|
|
0 commit comments