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

@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-designer

Basic 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