@grimoire-intel/mandala
v0.1.0
Published
Declarative, DOM-driven, AI-native SVG canvas Web Component
Readme
Mandala
Declarative, DOM-driven, AI-native SVG canvas Web Component.
<mnd-canvas width="400" height="300">
<mnd-rect x="50" y="50" width="100" height="80" fill="blue" rx="8"></mnd-rect>
<mnd-circle cx="250" cy="100" r="40" fill="red"></mnd-circle>
<mnd-text x="150" y="200" font-size="24" fill="black">Hello, Mandala</mnd-text>
</mnd-canvas>Installation
npm install @grimoire-intel/mandalaUsage
ES Modules
import '@grimoire-intel/mandala';Script Tag
<script src="https://unpkg.com/@grimoire-intel/mandala/dist/index.iife.js"></script>CommonJS
require('@grimoire-intel/mandala');Elements
Canvas
<mnd-canvas width="600" height="400" background="#fafafa">
<!-- children render as SVG -->
</mnd-canvas>| Attribute | Description |
|-----------|-------------|
| width | Canvas width (px, %, or viewBox units) |
| height | Canvas height |
| viewbox | SVG viewBox (auto-computed if omitted) |
| background | Background fill color |
| interactive | Enable selection, drag, resize |
| preserve-aspect-ratio | SVG preserveAspectRatio |
Primitives
| Element | SVG | Attributes |
|---------|-----|------------|
| <mnd-rect> | <rect> | x, y, width, height, rx, ry |
| <mnd-circle> | <circle> | cx, cy, r |
| <mnd-ellipse> | <ellipse> | cx, cy, rx, ry |
| <mnd-line> | <line> | x1, y1, x2, y2 |
| <mnd-polyline> | <polyline> | points |
| <mnd-polygon> | <polygon> | points |
| <mnd-path> | <path> | d |
| <mnd-text> | <text> | x, y, font-size, font-family |
| <mnd-image> | <image> | href, x, y, width, height |
| <mnd-use> | <use> | href, x, y, width, height |
Structural
| Element | SVG | Purpose |
|---------|-----|---------|
| <mnd-group> | <g> | Group with shared transform |
| <mnd-defs> | <defs> | Gradients, patterns, symbols |
Coordinate System
Three modes, distinguished by syntax:
<!-- ViewBox units (default, scales with canvas) -->
<mnd-rect x="50" y="50" width="100" height="80"></mnd-rect>
<!-- Pixels (fixed screen size) -->
<mnd-rect x="50px" y="50px" width="100px" height="80px"></mnd-rect>
<!-- Percentage (responsive) -->
<mnd-rect x="10%" y="10%" width="30%" height="20%"></mnd-rect>Styling
All SVG presentation attributes pass through:
<mnd-rect
fill="blue"
stroke="black"
stroke-width="2"
opacity="0.8"
transform="rotate(45)"
></mnd-rect>CSS custom properties work:
<style>
:root { --brand: #3b82f6; }
</style>
<mnd-rect fill="var(--brand)"></mnd-rect>Interactive Mode
<mnd-canvas interactive>
<mnd-rect x="50" y="50" width="100" height="80"></mnd-rect>
</mnd-canvas>- Click to select
- Shift+Click for multi-select
- Drag to move selected elements
- Resize handles on single selection
- Mouse wheel to zoom
- Space+drag or middle mouse to pan
Events:
canvas.addEventListener('mnd-select', e => console.log(e.detail.target));
canvas.addEventListener('mnd-move', e => console.log(e.detail.x, e.detail.y));
canvas.addEventListener('mnd-resize', e => console.log(e.detail.width, e.detail.height));Export
const canvas = document.querySelector('mnd-canvas');
// SVG string
const svg = canvas.toSVG();
// Data URL
const dataUrl = canvas.toDataURL();
// PNG Blob
const blob = await canvas.toPNG(2); // 2x resolutionAccessibility
ARIA attributes and title/desc pass through:
<mnd-rect
role="img"
aria-label="Blue square"
title="Sales Q1"
desc="Represents Q1 revenue"
></mnd-rect>Grouping and Transforms
<mnd-group transform="translate(100, 100) rotate(45)">
<mnd-rect x="0" y="0" width="50" height="50" fill="blue"></mnd-rect>
<mnd-rect x="60" y="0" width="50" height="50" fill="red"></mnd-rect>
</mnd-group>Gradients and Patterns
<mnd-canvas>
<mnd-defs>
<linearGradient id="sky" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" stop-color="#87CEEB"/>
<stop offset="100%" stop-color="#1E90FF"/>
</linearGradient>
</mnd-defs>
<mnd-rect x="0" y="0" width="100%" height="100%" fill="url(#sky)"></mnd-rect>
</mnd-canvas>API
const canvas = document.querySelector('mnd-canvas');
// Properties
canvas.svg // The rendered SVG element
canvas.interactive // Get/set interactive mode
// Methods
canvas.render() // Force re-render
canvas.toSVG() // Export as SVG string
canvas.toDataURL() // Export as data URL
canvas.toPNG(scale) // Export as PNG Blob
// Selection API (interactive mode)
canvas.getSelection() // Get selected elements
canvas.select(element) // Select programmatically
canvas.deselect(element)
canvas.clearSelection()
// Pan/Zoom API (interactive mode)
canvas.zoom(level) // Set zoom (1 = 100%)
canvas.pan(x, y) // Pan to position
canvas.resetView() // Reset to initial view
canvas.getZoom() // Get current zoom
canvas.getViewBox() // Get current viewBoxBrowser Support
Works in all modern browsers (Chrome, Firefox, Safari, Edge). Requires:
- Custom Elements v1
- Shadow DOM v1
- ResizeObserver
License
MIT
