Hover a node: a red ring appears outside it with a clear screen-space gap. Hover a link: the link turns red and thickens, and both endpoints get the ring.
hover a node or a link
// Hover rules describe the active node or edge treatment while topology remains unchanged.
// OGJS resolves connected endpoints and applies screen-space rings during hit testing,
// so unrelated entities retain their colors and applications do not redraw the graph.
import { Ogjs } from '../../src/index';
const og = new Ogjs({ container: '#viz', theme: 'light' });
// A compact social graph for checking connected hover states.
// slate fills, gray links, labels in pills.
const nodes = [], edges = [];
const NAMES = { 0: 'Instructor', 33: 'Administrator' };
const N = 34;
const pairs = [[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,10],[0,11],[0,12],[0,13],
[0,17],[0,19],[0,21],[0,31],[1,2],[1,3],[1,7],[1,13],[1,17],[1,19],[1,21],[1,30],[2,3],
[2,7],[2,8],[2,9],[2,13],[2,27],[2,28],[2,32],[3,7],[3,12],[3,13],[4,6],[4,10],[5,6],
[5,10],[5,16],[6,16],[8,30],[8,32],[8,33],[9,33],[13,33],[14,32],[14,33],[15,32],[15,33],
[18,32],[18,33],[19,33],[20,32],[20,33],[22,32],[22,33],[23,25],[23,27],[23,29],[23,32],
[23,33],[24,25],[24,27],[24,31],[25,31],[26,29],[26,33],[27,33],[28,31],[28,33],[29,32],
[29,33],[30,32],[30,33],[31,32],[31,33],[32,33]];
const deg = new Array(N).fill(0);
for (const [a, b] of pairs) { deg[a]++; deg[b]++; }
for (let i = 0; i < N; i++) {
nodes.push({ id: i, size: 5 + Math.sqrt(deg[i]) * 1.6,
color: i === 0 ? '#f5b73d' : i === 33 ? '#ef4444' : '#64748b',
label: NAMES[i] ?? String(i) });
}
for (const [a, b] of pairs) edges.push({ source: a, target: b });
og.setGraph({ nodes, edges });
og.layouts.force({ sync: true, iterations: 320, springLength: 70, repulsion: 2600, gravity: 0.05 });
og.camera.fit();
const info = document.querySelector('#info');
og.on('nodehover', ({ nodeId }) => {
info.textContent = 'node ' + nodeId + ' · degree ' + deg[Number(nodeId)];
});
og.on('nodeout', () => { info.textContent = 'hover a node or a link'; });
og.on('edgehover', ({ sourceId, targetId }) => {
info.textContent = 'link ' + sourceId + ' — ' + targetId
+ ' · both endpoints ringed';
});
og.on('edgeout', () => { info.textContent = 'hover a node or a link'; });
<!doctype html>
<html lang="en"><head><meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1"/>
<title>Ogjs example — Hover styles</title>
<link rel="stylesheet" href="../site.css"/>
<style>
#viz { position: fixed; inset: 52px 0 0 0; }
.panel { position: fixed; top: 66px; left: 14px; z-index: 5; max-width: 380px;
background: #ffffff; border: 1px solid #e2e6ec; border-radius: 8px;
padding: 12px 14px; box-shadow: 0 2px 12px rgba(15, 23, 42, 0.08); }
.panel h1 { font: 700 16px var(--sans); color: #0f172a; margin-bottom: 4px; }
.panel p { font: 400 12.5px/1.5 var(--sans); color: #475569; }
.panel .btns { display: flex; gap: 6px; margin-top: 10px; flex-wrap: wrap; }
.panel button { font: 600 12px var(--sans); background: #f1f5f9; color: #0f172a;
border: 1px solid #cbd5e1; border-radius: 5px; padding: 6px 11px; cursor: pointer; }
.panel button:hover { background: #e2e8f0; border-color: #94a3b8; }
</style></head><body>
<header class="rail">
<a class="wordmark" href="../index.html">OG<b>JS</b></a>
<nav><a href="../docs.html">Docs</a><a href="../demos.html">Demos</a>
<a href="./index.html" aria-current="page">Examples</a></nav>
</header>
<div id="viz"></div>
<div class="panel"><h1>Hover styles</h1><p>Hover a node: a red ring appears outside it with a clear screen-space gap. Hover a link: the link turns red and thickens, and both endpoints get the ring.</p><div class="btns"><span id="info" style="font:400 12px var(--mono);color:#475569">hover a node or a link</span></div></div>
<script type="module">
// Hover rules describe the active node or edge treatment while topology remains unchanged.
// OGJS resolves connected endpoints and applies screen-space rings during hit testing,
// so unrelated entities retain their colors and applications do not redraw the graph.
import { Ogjs } from '../../src/index';
const og = new Ogjs({ container: '#viz', theme: 'light' });
// A compact social graph for checking connected hover states.
// slate fills, gray links, labels in pills.
const nodes = [], edges = [];
const NAMES = { 0: 'Instructor', 33: 'Administrator' };
const N = 34;
const pairs = [[0,1],[0,2],[0,3],[0,4],[0,5],[0,6],[0,7],[0,8],[0,10],[0,11],[0,12],[0,13],
[0,17],[0,19],[0,21],[0,31],[1,2],[1,3],[1,7],[1,13],[1,17],[1,19],[1,21],[1,30],[2,3],
[2,7],[2,8],[2,9],[2,13],[2,27],[2,28],[2,32],[3,7],[3,12],[3,13],[4,6],[4,10],[5,6],
[5,10],[5,16],[6,16],[8,30],[8,32],[8,33],[9,33],[13,33],[14,32],[14,33],[15,32],[15,33],
[18,32],[18,33],[19,33],[20,32],[20,33],[22,32],[22,33],[23,25],[23,27],[23,29],[23,32],
[23,33],[24,25],[24,27],[24,31],[25,31],[26,29],[26,33],[27,33],[28,31],[28,33],[29,32],
[29,33],[30,32],[30,33],[31,32],[31,33],[32,33]];
const deg = new Array(N).fill(0);
for (const [a, b] of pairs) { deg[a]++; deg[b]++; }
for (let i = 0; i < N; i++) {
nodes.push({ id: i, size: 5 + Math.sqrt(deg[i]) * 1.6,
color: i === 0 ? '#f5b73d' : i === 33 ? '#ef4444' : '#64748b',
label: NAMES[i] ?? String(i) });
}
for (const [a, b] of pairs) edges.push({ source: a, target: b });
og.setGraph({ nodes, edges });
og.layouts.force({ sync: true, iterations: 320, springLength: 70, repulsion: 2600, gravity: 0.05 });
og.camera.fit();
const info = document.querySelector('#info');
og.on('nodehover', ({ nodeId }) => {
info.textContent = 'node ' + nodeId + ' · degree ' + deg[Number(nodeId)];
});
og.on('nodeout', () => { info.textContent = 'hover a node or a link'; });
og.on('edgehover', ({ sourceId, targetId }) => {
info.textContent = 'link ' + sourceId + ' — ' + targetId
+ ' · both endpoints ringed';
});
og.on('edgeout', () => { info.textContent = 'hover a node or a link'; });
</script>
</body></html>