Skip to content

Matdata-eu/yasgui-graph-plugin

Repository files navigation

YASGUI Graph Plugin

License npm version

A YASGUI plugin for visualizing SPARQL CONSTRUCT and DESCRIBE query results as interactive graphs with nodes (subjects/objects) and edges (predicates).

✨ Features

  • 🔷 Interactive Graph Visualization: Automatic force-directed layout with smooth physics-based positioning
  • 🎨 Smart Color Coding:
    • 🔵 Light Blue (#97C2FC) = URIs
    • 🟢 Light Green (#a6c8a6ff) = Literals
    • ⚪ Light Grey (#c5c5c5ff) = Blank nodes
    • 🟠 Orange (#e15b13ff) = rdf:type objects (classes)
  • 🖼️ Node Icons & Images: Render images or emoji/icons on nodes via schema:image / schema:icon properties (see Node icons and images)
  • � Compact Mode: Hide literal and class nodes; show rdf:type and datatype properties in enhanced tooltips instead
  • 🔍 Navigation: Mouse wheel zoom, drag to pan, "Zoom to Fit" button
  • ✋ Drag & Drop: Reorganize nodes by dragging them to new positions (nodes stay pinned after manual drag)
  • � Node Expansion: Double-click any URI node to fetch and merge related triples via DESCRIBE queries (see Expand Nodes with Double Click)
  • �💬 Rich Tooltips: Modern HTML tooltips with node type, value, namespace, and datatype information
  • 🌓 Theme Support: Automatic light/dark mode detection and dynamic color switching
  • ⚡ Performance: Handles up to 1,000 nodes with <2s render time
  • ♿ Accessible: WCAG AA color contrast, keyboard navigation support

📦 Installation

NPM

npm install @matdata/yasgui-graph-plugin
import Yasgui from '@matdata/yasgui';
import GraphPlugin from '@matdata/yasgui-graph-plugin';

Yasgui.Yasr.registerPlugin('Graph', GraphPlugin);

const yasgui = new Yasgui(document.getElementById('yasgui'));

CDN (UMD)

<!-- YASGUI -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@matdata/yasgui/build/yasgui.min.css">
<script src="https://cdn.jsdelivr.net/npm/@matdata/yasgui/build/yasgui.min.js"></script>

<!-- Graph Plugin -->
<script src="https://cdn.jsdelivr.net/npm/@matdata/yasgui-graph-plugin/dist/yasgui-graph-plugin.min.js"></script>

<script>
  // Plugin auto-registers as 'graph'
  const yasgui = new Yasgui(document.getElementById('yasgui'));
</script>

🚀 Quick Start

See the complete working example in demo/index.html.

Basic Usage

const yasgui = new Yasgui(document.getElementById('yasgui'), {
  requestConfig: { 
    endpoint: 'https://dbpedia.org/sparql' 
  }
});

Sample Queries

CONSTRUCT Query:

PREFIX ex: <http://example.org/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>

CONSTRUCT {
  ex:Alice rdf:type ex:Person .
  ex:Alice ex:knows ex:Bob .
  ex:Alice ex:name "Alice" .
  ex:Bob rdf:type ex:Person .
  ex:Bob ex:name "Bob" .
}
WHERE {}

DESCRIBE Query:

PREFIX ex: <http://example.org/>

# Returns all triples about the specified resources
DESCRIBE ex:Alice ex:Bob

After running the query, click the "Graph" tab to see the visualization.

🎮 User Guide

Navigation

  • Zoom: Mouse wheel (scroll up = zoom in, scroll down = zoom out)
  • Pan: Click and drag the background
  • Fit to View: Click the "Zoom to Fit" button to center the entire graph

Interaction

  • Drag Nodes: Click and drag any node to reposition it (nodes are automatically pinned in place after dragging)
  • Expand Nodes: 🆕 Double-click any blue URI node to fetch and merge additional RDF triples for that resource (see Node Expansion below)
  • Tooltips: Hover over nodes/edges to see rich HTML tooltips with type, value, namespace, and datatype information

Understanding Colors

| Color | Meaning | Example | |-------|---------|---------|| | 🔵 Light Blue (#97C2FC) | URI nodes | ex:Person, ex:Alice | | 🟢 Light Green (#a6c8a6ff) | Literal values | "Alice", "30"^^xsd:integer | | ⚪ Light Grey (#c5c5c5ff) | Blank nodes | _:b1, _:addr1 | | 🟠 Orange (#e15b13ff) | rdf:type objects (classes) | ex:Person in ex:Alice rdf:type ex:Person |

⚙️ Configuration

The plugin ships with sensible defaults and stores every change in localStorage so settings survive page reloads.

Settings panel

Click the ⚙ Settings button (top-right of the graph) to open the settings panel.

Setting Values Default Description
Compact mode on / off off Hide literal and class nodes; show rdf:type and datatype properties in tooltips instead
Arrow style Curved / Straight Curved Toggle between smooth curved edges and straight lines between nodes
Predicate display Label / Icon / Hidden Icon Show the full prefixed URI on edges, a compact symbol/icon, or nothing
Show literals on / off on Include or exclude literal value nodes (strings, numbers, dates, …)
Show classes on / off on Include or exclude nodes that are objects of rdf:type triples (class nodes)
Show blank nodes on / off on Include or exclude blank nodes (_:b0, _:b1, …)
Show node labels on / off on Render the prefixed URI / literal text inside each node
Enable physics on / off on Keep the force-directed layout simulation running so nodes keep adjusting
Node size Small / Medium / Large Medium Set the radius of all nodes

Predicate icons

When Predicate display is set to Icon, each edge displays a compact symbol instead of the full label. Symbols are defined for the 20+ most common predicates:

Predicate Symbol
rdf:type a
rdfs:label lbl
rdfs:comment cmt
rdfs:subClassOf
rdfs:subPropertyOf
rdfs:domain dom
rdfs:range rng
rdfs:seeAlso see
rdfs:isDefinedBy idb
owl:sameAs
owl:equivalentClass
owl:inverseOf
owl:disjointWith
skos:prefLabel
skos:altLabel
skos:definition def
skos:broader
skos:narrower
skos:related
skos:note note
skos:exactMatch
skos:closeMatch
dcterms:title ttl
dcterms:description dsc
dcterms:created crt
dcterms:modified mod
dcterms:creator by
dcterms:subject sbj
foaf:name nm
foaf:knows
foaf:member mbr
schema:name nm
schema:description dsc

For predicates not in the table the full prefixed label is used as a fallback.

🖼️ Node icons and images

Any URI node can display an image or an icon instead of (or in addition to) the default coloured dot by attaching schema:image or schema:icon as a property directly in the SPARQL result.

Property Object Effect
schema:image (https://schema.org/image) URL literal or URI Node is rendered as a circular image
schema:icon (https://schema.org/icon) emoji / short string The string is used as the node's label

schema:icon takes priority over schema:image. The corresponding schema:icon/schema:image triples are not rendered as separate nodes or edges, but their values are shown in the node tooltip. Similarly, any rdfs:label triple is consumed to determine the node's displayed label and is never drawn as an edge, even when predicate display is enabled.

Example – inline image on a resource

CONSTRUCT {
  ex:alice schema:image <https://example.com/alice.png> .
  ex:alice ex:knows ex:bob .
}
WHERE {}

ex:alice will be drawn as a circular photograph.

Example – icon/emoji on a class

CONSTRUCT {
  ex:alice  rdf:type    ex:Person .
  ex:Person schema:icon "👤" .
}
WHERE {}

ex:alice remains a normal dot node in regular mode. In compact mode the class node (ex:Person) is hidden and Alice's node inherits the 👤 emoji as its label.

Compact mode visual inheritance

When compact mode is enabled, class nodes are hidden and the plugin resolves the image/icon to show on the resource node using the following priority:

  1. schema:image / schema:icon directly on the resource (highest priority)
  2. schema:image / schema:icon on the rdf:type class
  3. schema:image / schema:icon on a rdfs:subClassOf superclass (one hop)

Programmatic configuration

You can also pass initial settings when extending the class:

class CustomGraphPlugin extends GraphPlugin {
  constructor(yasr) {
    super(yasr);
    // Override defaults
    this.settings.edgeStyle = 'straight';
    this.settings.predicateDisplay = 'label';
    this.settings.nodeSize = 'large';
  }
}

Yasgui.Yasr.registerPlugin('customGraph', CustomGraphPlugin);

� Expand Nodes with Double Click

The graph plugin supports interactive node expansion via double-clicking. This allows you to progressively explore RDF graphs by fetching additional triples for any URI node without redrawing the entire graph.

How It Works

  1. Double-click a blue URI node in the graph
  2. The node's border turns orange and thickens (loading state)
  3. A DESCRIBE <uri> query is sent to the SPARQL endpoint
  4. New triples are merged into the existing graph
  5. Node's border returns to normal width with thicker border (3px) to indicate expansion
  6. Graph layout and zoom level are preserved

Visual Feedback

State Border Meaning
Default 2px Node has not been expanded
Loading 4px, orange DESCRIBE query in progress
Expanded 3px, normal color Successfully expanded

Supported Node Types

Node Type Can Expand? Reason
🔵 URI nodes ✅ Yes DESCRIBE works on URIs
🟢 Literals ❌ No Cannot run DESCRIBE on literal values
Blank nodes ❌ No Blank nodes have no resolvable identity

Example: Exploring a Knowledge Graph

Initial Query:

PREFIX ex: <http://example.org/>
PREFIX foaf: <http://xmlns.com/foaf/0.1/>

CONSTRUCT {
  ex:alice foaf:knows ex:bob .
  ex:alice foaf:name "Alice" .
  ex:bob foaf:name "Bob" .
}
WHERE {}

Initial Graph: 3 nodes (Alice, "Alice", Bob, "Bob"), 2 edges

User Action: Double-click the ex:bob node

What Happens:

  • System executes: DESCRIBE <http://example.org/bob>
  • Endpoint returns all triples about Bob (from your SPARQL endpoint)
  • New nodes and edges appear in the graph
  • Graph layout shifts smoothly to accommodate new nodes
  • ex:bob node gets a thicker border

Result: You can now see Bob's relationships, properties, and connections without losing your current view

Requirements

The node expansion feature requires:

  1. SPARQL 1.1 DESCRIBE support: Your endpoint must support DESCRIBE queries
  2. Query execution callback: YASR must provide yasr.executeQuery() for background queries
  3. RDF response format: Endpoint must return results in RDF (JSON-LD, Turtle, N-Triples, etc.)

Limitations & Behavior

  • Only new triples are added (existing triples are skipped if already in graph)
  • Expansion is one-level deep - only triples directly about the URI are added
  • For very large result sets (1000+ triples from DESCRIBE), performance may be affected
  • Blank nodes returned by DESCRIBE may not connect properly if disconnected from existing nodes

Troubleshooting Expansion

"Nothing happens when I double-click"

  • Ensure the node is blue (URI node, not literal or blank node)
  • Check browser console for warnings about yasr.executeQuery
  • Verify your SPARQL endpoint supports DESCRIBE queries

"Graph becomes slow after many expansions"

  • Disable physics simulation in Settings panel for faster UI response
  • Consider limiting query results with WHERE clause constraints
  • Each expansion adds more triples to the visualization

"New nodes don't appear where I expect"

  • The force-directed layout will position new nodes to minimize overlaps
  • Disable Physics in Settings to lock positions if desired
  • Manually drag new nodes to preferred positions

Demo

See demo/expand.html for a working example with mock DESCRIBE responses and detailed logging.

�🔧 Development

Build

npm install
npm run build

Output:

  • dist/yasgui-graph-plugin.esm.js (ES Module for bundlers)
  • dist/yasgui-graph-plugin.cjs.js (CommonJS for Node.js)
  • dist/yasgui-graph-plugin.min.js (IIFE for browsers/unpkg)
  • dist/index.d.ts (TypeScript declarations)

Local Testing

  1. Build the plugin: npm run build
  2. Open demo/index.html in a browser (or run npm run dev)
  3. Try the sample queries in different tabs

Code Quality

npm test        # Run Jest unit tests
npm run lint    # ESLint check
npm run format  # Prettier format

📚 Documentation

  • Quickstart Guide - Installation, usage, troubleshooting
  • Node Expansion Feature - Complete guide to double-click expansion (FR-001 through FR-009)
  • Data Model - Entity definitions and relationships
  • Contracts - API specifications for YASR plugin and vis-network integration
  • Specification - Complete feature specification
  • [Constitution](./. specify/memory/constitution.md) - Project governance and principles

🧪 Browser Compatibility

Tested on latest 2 versions of:

  • ✅ Chrome
  • ✅ Firefox
  • ✅ Safari
  • ✅ Edge

Requires ES2018+ support and Canvas API.

🤝 Contributing

Contributions welcome! Please follow the project constitution (.specify/memory/constitution.md) for governance principles:

  1. Plugin-First Architecture - No YASGUI core modifications
  2. Visualization Quality - Performance (<2s for 1k nodes), accessibility (WCAG AA)
  3. Configuration Flexibility - Sensible defaults, but customizable
  4. Browser Compatibility - ES2018+, latest 2 browser versions
  5. Documentation - Keep docs updated with changes

📄 License

Apache 2.0

🙏 Acknowledgments

📊 Project Status

Current Version: 0.1.0 (MVP)

Implemented Features (v0.1.0):

  • Basic graph visualization (US1) - CONSTRUCT/DESCRIBE results as interactive graphs
  • Navigation controls (US2) - Zoom, pan, "Fit to View" button
  • Color-coded nodes - URIs, literals, blank nodes, rdf:type objects
  • Prefix abbreviation - Display prefixed URIs instead of full URLs
  • Blank node support - Handle anonymous RDF nodes
  • Drag & repositioning - Manually adjust node positions
  • Rich tooltips - Hover for detailed node/edge information
  • Theme support - Light/dark mode detection and switching
  • Settings panel - Configurable display options with localStorage persistence
  • Node icons & images - Display images via schema:image property
  • Compact mode - Hide literals and classes for cleaner visualization
  • Double-click expansion (US5) - Fetch and merge related triples via DESCRIBE queries (see Expand Nodes with Double Click)

🐛 Troubleshooting

Plugin tab not showing

  • Verify plugin is registered correctly
  • Check browser console for errors
  • Ensure you're running a CONSTRUCT or DESCRIBE query

Empty visualization

  • Ensure query type is CONSTRUCT or DESCRIBE
  • Confirm query returns triples (check "Table" or "Response" tab)
  • Verify results have RDF structure

Performance issues

  • Limit results to <1000 nodes for best performance
  • Disable physics after initial layout
  • Consider using LIMIT clause in SPARQL query

For more help, see Quickstart Guide - Troubleshooting.

🛠️ Development

Setup

git clone https://github.com/yourusername/yasgui-graph-plugin.git
cd yasgui-graph-plugin
npm install

Dev Workflow (Live Reload)

The project supports live development - edit source files and see changes immediately without rebuilding:

  1. Start a local dev server (any HTTP server will work):

    # Using Python
    python -m http.server 8000
    
    # Using Node.js (http-server)
    npx http-server -p 8000
    
    # Using VS Code Live Server extension
    # Right-click demo/index.html → "Open with Live Server"
  2. Open demo in browser:

    http://localhost:8000/demo/index.html
    
  3. Edit source files (e.g., src/colorUtils.js):

    export function getNodeColor(node) {
      // Change colors here
      if (node.isBlankNode) return '#FF00FF'; // Magenta
      // ...
    }
  4. Refresh browser - changes appear immediately! ⚡

The demo automatically loads ES modules directly from src/ in development mode, so no rebuild is needed.

Production Build

Build all distribution formats:

npm run build

Outputs:

  • dist/yasgui-graph-plugin.esm.js - ES Module format (bundled with vis-network)
  • dist/yasgui-graph-plugin.cjs.js - CommonJS format (bundled with vis-network)
  • dist/yasgui-graph-plugin.min.js - IIFE browser bundle (bundled with vis-network)
  • dist/index.d.ts - TypeScript type declarations

Testing

npm test          # Run all tests
npm run lint      # Check code style
npm run format    # Auto-fix formatting