feat: Enhance GraphView with improved zoom functionality and label styling, including shadows for better visibility and aesthetics
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m48s
Publish Fast Tabler Docker image / build-and-push-fast (push) Successful in 5m48s
This commit is contained in:
+59
-31
@@ -79,8 +79,11 @@ function GraphView({ servers, connections }) {
|
||||
|
||||
// Контролы масштабирования
|
||||
const zoomBy = (factor) => {
|
||||
if (!zoomRef.current || !svgRef.current) return;
|
||||
const svg = d3.select(svgRef.current);
|
||||
svg.transition().duration(200).call(zoomRef.current.scaleBy, factor);
|
||||
const node = svgRef.current;
|
||||
const center = [node.clientWidth / 2, node.clientHeight / 2];
|
||||
svg.transition().duration(220).call(zoomRef.current.scaleBy, factor, center);
|
||||
};
|
||||
|
||||
const fitToView = () => {
|
||||
@@ -263,6 +266,10 @@ function GraphView({ servers, connections }) {
|
||||
<filter id="cardShadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feDropShadow dx="0" dy="2" stdDeviation="3" floodOpacity="0.2" />
|
||||
</filter>
|
||||
{/* Тень для ярлыков ссылок */}
|
||||
<filter id="labelShadow" x="-50%" y="-50%" width="200%" height="200%">
|
||||
<feDropShadow dx="0" dy="1" stdDeviation="2" floodOpacity="0.25" />
|
||||
</filter>
|
||||
</defs>
|
||||
{/* Подложка сетки */}
|
||||
<rect width="100%" height="100%" fill="url(#grid)" />
|
||||
@@ -309,36 +316,57 @@ function GraphView({ servers, connections }) {
|
||||
style={{ vectorEffect: 'non-scaling-stroke' }}
|
||||
/>
|
||||
|
||||
{/* Подпись связи */}
|
||||
<rect
|
||||
x={mx - 50}
|
||||
y={my - 35}
|
||||
width="80"
|
||||
height="30"
|
||||
rx="15"
|
||||
fill="#ffffff"
|
||||
stroke={style.color}
|
||||
strokeWidth="1"
|
||||
/>
|
||||
<text
|
||||
x={mx - 10}
|
||||
y={my - 18}
|
||||
textAnchor="middle"
|
||||
fontSize="11"
|
||||
fill="#374151"
|
||||
fontWeight="bold"
|
||||
>
|
||||
{connection.tunnelType}
|
||||
</text>
|
||||
<text
|
||||
x={mx}
|
||||
y={my - 3}
|
||||
textAnchor="middle"
|
||||
fontSize="9"
|
||||
fill="#6b7280"
|
||||
>
|
||||
{connection.ipA} ⇄ {connection.ipB}
|
||||
</text>
|
||||
{/* Подпись связи: ярлык с подложкой и halo */}
|
||||
{(() => {
|
||||
const labelW = 140;
|
||||
const labelH = 38;
|
||||
const lx = cx - labelW / 2;
|
||||
const ly = cy - labelH / 2 - 4; // слегка выше вершины
|
||||
return (
|
||||
<g style={{ pointerEvents: 'none' }}>
|
||||
<rect
|
||||
x={lx}
|
||||
y={ly}
|
||||
width={labelW}
|
||||
height={labelH}
|
||||
rx="16"
|
||||
fill="#ffffff"
|
||||
stroke={style.color}
|
||||
strokeWidth="1"
|
||||
filter="url(#labelShadow)"
|
||||
/>
|
||||
{/* Halo для заголовка */}
|
||||
<text
|
||||
x={cx}
|
||||
y={ly + 16}
|
||||
textAnchor="middle"
|
||||
fontSize="12"
|
||||
fontWeight="700"
|
||||
stroke="#ffffff"
|
||||
strokeWidth="3"
|
||||
strokeLinejoin="round"
|
||||
fill="#374151"
|
||||
style={{ paintOrder: 'stroke fill' }}
|
||||
>
|
||||
{connection.tunnelType}
|
||||
</text>
|
||||
{/* Линия IP с более мелким шрифтом */}
|
||||
<text
|
||||
x={cx}
|
||||
y={ly + 30}
|
||||
textAnchor="middle"
|
||||
fontSize="10"
|
||||
fill="#6b7280"
|
||||
stroke="#ffffff"
|
||||
strokeWidth="2"
|
||||
strokeLinejoin="round"
|
||||
style={{ paintOrder: 'stroke fill' }}
|
||||
>
|
||||
{connection.ipA} ⇄ {connection.ipB}
|
||||
</text>
|
||||
</g>
|
||||
);
|
||||
})()}
|
||||
</g>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user