wtz 1d58d40185 feat: add onChanged callback, Delete key support, drag offset fix
- Add onChanged(callback) API for tracking page changes
- Support Delete/Backspace key to delete selected component
- Fix drag offset issue when moving components
- Add unsaved changes tracking in editor demo
- Update README documentation
2026-03-29 13:01:53 +08:00
2026-03-29 11:50:51 +08:00
2026-03-29 11:50:51 +08:00
2026-03-29 11:50:51 +08:00
2026-03-29 11:50:51 +08:00
2026-03-29 11:50:51 +08:00

WebBuilder.js

IoT Visual Editor Library - Grid-based Drag & Drop Page Builder

中文文档 | English

Features

  • 📱 Fixed mobile canvas (375×812)
  • 📐 Grid layout with 1:1 square cells
  • 🖱️ Drag & drop to add and move components
  • ⚙️ Property panel with real-time preview
  • 💾 JSONB format save/load
  • 🎨 Custom component support

Project Structure

.
├── js/lib/webbuilder/        # Core library (what you need to include)
│   ├── webbuilder.js         # Main file
│   └── types/                # Internal modules
├── editor.html               # Example editor
├── js/editor/editor.js       # Example editor logic
├── css/editor.css            # Example editor styles
├── README.md                 # Chinese
└── README_EN.md              # English

Note

: editor.html and js/editor/ are example code showing how to use this library. For actual use, you only need to include js/lib/webbuilder/webbuilder.js and implement your own editor logic.

Quick Start

1. Include the library

<script src="js/lib/webbuilder/webbuilder.js"></script>

2. Create container

<div id="editor" style="width: 100%; height: 600px;"></div>

3. Initialize editor

webbuilder.init('#editor');

4. Register components

webbuilder.define('gauge', {
    type: 'gauge',
    label: 'Gauge',
    icon: '📊',
    defaultColumnSpan: 6,
    defaultRowSpan: 6,
    defaultProps: {
        label: 'Temperature',
        value: 25,
        unit: '°C'
    },
    traits: [
        { type: 'text', name: 'label', label: 'Label' },
        { type: 'number', name: 'value', label: 'Value' },
        { type: 'text', name: 'unit', label: 'Unit' }
    ],
    render: function(props) {
        var el = document.createElement('div');
        el.className = 'my-gauge';
        el.innerHTML = '<div class="value">' + props.value + props.unit + '</div>' +
                       '<div class="label">' + props.label + '</div>';
        return el;
    }
});

API Reference

Initialize

webbuilder.init(containerSelector)
Parameter Type Description
containerSelector string/HTMLElement Container selector or element

Register component

webbuilder.define(name, definition)
Parameter Type Description
name string Unique component identifier
definition object Component definition object

definition structure:

{
    type: 'component-type',           // Component type
    label: 'Component Name',          // Display name
    icon: '📊',                       // Toolbox icon
    defaultColumnSpan: 6,             // Default column span
    defaultRowSpan: 4,                // Default row span
    defaultProps: { ... },            // Default properties
    traits: [ ... ],                  // Property definitions (for property panel)
    render: function(props) { ... }   // Render function, returns DOM element
}

Export JSONB

var jsonb = webbuilder.toJSONB();

Return format:

{
    version: '1.0',
    layouts: {
        phone: {
            canvas: {
                width: 375,
                height: 812,
                columns: 24,
                cellSize: 13.5,
                rows: 52,
                gap: 2,
                background: '#f5f5f5'
            },
            components: [
                {
                    id: 'gauge-1',
                    type: 'gauge',
                    grid: {
                        startCell: 0,
                        colSpan: 6,
                        rowSpan: 6
                    },
                    props: { ... }
                }
            ]
        },
        computer: null
    }
}

Load JSONB

webbuilder.fromJSONB(jsonb);

Render to container

var components = webbuilder.renderToDiv(container);

Returns component list:

[
    {
        element: HTMLElement,   // Component DOM element
        wrapper: HTMLElement,   // Wrapper container
        props: { ... },         // Component properties (deep copy)
        id: 'gauge-1',
        type: 'gauge'
    }
]

Other methods

// Get canvas config
webbuilder.getCanvasConfig();

// Get all components
webbuilder.getComponents();

// Clear canvas
webbuilder.clear();

Component Definition Specification

traits - Property definitions

Used to generate property panel:

traits: [
    { type: 'text', name: 'label', label: 'Label', default: '' },
    { type: 'number', name: 'value', label: 'Value', default: 0 },
    { type: 'checkbox', name: 'state', label: 'State', default: false }
]
type Description
text Text input
number Number input
checkbox Checkbox

render function

Must return a DOM element:

render: function(props) {
    var el = document.createElement('div');
    el.textContent = props.label;
    return el;
}

Grid System

  • Canvas width: 375px (fixed)
  • Columns: 24
  • Cell size: ~13.5px × 13.5px (square)
  • Component position: Defined by startCell (starting cell index) + colSpan (column span) + rowSpan (row span)

Cell index starts from 0 and increases row by row:

0   1   2   3   ... 23
24  25  26  27  ... 47
48  49  50  51  ... 71
...

Browser Compatibility

  • Chrome 60+
  • Firefox 55+
  • Safari 11+
  • Edge 79+

License

MIT


Based on webbuilder.js by qrai

Description
No description provided
Readme MIT 102 KiB
Languages
JavaScript 85.4%
CSS 11.9%
HTML 2.7%