Smart Canvas Getting Started Guide
Step-by-step guide to implementing Smart Canvas in your Angular applications
Smart Canvas Getting Started Guide
๐ฏ Quick Implementation
Step 1: Import the Component
import { SmartCanvasComponent } from '@smart-canvas';
@Component({
standalone: true,
imports: [SmartCanvasComponent],
template: `
<lib-smart-canvas
[nodes]="nodes"
[connections]="connections"
[config]="canvasConfig"
(nodeUpdate)="onNodeUpdate($event)"
(connectionCreate)="onConnectionCreate($event)">
</lib-smart-canvas>
`
})
export class MyCanvasComponent {
// Implementation here
}
Step 2: Define Your Data
import { CanvasNode, CanvasConnection, SmartCanvasConfig } from '@smart-canvas';
export class MyCanvasComponent {
// Define nodes with ports for connections
nodes: CanvasNode[] = [
{
id: 'start',
type: 'process',
position: { x: 100, y: 100, z: 1 },
size: { width: 120, height: 80 },
data: {
title: 'Start Process',
description: 'Beginning of workflow'
},
appearance: {
backgroundColor: '#e3f2fd',
border: { width: 2, style: 'solid', color: '#2196f3' },
borderRadius: 8
},
ports: [
{ id: 'output', type: 'output', position: { x: 1, y: 0.5 } }
]
},
{
id: 'process',
type: 'action',
position: { x: 300, y: 100, z: 1 },
size: { width: 120, height: 80 },
data: {
title: 'Process Data',
description: 'Main processing step'
},
appearance: {
backgroundColor: '#e8f5e8',
border: { width: 2, style: 'solid', color: '#4caf50' },
borderRadius: 8
},
ports: [
{ id: 'input', type: 'input', position: { x: 0, y: 0.5 } },
{ id: 'output', type: 'output', position: { x: 1, y: 0.5 } }
]
}
];
// Define connections between nodes
connections: CanvasConnection[] = [
{
id: 'conn-1',
type: 'flow',
source: { nodeId: 'start', portId: 'output' },
target: { nodeId: 'process', portId: 'input' },
appearance: {
color: '#666',
width: 2,
curve: { type: 'bezier', tension: 0.4 },
markers: { end: { type: 'arrow', size: 8 } }
}
}
];
// Configure canvas behavior
canvasConfig: Partial<SmartCanvasConfig> = {
features: {
enablePanning: true,
enableZooming: true,
enableSelection: true,
enableMultiSelection: true,
enableConnectionCreation: true,
showGrid: true,
showToolbar: true
},
appearance: {
theme: 'modern',
grid: {
enabled: true,
type: 'dots',
size: 40,
color: '#e5e5e5',
opacity: 0.4
}
},
interactions: {
panSensitivity: 1,
zoomSensitivity: 0.8,
selectionRectangle: true
}
};
}
Step 3: Handle Events
export class MyCanvasComponent {
// Handle node updates (position, size, data changes)
onNodeUpdate(event: { nodeId: string; updates: Partial<CanvasNode> }) {
console.log('Node updated:', event);
// Update your data model
const nodeIndex = this.nodes.findIndex(n => n.id === event.nodeId);
if (nodeIndex >= 0) {
this.nodes[nodeIndex] = { ...this.nodes[nodeIndex], ...event.updates };
}
}
// Handle new connections created by user
onConnectionCreate(event: { connection: CanvasConnection }) {
console.log('Connection created:', event);
// Add to your connections array
this.connections = [...this.connections, event.connection];
}
// Handle context menu events
onContextMenu(event: CanvasContextMenuEvent) {
console.log('Context menu:', event);
// Show your context menu
}
// Handle selection changes
onSelectionChange(event: { nodeIds: string[]; connectionIds: string[] }) {
console.log('Selection changed:', event);
// Update UI based on selection
}
}
๐จ Styling and Themes
Using Built-in Themes
// Modern theme (default)
canvasConfig.appearance.theme = 'modern';
// Space theme (dark with cosmic colors)
canvasConfig.appearance.theme = 'space';
// Professional theme (business-friendly)
canvasConfig.appearance.theme = 'professional';
// Editor theme (code editor inspired)
canvasConfig.appearance.theme = 'editor';
Custom Styling
// Custom node appearance
const customNode: CanvasNode = {
id: 'custom',
type: 'custom',
position: { x: 0, y: 0, z: 1 },
size: { width: 150, height: 100 },
appearance: {
backgroundColor: '#ff6b6b',
border: { width: 3, style: 'dashed', color: '#ee5a52' },
borderRadius: 15,
boxShadow: '0 4px 12px rgba(255, 107, 107, 0.3)'
},
data: { title: 'Custom Node' }
};
// Custom connection styling
const customConnection: CanvasConnection = {
id: 'custom-conn',
type: 'custom',
source: { nodeId: 'node1', portId: 'out' },
target: { nodeId: 'node2', portId: 'in' },
appearance: {
color: '#ff6b6b',
width: 4,
curve: { type: 'bezier', tension: 0.6 },
markers: {
end: { type: 'arrow', size: 12, color: '#ee5a52' },
start: { type: 'circle', size: 6, color: '#ff6b6b' }
},
strokeDasharray: '5,5' // Dashed line
}
};
Grid Customization
canvasConfig.appearance.grid = {
enabled: true,
type: 'lines', // 'dots', 'lines', 'squares'
size: 50, // Grid spacing
color: '#e0e0e0', // Grid color
opacity: 0.5, // Grid opacity
strokeWidth: 1, // Line thickness (for lines/squares)
snapToGrid: true, // Enable node snapping
snapThreshold: 10 // Snap distance
};
๐ฑ๏ธ User Interactions
Selection Modes
// Single selection only
canvasConfig.features.enableMultiSelection = false;
// Multi-selection with Ctrl/Cmd+Click
canvasConfig.features.enableMultiSelection = true;
// Selection rectangle (drag empty space)
canvasConfig.interactions.selectionRectangle = true;
Pan and Zoom Configuration
canvasConfig.interactions = {
// Pan settings
panSensitivity: 1.0, // Pan speed multiplier
panButton: 'left', // 'left', 'middle', 'right'
panWithSpace: false, // Require space key for panning
// Zoom settings
minZoom: 0.1, // Minimum zoom level
maxZoom: 5.0, // Maximum zoom level
zoomStep: 0.15, // Zoom increment
zoomSensitivity: 0.8, // Mouse wheel sensitivity
zoomToPoint: true, // Zoom to mouse position
// Touch gestures
touchGestures: {
enabled: true,
pinch: { enabled: true, minScale: 0.1, maxScale: 5 },
pan: { enabled: true, minDistance: 10 }
}
};
Connection Creation
// Enable connection creation
canvasConfig.features.enableConnectionCreation = true;
// Handle connection attempts
onConnectionAttempt(event: ConnectionAttemptEvent) {
// Validate connection rules
if (this.canConnect(event.source, event.target)) {
return true; // Allow connection
}
return false; // Reject connection
}
// Custom connection validation
canConnect(source: PortInfo, target: PortInfo): boolean {
// Example: Only allow output -> input connections
return source.type === 'output' && target.type === 'input';
}
๐ฑ Mobile Optimization
Touch-Friendly Configuration
canvasConfig.features.enableMobileOptimization = true;
canvasConfig.interactions.touchGestures = {
enabled: true,
// Tap gestures
tap: {
enabled: true,
maxDistance: 15, // Larger touch target
maxDuration: 300
},
// Long press for context menu
longPress: {
enabled: true,
duration: 500,
hapticFeedback: true
},
// Pinch to zoom
pinch: {
enabled: true,
minScale: 0.1,
maxScale: 5,
momentum: true
},
// Two-finger pan
pan: {
enabled: true,
multiFingerEnabled: true,
maxFingers: 2
}
};
Responsive Node Sizing
// Responsive node sizes based on screen size
const getResponsiveNodeSize = (baseWidth: number, baseHeight: number) => {
const isMobile = window.innerWidth < 768;
const scale = isMobile ? 1.2 : 1.0; // 20% larger on mobile
return {
width: baseWidth * scale,
height: baseHeight * scale
};
};
// Apply to nodes
nodes.forEach(node => {
node.size = getResponsiveNodeSize(node.size.width, node.size.height);
});
๐ง Advanced Features
Performance Optimization
canvasConfig.performance = {
// Virtual scrolling for large datasets
enableVirtualScrolling: true,
maxVisibleNodes: 1000,
// Rendering optimization
renderBounds: true, // Only render visible elements
debounceMs: 16, // Debounce updates (60fps)
// Connection optimization
enableConnectionPooling: true,
maxConnectionPoolSize: 500,
// Update strategy
updateStrategy: 'frame-aligned', // Align with requestAnimationFrame
batchSize: 50 // Batch operations
};
Keyboard Shortcuts
canvasConfig.features.enableKeyboardShortcuts = true;
// Handle custom keyboard shortcuts
onKeyboardShortcut(event: KeyboardEvent) {
switch (event.key) {
case 'Delete':
this.deleteSelectedNodes();
break;
case 'd':
if (event.ctrlKey) {
this.duplicateSelectedNodes();
}
break;
case 'a':
if (event.ctrlKey) {
this.selectAllNodes();
}
break;
}
}
Undo/Redo System
// Enable undo/redo
canvasConfig.features.enableUndo = true;
// Configure history
canvasConfig.history = {
maxOperations: 50, // Maximum undo steps
autoSave: true, // Auto-save operations
debounceMs: 1000 // Group rapid changes
};
// Manual undo/redo
onUndo() {
this.canvasService.undo();
}
onRedo() {
this.canvasService.redo();
}
๐๏ธ Configuration Panel
Enable Live Configuration
// Show configuration panel
canvasConfig.features.showConfigPanel = true;
// Handle configuration changes
onConfigChange(newConfig: Partial<SmartCanvasConfig>) {
this.canvasConfig = { ...this.canvasConfig, ...newConfig };
}
Custom Configuration Options
// Add custom configuration sections
const customConfigPanel = {
sections: [
{
title: 'Workflow Settings',
options: [
{
key: 'autoSave',
type: 'boolean',
label: 'Auto-save workflow',
value: true
},
{
key: 'validationMode',
type: 'select',
label: 'Validation mode',
options: ['strict', 'permissive', 'off'],
value: 'strict'
}
]
}
]
};
๐งช Testing Your Implementation
Unit Tests
describe('MyCanvasComponent', () => {
let component: MyCanvasComponent;
let fixture: ComponentFixture<MyCanvasComponent>;
beforeEach(() => {
TestBed.configureTestingModule({
imports: [SmartCanvasComponent, MyCanvasComponent]
});
fixture = TestBed.createComponent(MyCanvasComponent);
component = fixture.componentInstance;
});
it('should create nodes', () => {
expect(component.nodes.length).toBeGreaterThan(0);
});
it('should handle node selection', () => {
const nodeId = 'test-node';
component.onNodeSelect(nodeId);
expect(component.selectedNodes).toContain(nodeId);
});
});
Integration Tests
describe('Canvas Interactions', () => {
it('should create connections between nodes', async () => {
const canvas = await screen.findByRole('application');
const sourcePort = await screen.findByTestId('node-1-output');
const targetPort = await screen.findByTestId('node-2-input');
// Simulate port click to start connection
fireEvent.click(sourcePort);
fireEvent.click(targetPort);
// Verify connection was created
expect(component.connections).toHaveLength(1);
});
});
๐ Next Steps
- Explore Examples: Check out the demo implementation
- Read API Docs: Detailed API reference
- Migration Guide: Migrate from existing canvas implementations
- Advanced Features: Learn about performance optimization
You're now ready to build powerful, interactive canvas applications with Smart Canvas! ๐