npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

edgecraft

v1.0.0

Published

Advanced graph visualization library for RDF and LPG with sophisticated rendering capabilities

Downloads

106

Readme

EdgeCraft 🎨

Advanced Graph Visualization Library for RDF and LPG

EdgeCraft is a powerful, modern graph visualization library designed for building sophisticated network diagrams with support for both Resource Description Framework (RDF) and Labeled Property Graph (LPG) models. It combines the simplicity of Cytoscape with the power of D3, offering advanced features like association classes, multiple layout algorithms, and a clean, intuitive API.

✨ Features

  • Dual Graph Model Support: Native support for both RDF triples and LPG structures
  • Advanced Patterns: Association classes for n-ary relationships
  • Multiple Layout Algorithms: Force-directed, hierarchical, circular, and grid layouts
  • Rich Interactions: Drag, zoom, pan, select with customizable behaviors
  • Flexible Styling: Function-based styling for dynamic visual properties
  • TypeScript First: Fully typed API with excellent IDE support
  • Performance Optimized: Efficient rendering for large graphs
  • Extensible Architecture: Easy to extend with custom layouts and renderers

📦 Installation

npm install edgecraft

Or with yarn:

yarn add edgecraft

🚀 Quick Start

import { EdgeCraft } from 'edgecraft';

// Create a simple graph
const graph = new EdgeCraft({
  container: '#graph-container',
  data: {
    nodes: [
      { id: 1, labels: ['Person'], properties: { name: 'Alice' } },
      { id: 2, labels: ['Person'], properties: { name: 'Bob' } },
      { id: 3, labels: ['Company'], properties: { name: 'Tech Corp' } }
    ],
    edges: [
      { id: 'e1', source: 1, target: 2, label: 'KNOWS', properties: { since: 2020 } },
      { id: 'e2', source: 1, target: 3, label: 'WORKS_AT', properties: { role: 'Engineer' } }
    ]
  },
  layout: { type: 'force' }
});

📚 Examples

LPG (Labeled Property Graph)

import { EdgeCraft, LPGNode, LPGEdge } from 'edgecraft';

const nodes: LPGNode[] = [
  { id: 'alice', labels: ['Person'], properties: { name: 'Alice', age: 30 } },
  { id: 'bob', labels: ['Person'], properties: { name: 'Bob', age: 35 } },
  { id: 'techcorp', labels: ['Company'], properties: { name: 'Tech Corp' } }
];

const edges: LPGEdge[] = [
  { 
    id: 'e1', 
    source: 'alice', 
    target: 'bob', 
    label: 'KNOWS',
    properties: { since: 2015 },
    directed: true
  },
  { 
    id: 'e2', 
    source: 'alice', 
    target: 'techcorp', 
    label: 'WORKS_AT',
    properties: { position: 'Senior Engineer', since: 2020 }
  }
];

const graph = new EdgeCraft({
  container: '#graph',
  data: { nodes, edges },
  layout: { type: 'force', iterations: 500 },
  nodeStyle: (node) => ({
    fill: node.labels.includes('Person') ? '#4a90e2' : '#e74c3c',
    radius: 25,
    label: {
      text: node.properties.name,
      fontSize: 14,
      position: 'bottom'
    }
  }),
  edgeStyle: {
    stroke: '#95a5a6',
    strokeWidth: 2,
    arrow: 'forward'
  }
});

RDF (Resource Description Framework)

import { EdgeCraft, RDFNode, RDFTriple } from 'edgecraft';

const nodes: RDFNode[] = [
  { id: 'alice', type: 'uri', value: 'http://example.org/alice' },
  { id: 'bob', type: 'uri', value: 'http://example.org/bob' },
  { id: 'name1', type: 'literal', value: 'Alice', datatype: 'xsd:string' },
  { id: 'name2', type: 'literal', value: 'Bob', datatype: 'xsd:string' }
];

const triples: RDFTriple[] = [
  { id: 't1', subject: 'alice', predicate: 'foaf:knows', object: 'bob' },
  { id: 't2', subject: 'alice', predicate: 'foaf:name', object: 'name1' },
  { id: 't3', subject: 'bob', predicate: 'foaf:name', object: 'name2' }
];

const graph = new EdgeCraft({
  container: '#rdf-graph',
  data: { nodes, edges: triples },
  layout: { type: 'hierarchical' },
  nodeStyle: (node) => ({
    fill: node.type === 'uri' ? '#3498db' : '#f39c12',
    shape: node.type === 'uri' ? 'circle' : 'rectangle',
    radius: node.type === 'uri' ? 20 : 15
  })
});

Custom Styling

const graph = new EdgeCraft({
  container: '#graph',
  data: myData,
  nodeStyle: (node) => {
    // Dynamic styling based on node properties
    const degree = graph.getConnectedEdges(node.id).length;
    return {
      fill: degree > 5 ? '#e74c3c' : '#3498db',
      radius: 10 + degree * 2,
      stroke: '#2c3e50',
      strokeWidth: 2,
      label: {
        text: node.properties?.name || node.id,
        fontSize: 12,
        color: '#fff'
      }
    };
  },
  edgeStyle: (edge) => ({
    stroke: edge.properties?.weight > 0.5 ? '#e74c3c' : '#95a5a6',
    strokeWidth: 1 + (edge.properties?.weight || 0) * 3,
    strokeDasharray: edge.properties?.type === 'temporary' ? '5,5' : undefined,
    arrow: 'forward',
    label: {
      text: edge.label,
      fontSize: 10,
      color: '#7f8c8d',
      backgroundColor: 'rgba(255,255,255,0.8)'
    }
  })
});

Event Handling

// Node click
graph.on('node-click', (event) => {
  console.log('Clicked node:', event.target);
  console.log('Node position:', event.position);
});

// Node hover
graph.on('node-mouseenter', (event) => {
  console.log('Hovering over:', event.target);
});

// Drag events
graph.on('node-dragstart', (event) => {
  console.log('Started dragging:', event.target);
});

graph.on('node-drag', (event) => {
  console.log('Dragging:', event.target, 'to', event.position);
});

graph.on('node-dragend', (event) => {
  console.log('Finished dragging:', event.target);
});

// Background click
graph.on('background-click', () => {
  graph.clearSelection();
});

Dynamic Updates

// Add nodes dynamically
graph.addNode({
  id: 'new-node',
  labels: ['Person'],
  properties: { name: 'Charlie' }
});

// Add edges
graph.addEdge({
  id: 'e-new',
  source: 'alice',
  target: 'new-node',
  label: 'KNOWS',
  properties: {}
});

// Remove elements
graph.removeNode('bob');
graph.removeEdge('e1');

// Update layout
graph.setLayout({ type: 'circular' });

// Query the graph
const neighbors = graph.getNeighbors('alice');
const allEdges = graph.getConnectedEdges('alice');

View Control

// Fit entire graph in view
graph.fitView();

// Center the graph
graph.centerView();

// Zoom controls
graph.zoomIn();
graph.zoomOut();
graph.resetZoom();

// Selection
graph.selectNode('alice');
const selected = graph.getSelectedNodes();
graph.clearSelection();

🎨 Layout Algorithms

Force-Directed Layout

Simulates physical forces between nodes for organic-looking graphs.

graph.setLayout({
  type: 'force',
  iterations: 300,
  nodeSpacing: 100
});

Hierarchical Layout

Arranges nodes in levels, ideal for trees and DAGs.

graph.setLayout({
  type: 'hierarchical',
  levelSpacing: 150,
  nodeSpacing: 100
});

Circular Layout

Places nodes in a circle, great for showing relationships.

graph.setLayout({
  type: 'circular'
});

Grid Layout

Arranges nodes in a regular grid pattern.

graph.setLayout({
  type: 'grid',
  nodeSpacing: 100
});

🔧 Configuration Options

interface EdgeCraftConfig {
  container: HTMLElement | string;        // Container element or selector
  data?: GraphData;                        // Initial graph data
  layout?: LayoutConfig;                   // Layout algorithm config
  interaction?: InteractionConfig;         // Interaction settings
  nodeStyle?: NodeStyle | StyleFunction;   // Node visual styling
  edgeStyle?: EdgeStyle | StyleFunction;   // Edge visual styling
  renderer?: RendererConfig;               // Renderer configuration (see below)
  width?: number;                          // Canvas width
  height?: number;                         // Canvas height
  backgroundColor?: string;                // Background color
  minZoom?: number;                        // Minimum zoom level
  maxZoom?: number;                        // Maximum zoom level
}

Renderer Configuration

EdgeCraft uses a WebGL-first approach (like Keylines) for optimal performance:

// Default behavior: WebGL with Canvas fallback
const graph = new EdgeCraft({
  container: '#graph',
  data: myData
  // Automatically uses WebGL if supported, falls back to Canvas
});

// Explicit WebGL (with Canvas fallback if not supported)
const graph = new EdgeCraft({
  container: '#graph',
  data: myData,
  renderer: {
    type: 'webgl'  // Tries WebGL, auto-falls back to Canvas
  }
});

// Force Canvas renderer (useful for testing or specific requirements)
const graph = new EdgeCraft({
  container: '#graph',
  data: myData,
  renderer: {
    type: 'canvas',  // Explicitly use Canvas renderer
    enableCache: true,
    enableDirtyRegions: true  // Optimize Canvas performance
  }
});

// Renderer with additional options
const graph = new EdgeCraft({
  container: '#graph',
  data: myData,
  renderer: {
    type: 'auto',  // Default: WebGL-first with Canvas fallback
    pixelRatio: window.devicePixelRatio,  // For high-DPI displays
    enableCache: true,  // Cache rendered elements (Canvas only)
    enableDirtyRegions: true  // Only re-render changed areas (Canvas only)
  }
});

Renderer Types:

  • 'auto' (default): Tries WebGL first, falls back to Canvas if not supported
  • 'webgl': Explicitly requests WebGL (falls back to Canvas if not available)
  • 'canvas': Forces Canvas renderer (good for compatibility or debugging)

Why WebGL-first?

  • 🚀 GPU-accelerated rendering for better performance
  • 📊 Handles large graphs (10,000+ nodes) efficiently
  • ⚡ Smooth animations and interactions
  • 🔄 Automatic fallback ensures compatibility

📖 API Reference

Graph Management

  • setData(data: GraphData): void - Replace entire graph
  • getData(): GraphData - Get current graph data
  • addNode(node: GraphNode): void - Add a node
  • removeNode(nodeId): boolean - Remove a node
  • addEdge(edge: GraphEdge): void - Add an edge
  • removeEdge(edgeId): boolean - Remove an edge

Queries

  • getNode(nodeId): GraphNode | undefined - Get node by ID
  • getEdge(edgeId): GraphEdge | undefined - Get edge by ID
  • getAllNodes(): GraphNode[] - Get all nodes
  • getAllEdges(): GraphEdge[] - Get all edges
  • getNeighbors(nodeId): GraphNode[] - Get adjacent nodes
  • getConnectedEdges(nodeId): GraphEdge[] - Get connected edges
  • queryTriples(subject?, predicate?, object?): RDFTriple[] - RDF query

View Control

  • fitView(): void - Fit graph to view
  • centerView(): void - Center the graph
  • zoomIn(): void - Zoom in
  • zoomOut(): void - Zoom out
  • resetZoom(): void - Reset zoom to 100%

Events

  • on(eventType: string, callback): void - Register event listener
  • off(eventType: string, callback): void - Remove event listener

Selection

  • selectNode(nodeId): void - Select a node
  • clearSelection(): void - Clear selection
  • getSelectedNodes(): NodeId[] - Get selected nodes

Export

  • toJSON(): string - Export graph as JSON
  • fromJSON(json: string): void - Import graph from JSON
  • exportSVG(): string - Export as SVG string

🔍 RDF-Specific Features

EdgeCraft provides excellent support for semantic web applications:

// Query triples by pattern
const aliceTriples = graph.queryTriples('alice');
const nameTriples = graph.queryTriples(undefined, 'foaf:name');
const allKnows = graph.queryTriples(undefined, 'foaf:knows');

// Add triples programmatically
graph.addTriple('alice', 'foaf:knows', 'charlie');

// Work with different node types
const uriNodes = graph.getRDFNodes().filter(n => n.type === 'uri');
const literals = graph.getRDFNodes().filter(n => n.type === 'literal');

🏗️ Association Classes

Support for n-ary relationships:

const data = {
  nodes: [
    { id: 'alice', labels: ['Person'], properties: { name: 'Alice' } },
    { id: 'bob', labels: ['Person'], properties: { name: 'Bob' } },
    { id: 'project', labels: ['Project'], properties: { name: 'EdgeCraft' } }
  ],
  edges: [
    { id: 'e1', source: 'alice', target: 'membership1', label: 'HAS_ROLE', properties: {} },
    { id: 'e2', source: 'membership1', target: 'project', label: 'ON_PROJECT', properties: {} }
  ],
  associationClasses: [
    {
      id: 'membership1',
      name: 'ProjectMembership',
      sourceEdges: ['e1', 'e2'],
      properties: { role: 'Lead Developer', since: '2023' }
    }
  ]
};

🎯 Use Cases

  • Knowledge Graphs: Visualize semantic web data and ontologies
  • Social Networks: Display relationships between people and entities
  • Data Lineage: Track data flow and transformations
  • Dependency Graphs: Visualize software dependencies and relationships
  • Organization Charts: Display hierarchical structures
  • Mind Maps: Create and visualize concept relationships
  • Network Diagrams: Infrastructure and system architecture visualization

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

📄 License

MIT License - see LICENSE file for details

🔗 Links

🙏 Acknowledgments

EdgeCraft builds upon the excellent work of:

  • D3.js for force simulation and interactions
  • The graph visualization community

Made with ❤️ for the graph visualization community#� �E�d�g�e�C�r�a�f�t� � �