@a-it/scheme-designer
v1.0.0
Published
Canvas scheme designer, scheme constructor on javascript (typescript)
Readme
Scheme Designer
A powerful Vue.js-based canvas library for creating interactive diagrams, layouts, and scheme visualizations with support for layers, zooming, panning, and object manipulation.
Features
- Interactive Canvas: Smooth panning, zooming, and object manipulation
- Layer Management: Organize objects across multiple layers with visibility control
- Spatial Partitioning: Efficient quad-tree implementation for handling large numbers of objects
- Event System: Rich event handling for mouse interactions (click, hover, drag)
- Custom Objects: Create custom objects with your own rendering and interaction logic
- Rotation Support: Handle rotated objects with proper hit detection
- Vue 3 Integration: Reactive state management with Vue 3 composition API
Installation
npm install scheme-designerBasic Usage
<template>
<div>
<canvas ref="canvas" width="800" height="600"></canvas>
<div class="controls">
<button @click="zoomIn">Zoom In</button>
<button @click="zoomOut">Zoom Out</button>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import { useScheme, useLayer, useSchemeObject } from 'scheme-designer';
const canvas = ref(null);
let schemeDesigner = null;
onMounted(() => {
// Initialize the scheme designer
schemeDesigner = useScheme(canvas.value, {
options: {
background: '#F7F7F7',
cacheSchemeRatio: 2
},
zoom: {
maxScale: 4,
minScale: 0.5
}
});
// Create a layer
const defaultLayer = useLayer('default', {
zIndex: 1,
visible: true,
active: true
});
// Add the layer to the scheme
schemeDesigner.addLayer(defaultLayer);
// Create a rectangle object
const rectangleObject = useSchemeObject({
x: 100,
y: 100,
width: 80,
height: 50,
renderFunction: (obj, scheme, view) => {
const ctx = view.getContext();
ctx.save();
// Change appearance on hover
if (obj.state.isHovered) {
ctx.fillStyle = '#FF6B6B';
ctx.strokeStyle = '#C44D4D';
} else {
ctx.fillStyle = '#4ECDC4';
ctx.strokeStyle = '#1A535C';
}
ctx.lineWidth = 2;
ctx.beginPath();
ctx.rect(obj.getX(), obj.getY(), obj.getWidth(), obj.getHeight());
ctx.fill();
ctx.stroke();
ctx.restore();
},
mouseOverFunction: () => true, // Return true to trigger a re-render
mouseLeaveFunction: () => true // Return true to trigger a re-render
});
// Add the object to the layer
defaultLayer.addObject(rectangleObject);
// Register event listeners
canvas.value.addEventListener('schemeDesigner.clickOnObject', (e) => {
console.log('Object clicked:', e.detail);
});
// Render the scheme
schemeDesigner.render();
});
// Control functions
function zoomIn() {
schemeDesigner?.getZoomManager().zoomToCenter(10);
}
function zoomOut() {
schemeDesigner?.getZoomManager().zoomToCenter(-10);
}
</script>Core Components
Scheme
The main controller that coordinates all the managers and handles the rendering pipeline.
const scheme = useScheme(canvasElement, options);Layer
Manages a collection of objects with the same visibility and z-index.
const layer = useLayer('layerId', {
zIndex: 2,
visible: true,
active: true
});SchemeObject
Represents a visual element in the scheme.
const object = useSchemeObject({
x: 100,
y: 100,
width: 80,
height: 50,
// Custom render function
renderFunction: (obj, scheme, view) => {
// Your drawing logic here
}
});Managers
- StorageManager: Manages layers and objects with spatial partitioning
- EventManager: Handles user interactions and event dispatching
- ZoomManager: Controls zooming functionality
- ScrollManager: Manages panning and scrolling
- MapManager: Provides a navigation overview (optional)
Advanced Examples
Creating a Connection Between Objects
// Create a connection line between two objects
const connectionObject = useSchemeObject({
renderFunction: (obj, scheme, view) => {
const sourceObj = obj.getParams().source;
const targetObj = obj.getParams().target;
const ctx = view.getContext();
ctx.save();
ctx.strokeStyle = obj.state.isHovered ? '#FF6B6B' : '#1A535C';
ctx.lineWidth = 2;
// Draw a line from source to target
ctx.beginPath();
ctx.moveTo(sourceObj.getX() + sourceObj.getWidth()/2,
sourceObj.getY() + sourceObj.getHeight()/2);
ctx.lineTo(targetObj.getX() + targetObj.getWidth()/2,
targetObj.getY() + targetObj.getHeight()/2);
ctx.stroke();
ctx.restore();
},
params: {
source: object1,
target: object2
}
});
// Add connection to the layer
defaultLayer.addObject(connectionObject);Implementing Draggable Objects
// Event handlers in your scheme setup
canvas.addEventListener('schemeDesigner.mouseDown', function(e) {
const obj = e.detail;
if (obj) {
obj.getParams().isDragging = true;
obj.getParams().lastX = e.detail.originalEvent.clientX;
obj.getParams().lastY = e.detail.originalEvent.clientY;
}
});
canvas.addEventListener('schemeDesigner.mouseMove', function(e) {
const objects = schemeDesigner.getStorageManager().getVisibleObjects();
for (const obj of objects) {
if (obj.getParams().isDragging) {
const dx = e.detail.clientX - obj.getParams().lastX;
const dy = e.detail.clientY - obj.getParams().lastY;
obj.setX(obj.getX() + dx / schemeDesigner.getZoomManager().getScale());
obj.setY(obj.getY() + dy / schemeDesigner.getZoomManager().getScale());
obj.getParams().lastX = e.detail.clientX;
obj.getParams().lastY = e.detail.clientY;
schemeDesigner.requestRenderAll();
}
}
});
canvas.addEventListener('schemeDesigner.mouseUp', function() {
const objects = schemeDesigner.getStorageManager().getVisibleObjects();
for (const obj of objects) {
if (obj.getParams().isDragging) {
obj.getParams().isDragging = false;
}
}
});License
MIT
