Skip to content

Commit 0df5fde

Browse files
timearcs improvements
1 parent 2aba4c4 commit 0df5fde

6 files changed

Lines changed: 4476 additions & 53 deletions

File tree

attack_timearcs.js

Lines changed: 43 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,45 +2478,54 @@
24782478
return xStart + distortedT * totalWidth;
24792479
},
24802480

2481-
// Fisheye distortion function that keeps the focus point fixed
2482-
// Simple formula: multiply distance by distortion factor near focus
2481+
// Fisheye distortion function that preserves monotonicity
2482+
// Maps normalized time [0,1] to distorted normalized position [0,1]
2483+
// Ensures order is preserved: if t1 < t2, then distorted(t1) < distorted(t2)
24832484
fisheyeDistortion: function(t, focus, distortion) {
24842485
if (distortion <= 1) return t;
24852486

2486-
// Distance from focus point
2487-
const delta = t - focus;
2488-
const distance = Math.abs(delta);
2489-
const sign = delta < 0 ? -1 : 1;
2490-
2491-
if (distance < 0.0001) {
2492-
// At the focus point, no distortion
2493-
return t;
2494-
}
2495-
2496-
// Fisheye effect: points near focus expand, far points compress
2497-
// Use a smooth falloff based on distance
2498-
const effectRadius = 0.5; // Half the range is affected
2499-
2500-
// Calculate how much to magnify based on distance from focus
2501-
// Close to focus: multiply by distortion (expand)
2502-
// Far from focus: divide by distortion (compress)
2503-
let scale;
2504-
if (distance < effectRadius) {
2505-
// Inside radius: interpolate from distortion (at focus) to 1 (at radius edge)
2506-
const normalized = distance / effectRadius;
2507-
// Use cosine for smooth interpolation
2508-
const blend = (1 - Math.cos(normalized * Math.PI)) / 2;
2509-
scale = distortion - (distortion - 1) * blend;
2487+
// Clamp input to valid range
2488+
t = Math.max(0, Math.min(1, t));
2489+
focus = Math.max(0, Math.min(1, focus));
2490+
2491+
// Effect radius around focus (fraction of total range)
2492+
const effectRadius = 0.15; // 15% on each side of focus = 30% total magnified region
2493+
2494+
// Define regions: [0, focusLeft], [focusLeft, focusRight], [focusRight, 1]
2495+
const focusLeft = Math.max(0, focus - effectRadius);
2496+
const focusRight = Math.min(1, focus + effectRadius);
2497+
2498+
// Calculate how much space each region should occupy after distortion
2499+
// The magnified region expands, other regions compress to compensate
2500+
const magnifiedWidth = focusRight - focusLeft;
2501+
const leftWidth = focusLeft;
2502+
const rightWidth = 1 - focusRight;
2503+
2504+
// Total "virtual" width if we expand magnified region by distortion factor
2505+
const virtualWidth = leftWidth + magnifiedWidth * distortion + rightWidth;
2506+
2507+
// Normalize back to [0,1] range - each region gets proportional space
2508+
const leftTargetWidth = leftWidth / virtualWidth;
2509+
const magnifiedTargetWidth = (magnifiedWidth * distortion) / virtualWidth;
2510+
const rightTargetWidth = rightWidth / virtualWidth;
2511+
2512+
// Map t to output position based on which region it's in
2513+
if (t <= focusLeft) {
2514+
// Left region: compress linearly
2515+
if (leftWidth === 0) return 0;
2516+
const localT = t / leftWidth; // Normalize to [0,1] within region
2517+
return localT * leftTargetWidth;
2518+
} else if (t <= focusRight) {
2519+
// Magnified region: expand linearly
2520+
if (magnifiedWidth === 0) return leftTargetWidth;
2521+
const localT = (t - focusLeft) / magnifiedWidth; // Normalize to [0,1] within region
2522+
return leftTargetWidth + localT * magnifiedTargetWidth;
25102523
} else {
2511-
// Outside radius: compress more as we go further
2512-
const excessDistance = distance - effectRadius;
2513-
const compressionFactor = 1 / distortion;
2514-
scale = 1 - (1 - compressionFactor) * Math.min(1, excessDistance / (1 - effectRadius));
2524+
// Right region: compress linearly
2525+
if (rightWidth === 0) return leftTargetWidth + magnifiedTargetWidth;
2526+
const localT = (t - focusRight) / rightWidth; // Normalize to [0,1] within region
2527+
return leftTargetWidth + magnifiedTargetWidth + localT * rightTargetWidth;
25152528
}
2516-
2517-
// Apply the scale to the distance
2518-
const distorted = focus + sign * distance * scale;
2519-
return Math.max(0, Math.min(1, distorted));
25202529
}
25212530
};
25222531

force_layout_functions.txt

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
2+
// Build force layout nodes and links from current packets
3+
function buildForceLayoutData(packets, selectedIPs) {
4+
if (!packets || packets.length === 0 || !selectedIPs || selectedIPs.length === 0) {
5+
return { nodes: [], links: [] };
6+
}
7+
8+
// Create nodes for each IP
9+
const nodes = selectedIPs.map((ip, idx) => ({
10+
id: ip,
11+
ip: ip,
12+
index: idx,
13+
x: width / 2,
14+
y: TOP_PAD + idx * ROW_GAP,
15+
vx: 0,
16+
vy: 0,
17+
fixed: false
18+
}));
19+
20+
// Build links from packet connections
21+
const linkMap = new Map();
22+
packets.forEach(packet => {
23+
if (!packet.src_ip || !packet.dst_ip) return;
24+
if (packet.src_ip === packet.dst_ip) return; // Skip self-connections
25+
26+
const key = packet.src_ip < packet.dst_ip
27+
? `${packet.src_ip}|${packet.dst_ip}`
28+
: `${packet.dst_ip}|${packet.src_ip}`;
29+
30+
if (!linkMap.has(key)) {
31+
linkMap.set(key, { count: 0, bytes: 0 });
32+
}
33+
const link = linkMap.get(key);
34+
link.count++;
35+
link.bytes += (packet.length || 0);
36+
});
37+
38+
// Convert link map to array
39+
const ipIndexMap = new Map(nodes.map((n, i) => [n.ip, i]));
40+
const links = [];
41+
linkMap.forEach((data, key) => {
42+
const [src, dst] = key.split('|');
43+
const srcIdx = ipIndexMap.get(src);
44+
const dstIdx = ipIndexMap.get(dst);
45+
if (srcIdx !== undefined && dstIdx !== undefined) {
46+
links.push({
47+
source: srcIdx,
48+
target: dstIdx,
49+
count: data.count,
50+
bytes: data.bytes
51+
});
52+
}
53+
});
54+
55+
return { nodes, links };
56+
}
57+
58+
// Initialize and run force layout to position IPs
59+
function computeForceLayoutPositions(packets, selectedIPs, onComplete) {
60+
if (isForceLayoutRunning) {
61+
LOG('Force layout already running, stopping previous layout');
62+
if (forceLayout) forceLayout.stop();
63+
}
64+
65+
const { nodes, links } = buildForceLayoutData(packets, selectedIPs);
66+
67+
if (nodes.length === 0) {
68+
if (onComplete) onComplete();
69+
return;
70+
}
71+
72+
forceNodes = nodes;
73+
forceLinks = links;
74+
75+
LOG(`Starting force layout with ${nodes.length} nodes and ${links.length} links`);
76+
77+
// Create force simulation
78+
forceLayout = d3.layout.force()
79+
.size([width / 4, height]) // Constrain to narrow vertical strip
80+
.nodes(forceNodes)
81+
.links(forceLinks)
82+
.charge(-180) // Repulsion between nodes
83+
.linkDistance(ROW_GAP * 1.5) // Desired distance between connected nodes
84+
.linkStrength(d => Math.min(1.0, d.count / 100)) // Stronger links for more packets
85+
.gravity(0.02) // Weak centering force
86+
.friction(0.9)
87+
.alpha(0.1)
88+
.on('tick', () => {
89+
// Update during simulation (optional - we mainly care about final positions)
90+
})
91+
.on('end', () => {
92+
LOG('Force layout converged');
93+
isForceLayoutRunning = false;
94+
applyForceLayoutPositions();
95+
if (onComplete) onComplete();
96+
});
97+
98+
isForceLayoutRunning = true;
99+
forceLayout.start();
100+
}
101+
102+
// Apply computed force layout positions to IP positions
103+
function applyForceLayoutPositions() {
104+
if (!forceNodes || forceNodes.length === 0) return;
105+
106+
LOG('Applying force layout positions to IPs');
107+
108+
// Sort nodes by their computed Y position
109+
const sortedNodes = forceNodes.slice().sort((a, b) => a.y - b.y);
110+
111+
// Update ipOrder and ipPositions based on sorted Y positions
112+
ipOrder = sortedNodes.map(n => n.ip);
113+
114+
// Assign evenly-spaced Y positions based on sorted order
115+
ipOrder.forEach((ip, idx) => {
116+
ipPositions.set(ip, TOP_PAD + idx * ROW_GAP);
117+
});
118+
119+
LOG('Updated IP positions:', Array.from(ipPositions.entries()));
120+
}

0 commit comments

Comments
 (0)