跪拜 Guibai
← Back to the summary

Meta2d.js 2.0 Rewrites the 2D Visualization Engine for Million-Node Canvases and Built-In Collaboration

Preface

Meta2d.js is a domestic open-source 2D visualization engine used to quickly build Web HMI/SCADA, monitoring dashboards, flowcharts, central-control visualizations, and graphic editing/interaction applications — it connects to real-time data, sets animations and conditions, and the view updates automatically in real time. It also supports drawing, editing, and interaction. Meta2d.js serves a large number of industrial and IoT projects with its "data-driven display" philosophy, and the performance of 1.0 was already solid. Now, after a year of self-revolution, it has been completely restructured and rewritten — the rendering pipeline, event picking, animation system, and data communication have all been rebuilt from scratch, aiming for even higher performance and adding multiplayer collaboration from zero.

image.png

image.png

1. What is Meta2d.js

Meta2d.js is an open-source 2D visualization engine, whose core is "data-driven display + dynamic interaction":

Typical use cases

2. A visualization base for the AI era

Meta2d.js 2.0 does not embed an AI model, but it is naturally AI-friendly:

In a word: AI does the "generation", Meta2d does "rendering, interaction, collaboration" — that is what a visualization base for the AI era should look like.

3. Powerful performance, one million nodes still real-time

Performance benchmark: based on official stress and performance test (examples/benchmark)

Test environment: 8-core 3.8GHz CPU, 32GB RAM

Nodes Performance: FPS Performance: memory (MB) Notes
10k 117 - 120 44 - 50 drag/zoom unaffected
100k 114 - 120 80 - 110 mouse picking no frame drop
1M 109 - 117 510 - 840 mouse picking no frame drop

Note: 200 images, 2000 data points, 400 animations all the same, no extra settings

100k nodes, page zoomed to fit all nodes, canvas not zoomed image.png

100k nodes, page not zoomed, canvas zoomed image.png

1M nodes, page not zoomed, canvas zoomed

image.png

A note on the performance optimization: The original plan was to release 2.0 before the Mid-Autumn Festival on September 25, 2026. Our tests showed about 100k nodes were smooth, enough for real production cases. But we developed based on an "architecture -> design implementation" pattern, with performance optimization originally planned after release. Coincidentally, Claude 5.5 and GPT-6 were released, so we decided to try letting AI do deep performance optimization, though previously our engineers designed the new architecture based on five years of accumulated experience, and we were a bit worried AI would "mess up" our code. We were pleasantly surprised that AI's assessment roughly matched ours, and the code changes for optimization were acceptable to us. So we decided to let AI do deep performance optimization before release, which required a lot of review and testing, delaying the release, but the optimized performance exceeded our expectations.

AI analysis: meta2d each animated node computes its own dirty region → each postMessage → render worker does its own clip+clear+redraw for each; hover worker also does full-screen clear and redraw for each N (number of animated nodes) × 2

meta2d's individual primitives (dirty rectangles, spatial grid, worker threads, style diff) are all correct, but there is no aggregation layer within a frame, so the complexity is O(number of animated nodes) independent redraw pipelines, not O(1). With 20k nodes, even if only 200 are animating, each frame is 400 messages + 400 clip/clear/draw + 400 full-screen overlay redraws.

4. Differences from Konva.js, Fabric.js, PixiJS

All are excellent Canvas tech stacks, but the positioning is completely different: Konva / Fabric / Pixi are "canvas basic capability" providers, while Meta2d is a "business out-of-the-box" visualization engine.

Dimension Meta2d.js 2.0 Konva.js Fabric.js PixiJS
Positioning Business-level 2D visualization engine General Canvas drawing interaction library Canvas object model library High-performance 2D rendering engine
Core selling point Data-driven display, out of the box Drawing and interaction (drag/zoom/events) Object model and serialization (JSON/SVG interchange) Rendering performance (WebGL first)
Data communication Built-in MQTT/WS/HTTP/SSE/SQL + data-point binding None, need to integrate None, need to integrate None, need to integrate
Conditional alarms / lifecycle Built-in None None None
Online multiplayer collaboration 2.0 built-in delta sync Need to build Need to build Need to build
Editor interaction Built-in (snapping / layers / undo/redo / Web components) Partial, need to assemble Partial (selection / transform) None
Typical scenarios HMI, SCADA, monitoring dashboards, flowcharts Drawing boards, annotations, H5 interactions Image/poster editors Games, high-performance visualization
Open source license MIT MIT MIT MIT

How to choose:

In a word: no need to integrate MQTT/WebSocket yourself, no need to write picking and partial rendering optimization yourself, no need to build editor interaction yourself, no need to implement multiplayer collaboration yourself — choose Meta2d.js 2.0.

5. Key design of Meta2d.js 2.0

5.1 Multi-threaded architecture

2.0 splits the whole engine into 1 main thread + 4 Web Workers (packages/core/src/workers/):

5.2 Partial repaint

1.x used full-canvas clear + full redraw, simple and stable; 2.0 upgrades to per-bounding-box partial repaint. 2.0 maintains a boundary for each node, and precomputes all nodes within its influence range (penBoundarys). The render thread only executes clearRect + clip on dirty regions:

// workers/render/worker.ts (key logic)
if (boundary && boundary.width > 0 && pens === patchPens) {
  // compute screen-pixel-aligned dirty region
  ctx.clearRect(x, y, width, height);
  // set partial redraw region
  ctx.beginPath();
  ctx.rect(x, y, width, height);
  ctx.clip();
}

Several typical incremental scenarios:

  1. Drag move: first erase and redraw the "old position" region, then draw the "new position" region; nothing outside the two dirty regions changes:

    // 1. erase and redraw the old position region if (e.data.oldBoundary) { boundary = e.data.oldBoundary; renderPens(ctx, patchPens, true); } // 2. redraw the new position region boundary = e.data.newBoundary; renderPens(ctx, patchPens, true);

  2. Hover / selection: track the set of nodes drawn in the previous frame (lastHoverPens / lastInActivePens); on state change, only clear and redraw those nodes;

  3. Animation refresh: each frame only redraws nodes within the bounding boxes of animated nodes;

  4. Text overflow awareness: when text overflows a node's bounds, the textBox syncs into the picking range (textOutsides are returned to the calc thread), ensuring complete redraw coverage.

5.3 Spatial-grid picking: from "iterate all" to "check one grid"

Picking is the lifeblood of an editor. 1.x used linear traversal, which still had clear room for optimization at tens of thousands of nodes; 2.0 introduces an adaptive spatial grid index (workers/calc/pick.ts) to greatly reduce picking cost:

// when nodes are fewer than 2000, the whole canvas is one grid
if (penMap.size < 2000) {
  cols = 1; rows = 1;
  cellSize = Math.max(width, height);
} else {
  // dynamically compute grid rows and columns
  const size = Math.ceil(penMap.size / 1000);
  ...
}

During picking, first locate the cell based on mouse coordinates, then only traverse candidate nodes within that cell (grid[cell]), reducing the candidate set from "all N" to "this cell ≤1000". Several detail optimizations:

5.4 Native GIF / APNG parsing for free animated images

GIF animation on industrial dashboards has always been limited by the browser's <img> capability: you cannot control frame rate or pause, and frequent decoding blocks the main thread. 2.0 does frame-level native parsing in the tool thread:

5.5 Animation engine optimization

2.0 moves the animation player (workers/calc/animate.ts) entirely into the calc thread: keyframe interpolation happens inside the Worker, and only changed properties (changedProperties) are sent to the render thread for partial repaint each frame. With 1000+ animations on screen simultaneously, the main thread and render thread never interfere, and performance improves greatly.

5.6 Online multiplayer collaboration

This is a capability long awaited by the community, and one of the patch features newly designed in 2.0. Key design points:

6. (A few lines) Quick start

npm install @meta2d/core @meta2d/<extension> --save
<le5le-meta2d />
import { createMeta2d, Mode } from '@meta2d/core';

createMeta2d();

const meta2d = document.querySelector('le5le-meta2d');

// Load data
fetch('data.json').then((res) => res.json()).then((data) => meta2d.open(data));
   
// Set edit mode. Default is run mode
meta2d.setMode(Mode.Edit); 

Conclusion

Dedicated to providing users with a better experience, Meta2d.js 2.0 has completely restructured its "rendering, picking, and communication" architecture, using spatial indexing and partial repaint to minimize wasted computation per frame, and using delta patches to enable multiplayer collaboration. For scenarios like HMI, SCADA, and dashboards — "many nodes, real-time data, need interactive editing" — it brings better experience and a leap in capability.

Resource links:

Comments

Top 2 of 3 from juejin.cn, machine-translated. The original thread is authoritative.

七月的后花园

Finally, version 2.0 has arrived!

alsmile

Thanks for your continued attention.

王三岁_ 1 likes

Great article, thanks for sharing.