считывание точки прицеливания с карты

This commit is contained in:
emelianov
2026-06-23 17:13:30 +03:00
parent 1e8b9f6998
commit d0ec0ef754
2 changed files with 106 additions and 29 deletions
@@ -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 = '<span class="angular-motion-target-marker__label">ЦЛМ</span><span class="angular-motion-target-marker__dot"></span>';
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) {
@@ -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;
}