+ {!modelPath ? (
+
+
+
+ 3D модель не выбрана
+
+
+ Выберите модель в панели «Зоны мониторинга», чтобы начать просмотр
+
+
+ Если список пуст, добавьте файлы в каталог assets/big-models или проверьте API
+
+
+
+ ) : (
+ <>
+
+ {webglError ? (
+
+
+
+ 3D просмотр недоступен
+
+
+ {webglError}
+
+
+ Включите аппаратное ускорение в браузере или откройте страницу в другом браузере/устройстве
+
+
+
+ ) : isLoading ? (
+
+
+
+ ) : !modelReady ? (
+
+
+
+ 3D модель не загружена
+
+
+ Модель не готова к отображению
+
+
+
+ ) : null}
+
+
+ >
+ )}
+ {/* UPDATED: Interactive overlay circles with hover effects */}
+ {allSensorsOverlayCircles.map(circle => {
+ const size = 36
+ const radius = size / 2
+ const fill = hexWithAlpha(circle.colorHex, 0.2)
+ const isHovered = hoveredSensorId === circle.sensorId
+
+ return (
+
handleOverlayCircleClick(circle.sensorId)}
+ onMouseEnter={() => setHoveredSensorId(circle.sensorId)}
+ onMouseLeave={() => setHoveredSensorId(null)}
+ style={{
+ position: 'absolute',
+ left: circle.left - radius,
+ top: circle.top - radius,
+ width: size,
+ height: size,
+ borderRadius: '9999px',
+ border: `2px solid ${circle.colorHex}`,
+ backgroundColor: fill,
+ pointerEvents: 'auto',
+ cursor: 'pointer',
+ transition: 'all 0.2s cubic-bezier(0.34, 1.56, 0.64, 1)',
+ transform: isHovered ? 'scale(1.4)' : 'scale(1)',
+ boxShadow: isHovered
+ ? `0 0 25px ${circle.colorHex}, inset 0 0 10px ${circle.colorHex}`
+ : `0 0 8px ${circle.colorHex}`,
+ zIndex: isHovered ? 50 : 10,
+ }}
+ title={`Датчик: ${circle.sensorId}`}
+ />
+ )
+ })}
+ {renderOverlay && overlayPos && overlayData
+ ? renderOverlay({ anchor: overlayPos, info: overlayData })
+ : null
+ }
+
+ )
+}
+
+export default React.memo(ModelViewer)
diff --git a/frontend/components/objects/ObjectCard.tsx b/frontend/components/objects/ObjectCard.tsx
index 8c2026e..27b74af 100644
--- a/frontend/components/objects/ObjectCard.tsx
+++ b/frontend/components/objects/ObjectCard.tsx
@@ -21,12 +21,7 @@ interface ObjectCardProps {
isSelected?: boolean
}
-// Иконка редактирования
-const EditIcon = ({ className }: { className?: string }) => (
-
-)
+
const ObjectCard: React.FC
= ({ object, onSelect, isSelected = false }) => {
const navigationService = useNavigationService()
@@ -39,11 +34,7 @@ const ObjectCard: React.FC = ({ object, onSelect, isSelected =
navigationService.selectObjectAndGoToDashboard(object.object_id, object.title)
}
- const handleEditClick = (e: React.MouseEvent) => {
- e.stopPropagation()
- console.log('Edit object:', object.object_id)
- // Логика редактирования объекта
- }
+
// Возврат к тестовому изображению, если src отсутствует/некорректен; нормализация относительных путей
const resolveImageSrc = (src?: string | null): string => {
@@ -82,7 +73,7 @@ const ObjectCard: React.FC = ({ object, onSelect, isSelected =
return (
= ({ object, onSelect, isSelected =
{object.description}
-