fix(materials): синхронизация легенды и маркеров на превью и презентации

Легенда и цифры на материале масштабируются от экрана игроков и не обрезаются жёлтой рамкой. Переключение сцен без записи project.json на диск.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Ivan Fontosh
2026-09-02 10:57:50 +08:00
parent ea718a26df
commit 153be98780
17 changed files with 531 additions and 128 deletions
@@ -2,6 +2,7 @@ import React, { useRef } from 'react';
import type { MaterialLegend, MaterialsOverlayLayout } from '../../../shared/types';
import { DEFAULT_MATERIALS_OVERLAY_LAYOUT } from '../../../shared/types';
import { legendPanelVisualLayout } from '../../../shared/types/materialLegend';
import { useSceneOverlayView } from '../sceneOverlay/SceneOverlayViewContext';
import styles from './MaterialLegendPanel.module.css';
@@ -21,20 +22,24 @@ export function MaterialLegendPanel({
}: Props) {
const host = useSceneOverlayView();
const view = host?.view ?? { w: 1, h: 1 };
const viewport = host?.viewport ?? { x: 0, y: 0, w: view.w, h: view.h };
const dragRef = useRef<{ startX: number; startY: number; origin: MaterialsOverlayLayout } | null>(
null,
);
const effective = layout ?? DEFAULT_MATERIALS_OVERLAY_LAYOUT;
const w = Math.max(180, Math.min(view.w * 0.36, 340) * effective.scale);
const left = effective.cx * view.w - w / 2;
const top = effective.cy * view.h - 40;
const vis = legendPanelVisualLayout(effective, viewport);
if (!legend.enabled || legend.items.length === 0) return null;
return (
<div
className={styles.panel}
style={{ left, top, width: w }}
style={{
left: vis.left,
top: vis.top,
width: vis.width,
transform: `translate(-50%, -50%) scale(${String(vis.scale)})`,
}}
onPointerDown={(e) => {
if (!editable || !onLayoutChange) return;
e.stopPropagation();