Introducing Pictode: A Konva.js‑Based Graphical Editor Framework with Tutorials and Plugin Guide
This article presents Pictode, a Konva.js‑driven graphics editor framework, explains its core features, demonstrates how to set up a canvas, use drawing tools, selector and history plugins, and provides step‑by‑step code examples for integration with Vue or other front‑end projects.
Origin
Inspired by many technical experts sharing their own graphic editor projects on Juejin, the author decided to create a personal editor named Pictode using spare time over two months.
Previous work includes a 3D editor based on Three.js, a BPMN editor, a topology editor based on X6, and a low‑code editor with Vue, but corporate constraints prevented those from reaching the desired level.
Since August, the author has been developing Pictode , which now integrates useful functions such as tool switching, property editing, context menu, local saving, image export, canvas zoom/drag, history, language and theme switching.
Pictode Main Features Demo
Graphic Drawing
Selection / Transformation
Layer Move
Align / Distribute
Group / Ungroup
Export Image
Tip: Experience the editor yourself at https://pictode.com/#/ and star the GitHub repository.
What Pictode Can Bring You
Many articles show how to build a canvas or image editor, but often the code is hard to reuse in your own project, especially when the original editor is built with a different framework.
Pictode is framework‑agnostic, built on Konva.js, allowing easy integration with Vue, React, or plain JavaScript, and provides a lightweight API.
DIY Canvas
Below is a quick guide to creating a canvas with Pictode.
Creating the Canvas
Install the core package:
npm install @pictode/coreInstantiate the App object:
import { App } from "@pictode/core";
const app = new App();Mount the canvas to a DIV container:
<script setup lang="ts">
import { ref, onMounted } from "vue";
import { App } from "@pictode/core";
const canvasRef = ref<HTMLDivElement>();
const app = new App();
onMounted(() => {
if (canvasRef.value) {
app.mount(canvasRef.value);
}
});
</script>
<template>
<div class="wrapper">
<div ref="canvasRef"></div>
</div>
</template>Drawing Tools
Install the tools package:
npm install @pictode/toolsInstantiate a rectangle tool:
import { RectTool } from "@pictode/tools";
new RectTool({
config: {
stroke: "black",
strokeWidth: 2,
fill: "gray",
cornerRadius: 0,
opacity: 1,
},
});Switch to the rectangle tool:
app.setTool(
new RectTool({
config: {
stroke: "black",
strokeWidth: 2,
fill: "gray",
cornerRadius: 0,
opacity: 1,
},
})
);Selection / Transformation
Install the selector plugin:
npm install @pictode/plugin-selectorInstantiate and load it:
import { SelectorPlugin } from "@pictode/plugin-selector";
const selectorPlugin = new SelectorPlugin();
app.use(selectorPlugin);Use app.select(...) / app.cancelSelect(...) for selection, and hold Shift for multi‑select.
To avoid interference between drawing and selection, disable the selector when a drawing tool is active and re‑enable it when the tool is cleared:
app.setTool(tool); // disables selectorPlugin
app.setTool(null); // re‑enables selectorPluginThe @pictode/tools package also provides a dedicated SelectTool with onActive and onInactive hooks to manage this automatically.
const selectTool = new SelectTool({
hooks: {
onActive() { selectorPlugin.enable(); },
onInactive() { selectorPlugin.disable(); },
},
});
const rectTool = new RectTool({
config: { stroke: "black", strokeWidth: 2, fill: "gray" },
hooks: { onActive() { app.cancelSelect(); } },
});
app.setTool(selectTool);Undo / Redo
Install the history plugin:
npm install @pictode/plugin-historyInstantiate and load it:
import { HistoryPlugin } from "@pictode/plugin-history";
const historyPlugin = new HistoryPlugin();
app.use(historyPlugin);Now app.undo() and app.redo() work, e.g.:
<button @click="app.undo()">Undo</button>
<button @click="app.redo()">Redo</button>Align / Distribute
Install the alignment plugin:
npm install @pictode/plugin-alignmentInstantiate and load it:
import { AlignmentPlugin } from "@pictode/plugin-alignment";
const alignmentPlugin = new AlignmentPlugin();
app.use(alignmentPlugin);Use methods such as app.alignTop , app.alignRight , app.alignBottom , app.alignLeft , app.alignCenterX , app.alignCenterY , as well as app.distributeX and app.distributeY to arrange objects.
Note: All @pictode/* packages are currently pre‑release versions undergoing testing and bug fixing.
Architecture and Technology Choices
Pictode aims to be a universal graphics editor framework, choosing konva.js as the core library because of its clear TypeScript support, active community, and stable API. An earlier consideration of fabric.js was dropped due to messy code structure and outdated syntax.
Design
The library consists of two parts: a core engine that is UI‑framework independent, and a Vue 3 based UI layer that demonstrates how to use the core.
The design follows separation of concerns and event‑driven data interaction, offering flexible plugins and tool mechanisms for easy extension.
Project Roadmap
v1.0.0
(Roadmap image omitted)
v2.0.0
(Roadmap image omitted)
v3.0.0
(Roadmap image omitted)
Open‑Source Plan
The author intends to open source Pictode, seeking help with licensing, issue tracking, and community building.
Conclusion
If you find Pictode interesting, please star the GitHub repository, like, collect, and follow the author for updates.
🎨 Experience Pictode: https://pictode.com/#/
✨ Star on GitHub: https://github.com/JessYan0913/pictode
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.