@zouchengxin/pixi-editor
v1.0.9
Published
An infinite canvas component built with PixiJS
Maintainers
Readme
pixi-editor
An infinite canvas component built with PixiJS, featuring viewport panning, element transformation (translate/rotate/scale), and a customizable element toolbar. Ideal for flowchart editors, whiteboard applications, map editors, and other large-scale interactive spaces.
✨ Features
- Infinite Canvas: Boundary-free drawing area via viewport transformations
- Smooth Viewport Control: Mouse/touch drag to pan the canvas
- Element Transformation: Translate, rotate, and scale selected elements (with configurable control handles)
- Element Toolbar: Context-aware toolbar for selected elements (delete, duplicate, layer adjustment, etc.)
- High Performance: WebGL rendering via PixiJS, supports a large number of graphic elements
- TypeScript Friendly: Includes complete type definitions
📦 Installation
npm install pixi.js @zouchengxin/pixi-editor🌐 Live Demo
Try it online: pixi-editor
Edge Extension: free-canvas
🚀 Quick Start
Initialization
// tsconfig.json
// If you need to use a decorator
{
"compilerOptions": {
"experimentalDecorators": true
}
}<div id="editor-container">
<!-- The editor will be mounted here -->
</div>import { Editor } from "@zouchengxin/pixi-editor";
import "@zouchengxin/pixi-editor/style.css";
import { Element } from "@zouchengxin/pixi-editor/elements";
const editor = new Editor();
// API_KEY not provided, validity period until 2027-01-01,.
// You can adjust the system time for testing.
// Or contact the developer to obtain the API key.
await editor.init(API_KEY);
editor.mount("#editor-container");Elements
// Add Shape element.
editor.addElement("shape", { type: "rect", x: 100, y: 10, w: 60, h: 80 });
editor.addElement("shape", { type: "circle", x: 10, y: 10, fillColor: "red" });
// Add Image element.
async function selectImage() {
const pickerOpts = {
types: [
{
description: "Images",
accept: {
"image/*": [".png", ".jpeg", ".jpg"],
},
},
],
excludeAcceptAllOption: true,
multiple: false,
};
const [fileHandle] = await window.showOpenFilePicker(pickerOpts);
const fileData = await fileHandle.getFile();
return fileData;
}
const blob = await selectImage();
const srcId = "test-" + Date.now();
await editor.source.set(srcId, blob);
const imgEl = editor.addElement("image", { x: 10, y: 200, sourceId: srcId });
// Add Text element.
const textEl = editor.addElement("text", {
x: 10,
y: 300,
text: "hello word!",
color: "#ff0000",
font: "Arial",
});
// Add Brush element.
const brushEl = editor.addElement("brush", {
x: 10,
y: 400,
strokeColor: "#ff0000",
strokeWidth: 6,
points: [
[4, 4],
[100, 4],
[100, 100],
],
});
// Add Connector element.
const connEl = editor.addElement("connector", {
x: 10,
y: 500,
type: "line",
strokeColor: "#ff0000",
strokeWidth: 6,
sPoint: [4, 4],
ePoint: [60, 60],
});
// Add Group element.
const groupEl = editor.addElement("group", {
childIds: [textEl.model.id, brushEl.model.id],
});
// Other elements are under developmentToolbar
// Add the internally provided toolbar.
const toolEl = document.createElement("pe-toolbar");
// @ts-ignore
toolEl.$editor = editor;
editor.container.appendChild(toolEl);Custom Element
import { Text } from 'pixi.js';
import { Element } from '@zouchengxin/pixi-editor/elements';
import { Model } from '@zouchengxin/pixi-editor/models';
import { BaseTool } from '@zouchengxin/pixi-editor/tools';
import { Reactive, Ref, Watch } from '@zouchengxin/pixi-editor/decorators';
import type { IModelOpt } from "@zouchengxin/pixi-editor/models";
interface ITestModelOpt extends IModelOpt {
text: string;
}
@Reactive
class TestModel extends Model{
@Ref text='test';
}
// inherits from Container class of pixijs
class TestElement extends Element<TestModel> {
static ident = 'test';
createModel(opt: ITestModelOpt) {
this.model = new TestModel(opt);
}
// Execute during initialization
init() {
super.init();
}
// Execute when reactive property changes (properties decorated with Ref)
render() {
super.render();
// You can add any scene objects to the Container.
// such as Text, Graphics, Sprite, etc
const text = new Text({
text: this.model.text,
style: {
fill: '#ffffff',
fontSize: 16,
},
});
this.addChild(text);
}
}
// inherits from Container class of pixijs
class TestTool extends BaseTool{
static ident = 'test';
// Execute during initialization
init(){
const text = new Text({
text: 'This is test tool',
});
this.addChild(text);
}
}
// Register tool
editor.registerTool(TestTool);
// Set current tool
editor.setTool('test');
// Register element
editor.registerElement(TestElement);
// Add test element
editor.addElement('test', { text: 'hello world', x: 200, y: 200 });Element Toolbar
import { html, LitElement } from 'lit';
import { customElement } from 'lit/decorators.js';
// Tag name: pe-el-${ident}
@customElement('pe-el-test')
class ElTest extends LitElement {
$editor: Editor;
$el: TestElement;
render() {
return html`
<div>Test</div>
`
}
}🖌️ API Reference
Editor
| Field | Type | Description |
| ----------- | ------------------ | ------------------------------------------- |
| app | PIXI.Application | Application instance in the pixi library |
| plugins | Plugin[] | Registered plugins |
| elements | Element[] | Registered elements |
| container | HTMLElement | The Dom element where the Editor is mounted |
| mode | Ref:EditorMode | Editor mode |
| toolName | Ref:string | Current tool name |
| Method | Description |
| ----------------- | -------------------------------------------- |
| getPlugin | Get the corresponding plugin by name |
| init | Initialization function, API_KEY is optional |
| mount | Mount function |
| registerElement | Register element |
| registerTool | Register tool |
| addPlugin | Add plugin |
| addElement | Add element |
| removeElement | Remove element |
| exportPng | Export PNG image |
| toJSON | Convert to JSON data |
| parseJSON | Parse JSON data |
Element
| Field | Type | Description |
| ----------- | ------------------ | ---------------------------------------- |
| ident | string | Unique identifier |
| $editor | Editor | Editor instance |
| model | Model | Associated model |
| app | PIXI.Application | Application instance in the pixi library |
| viewport | Viewport | Viewport plugin |
| selection | Selection | Selection plugin |
| Method | Description |
| ---------------- | ----------------------------------------------------- |
| createModel | Create model instance |
| init | Initialization function |
| toJSON | Convert to JSON data |
| containPoint | Whether the boundary contains a certain point |
| intersectBound | Whether the boundary intersects with another boundary |
| update | Update function |
| render | Render function |
| onClick | Click event |
| onBlur | Blur event |
| onRotate | Rotating event |
| onRotateEnd | Rotation end event |
| onResize | Resizing event |
| onResizeEnd | Resize end data |
| onMove | Move event |
| onMoveEnd | Move end data |
Model
| Field | Type | Description |
| -------- | ------------- | ----------------------------- |
| id | Ref:string | Unique id |
| x | Ref:number | x-axis coordinate |
| y | Ref:number | y-axis coordinate |
| w | Ref:number | Element width |
| h | Ref:number | Element height |
| rotate | Ref:number | Element rotation radian |
| zIndex | Ref:number | Element layer index |
| locked | Ref:boolean | Whether the element is locked |
| Method | Description |
| -------- | -------------------- |
| toJSON | Convert to JSON data |
💬 Contact
- 交流群: 877673376
- API_KEY: https://ifdian.net/a/zouchengxin
