mirror of
https://github.com/bilawalsidhu/gods-eye-view.git
synced 2026-11-04 02:14:01 +00:00
feat(wind): render the inspection marker from a store
createWindInspectionMarker() moves to src/layers/wind/inspectionMarker.js, so the portable ./tools entry that reads wind/inspection.js stays free of Vue. It keeps the frame listener and projection and presents where the inspected point falls to the gev-wind-inspection store after each rendered frame, publishing nothing for an unchanged frame; the scene chrome teleports the marker into the wind layer's container with the same class, inline style, hidden state and position. The application guide lists everything leaving out the scene chrome now leaves out.
This commit is contained in:
1 parent
0926cbc105
commit
e0bfa471ac
13 files changed
+292
-131
No files matched your search
+3
-2
@@ -208,8 +208,9 @@ anything reads the page; `omitViews` names views the application leaves out,
|
||||
such as `provider-settings`, and their hosts are removed. Leaving out
|
||||
`layer-panels` also leaves out the scene sharing dialogs it draws, and leaving
|
||||
out `scene-chrome` the before/after imagery dividers (the imagery still splits,
|
||||
with no line or handle to move it), the status chips, the toast and the ORBIT
|
||||
indicator, and leaving out `command-dock` the voice control and its pointer
|
||||
with no line or handle to move it), the status chips, the toast, the ORBIT
|
||||
indicator, the FPS readout, the Scene actions panel, the data-pack attribution
|
||||
cards and the wind inspection marker, and leaving out `command-dock` the voice control and its pointer
|
||||
reticle. An unknown
|
||||
view name is an error. A host that does not initialize Core's locale passes
|
||||
`localePicker: false` to `createApplicationControls` instead of editing the
|
||||
|
||||
@@ -158,7 +158,12 @@ a feature supplying only its accent.
|
||||
keeps the pick handler and focuses the picked action), the data-pack
|
||||
attribution cards (`DataPacks` teleports what the data-pack presentations
|
||||
publish to the `gev-data-packs` store into the viewer's container and
|
||||
stops a removed card's player), then
|
||||
stops a removed card's player), the wind inspection marker
|
||||
(`WindInspectionMarker` teleports the marker into the wind layer's
|
||||
container where `createWindInspectionMarker()`, now in
|
||||
`src/layers/wind/inspectionMarker.js` so the portable `./tools` entry
|
||||
needs no Vue, places it after each rendered frame; an unchanged frame
|
||||
publishes nothing), then
|
||||
Cockpit (in progress: `CockpitBriefing` renders the briefing card's
|
||||
pages, cycle toggle, regional news and local conditions, and
|
||||
`CockpitContext` the Contact card's scope, navigation, counts, nearest
|
||||
|
||||
@@ -1139,5 +1139,8 @@
|
||||
"src/ui/stores/sceneInteractions.js",
|
||||
"src/scenes/dataPacks/presentationView.test.mjs",
|
||||
"src/ui/stores/dataPacks.js",
|
||||
"src/scenes/interactionsView.test.mjs"
|
||||
"src/scenes/interactionsView.test.mjs",
|
||||
"src/layers/wind/inspectionMarker.js",
|
||||
"src/layers/wind/inspectionMarker.test.mjs",
|
||||
"src/ui/stores/windInspection.js"
|
||||
]
|
||||
@@ -102,7 +102,9 @@
|
||||
"src/ui/views/panels/SceneInteractions.vue",
|
||||
"src/ui/stores/dataPacks.js",
|
||||
"src/ui/views/panels/DataPacks.vue",
|
||||
"src/ui/stores/pointerReticle.js"
|
||||
"src/ui/stores/pointerReticle.js",
|
||||
"src/ui/stores/windInspection.js",
|
||||
"src/ui/views/panels/WindInspectionMarker.vue"
|
||||
],
|
||||
"external": ["vue", "pinia"]
|
||||
},
|
||||
@@ -3015,7 +3017,9 @@
|
||||
"src/ui/toast.js",
|
||||
"src/ui/stores/sceneInteractions.js",
|
||||
"src/ui/stores/dataPacks.js",
|
||||
"src/ui/stores/pointerReticle.js"
|
||||
"src/ui/stores/pointerReticle.js",
|
||||
"src/ui/stores/windInspection.js",
|
||||
"src/layers/wind/inspectionMarker.js"
|
||||
],
|
||||
"external": [
|
||||
"hls.js",
|
||||
@@ -3603,7 +3607,9 @@
|
||||
"src/data/geoImportPins.js",
|
||||
"src/data/geoFileImport.js",
|
||||
"src/ui/stores/imagerySplit.js",
|
||||
"src/ui/vueRuntime.js"
|
||||
"src/ui/vueRuntime.js",
|
||||
"src/ui/stores/windInspection.js",
|
||||
"src/layers/wind/inspectionMarker.js"
|
||||
],
|
||||
"external": [
|
||||
"hls.js",
|
||||
|
||||
@@ -6,11 +6,8 @@ import {
|
||||
windReadingResult,
|
||||
windUnitChips,
|
||||
} from './presentation.js';
|
||||
import {
|
||||
inspectWindAtCenter,
|
||||
createWindInspectionMarker,
|
||||
WIND_UNITS,
|
||||
} from './inspection.js';
|
||||
import { inspectWindAtCenter, WIND_UNITS } from './inspection.js';
|
||||
import { createWindInspectionMarker } from './inspectionMarker.js';
|
||||
import { t, msg, translateKnown } from '../../i18n/index.js';
|
||||
import { unitLabel } from '../../ui/unitLabels.js';
|
||||
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createWindLayer, formatWindValidTime, windStats } from './index.js';
|
||||
import { useWindInspectionStore } from '../../ui/stores/windInspection.js';
|
||||
import { applicationPinia } from '../../ui/vueRuntime.js';
|
||||
|
||||
const snapshot = (model) => ({
|
||||
model,
|
||||
@@ -302,12 +304,12 @@ test('weather summary describes the selected forecast and count remains numeric'
|
||||
});
|
||||
|
||||
test('sample stays fixed across model, field and unit changes; dismissal and disable clear marker', async () => {
|
||||
const nodes = [];
|
||||
// The marker the scene chrome renders, as the wind layer presents it.
|
||||
const marker = () => useWindInspectionStore(applicationPinia()).marker;
|
||||
let listener;
|
||||
let samples = 0;
|
||||
const container = {
|
||||
ownerDocument: { createElement: () => ({ style: {}, setAttribute() {}, remove() { nodes.splice(nodes.indexOf(this), 1); } }) },
|
||||
appendChild(node) { nodes.push(node); },
|
||||
ownerDocument: {},
|
||||
getBoundingClientRect: () => ({ left: 0, top: 0 }),
|
||||
};
|
||||
const viewer = {
|
||||
@@ -338,9 +340,9 @@ test('sample stays fixed across model, field and unit changes; dismissal and dis
|
||||
layer.setParams({ inspect: true });
|
||||
const captured = layer.getRowControls().summary.reading;
|
||||
assert.equal(samples, 1);
|
||||
const retained = nodes[0];
|
||||
const retained = marker().owner;
|
||||
layer.setParams({ units: 'mph' });
|
||||
assert.equal(nodes[0], retained);
|
||||
assert.ok(marker().owner === retained);
|
||||
const changed = layer.getRowControls().summary.reading;
|
||||
assert.equal(changed.speed, captured.speed);
|
||||
assert.equal(changed.coordinates, captured.coordinates);
|
||||
@@ -348,7 +350,7 @@ test('sample stays fixed across model, field and unit changes; dismissal and dis
|
||||
assert.equal(samples, 1, 'units do not resample');
|
||||
assert.equal(layer.getRowControls().summary.result.id, 'reading');
|
||||
assert.deepEqual(layer.getRowControls().summary.settings.map(({ label }) => label), ['MODEL', 'FIELD', 'UNITS', 'MOTION']);
|
||||
assert.equal(nodes.length, 1);
|
||||
assert.ok(marker());
|
||||
assert.equal(typeof listener, 'function');
|
||||
viewer.camera.pickEllipsoid = () => { samples++; return { longitude: 70, latitude: 20 }; };
|
||||
layer.setParams({ overlay: 'speed' });
|
||||
@@ -368,9 +370,9 @@ test('sample stays fixed across model, field and unit changes; dismissal and dis
|
||||
assert.equal(samples, 2, 'the next explicit read samples the new center');
|
||||
for (const change of [() => layer.setParams({ inspect: false }), () => layer.disable()]) {
|
||||
layer.setParams({ inspect: true });
|
||||
assert.equal(nodes.length, 1);
|
||||
assert.ok(marker());
|
||||
change();
|
||||
assert.equal(nodes.length, 0);
|
||||
assert.equal(marker(), null);
|
||||
assert.equal(layer.getRowControls().summary.reading, null);
|
||||
assert.equal(layer.getRowControls().summary.result, null);
|
||||
assert.equal(listener, null);
|
||||
|
||||
@@ -112,62 +112,3 @@ export function inspectWindAtCenter(
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
/** One passive marker for the captured location; it never samples on camera movement. */
|
||||
export function createWindInspectionMarker({ container, viewer, cesium }) {
|
||||
let removeRender = null;
|
||||
let marker = null;
|
||||
const clear = () => {
|
||||
removeRender?.();
|
||||
removeRender = null;
|
||||
marker?.remove();
|
||||
marker = null;
|
||||
viewer?.scene?.requestRender?.();
|
||||
};
|
||||
return {
|
||||
show(position) {
|
||||
clear();
|
||||
const scene = viewer?.scene;
|
||||
if (
|
||||
!position ||
|
||||
!container?.ownerDocument?.createElement ||
|
||||
!scene?.postRender?.addEventListener ||
|
||||
!scene.cartesianToCanvasCoordinates
|
||||
)
|
||||
return;
|
||||
marker = container.ownerDocument.createElement('div');
|
||||
marker.className = 'gev-wind-inspection-marker';
|
||||
marker.setAttribute('aria-hidden', 'true');
|
||||
marker.style.cssText =
|
||||
'position:absolute;width:18px;height:18px;border:2px solid #fff;border-radius:50%;box-shadow:0 0 0 2px #153440,0 0 0 5px rgba(102,225,242,.35);transform:translate(-50%,-50%);pointer-events:none;z-index:150;';
|
||||
container.appendChild(marker);
|
||||
const occluder = new cesium.EllipsoidalOccluder(
|
||||
scene.globe?.ellipsoid || cesium.Ellipsoid.WGS84,
|
||||
viewer.camera.positionWC,
|
||||
);
|
||||
const render = () => {
|
||||
occluder.cameraPosition = viewer.camera.positionWC;
|
||||
const point = scene.cartesianToCanvasCoordinates(position);
|
||||
const visible =
|
||||
point &&
|
||||
point.x >= 0 &&
|
||||
point.y >= 0 &&
|
||||
point.x <= scene.canvas.clientWidth &&
|
||||
point.y <= scene.canvas.clientHeight &&
|
||||
(scene.mode !== cesium.SceneMode.SCENE3D ||
|
||||
occluder.isPointVisible(position));
|
||||
marker.hidden = !visible;
|
||||
if (!visible) return;
|
||||
const canvasRect = scene.canvas.getBoundingClientRect();
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
marker.style.left = `${point.x + canvasRect.left - containerRect.left}px`;
|
||||
marker.style.top = `${point.y + canvasRect.top - containerRect.top}px`;
|
||||
};
|
||||
removeRender = scene.postRender.addEventListener(render);
|
||||
render();
|
||||
scene.requestRender?.();
|
||||
},
|
||||
clear,
|
||||
destroy: clear,
|
||||
};
|
||||
}
|
||||
@@ -58,55 +58,3 @@ test('center inspection uses a fixed forecast reading without double-converting
|
||||
'No surface reading',
|
||||
);
|
||||
});
|
||||
|
||||
test('inspection marker follows only its captured point, hides beyond limb, and releases its listener', async () => {
|
||||
const { createWindInspectionMarker } = await import('./inspection.js');
|
||||
let listener = null;
|
||||
let visible = true;
|
||||
const projected = [];
|
||||
const nodes = [];
|
||||
const container = {
|
||||
ownerDocument: { createElement: () => ({ style: {}, setAttribute() {}, remove() { nodes.splice(nodes.indexOf(this), 1); } }) },
|
||||
appendChild(node) { nodes.push(node); },
|
||||
getBoundingClientRect: () => ({ left: 5, top: 10 }),
|
||||
};
|
||||
const viewer = {
|
||||
camera: { positionWC: {} },
|
||||
scene: {
|
||||
mode: 3,
|
||||
canvas: { clientWidth: 800, clientHeight: 600, getBoundingClientRect: () => ({ left: 15, top: 30 }) },
|
||||
postRender: { addEventListener(fn) { assert.equal(listener, null); listener = fn; return () => { listener = null; }; } },
|
||||
cartesianToCanvasCoordinates(point) { projected.push(point); return { x: 100, y: 200 }; },
|
||||
requestRender() {},
|
||||
},
|
||||
};
|
||||
const cesium = {
|
||||
SceneMode: { SCENE3D: 3 }, Ellipsoid: { WGS84: {} },
|
||||
EllipsoidalOccluder: class { isPointVisible() { return visible; } },
|
||||
};
|
||||
const owner = createWindInspectionMarker({ container, viewer, cesium });
|
||||
const point = { x: 1, y: 2, z: 3 };
|
||||
owner.show(point);
|
||||
assert.equal(nodes.length, 1);
|
||||
assert.match(nodes[0].style.cssText, /pointer-events:none/);
|
||||
assert.equal(nodes[0].style.left, '110px');
|
||||
assert.equal(nodes[0].style.top, '220px');
|
||||
viewer.camera.positionWC = { moved: true };
|
||||
visible = false;
|
||||
listener();
|
||||
assert.equal(nodes[0].hidden, true);
|
||||
assert.ok(projected.every((value) => value === point));
|
||||
visible = true;
|
||||
listener();
|
||||
assert.equal(nodes[0].hidden, false);
|
||||
owner.show({ x: 4 });
|
||||
assert.equal(nodes.length, 1);
|
||||
owner.clear();
|
||||
assert.equal(nodes.length, 0);
|
||||
assert.equal(listener, null);
|
||||
owner.show(point);
|
||||
owner.destroy();
|
||||
owner.destroy();
|
||||
assert.equal(nodes.length, 0);
|
||||
assert.equal(listener, null);
|
||||
});
|
||||
@@ -0,0 +1,80 @@
|
||||
import { useWindInspectionStore } from '../../ui/stores/windInspection.js';
|
||||
import { applicationPinia } from '../../ui/vueRuntime.js';
|
||||
|
||||
/**
|
||||
* One passive marker for the captured location; it never samples on camera
|
||||
* movement. Where the point falls is presented to the wind inspection store
|
||||
* after every rendered frame, and the scene chrome renders the marker in
|
||||
* `container`.
|
||||
*/
|
||||
export function createWindInspectionMarker({
|
||||
container,
|
||||
viewer,
|
||||
cesium,
|
||||
store = useWindInspectionStore(applicationPinia()),
|
||||
}) {
|
||||
const owner = {};
|
||||
let removeRender = null;
|
||||
let marker = null;
|
||||
// Only the owner whose marker the store shows may move or remove it.
|
||||
const shown = () => marker && store.marker?.owner === owner;
|
||||
const present = (patch) => {
|
||||
marker = { ...marker, ...patch };
|
||||
store.publish(marker);
|
||||
};
|
||||
const clear = () => {
|
||||
removeRender?.();
|
||||
removeRender = null;
|
||||
if (shown()) store.publish(null);
|
||||
marker = null;
|
||||
viewer?.scene?.requestRender?.();
|
||||
};
|
||||
return {
|
||||
show(position) {
|
||||
clear();
|
||||
const scene = viewer?.scene;
|
||||
if (
|
||||
!position ||
|
||||
!container?.ownerDocument ||
|
||||
!scene?.postRender?.addEventListener ||
|
||||
!scene.cartesianToCanvasCoordinates
|
||||
)
|
||||
return;
|
||||
present({ owner, container, visible: false, left: 0, top: 0 });
|
||||
const occluder = new cesium.EllipsoidalOccluder(
|
||||
scene.globe?.ellipsoid || cesium.Ellipsoid.WGS84,
|
||||
viewer.camera.positionWC,
|
||||
);
|
||||
const render = () => {
|
||||
if (!shown()) return;
|
||||
occluder.cameraPosition = viewer.camera.positionWC;
|
||||
const point = scene.cartesianToCanvasCoordinates(position);
|
||||
const visible =
|
||||
point &&
|
||||
point.x >= 0 &&
|
||||
point.y >= 0 &&
|
||||
point.x <= scene.canvas.clientWidth &&
|
||||
point.y <= scene.canvas.clientHeight &&
|
||||
(scene.mode !== cesium.SceneMode.SCENE3D ||
|
||||
occluder.isPointVisible(position));
|
||||
if (!visible) {
|
||||
// A hidden marker keeps its last place, as the element did.
|
||||
if (marker.visible) present({ visible: false });
|
||||
return;
|
||||
}
|
||||
const canvasRect = scene.canvas.getBoundingClientRect();
|
||||
const containerRect = container.getBoundingClientRect();
|
||||
const left = point.x + canvasRect.left - containerRect.left;
|
||||
const top = point.y + canvasRect.top - containerRect.top;
|
||||
if (marker.visible && marker.left === left && marker.top === top)
|
||||
return;
|
||||
present({ visible: true, left, top });
|
||||
};
|
||||
removeRender = scene.postRender.addEventListener(render);
|
||||
render();
|
||||
scene.requestRender?.();
|
||||
},
|
||||
clear,
|
||||
destroy: clear,
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,137 @@
|
||||
// src/layers/wind/inspectionMarker.test.mjs — the wind inspection marker
|
||||
// follows only its captured point, renders in its container, and releases
|
||||
// its frame listener.
|
||||
import '../../testSupport/registerDom.mjs';
|
||||
import test from 'node:test';
|
||||
import assert from 'node:assert/strict';
|
||||
import { createApp, nextTick } from 'vue';
|
||||
import { createPinia } from 'pinia';
|
||||
import { useWindInspectionStore } from '../../ui/stores/windInspection.js';
|
||||
import WindInspectionMarker from '../../ui/views/panels/WindInspectionMarker.vue';
|
||||
import { createWindInspectionMarker } from './inspectionMarker.js';
|
||||
|
||||
const cesium = {
|
||||
SceneMode: { SCENE3D: 3 },
|
||||
Ellipsoid: { WGS84: {} },
|
||||
EllipsoidalOccluder: class {
|
||||
isPointVisible() {
|
||||
return cesium.visible;
|
||||
}
|
||||
},
|
||||
visible: true,
|
||||
};
|
||||
|
||||
function fixture(t) {
|
||||
document.body.replaceChildren();
|
||||
const container = document.body.appendChild(document.createElement('div'));
|
||||
container.getBoundingClientRect = () => ({ left: 5, top: 10 });
|
||||
const pinia = createPinia();
|
||||
const app = createApp(WindInspectionMarker).use(pinia);
|
||||
app.mount(document.body.appendChild(document.createElement('div')));
|
||||
t.after(() => app.unmount());
|
||||
const frames = { listener: null };
|
||||
const projected = [];
|
||||
const viewer = {
|
||||
camera: { positionWC: {} },
|
||||
scene: {
|
||||
mode: 3,
|
||||
canvas: {
|
||||
clientWidth: 800,
|
||||
clientHeight: 600,
|
||||
getBoundingClientRect: () => ({ left: 15, top: 30 }),
|
||||
},
|
||||
postRender: {
|
||||
addEventListener(fn) {
|
||||
assert.equal(frames.listener, null);
|
||||
frames.listener = fn;
|
||||
return () => {
|
||||
frames.listener = null;
|
||||
};
|
||||
},
|
||||
},
|
||||
cartesianToCanvasCoordinates(point) {
|
||||
projected.push(point);
|
||||
return { x: 100, y: 200 };
|
||||
},
|
||||
requestRender() {},
|
||||
},
|
||||
};
|
||||
const store = useWindInspectionStore(pinia);
|
||||
cesium.visible = true;
|
||||
const owner = createWindInspectionMarker({
|
||||
container,
|
||||
viewer,
|
||||
cesium,
|
||||
store,
|
||||
});
|
||||
const nodes = () => [
|
||||
...container.querySelectorAll('.gev-wind-inspection-marker'),
|
||||
];
|
||||
return { owner, viewer, store, frames, projected, nodes, container, cesium };
|
||||
}
|
||||
|
||||
test('the marker follows only its captured point, hides beyond the limb, and releases its listener', async (t) => {
|
||||
const { owner, viewer, frames, projected, nodes } = fixture(t);
|
||||
const point = { x: 1, y: 2, z: 3 };
|
||||
owner.show(point);
|
||||
await nextTick();
|
||||
assert.equal(nodes().length, 1);
|
||||
const [marker] = nodes();
|
||||
assert.equal(marker.getAttribute('aria-hidden'), 'true');
|
||||
assert.equal(marker.style.pointerEvents, 'none');
|
||||
assert.equal(marker.style.position, 'absolute');
|
||||
assert.equal(marker.style.zIndex, '150');
|
||||
assert.equal(marker.style.left, '110px');
|
||||
assert.equal(marker.style.top, '220px');
|
||||
assert.equal(marker.hidden, false);
|
||||
viewer.camera.positionWC = { moved: true };
|
||||
cesium.visible = false;
|
||||
frames.listener();
|
||||
await nextTick();
|
||||
assert.equal(marker.hidden, true);
|
||||
assert.equal(marker.style.left, '110px', 'a hidden marker keeps its place');
|
||||
assert.ok(projected.every((value) => value === point));
|
||||
cesium.visible = true;
|
||||
frames.listener();
|
||||
await nextTick();
|
||||
assert.equal(marker.hidden, false);
|
||||
owner.show({ x: 4 });
|
||||
await nextTick();
|
||||
assert.equal(nodes().length, 1);
|
||||
owner.clear();
|
||||
await nextTick();
|
||||
assert.equal(nodes().length, 0);
|
||||
assert.equal(frames.listener, null);
|
||||
owner.show(point);
|
||||
owner.destroy();
|
||||
owner.destroy();
|
||||
await nextTick();
|
||||
assert.equal(nodes().length, 0);
|
||||
assert.equal(frames.listener, null);
|
||||
});
|
||||
|
||||
test('an unchanged frame publishes nothing, and an older owner leaves a newer marker', (t) => {
|
||||
const { owner, viewer, store, frames, container } = fixture(t);
|
||||
owner.show({ x: 1 });
|
||||
let publishes = 0;
|
||||
const publish = store.publish;
|
||||
store.publish = (next) => {
|
||||
publishes += 1;
|
||||
publish(next);
|
||||
};
|
||||
frames.listener();
|
||||
assert.equal(publishes, 0);
|
||||
frames.listener = null;
|
||||
const newer = createWindInspectionMarker({
|
||||
container,
|
||||
viewer,
|
||||
cesium,
|
||||
store,
|
||||
});
|
||||
newer.show({ x: 2 });
|
||||
const shown = store.marker;
|
||||
owner.destroy();
|
||||
assert.ok(store.marker === shown);
|
||||
newer.destroy();
|
||||
assert.equal(store.marker, null);
|
||||
});
|
||||
@@ -0,0 +1,22 @@
|
||||
import { defineStore } from 'pinia';
|
||||
import { markRaw, shallowRef } from 'vue';
|
||||
|
||||
/**
|
||||
* The wind inspection marker as its view renders it. The marker owner
|
||||
* (src/layers/wind/inspectionMarker.js) presents where the inspected point
|
||||
* falls on screen after every rendered frame.
|
||||
*/
|
||||
export const useWindInspectionStore = defineStore('gev-wind-inspection', () => {
|
||||
/**
|
||||
* `{owner, container, visible, left, top}`, in pixels from the container's
|
||||
* corner, or null while no point is inspected.
|
||||
*/
|
||||
const marker = shallowRef(null);
|
||||
|
||||
/** @param {?object} next A fresh presentation; every publish re-renders. */
|
||||
function publish(next) {
|
||||
marker.value = next && markRaw(next);
|
||||
}
|
||||
|
||||
return { marker, publish };
|
||||
});
|
||||
@@ -9,6 +9,7 @@ import ImagerySplitView from './panels/ImagerySplitView.vue';
|
||||
import DataPacks from './panels/DataPacks.vue';
|
||||
import SceneInteractions from './panels/SceneInteractions.vue';
|
||||
import SplitFlapText from './panels/SplitFlapText.vue';
|
||||
import WindInspectionMarker from './panels/WindInspectionMarker.vue';
|
||||
|
||||
// The ACTIVE STYLE corner shows the style VisualSettings publishes.
|
||||
const { style } = storeToRefs(useDisplayStore());
|
||||
@@ -100,4 +101,5 @@ const vToastText = {
|
||||
<ImagerySplitView />
|
||||
<DataPacks />
|
||||
<SceneInteractions />
|
||||
<WindInspectionMarker />
|
||||
</template>
|
||||
@@ -0,0 +1,17 @@
|
||||
<script setup>
|
||||
import { storeToRefs } from 'pinia';
|
||||
import { useWindInspectionStore } from '../../stores/windInspection.js';
|
||||
|
||||
// The inspected wind point, inside the container the wind layer renders in,
|
||||
// where the marker owner (src/layers/wind/inspectionMarker.js) places it.
|
||||
const { marker } = storeToRefs(useWindInspectionStore());
|
||||
|
||||
const markerStyle =
|
||||
'position:absolute;width:18px;height:18px;border:2px solid #fff;border-radius:50%;box-shadow:0 0 0 2px #153440,0 0 0 5px rgba(102,225,242,.35);transform:translate(-50%,-50%);pointer-events:none;z-index:150;';
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<Teleport v-if="marker" :to="marker.container">
|
||||
<div class="gev-wind-inspection-marker" aria-hidden="true" :hidden="!marker.visible" :style="[markerStyle, { left: `${marker.left}px`, top: `${marker.top}px` }]"></div>
|
||||
</Teleport>
|
||||
</template>
|
||||
Reference in new issue
Block a user