Skip to content

Commit 2b862b6

Browse files
authored
Merge pull request #668 from SlideRuleEarth/carlos-dev3
Carlos dev3
2 parents 0643205 + 13c2d47 commit 2b862b6

File tree

3 files changed

+145
-28
lines changed

3 files changed

+145
-28
lines changed

web-client/src/components/SrMap.vue

Lines changed: 134 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -6,55 +6,72 @@
66
import { useProjectionNames } from "@/composables/SrProjections";
77
import { srProjections } from "@/composables/SrProjections";
88
import proj4 from 'proj4';
9-
import { register } from 'ol/proj/proj4';
9+
import { register } from 'ol/proj/proj4.js';
1010
import 'ol-geocoder/dist/ol-geocoder.min.css';
1111
import { useMapStore } from "@/stores/mapStore";
1212
import { useGeoCoderStore } from '@/stores/geoCoderStore';
1313
import { get as getProjection } from 'ol/proj.js';
1414
import { addLayersForCurrentView } from "@/composables/SrLayers";
15-
import { Layer } from 'ol/layer';
15+
import { Layer } from 'ol/layer.js';
1616
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';
2624
import { clearPolyCoords, clearReqGeoJsonData, drawGeoJson, enableTagDisplay, disableTagDisplay, saveMapZoomState, renderRequestPolygon, canRestoreZoomCenter, assignStyleFunctionToPinLayer } from "@/utils/SrMapUtils";
2725
import { onActivated } from "vue";
2826
import { onDeactivated } from "vue";
2927
import type { Ref } from "vue";
3028
import { checkAreaOfConvexHullWarning,updateSrViewName,renderReqPin } from "@/utils/SrMapUtils";
31-
import { toLonLat } from 'ol/proj';
29+
import { toLonLat } from 'ol/proj.js';
3230
import { useReqParamsStore } from "@/stores/reqParamsStore";
3331
import { convexHull, isClockwise } from "@/composables/SrTurfUtils";
34-
import { type Coordinate } from "ol/coordinate";
32+
import { type Coordinate } from "ol/coordinate.js";
3533
import { hullColor, type SrRegion } from '@/types/SrTypes'
36-
import { format } from 'ol/coordinate';
34+
import { format } from 'ol/coordinate.js';
3735
import SrViewControl from "./SrViewControl.vue";
3836
import SrBaseLayerControl from "./SrBaseLayerControl.vue";
3937
import SrDrawControl from "@/components/SrDrawControl.vue";
4038
import { Map, MapControls } from "vue3-openlayers";
4139
import { useRequestsStore } from "@/stores/requestsStore";
42-
import VectorLayer from "ol/layer/Vector";
40+
import VectorLayer from "ol/layer/Vector.js";
4341
import { useDebugStore } from "@/stores/debugStore";
4442
import { updateMapView } from "@/utils/SrMapUtils";
4543
import { renderSvrReqPoly,renderSvrReqRegionMask,zoomOutToFullMap,renderSvrReqPin} from "@/utils/SrMapUtils";
4644
import router from '@/router/index.js';
4745
import { useRecTreeStore } from "@/stores/recTreeStore";
4846
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';
5149
import SrCustomTooltip from "@/components//SrCustomTooltip.vue";
5250
import SrDropPinControl from "@/components//SrDropPinControl.vue";
5351
import SrUploadRegionControl from "@/components/SrUploadRegionControl.vue";
54-
import Point from 'ol/geom/Point';
52+
import Point from 'ol/geom/Point.js';
5553
import { readShapefileToOlFeatures } from "@/composables/useReadShapefiles";
5654
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+
5875
const defaultBathymetryFeatures: Ref<Feature<Geometry>[] | null> = ref(null);
5976
const showBathymetryFeatures = computed(() => {
6077
return ((reqParamsStore.missionValue === 'ICESat-2') && (reqParamsStore.iceSat2SelectedAPI === 'atl24x'));
@@ -103,7 +120,7 @@
103120
const mapStore = useMapStore();
104121
const controls = ref([]);
105122
const toast = useToast();
106-
const dragBox = new DragBoxType();
123+
const dragBox = new DragBox();
107124
const drawVectorSource = new VectorSource({wrapX: false});
108125
const drawVectorLayer = new VectorLayer({
109126
source: drawVectorSource,
@@ -135,7 +152,7 @@
135152
});
136153
137154
// Set a custom property, like 'name'
138-
const drawPolygon = new DrawType({
155+
const drawPolygon = new Draw({
139156
source: drawVectorSource,
140157
type: 'Polygon',
141158
style: new Style({
@@ -199,6 +216,44 @@
199216
}),
200217
});
201218
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+
202257
dragBox.on('boxend', function() {
203258
//console.log("dragBox.on boxend");
204259
isDrawing.value = true;
@@ -251,7 +306,8 @@
251306
const vectorSource = vectorLayer?.getSource();
252307
if(vectorSource){
253308
// 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));
255311
// Apply the style to the feature
256312
boxFeature.setStyle(boxStyle);
257313
//console.log("dragBox.on boxend boxFeature tag:",tag);
@@ -284,6 +340,7 @@
284340
if (srDrawControlRef.value) {
285341
srDrawControlRef.value.resetPicked();
286342
}
343+
dragAreaOverlay.value?.setPosition(undefined);
287344
});
288345
289346
// Function to toggle the Draw interaction.
@@ -310,6 +367,30 @@
310367
map?.addInteraction(drawPolygon);
311368
//console.log("enableDrawPolygon");
312369
}
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+
});
313394
314395
drawPolygon.on('drawend', function(event) {
315396
//console.log("drawend:", event);
@@ -325,7 +406,7 @@
325406
feature.setStyle(polygonStyle);
326407
//console.log("feature:", feature);
327408
// Get the geometry of the feature
328-
const geometry = feature.getGeometry() as OlPolygon;
409+
const geometry = feature.getGeometry() as Polygon;
329410
//console.log("geometry:", geometry);
330411
// Check if the geometry is a polygon
331412
if (geometry && geometry.getType() === 'Polygon') {
@@ -423,6 +504,14 @@
423504
} else {
424505
console.error("Error:vectorLayer is null");
425506
}
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+
426515
isDrawing.value = false;
427516
const records = getLayerByName("Records Layer");
428517
if (map && records && wasRecordsLayerVisible.value) {
@@ -673,6 +762,14 @@
673762
// const plink = mapStore.plink as any;
674763
// map.addControl(plink);
675764
// }
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);
676773
await updateReqMapView("SrMap onMounted",canRestoreZoomCenter(map));
677774
map.getView().on('change:resolution', () => {
678775
//const zoom = map.getView().getZoom();
@@ -1443,6 +1540,20 @@
14431540
padding: 0.25rem;
14441541
}
14451542
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+
14461557
14471558
14481559

web-client/src/stores/areaThresholdsStore.ts

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,14 @@ import { type ApiName } from '@/types/SrTypes'
66
export const useAreaThresholdsStore = defineStore('areaThresholdStore', () => {
77
// State: maps an API name to a numeric threshold
88
const areaErrorThreshold = ref<Record<ApiName, number>>({
9-
atl06p: 20000,
9+
atl06p: 15000,
1010
atl06sp: 10000,
1111
atl08p: 10000,
1212
atl03sp: 350,
1313
atl03x: 350,
1414
atl03vp: 350,
15+
'atl03x-surface': 15000,
16+
'atl03x-phoreal': 10000,
1517
atl13x: 10000,
1618
atl24x: 1000,
1719
gedi01bp: 200,
@@ -21,12 +23,14 @@ export const useAreaThresholdsStore = defineStore('areaThresholdStore', () => {
2123
const areaErrorThresholdFallback = ref<number>(350)
2224

2325
const areaWarningThreshold = ref<Record<ApiName, number>>({
24-
atl06p: 5000,
25-
atl06sp: 5000,
26-
atl08p: 5000,
26+
atl06p: 10000,
27+
atl06sp: 7500,
28+
atl08p: 8000,
2729
atl03sp: 100,
2830
atl03x: 100,
2931
atl03vp: 100,
32+
'atl03x-surface': 12000,
33+
'atl03x-phoreal': 7500,
3034
atl13x: 10000,
3135
atl24x: 750,
3236
gedi01bp: 100,

web-client/src/utils/SrMapUtils.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -866,7 +866,8 @@ export function swapLongLatToLatLong(coordString: string): string {
866866
export function checkAreaOfConvexHullWarning(): boolean {
867867
const currentApi = useReqParamsStore().getCurAPIObj();
868868
if (currentApi) {
869-
const limit = useAreaThresholdsStore().getAreaWarningThreshold(currentApi)
869+
const limit = useAreaThresholdsStore().getAreaWarningThreshold(currentApi);
870+
console.log(`checkAreaOfConvexHullWarning: currentApi: ${currentApi} limit: ${limit} area: ${useReqParamsStore().getAreaOfConvexHull()}`);
870871
if (useReqParamsStore().getAreaOfConvexHull() > limit) {
871872
const msg = `The area of the convex hull might be too large (${useReqParamsStore().getFormattedAreaOfConvexHull()}).\n Please zoom in and then select a smaller area (try < ${useAreaThresholdsStore().getAreaWarningThreshold(currentApi)} km²).`;
872873
if (!useAdvancedModeStore().getAdvanced()) {
@@ -889,6 +890,7 @@ export function checkAreaOfConvexHullError(): { ok: boolean, msg?: string } {
889890
}
890891
if (currentApi) {
891892
const limit = useAreaThresholdsStore().getAreaErrorThreshold(currentApi)
893+
console.log(`checkAreaOfConvexHullError: currentApi: ${currentApi} limit: ${limit} area: ${useReqParamsStore().getAreaOfConvexHull()}`);
892894
if (useReqParamsStore().getAreaOfConvexHull() > limit) {
893895
const msg = `The area of the convex hull is too large (${useReqParamsStore().getFormattedAreaOfConvexHull()}).\n Please zoom in and then select a smaller area < ${limit} km²).`;
894896
if (!useAdvancedModeStore().getAdvanced()) {

0 commit comments

Comments
 (0)