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

dytools-canvas-engine

v1.6.3

Published

A powerful, extensible HTML5 canvas-based engine for building interactive visual applications. Built with TypeScript, Canvas Engine provides a complete event-driven architecture with support for interactive objects, gestures, tools, and multi-mode interac

Readme

Canvas Engine

A powerful, extensible HTML5 canvas-based engine for building interactive visual applications. Built with TypeScript, Canvas Engine provides a complete event-driven architecture with support for interactive objects, gestures, tools, and multi-mode interactions.

Features

  • 🎯 Interactive Objects - Create zones with drag, resize, and selection capabilities
  • 🖱️ Rich Gesture Recognition - Built-in support for clicks, drags, and complex multi-touch gestures
  • 🔧 Extensible Tool System - Modular tools for selection, drawing, lasso selection, zooming, and more
  • 🎨 Flexible Rendering Pipeline - Customizable rendering with support for multiple render nodes
  • 📐 Viewport Management - Pan and zoom with configurable limits and controls
  • 🎭 Mode System - Switch between different interaction modes (select, draw, etc.)
  • 📡 Event-Driven Architecture - Clean separation between internal canvas events and external engine events
  • 🐛 Debug Support - Built-in debugging options for event logging
  • 🎪 Background Images - Support for custom background images with proper scaling

Installation

npm install dytools-canvas-engine

Quick Start

import { CanvasEngine, Zone } from 'dytools-canvas-engine';

// Create a canvas engine attached to a DOM element
const engine = new CanvasEngine('#app', {
    initialZoom: 1,
    initialPan: { x: 10, y: 10 },
    defaultMode: 'select'
});

// Add an interactive zone
const zone = new Zone(
    'zone-1',           // id
    100, 100,           // x, y
    200, 150,           // width, height
    '#3498db',          // color
    true,               // selectable
    true,               // movable
    true                // resizable
);

engine.addObject(zone);

// Listen to engine events
engine.on('object:selected', (payload) => {
    console.log('Object selected:', payload.object.id);
});

engine.on('object:moved', (payload) => {
    console.log('Object moved to:', payload.newPoint);
});

// Start the engine
engine.start();

Core Concepts

Interactive Objects

Interactive objects are entities that can be rendered and interacted with on the canvas. The primary built-in object type is Zone:

const zone = new Zone('my-zone', x, y, width, height, color, selectable, movable, resizable);

// Configure zone properties
zone.name = 'My Zone';
zone.showName = true;
zone.nameAnchor = 'TopLeft';
zone.zIndex = 10;
zone.visible = true;

Modes

Modes define different interaction contexts with their own tools and behaviors:

engine.defineMode('draw', {
    tools: ['drawing'],
    renderers: []
});

engine.defineMode('select', {
    tools: ['select', 'move', 'resize', 'hover'],
    renderers: []
});

// Switch between modes
engine.switchMode('draw');

Built-in Tools

Canvas Engine comes with several pre-built tools:

  • SelectTool - Click to select objects
  • MoveTool - Drag to move selected objects
  • ResizeTool - Resize objects via handles
  • HoverTool - Track mouse hover state
  • DrawingTool - Draw new rectangular zones
  • LassoTool - Select multiple objects with lasso
  • ZoomTool - Mouse wheel and pinch-to-zoom
  • PanTool - Pan the viewport
  • ApiTool - Handle object property changes via API calls

Custom Tools

Create your own tools by implementing the ToolPipelineNode interface:

class CustomTool implements ToolPipelineNode {
    processToolEvent(
        evt: CanvasEvent,
        emit: (evt: CanvasEvent) => void,
        emitExternal: <K extends keyof EngineEventPayloads>(type: K, payload: EngineEventPayloads[K]) => void,
        engine: CanvasEngine,
        toolLock: ToolLock | null
    ) {
        if (evt.type === 'pointerdown') {
            // Handle pointer down event
            console.log('Pointer down at:', evt.data.point);
        }
    }
}

// Register and use the tool
engine.registerTool('custom', () => new CustomTool());
engine.defineMode('custom-mode', {
    tools: ['custom'],
    renderers: []
});

Event System

Canvas Engine has two types of events:

Canvas Events (Internal)

Low-level events flowing through the event pipeline:

  • pointerdown, pointermove, pointerup, pointercancel
  • touchstart, touchmove, touchend, touchcancel
  • wheel, windowresize
  • drag, dragstart, dragend, dragpotential
  • click

Engine Events (External)

High-level events emitted to external listeners:

// Object events
engine.on('object:selected', (payload) => { });
engine.on('object:deselected', (payload) => { });
engine.on('object:moved', (payload) => { });
engine.on('object:resized', (payload) => { });
engine.on('object:colorchanged', (payload) => { });
engine.on('object:added', (payload) => { });
engine.on('object:removed', (payload) => { });

// Viewport events
engine.on('viewport:changed', (payload) => { });

// Engine events
engine.on('engine:started', (payload) => { });
engine.on('engine:modechanged', (payload) => { });
engine.on('engine:backgroundchanged', (payload) => { });

Viewport Controls

// Pan the viewport
engine.setPan(new Vector(100, 100));

// Zoom the viewport
engine.setZoom(2.0);

// Get current viewport state
const pan = engine.pan;
const zoom = engine.zoom;

// Coordinate conversion
const worldPoint = engine.screenToWorld(new Point(100, 100));
const screenPoint = engine.worldToScreen(new Point(50, 50));

Object Management

// Add objects
engine.addObject(zone);

// Remove objects
engine.removeObject(zone);

// Get all objects
const objects = engine.getObjects();

// Object flags (for custom state management)
engine.addFlag(zone, 'highlighted');
engine.removeFlag(zone, 'highlighted');
engine.clearFlags(zone);

// Check selection state
const isSelected = engine.hasFlag(zone, 'selected');

Background Images

// Set a background image
await engine.setBackgroundFromUrl('https://example.com/image.jpg');

// Or from a File/Blob
await engine.setBackground(imageBlob);

Configuration Options

interface CanvasEngineOptions {
    initialZoom?: number;                    // Default: 1
    initialPan?: { x: number; y: number };  // Default: { x: 10, y: 10 }
    defaultMode?: string;                    // Default: "default"
    addTimerEventSource?: boolean;          // Default: false
    proxyObjectsForEvents?: boolean;        // Default: true

    zoomOptions?: {
        wheelZoomFactor?: number;           // Default: 0.1
        pinchZoomFactor?: number;           // Default: 0.01
        minZoom?: number;                   // Default: 0.1
        maxZoom?: number;                   // Default: 10
    };

    // Debug options
    debugLogCanvasEvents?: boolean;         // Default: false
    debugLogEngineEvents?: boolean;         // Default: false
}

Debug Mode

Enable debug logging to track events:

const engine = new CanvasEngine('#app', {
    debugLogCanvasEvents: true,   // Log internal canvas events
    debugLogEngineEvents: true    // Log external engine events
});

// Console output:
// CanvasEvent: pointerdown { type: 'pointerdown', data: {...} }
// EngineEvent: object:selected { object: {...} }

Advanced Usage

Custom Renderers

Implement custom rendering logic:

class CustomRenderer implements RenderPipelineNode {
    render(ctx: CanvasRenderingContext2D, engine: CanvasEngine) {
        // Custom rendering code
        ctx.fillStyle = 'red';
        ctx.fillRect(10, 10, 100, 100);
    }
}

engine.addRenderer(new CustomRenderer());

Gesture Recognizers

Create custom gesture recognizers:

class CustomGestureRecognizer implements GestureRecognizer {
    process(evt: CanvasEvent, emit: (evt: CanvasEvent) => void) {
        // Process events and emit custom gestures
        if (evt.type === 'pointerdown') {
            // Detect custom gesture
            emit({ type: 'customgesture', data: { } });
        }
    }
}

engine.addRecognizer(new CustomGestureRecognizer());

Event Sources

Add custom event sources:

class CustomEventSource implements EventSource {
    attach(emit: (evt: CanvasEvent) => void, engine: CanvasEngine) {
        // Set up event listeners
        window.addEventListener('keydown', (e) => {
            emit({ type: 'keydown', data: { key: e.key } });
        });
    }

    detach() {
        // Clean up listeners
    }
}

engine.addEventSource(new CustomEventSource());

API Reference

CanvasEngine

Methods

  • start() - Start the engine
  • addObject(obj) - Add an interactive object
  • removeObject(obj) - Remove an interactive object
  • getObjects() - Get all objects
  • setPan(vector) - Set viewport pan
  • setZoom(zoom) - Set viewport zoom
  • switchMode(name) - Switch to a different mode
  • defineMode(name, config) - Define a new mode
  • registerTool(name, factory, singleton) - Register a custom tool
  • addRenderer(renderer) - Add a custom renderer
  • addRecognizer(recognizer) - Add a gesture recognizer
  • setBackground(blob) - Set background from File/Blob
  • setBackgroundFromUrl(url) - Set background from URL
  • on(event, callback) - Subscribe to engine events
  • off(event, callback) - Unsubscribe from engine events

Zone

Properties

  • id - Unique identifier
  • rect - Rectangle defining position and size
  • color - Fill color
  • name - Optional display name
  • showName - Whether to display the name
  • nameAnchor - Position of the name label
  • zIndex - Rendering order
  • visible - Visibility flag
  • selectable - Whether the zone can be selected
  • movable - Whether the zone can be moved
  • resizable - Whether the zone can be resized

TypeScript Support

Canvas Engine is written in TypeScript and provides full type definitions out of the box.

License

MIT

Contributing

Contributions are welcome! Please feel free to submit issues or pull requests.

Dependencies