Custom element (no framework)
It runs anywhere plain DOM does β including live on this page:
CDN one-pagerβ
A complete HTML file β no build step:
<!doctype html>
<html>
<head>
<script
type="module"
src="https://unpkg.com/@oh-just-another/diagram/dist/oja-diagram.global.js"
></script>
<style>
body {
margin: 0;
}
oja-diagram {
display: block;
height: 100vh;
}
</style>
</head>
<body>
<oja-diagram grid snap theme="dark"></oja-diagram>
<script type="module">
const el = document.querySelector("oja-diagram");
el.addEventListener("ready", () => el.zoomToFit());
el.addEventListener("scenechange", (e) => console.log("scene", e.detail));
el.addEventListener("selectionchange", (e) => console.log("selected", e.detail));
</script>
</body>
</html>
npm / ESMβ
npm i @oh-just-another/diagram
import "@oh-just-another/diagram"; // side effect: registers <oja-diagram>
<oja-diagram grid theme="dark" style="height: 100vh"></oja-diagram>
Importing the package registers the element automatically. defineOjaDiagram(tag?) is exported for registering under a different tag name; calling it is otherwise unnecessary (it is idempotent).
APIβ
- Attributes:
theme(dark|light|systemβ themes the chrome; the canvas itself always stays light),renderer(canvas2d|webgl2|offscreen, omit to auto-detect),grid/snap(boolean β attribute present = on). - Property:
sceneβ aSceneobject; assigning loads it (queued until the editor is ready), reading returns the current scene. - Events (
CustomEvent, payload inevent.detail):ready(detail.editoris the live engine),scenechange(the newScene),selectionchange(array of selected element ids),themechange(the new theme). - Methods:
getScene()/loadScene(scene),undo()/redo(),zoomToFit(),getActiveTool()/setActiveTool(tool),getSelection()/setSelection(ids). - Escape hatch: the
editorproperty is the full live engine (nullbeforeready) β same surface as in React: driving from code.
el.setActiveTool("draw-rect"); // "select" | "hand" | "draw-rect" | "draw-ellipse" | ...
el.loadScene(savedScene);
const editor = el.editor; // full engine after `ready`
The Vue / Svelte / Angular wrappers below are thin bindings over this exact element.