Explainer Canvas
Interactive knowledge visualization with nested hierarchies
Interactive Demo
Click any card to expand it and see detailed content. Click links to navigate between related cards. Cards with a grid icon have nested content - click "Explore nested content" to dive in. Use Ctrl+F to search. Pan and scroll to zoom.
Loading canvas...
Features
- Pan & Zoom: Navigate large canvases with mouse drag and scroll wheel
- Expand/Collapse Cards: Click cards to reveal detailed content with markdown support
- Nested Hierarchies: Dive into cards that contain sub-canvases for unlimited depth
- Connection Lines: Visual links between related cards with hover highlights
- Fuzzy Search: Find cards by title, summary, or content across all levels
- Breadcrumb Navigation: Track your path and navigate back through nested levels
- Tooltips: Define terms that show explanations on hover
- Responsive: Simplified mobile view with accordion-style cards
- Accessible: Keyboard navigation, ARIA labels, screen reader support
Data Structure
The component accepts structured data defining the canvas and its cards:
const canvasData = {
id: 'my-canvas',
title: 'My Knowledge Base',
defaultCardId: 'intro', // Card to center on load
config: {
lineStyle: 'bezier', // 'straight' | 'bezier' | 'orthogonal'
background: { type: 'dots', color: '#00000010', gap: 24 },
enableSearch: true,
maxZoomOut: 0.1,
maxZoomIn: 2
},
cards: [
{
id: 'intro',
title: 'Introduction',
summary: 'Brief overview shown when collapsed',
position: { x: 0, y: 0 },
content: [
{ type: 'markdown', content: '## Hello World\n...' },
{ type: 'image', src: '/diagram.png', alt: 'Diagram' }
],
links: ['concept-a', 'concept-b'], // IDs of related cards
tooltips: [
{ term: 'example', definition: 'Shown on hover' }
],
children: [ // Nested sub-canvas
{
id: 'detail-1',
title: 'Detail 1',
summary: '...',
position: { x: 0, y: 0 },
content: [{ type: 'markdown', content: '...' }]
}
]
}
]
};Usage Examples
Direct Data
<script>
import ExplainerCanvas from '$lib/components/ExplainerCanvas/ExplainerCanvas.svelte';
import { myCanvasData } from './data';
</script>
<ExplainerCanvas data={myCanvasData} />Load from JSON
<ExplainerCanvas src="/data/canvas.json" />Custom Async Loader
<ExplainerCanvas
loader={async () => {
const res = await fetch('/api/canvas/123');
return res.json();
}}
/>With Event Handlers
<ExplainerCanvas
data={canvasData}
onNavigate={(cardId, path) => console.log('Navigated:', cardId)}
onExpand={(cardId) => trackAnalytics('card_expand', cardId)}
onSearch={(query, results) => console.log('Search:', query)}
/>Content Block Types
| Type | Properties | Description |
|---|---|---|
markdown | content: string | Markdown text with syntax highlighting for code |
image | src, alt?, caption? | Responsive image with optional caption |
embed | url, aspectRatio? | iframe embed (videos, etc.) |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
data | ExplainerCanvasData | β | Direct data object |
src | string | β | URL to JSON file |
loader | () => Promise | β | Custom async loader function |
initialCardId | string | β | Override defaultCardId from data |
lineStyle | 'straight' | 'bezier' | 'orthogonal' | 'bezier' | Style of connection lines |
class | string | β | Additional CSS classes |
onNavigate | (cardId, path) => void | β | Called when navigating to a card |
onExpand | (cardId) => void | β | Called when a card is expanded |
onCollapse | (cardId) => void | β | Called when a card is collapsed |
onSearch | (query, results) => void | β | Called when search is performed |
Keyboard Shortcuts
| Key | Action |
|---|---|
Ctrl/Cmd + F | Open search panel |
Escape | Close expanded card or search |
+ / - | Zoom in / out |
Tab | Navigate between cards |
Enter | Expand/collapse focused card |
CSS Custom Properties
Customise the canvas appearance using CSS variables:
/* In your parent CSS */
.my-canvas {
--ec-bg: #f9fafb;
--ec-bg-card: #ffffff;
--ec-border: #e0e0e0;
--ec-text: #1a1a1a;
--ec-text-muted: #666666;
--ec-primary: #3b82f6;
--ec-radius: 12px;
--ec-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
--ec-line-color: #999999;
--ec-line-opacity: 0.15;
--ec-line-opacity-active: 1;
}Dependencies
@panzoom/panzoom- Canvas pan and zoommarked- Markdown renderinghighlight.js- Code syntax highlightingfuse.js- Fuzzy search
Install with: bun add @panzoom/panzoom marked highlight.js fuse.js
Use Cases
- Technical Documentation: Component architecture, API explanations
- Business Process Mapping: Workflows, decision trees
- Educational Content: Tutorials, course materials
- Product Features: Feature explanations, onboarding flows
- Knowledge Bases: Interconnected concepts, wikis