Skip to content

Commit 80062bd

Browse files
committed
Graph explorer: fcose layout + fullscreen; compact-Turtle worked example
Knowledge-graph page was too zoomed-in and cluttered. Switch cytoscape from cose to fcose (cytoscape-fcose) with wider node separation, and re-fit to the container after layout settles so it no longer starts overzoomed. Add a toolbar with Fit and Full screen: full screen takes the whole explorer (search + filters + graph) to the viewport as a graph browser. Docs: the "Markdown -> RDF" worked example was labelled Turtle but printed flat N-Triples. Rewrite it as compact, prefixed, indented Turtle. Fence the weekly-active-users.nt example as `turtle` (N-Triples is a Turtle subset) so both it and the YAML frontmatter get syntax highlighting.
1 parent 1e49536 commit 80062bd

5 files changed

Lines changed: 121 additions & 121 deletions

File tree

SPEC.md

Lines changed: 21 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -286,20 +286,30 @@ dependsOn: [ https://acme.example/knowledge/glossary/active-user ]
286286
```
287287
<!-- --8<-- [end:worked-yaml] -->
288288

289-
Attaching the context and expanding yields (N-Triples, abridged):
289+
Attaching the context and expanding yields (Turtle, abridged):
290290

291291
<!-- --8<-- [start:worked-ttl] -->
292292
```turtle
293-
<…/metrics/weekly-active-users> a lokf:Metric .
294-
<…/metrics/weekly-active-users> schema:name "Weekly Active Users" .
295-
<…/metrics/weekly-active-users> schema:unitText "users" .
296-
<…/metrics/weekly-active-users> schema:keywords "growth", "engagement" .
297-
<…/metrics/weekly-active-users> schema:dateModified "2026-06-30T12:00:00Z"^^xsd:dateTime .
298-
<…/metrics/weekly-active-users> schema:author <…/people/jsmith> .
299-
<…/people/jsmith> a schema:Person ; schema:name "Jordan Smith" .
300-
<…/metrics/weekly-active-users> lokf:measures <…/glossary/active-user> .
301-
<…/metrics/weekly-active-users> prov:wasDerivedFrom <…/tables/user-events> .
302-
<…/metrics/weekly-active-users> dcterms:requires <…/glossary/active-user> .
293+
@prefix lokf: <https://w3id.org/lokf/> .
294+
@prefix schema: <http://schema.org/> .
295+
@prefix prov: <http://www.w3.org/ns/prov#> .
296+
@prefix dcterms: <http://purl.org/dc/terms/> .
297+
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
298+
299+
<…/metrics/weekly-active-users>
300+
a lokf:Metric ;
301+
schema:name "Weekly Active Users" ;
302+
schema:unitText "users" ;
303+
schema:keywords "growth", "engagement" ;
304+
schema:dateModified "2026-06-30T12:00:00Z"^^xsd:dateTime ;
305+
schema:author <…/people/jsmith> ;
306+
lokf:measures <…/glossary/active-user> ;
307+
prov:wasDerivedFrom <…/tables/user-events> ;
308+
dcterms:requires <…/glossary/active-user> .
309+
310+
<…/people/jsmith>
311+
a schema:Person ;
312+
schema:name "Jordan Smith" .
303313
```
304314
<!-- --8<-- [end:worked-ttl] -->
305315

web/package-lock.json

Lines changed: 2 additions & 107 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

web/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"astro": "^7.0.2",
2121
"astro-mermaid": "^2.1.0",
2222
"cytoscape": "^3.34.0",
23+
"cytoscape-fcose": "^2.2.0",
2324
"mermaid": "^11.16.0",
2425
"sharp": "^0.34.5"
2526
},

web/scripts/sync-content.mjs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,9 @@ writePartial(
5656
);
5757
writePartial(
5858
"metric-nt",
59+
// N-Triples is a subset of Turtle, so the `turtle` grammar highlights it.
5960
fenced(
60-
'text title="examples/weekly-active-users.nt"',
61+
'turtle title="examples/weekly-active-users.nt"',
6162
read("examples/weekly-active-users.nt"),
6263
),
6364
);

web/src/components/KnowledgeGraph.astro

Lines changed: 95 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@
2626
</div>
2727
</div>
2828
<div class="lokf-graph__stage">
29+
<div class="lokf-graph__toolbar">
30+
<button type="button" class="lokf-graph__btn" data-action="fit" title="Fit graph to view">
31+
⤢ Fit
32+
</button>
33+
<button
34+
type="button"
35+
class="lokf-graph__btn"
36+
data-action="fullscreen"
37+
title="Open the full-screen graph browser"
38+
>
39+
⛶ Full screen
40+
</button>
41+
</div>
2942
<div class="lokf-graph__canvas"></div>
3043
<aside class="lokf-graph__detail" hidden>
3144
<button type="button" class="lokf-graph__close" aria-label="Close">&times;</button>
@@ -42,6 +55,9 @@
4255

4356
<script>
4457
import cytoscape from "cytoscape";
58+
import fcose from "cytoscape-fcose";
59+
60+
cytoscape.use(fcose);
4561

4662
const PALETTE = [
4763
"#5b8def", "#e8833a", "#2ea77d", "#c1558b",
@@ -88,7 +104,20 @@
88104
const cy = cytoscape({
89105
container: mount,
90106
elements: graph,
91-
layout: { name: "cose", padding: 30, idealEdgeLength: () => 130, nodeRepulsion: () => 9000, animate: false },
107+
minZoom: 0.2,
108+
maxZoom: 2.5,
109+
wheelSensitivity: 0.3,
110+
layout: {
111+
name: "fcose",
112+
quality: "proof",
113+
animate: false,
114+
padding: 50,
115+
nodeSeparation: 160,
116+
idealEdgeLength: 150,
117+
nodeRepulsion: 7000,
118+
gravity: 0.2,
119+
fit: true,
120+
},
92121
style: [
93122
{
94123
selector: "node",
@@ -194,6 +223,30 @@
194223
"click",
195224
() => (detail.hidden = true),
196225
);
226+
227+
// Zoom to fit once the force layout settles (fcose fits too, but a re-fit
228+
// after the container has its final size avoids the "too zoomed in" start).
229+
const fit = () => cy.fit(undefined, 45);
230+
cy.one("layoutstop", () => requestAnimationFrame(fit));
231+
232+
// Toolbar: fit + a full-screen graph browser (the whole explorer — search,
233+
// filters, and graph — fills the viewport).
234+
root.querySelector('[data-action="fit"]')!.addEventListener("click", fit);
235+
const fsBtn = root.querySelector('[data-action="fullscreen"]') as HTMLButtonElement;
236+
fsBtn.addEventListener("click", () => {
237+
if (document.fullscreenElement) document.exitFullscreen();
238+
else root.requestFullscreen?.();
239+
});
240+
document.addEventListener("fullscreenchange", () => {
241+
const full = document.fullscreenElement === root;
242+
root.classList.toggle("is-fullscreen", full);
243+
fsBtn.textContent = full ? "⛶ Exit full screen" : "⛶ Full screen";
244+
// Let the layout reflow to the new size before resizing the canvas.
245+
requestAnimationFrame(() => {
246+
cy.resize();
247+
fit();
248+
});
249+
});
197250
}
198251

199252
// This module script is deferred, so the DOM is ready — boot now. Also
@@ -262,14 +315,54 @@
262315
.lokf-graph__stage {
263316
position: relative;
264317
}
318+
.lokf-graph__toolbar {
319+
position: absolute;
320+
top: 0.55rem;
321+
left: 0.55rem;
322+
z-index: 3;
323+
display: flex;
324+
gap: 0.4rem;
325+
}
326+
.lokf-graph__btn {
327+
font-size: 0.75rem;
328+
padding: 0.28rem 0.6rem;
329+
color: var(--sl-color-text);
330+
background: var(--sl-color-black);
331+
border: 1px solid var(--sl-color-gray-5);
332+
border-radius: 0.35rem;
333+
cursor: pointer;
334+
line-height: 1.4;
335+
}
336+
.lokf-graph__btn:hover {
337+
border-color: var(--sl-color-accent);
338+
color: var(--sl-color-accent-high);
339+
}
265340
.lokf-graph__canvas {
266341
width: 100%;
267342
height: 60vh;
268-
min-height: 420px;
343+
min-height: 460px;
269344
border: 1px solid var(--sl-color-gray-5);
270345
border-radius: 0.5rem;
271346
background: var(--sl-color-gray-7, var(--sl-color-black));
272347
}
348+
/* Full-screen graph browser: the whole explorer — search, filters, and
349+
graph — fills the viewport, with the graph stage taking the leftover
350+
height. */
351+
.lokf-graph.is-fullscreen {
352+
margin: 0;
353+
padding: 1rem;
354+
display: flex;
355+
flex-direction: column;
356+
background: var(--sl-color-bg);
357+
}
358+
.lokf-graph.is-fullscreen .lokf-graph__stage {
359+
flex: 1;
360+
min-height: 0;
361+
}
362+
.lokf-graph.is-fullscreen .lokf-graph__canvas {
363+
height: 100%;
364+
min-height: 0;
365+
}
273366
.lokf-graph__detail {
274367
position: absolute;
275368
top: 0.7rem;

0 commit comments

Comments
 (0)