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';
|
||||
|
||||
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 [draggedNode, setDraggedNode] = useState(null);
|
||||
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
|
||||
@@ -80,16 +84,34 @@ function GraphView({ servers, connections }) {
|
||||
.translateExtent([[-10000, -10000], [10000, 10000]])
|
||||
.on('zoom', (event) => {
|
||||
g.attr('transform', event.transform);
|
||||
// dbg('onZoom', { k: event.transform.k, x: event.transform.x, y: event.transform.y });
|
||||
});
|
||||
svg.call(zoomRef.current);
|
||||
dbg('zoom initialized', { width, height });
|
||||
}, []);
|
||||
|
||||
// Контролы масштабирования
|
||||
const zoomBy = (factor) => {
|
||||
if (!zoomRef.current || !svgRef.current) return;
|
||||
const svg = d3.select(svgRef.current);
|
||||
// Используем встроенную математику d3.zoom с учётом extent
|
||||
svg.transition().duration(220).call(zoomRef.current.scaleBy, factor);
|
||||
const svgEl = svgRef.current;
|
||||
const current = d3.zoomTransform(svgEl);
|
||||
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 = () => {
|
||||
@@ -127,6 +149,7 @@ function GraphView({ servers, connections }) {
|
||||
const toggleFullscreen = () => {
|
||||
const el = containerRef.current;
|
||||
if (!el) return;
|
||||
dbg('toggleFullscreen', { isFullscreen: Boolean(document.fullscreenElement) });
|
||||
if (!document.fullscreenElement) {
|
||||
el.requestFullscreen?.();
|
||||
} else {
|
||||
@@ -236,11 +259,13 @@ function GraphView({ servers, connections }) {
|
||||
return map[tunnelType] || { color: '#667382', dash: '5,5', width: 2 };
|
||||
};
|
||||
|
||||
// Флаг страны по ISO-2 (emoji). Для не-ISO-2 вернём код как есть
|
||||
const getFlagEmoji = (countryCode) => {
|
||||
if (!countryCode) return '';
|
||||
const cc = String(countryCode).trim().toUpperCase();
|
||||
if (cc.length !== 2) return cc; // например, SWE
|
||||
// Флаг страны по ISO-2 с поддержкой нестандартных кодов из списка (SWE->SE)
|
||||
const getFlagEmoji = (code) => {
|
||||
if (!code) return '';
|
||||
const map = { SWE: 'SE', UK: 'GB' };
|
||||
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()));
|
||||
};
|
||||
|
||||
@@ -429,21 +454,29 @@ function GraphView({ servers, connections }) {
|
||||
y={badgeY}
|
||||
rx={8}
|
||||
ry={8}
|
||||
width={36}
|
||||
height={18}
|
||||
width={52}
|
||||
height={20}
|
||||
fill="#fff"
|
||||
stroke={countryColor}
|
||||
/>
|
||||
<text
|
||||
x={badgeX + 18}
|
||||
y={badgeY + 12}
|
||||
textAnchor="middle"
|
||||
x={badgeX + 10}
|
||||
y={badgeY + 13}
|
||||
fontSize="14"
|
||||
dominantBaseline="middle"
|
||||
style={{ fontFamily: 'Segoe UI Emoji, Noto Color Emoji, Apple Color Emoji, "Twemoji Mozilla", "EmojiOne Color", sans-serif' }}
|
||||
>
|
||||
{flag}
|
||||
</text>
|
||||
<text
|
||||
x={badgeX + 28}
|
||||
y={badgeY + 13}
|
||||
fontSize="11"
|
||||
fill="#475569"
|
||||
dominantBaseline="middle"
|
||||
>
|
||||
{String(server.country).toUpperCase().slice(0,3)}
|
||||
</text>
|
||||
</g>
|
||||
);
|
||||
})()}
|
||||
|
||||
Reference in New Issue
Block a user