feat: Add fullscreen toggle functionality to GraphView for enhanced user experience and improved interaction
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m52s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m52s
This commit is contained in:
@@ -1,15 +1,17 @@
|
|||||||
import React, { useState, useRef, useEffect } from 'react';
|
import React, { useState, useRef, useEffect } from 'react';
|
||||||
import * as d3 from 'd3';
|
import * as d3 from 'd3';
|
||||||
import { IconZoomIn, IconZoomOut, IconMaximize } from '@tabler/icons-react';
|
import { IconZoomIn, IconZoomOut, IconMaximize, IconMinimize } from '@tabler/icons-react';
|
||||||
|
|
||||||
function GraphView({ servers, connections }) {
|
function GraphView({ servers, connections }) {
|
||||||
const [nodePositions, setNodePositions] = useState({});
|
const [nodePositions, setNodePositions] = useState({});
|
||||||
const [draggedNode, setDraggedNode] = useState(null);
|
const [draggedNode, setDraggedNode] = useState(null);
|
||||||
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
||||||
const [hoveredLinkId, setHoveredLinkId] = useState(null);
|
const [hoveredLinkId, setHoveredLinkId] = useState(null);
|
||||||
|
const containerRef = useRef(null);
|
||||||
const svgRef = useRef(null);
|
const svgRef = useRef(null);
|
||||||
const gRef = useRef(null);
|
const gRef = useRef(null);
|
||||||
const zoomRef = useRef(null);
|
const zoomRef = useRef(null);
|
||||||
|
const [isFullscreen, setIsFullscreen] = useState(false);
|
||||||
|
|
||||||
// Размеры карточки узла
|
// Размеры карточки узла
|
||||||
const NODE_WIDTH = 160;
|
const NODE_WIDTH = 160;
|
||||||
@@ -111,6 +113,23 @@ function GraphView({ servers, connections }) {
|
|||||||
d3.select(svgEl).transition().duration(250).call(zoomRef.current.transform, t);
|
d3.select(svgEl).transition().duration(250).call(zoomRef.current.transform, t);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Полноэкранный режим
|
||||||
|
useEffect(() => {
|
||||||
|
const handler = () => setIsFullscreen(Boolean(document.fullscreenElement));
|
||||||
|
document.addEventListener('fullscreenchange', handler);
|
||||||
|
return () => document.removeEventListener('fullscreenchange', handler);
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const toggleFullscreen = () => {
|
||||||
|
const el = containerRef.current;
|
||||||
|
if (!el) return;
|
||||||
|
if (!document.fullscreenElement) {
|
||||||
|
el.requestFullscreen?.();
|
||||||
|
} else {
|
||||||
|
document.exitFullscreen?.();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (servers.length === 0) {
|
if (servers.length === 0) {
|
||||||
return (
|
return (
|
||||||
<div className="text-center py-5">
|
<div className="text-center py-5">
|
||||||
@@ -222,7 +241,7 @@ function GraphView({ servers, connections }) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ width: '100%', height: '500px', border: '1px solid #e5e7eb', borderRadius: '8px', overflow: 'hidden', background: '#f8fafc', position: 'relative' }}>
|
<div ref={containerRef} style={{ width: '100%', height: '500px', border: '1px solid #e5e7eb', borderRadius: '8px', overflow: 'hidden', background: '#f8fafc', position: 'relative' }}>
|
||||||
<svg
|
<svg
|
||||||
ref={svgRef}
|
ref={svgRef}
|
||||||
width="100%"
|
width="100%"
|
||||||
@@ -415,8 +434,9 @@ function GraphView({ servers, connections }) {
|
|||||||
x={badgeX + 18}
|
x={badgeX + 18}
|
||||||
y={badgeY + 12}
|
y={badgeY + 12}
|
||||||
textAnchor="middle"
|
textAnchor="middle"
|
||||||
fontSize="12"
|
fontSize="14"
|
||||||
dominantBaseline="middle"
|
dominantBaseline="middle"
|
||||||
|
style={{ fontFamily: 'Segoe UI Emoji, Noto Color Emoji, Apple Color Emoji, "Twemoji Mozilla", "EmojiOne Color", sans-serif' }}
|
||||||
>
|
>
|
||||||
{flag}
|
{flag}
|
||||||
</text>
|
</text>
|
||||||
@@ -462,7 +482,7 @@ function GraphView({ servers, connections }) {
|
|||||||
</g>
|
</g>
|
||||||
</svg>
|
</svg>
|
||||||
{/* Контролы масштабирования */}
|
{/* Контролы масштабирования */}
|
||||||
<div className="position-absolute" style={{ right: 10, top: 10 }}>
|
<div className="position-absolute" style={{ right: 10, top: 10, zIndex: 10, pointerEvents: 'auto' }}>
|
||||||
<div className="btn-group btn-group-sm">
|
<div className="btn-group btn-group-sm">
|
||||||
<button className="btn btn-outline-secondary" onClick={() => zoomBy(1.2)} title="Увеличить">
|
<button className="btn btn-outline-secondary" onClick={() => zoomBy(1.2)} title="Увеличить">
|
||||||
<IconZoomIn size={16} />
|
<IconZoomIn size={16} />
|
||||||
@@ -470,8 +490,8 @@ function GraphView({ servers, connections }) {
|
|||||||
<button className="btn btn-outline-secondary" onClick={() => zoomBy(1/1.2)} title="Уменьшить">
|
<button className="btn btn-outline-secondary" onClick={() => zoomBy(1/1.2)} title="Уменьшить">
|
||||||
<IconZoomOut size={16} />
|
<IconZoomOut size={16} />
|
||||||
</button>
|
</button>
|
||||||
<button className="btn btn-outline-secondary" onClick={fitToView} title="Подогнать по окну">
|
<button className="btn btn-outline-secondary" onClick={toggleFullscreen} title={isFullscreen ? 'Выйти из полноэкранного' : 'Во весь экран'}>
|
||||||
<IconMaximize size={16} />
|
{isFullscreen ? <IconMinimize size={16} /> : <IconMaximize size={16} />}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user