feat: Add debug logging and enhance flag emoji handling in GraphView for improved debugging and country code support
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m42s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m42s
This commit is contained in:
+46
-13
@@ -3,6 +3,10 @@ import * as d3 from 'd3';
|
|||||||
import { IconZoomIn, IconZoomOut, IconMaximize, IconMinimize } from '@tabler/icons-react';
|
import { IconZoomIn, IconZoomOut, IconMaximize, IconMinimize } from '@tabler/icons-react';
|
||||||
|
|
||||||
function GraphView({ servers, connections }) {
|
function GraphView({ servers, connections }) {
|
||||||
|
// Debug helper (enable/disable via window.GRAPH_DEBUG = true/false in console)
|
||||||
|
const isDebug = typeof window !== 'undefined' ? (window.GRAPH_DEBUG !== false) : true;
|
||||||
|
const dbg = (...args) => { if (isDebug && typeof console !== 'undefined') console.log('[GraphView]', ...args); };
|
||||||
|
|
||||||
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 });
|
||||||
@@ -80,16 +84,34 @@ function GraphView({ servers, connections }) {
|
|||||||
.translateExtent([[-10000, -10000], [10000, 10000]])
|
.translateExtent([[-10000, -10000], [10000, 10000]])
|
||||||
.on('zoom', (event) => {
|
.on('zoom', (event) => {
|
||||||
g.attr('transform', event.transform);
|
g.attr('transform', event.transform);
|
||||||
|
// dbg('onZoom', { k: event.transform.k, x: event.transform.x, y: event.transform.y });
|
||||||
});
|
});
|
||||||
svg.call(zoomRef.current);
|
svg.call(zoomRef.current);
|
||||||
|
dbg('zoom initialized', { width, height });
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
// Контролы масштабирования
|
// Контролы масштабирования
|
||||||
const zoomBy = (factor) => {
|
const zoomBy = (factor) => {
|
||||||
if (!zoomRef.current || !svgRef.current) return;
|
if (!zoomRef.current || !svgRef.current) return;
|
||||||
const svg = d3.select(svgRef.current);
|
const svgEl = svgRef.current;
|
||||||
// Используем встроенную математику d3.zoom с учётом extent
|
const current = d3.zoomTransform(svgEl);
|
||||||
svg.transition().duration(220).call(zoomRef.current.scaleBy, factor);
|
const cx = svgEl.clientWidth / 2;
|
||||||
|
const cy = svgEl.clientHeight / 2;
|
||||||
|
dbg('zoomBy click', { factor, current: { k: current.k, x: current.x, y: current.y }, center: { cx, cy } });
|
||||||
|
const next = d3.zoomIdentity
|
||||||
|
.translate(current.x, current.y)
|
||||||
|
.scale(current.k)
|
||||||
|
.translate(cx, cy)
|
||||||
|
.scale(factor)
|
||||||
|
.translate(-cx, -cy);
|
||||||
|
d3.select(svgEl)
|
||||||
|
.transition()
|
||||||
|
.duration(220)
|
||||||
|
.call(zoomRef.current.transform, next)
|
||||||
|
.on('end', () => {
|
||||||
|
const nt = d3.zoomTransform(svgEl);
|
||||||
|
dbg('zoomBy end', { next: { k: nt.k, x: nt.x, y: nt.y } });
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const fitToView = () => {
|
const fitToView = () => {
|
||||||
@@ -127,6 +149,7 @@ function GraphView({ servers, connections }) {
|
|||||||
const toggleFullscreen = () => {
|
const toggleFullscreen = () => {
|
||||||
const el = containerRef.current;
|
const el = containerRef.current;
|
||||||
if (!el) return;
|
if (!el) return;
|
||||||
|
dbg('toggleFullscreen', { isFullscreen: Boolean(document.fullscreenElement) });
|
||||||
if (!document.fullscreenElement) {
|
if (!document.fullscreenElement) {
|
||||||
el.requestFullscreen?.();
|
el.requestFullscreen?.();
|
||||||
} else {
|
} else {
|
||||||
@@ -236,11 +259,13 @@ function GraphView({ servers, connections }) {
|
|||||||
return map[tunnelType] || { color: '#667382', dash: '5,5', width: 2 };
|
return map[tunnelType] || { color: '#667382', dash: '5,5', width: 2 };
|
||||||
};
|
};
|
||||||
|
|
||||||
// Флаг страны по ISO-2 (emoji). Для не-ISO-2 вернём код как есть
|
// Флаг страны по ISO-2 с поддержкой нестандартных кодов из списка (SWE->SE)
|
||||||
const getFlagEmoji = (countryCode) => {
|
const getFlagEmoji = (code) => {
|
||||||
if (!countryCode) return '';
|
if (!code) return '';
|
||||||
const cc = String(countryCode).trim().toUpperCase();
|
const map = { SWE: 'SE', UK: 'GB' };
|
||||||
if (cc.length !== 2) return cc; // например, SWE
|
const ccRaw = String(code).trim().toUpperCase();
|
||||||
|
const cc = (map[ccRaw] || ccRaw).slice(0, 2);
|
||||||
|
if (cc.length !== 2) return ccRaw;
|
||||||
return cc.replace(/./g, (ch) => String.fromCodePoint(127397 + ch.charCodeAt()));
|
return cc.replace(/./g, (ch) => String.fromCodePoint(127397 + ch.charCodeAt()));
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -429,21 +454,29 @@ function GraphView({ servers, connections }) {
|
|||||||
y={badgeY}
|
y={badgeY}
|
||||||
rx={8}
|
rx={8}
|
||||||
ry={8}
|
ry={8}
|
||||||
width={36}
|
width={52}
|
||||||
height={18}
|
height={20}
|
||||||
fill="#fff"
|
fill="#fff"
|
||||||
stroke={countryColor}
|
stroke={countryColor}
|
||||||
/>
|
/>
|
||||||
<text
|
<text
|
||||||
x={badgeX + 18}
|
x={badgeX + 10}
|
||||||
y={badgeY + 12}
|
y={badgeY + 13}
|
||||||
textAnchor="middle"
|
|
||||||
fontSize="14"
|
fontSize="14"
|
||||||
dominantBaseline="middle"
|
dominantBaseline="middle"
|
||||||
style={{ fontFamily: 'Segoe UI Emoji, Noto Color Emoji, Apple Color Emoji, "Twemoji Mozilla", "EmojiOne Color", sans-serif' }}
|
style={{ fontFamily: 'Segoe UI Emoji, Noto Color Emoji, Apple Color Emoji, "Twemoji Mozilla", "EmojiOne Color", sans-serif' }}
|
||||||
>
|
>
|
||||||
{flag}
|
{flag}
|
||||||
</text>
|
</text>
|
||||||
|
<text
|
||||||
|
x={badgeX + 28}
|
||||||
|
y={badgeY + 13}
|
||||||
|
fontSize="11"
|
||||||
|
fill="#475569"
|
||||||
|
dominantBaseline="middle"
|
||||||
|
>
|
||||||
|
{String(server.country).toUpperCase().slice(0,3)}
|
||||||
|
</text>
|
||||||
</g>
|
</g>
|
||||||
);
|
);
|
||||||
})()}
|
})()}
|
||||||
|
|||||||
Reference in New Issue
Block a user