diff --git a/services/pcp-ui-service/src/main/resources/static/angular_motion_scripts.js b/services/pcp-ui-service/src/main/resources/static/angular_motion_scripts.js
index 29adcc6..b6d348a 100644
--- a/services/pcp-ui-service/src/main/resources/static/angular_motion_scripts.js
+++ b/services/pcp-ui-service/src/main/resources/static/angular_motion_scripts.js
@@ -8,7 +8,9 @@
viewer: null,
mapDataSource: null,
pickHandler: null,
+ resizeObserver: null,
cursorCoordsPanel: null,
+ targetOverlay: null,
};
function el(id) {
@@ -169,13 +171,15 @@
...naturalEarthLayerOptions(),
});
state.viewer.scene.globe.enableLighting = false;
- state.viewer.scene.requestRenderMode = true;
+ state.viewer.scene.requestRenderMode = false;
state.mapDataSource = new Cesium.CustomDataSource('angular-motion-map-data');
state.viewer.dataSources.add(state.mapDataSource);
initCursorCoordinates();
+ initTargetOverlay();
state.pickHandler = new Cesium.ScreenSpaceEventHandler(state.viewer.scene.canvas);
state.pickHandler.setInputAction(function (movement) {
if (!state.picking) return;
+ resizeMap();
const cartesian = pickGlobePoint(movement.position);
if (!cartesian) return;
const cartographic = Cesium.Cartographic.fromCartesian(cartesian);
@@ -183,10 +187,37 @@
el('angular-motion-lon').value = Cesium.Math.toDegrees(cartographic.longitude).toFixed(6);
setPicking(false);
drawMap();
+ updateTargetOverlay(movement.position);
}, Cesium.ScreenSpaceEventType.LEFT_CLICK);
+ initMapResizeSync();
+ state.viewer.scene.postRender.addEventListener(() => updateTargetOverlay());
drawMap();
}
+ function initMapResizeSync() {
+ window.addEventListener('resize', scheduleMapResize);
+ if (typeof ResizeObserver !== 'undefined') {
+ state.resizeObserver = new ResizeObserver(scheduleMapResize);
+ state.resizeObserver.observe(el('angular-motion-map'));
+ }
+ scheduleMapResize();
+ }
+
+ function scheduleMapResize() {
+ resizeMap();
+ requestAnimationFrame(() => {
+ resizeMap();
+ requestAnimationFrame(resizeMap);
+ });
+ setTimeout(resizeMap, 100);
+ }
+
+ function resizeMap() {
+ if (!state.viewer) return;
+ state.viewer.resize();
+ state.viewer.scene.requestRender();
+ }
+
function initCursorCoordinates() {
state.cursorCoordsPanel = document.createElement('div');
state.cursorCoordsPanel.className = 'angular-motion-cursor-coords-panel';
@@ -207,6 +238,13 @@
});
}
+ function initTargetOverlay() {
+ state.targetOverlay = document.createElement('div');
+ state.targetOverlay.className = 'angular-motion-target-marker';
+ state.targetOverlay.innerHTML = 'ЦЛМ';
+ state.viewer.cesiumWidget.container.appendChild(state.targetOverlay);
+ }
+
function naturalEarthLayerOptions() {
const url = '/webjars/cesium/1.107.2/Build/Cesium/Assets/Textures/NaturalEarthII';
if (Cesium.ImageryLayer?.fromProviderAsync && Cesium.TileMapServiceImageryProvider?.fromUrl) {
@@ -225,9 +263,10 @@
function pickGlobePoint(position) {
if (!state.viewer || !position) return null;
const scene = state.viewer.scene;
- if (scene.pickPositionSupported) {
- const picked = scene.pickPosition(position);
- if (Cesium.defined(picked)) return picked;
+ const ray = state.viewer.camera.getPickRay(position);
+ if (ray) {
+ const globePoint = scene.globe.pick(ray, scene);
+ if (Cesium.defined(globePoint)) return globePoint;
}
return state.viewer.camera.pickEllipsoid(position, scene.globe.ellipsoid);
}
@@ -324,32 +363,27 @@
});
}
- function addTarget() {
- if (!state.mapDataSource) return;
+ function updateTargetOverlay(screenPosition = null) {
+ if (!state.viewer || !state.targetOverlay) return;
const lat = Number(el('angular-motion-lat').value);
const lon = Number(el('angular-motion-lon').value);
- if (!Number.isFinite(lat) || !Number.isFinite(lon)) return;
- state.mapDataSource.entities.add({
- name: 'Точка съемки',
- position: Cesium.Cartesian3.fromDegrees(lon, lat, 0),
- point: {
- pixelSize: 10,
- color: Cesium.Color.RED,
- outlineColor: Cesium.Color.WHITE,
- outlineWidth: 2,
- heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
- },
- label: {
- text: 'ЦЛМ',
- font: '12px sans-serif',
- fillColor: Cesium.Color.RED,
- outlineColor: Cesium.Color.WHITE,
- outlineWidth: 2,
- style: Cesium.LabelStyle.FILL_AND_OUTLINE,
- pixelOffset: new Cesium.Cartesian2(0, -18),
- heightReference: Cesium.HeightReference.CLAMP_TO_GROUND,
- },
- });
+ if (!Number.isFinite(lat) || !Number.isFinite(lon)) {
+ state.targetOverlay.style.display = 'none';
+ return;
+ }
+
+ const position = screenPosition || Cesium.SceneTransforms.wgs84ToWindowCoordinates(
+ state.viewer.scene,
+ Cesium.Cartesian3.fromDegrees(lon, lat, 0)
+ );
+ if (!Cesium.defined(position)) {
+ state.targetOverlay.style.display = 'none';
+ return;
+ }
+
+ state.targetOverlay.style.display = 'block';
+ state.targetOverlay.style.left = `${position.x}px`;
+ state.targetOverlay.style.top = `${position.y}px`;
}
function flightLineBounds() {
@@ -400,19 +434,29 @@
function drawMap(centerMode = null) {
if (!state.mapDataSource || typeof Cesium === 'undefined') return;
+ resizeMap();
state.mapDataSource.entities.removeAll();
const points = Array.isArray(state.flightLine) ? state.flightLine : [];
addPolyline(points, 'leftLatitudeDeg', 'leftLongitudeDeg', Cesium.Color.CORNFLOWERBLUE.withAlpha(0.85), 2, 'Левая граница полосы');
addPolyline(points, 'rightLatitudeDeg', 'rightLongitudeDeg', Cesium.Color.CORNFLOWERBLUE.withAlpha(0.85), 2, 'Правая граница полосы');
addPolyline(points, 'latitudeDeg', 'longitudeDeg', Cesium.Color.YELLOW, 3, 'Трасса полета');
addSurveyContour();
- addTarget();
+ updateTargetOverlay();
if (centerMode === 'flight-line') {
fitMapToFlightLine();
} else if (centerMode === 'target') {
centerMapOnTarget();
}
+ requestMapRender();
+ }
+
+ function requestMapRender() {
+ if (!state.viewer) return;
state.viewer.scene.requestRender();
+ requestAnimationFrame(() => {
+ state.viewer?.scene.requestRender();
+ requestAnimationFrame(() => state.viewer?.scene.requestRender());
+ });
}
function setPicking(value) {
diff --git a/services/pcp-ui-service/src/main/resources/static/css/angular-motion.css b/services/pcp-ui-service/src/main/resources/static/css/angular-motion.css
index ad19eb3..f0e5d3c 100644
--- a/services/pcp-ui-service/src/main/resources/static/css/angular-motion.css
+++ b/services/pcp-ui-service/src/main/resources/static/css/angular-motion.css
@@ -65,6 +65,39 @@
white-space: nowrap;
}
+.angular-motion-target-marker {
+ position: absolute;
+ z-index: 1001;
+ display: none;
+ pointer-events: none;
+ transform: translate(-50%, -50%);
+}
+
+.angular-motion-target-marker__dot {
+ display: block;
+ width: 14px;
+ height: 14px;
+ border: 2px solid #fff;
+ border-radius: 50%;
+ background: #ff1f2f;
+ box-shadow: 0 0 0 1px rgba(255, 31, 47, 0.65);
+}
+
+.angular-motion-target-marker__label {
+ position: absolute;
+ left: 50%;
+ bottom: 16px;
+ color: #ff4d5d;
+ font: 700 12px sans-serif;
+ text-shadow:
+ -1px -1px 0 #fff,
+ 1px -1px 0 #fff,
+ -1px 1px 0 #fff,
+ 1px 1px 0 #fff;
+ transform: translateX(-50%);
+ white-space: nowrap;
+}
+
.angular-motion-result-card {
min-height: 360px;
}