# Canvas Panel - Technical Documentation
This documentation provides a comprehensive technical overview of the Canvas visualization panel in Grafana.
## Table of Contents
1. [Overview](#overview)
2. [Architecture](#architecture)
3. [File Structure](#file-structure)
4. [Key Components](#key-components)
5. [External Dependencies](#external-dependencies)
6. [Configuration Schema](#configuration-schema)
7. [Element System](#element-system)
8. [Connection System](#connection-system)
9. [Editing System](#editing-system)
10. [Performance Considerations](#performance-considerations)
11. [Current Limitations and TODOs](#current-limitations-and-todos)
12. [Migration System](#migration-system)
13. [Evolution History](#evolution-history)
---
## Overview
The Canvas panel is a native Grafana visualization that allows users to create custom layouts with explicit element placement. Unlike standard Grafana visualizations, Canvas provides a freeform design surface where elements can be positioned, resized, rotated, and connected to each other.
**Key Capabilities:**
- Freeform element placement with drag-and-drop
- Multiple element types (shapes, icons, text, metric values, etc.)
- Visual connections between elements with customizable styling
- Constraint-based responsive layouts
- Inline editing mode for direct manipulation
- Pan and zoom functionality (feature-toggled)
- Data-driven element styling via dimensions
- One-click links and actions
- Tooltip support
**Plugin Metadata:**
- ID: `canvas`
- Type: `panel`
- Description: "Explicit element placement"
---
## Architecture
### High-Level Architecture
```
┌─────────────────────────────────────────────────────────────────┐
│ CanvasPanel │
│ (React Component - Entry Point) │
│ │
│ ┌─────────────────────────────────────────────────────────────┐│
│ │ Scene ││
│ │ (Runtime Manager - Core Orchestrator) ││
│ │ ││
│ │ ┌───────────────┐ ┌───────────────┐ ┌──────────────────┐ ││
│ │ │ RootElement │ │ Connections │ │ Moveable/ │ ││
│ │ │ (FrameState) │ │ (SVG Lines) │ │ Selecto │ ││
│ │ │ │ │ │ │ (Interactions) │ ││
│ │ │ ┌───────────┐ │ │ │ │ │ ││
│ │ │ │FrameState │ │ │ │ │ │ ││
│ │ │ │ Elements │ │ │ │ │ │ ││
│ │ │ │ ┌───────┐ │ │ │ │ │ │ ││
│ │ │ │ │Element│ │ │ │ │ │ │ ││
│ │ │ │ │State │ │ │ │ │ │ │ ││
│ │ │ │ └───────┘ │ │ │ │ │ │ ││
│ │ │ └───────────┘ │ │ │ │ │ ││
│ │ └───────────────┘ └───────────────┘ └──────────────────┘ ││
│ └─────────────────────────────────────────────────────────────┘│
└─────────────────────────────────────────────────────────────────┘
```
### Data Flow
1. **Panel Props** → `CanvasPanel` receives props from Grafana's panel system
2. **Scene Creation** → Scene is instantiated with options and callbacks
3. **Root Element** → Root element tree is built from saved configuration
4. **Data Update** → Panel data flows through dimension context to update element styling
5. **User Interaction** → Moveable/Selecto handle drag/resize/select operations
6. **State Changes** → Element changes propagate back through Scene to save model
7. **Rendering** → React re-renders triggered by revision IDs and state changes
### State Management
The Canvas uses a hybrid state management approach:
- **RxJS Subjects** for reactive updates (selection, edit mode, moved events)
- **React state** for UI-level concerns (inline edit open, refresh counter)
- **Mutable class state** for performance-critical element positioning
- **Revision IDs** (`revId`) to trigger React re-renders when needed
---
## File Structure
```
public/app/
├── plugins/panel/canvas/
│ ├── CanvasPanel.tsx # Main panel component
│ ├── module.tsx # Plugin registration and options
│ ├── panelcfg.gen.ts # Generated TypeScript types from schema
│ ├── panelcfg.cue # CUE schema definition
│ ├── types.ts # TypeScript type definitions
│ ├── utils.ts # Utility functions
│ ├── migrations.ts # Panel migration handlers
│ ├── globalStyles.ts # Global CSS styles
│ ├── plugin.json # Plugin metadata
│ ├── components/
│ │ ├── CanvasContextMenu.tsx # Right-click context menu
│ │ ├── CanvasTooltip.tsx # Hover tooltips
│ │ ├── SetBackground.tsx # Background configuration UI
│ │ └── connections/
│ │ ├── ConnectionAnchors.tsx # Connection anchor points
│ │ ├── ConnectionAnchors2.tsx # Pan/zoom version
│ │ ├── Connections.tsx # Connection rendering
│ │ ├── Connections2.tsx # Pan/zoom version
│ │ ├── ConnectionSVG.tsx # SVG connection lines
│ │ └── ConnectionSVG2.tsx # Pan/zoom version
│ └── editor/
│ ├── connectionEditor.tsx # Connection property editor
│ ├── LineStyleEditor.tsx # Connection line styling
│ ├── options.ts # Editor option utilities
│ ├── panZoomHelp.tsx # Pan/zoom help text
│ ├── element/
│ │ ├── elementEditor.tsx # Element property editor
│ │ ├── ActionsEditor.tsx # Action configuration
│ │ ├── APIEditor.tsx # API call configuration
│ │ ├── ButtonStyleEditor.tsx # Button styling
│ │ ├── ConstraintSelectionBox.tsx
│ │ ├── DataLinksEditor.tsx # Data link configuration
│ │ ├── ParamsEditor.tsx # Parameter editing
│ │ ├── PlacementEditor.tsx # Position/size editor
│ │ ├── QuickPositioning.tsx # Quick position buttons
│ │ └── utils.ts
│ ├── inline/
│ │ ├── InlineEdit.tsx # Draggable inline editor
│ │ ├── InlineEditBody.tsx # Inline editor content
│ │ └── TabsEditor.tsx # Tab-based editing
│ └── layer/
│ ├── layerEditor.tsx # Layer management
│ ├── tree.ts # Tree data structures
│ ├── TreeNavigationEditor.tsx # Tree view
│ └── TreeNodeTitle.tsx # Tree node rendering
│
└── features/canvas/
├── element.ts # CanvasElementItem interface
├── frame.ts # CanvasFrameOptions type
├── registry.ts # Element type registry
├── types.ts # Shared types
├── elements/
│ ├── button.tsx # Button element
│ ├── cloud.tsx # Cloud shape
│ ├── droneFront.tsx # Drone visualization
│ ├── droneSide.tsx # Drone visualization
│ ├── droneTop.tsx # Drone visualization
│ ├── ellipse.tsx # Ellipse/circle shape
│ ├── icon.tsx # Icon element
│ ├── metricValue.tsx # Metric value display
│ ├── notFound.tsx # Fallback element
│ ├── parallelogram.tsx # Parallelogram shape
│ ├── rectangle.tsx # Rectangle shape
│ ├── text.tsx # Text element
│ ├── triangle.tsx # Triangle shape
│ ├── windTurbine.tsx # Wind turbine visualization
│ └── server/
│ ├── server.tsx # Server element
│ └── types/
│ ├── database.tsx
│ ├── single.tsx
│ ├── stack.tsx
│ └── terminal.tsx
└── runtime/
├── ables.tsx # Custom Moveable abilities
├── element.tsx # ElementState class
├── frame.tsx # FrameState class
├── root.tsx # RootElement class
├── scene.tsx # Scene class (main runtime)
├── sceneAbleManagement.ts # Moveable/Selecto setup
└── sceneElementManagement.ts # Element DOM manipulation
```
---
## Key Components
### CanvasPanel (`CanvasPanel.tsx`)
The main React component that serves as the entry point for the Canvas panel.
**Responsibilities:**
- Instantiates and manages the Scene object
- Handles panel lifecycle (mount, update, unmount)
- Subscribes to panel edit events
- Manages inline edit and background setting modals
- Coordinates between React and Scene state
**Key State:**
```typescript
interface State {
refresh: number; // Trigger re-renders
openInlineEdit: boolean; // Inline editor visibility
openSetBackground: boolean; // Background modal visibility
contextMenuAnchorPoint: AnchorPoint;
moveableAction: boolean; // Connection update flag
}
```
### Scene (`runtime/scene.tsx`)
The core runtime manager that orchestrates all canvas functionality.
**Responsibilities:**
- Element tree management (root, frames, elements)
- Selection state via RxJS ReplaySubject
- Data context for dimension resolution
- Moveable/Selecto lifecycle management
- Connection state management
- Pan/zoom via InfiniteViewer (feature-toggled)
- Save model generation
**Key Properties:**
```typescript
class Scene {
root: RootElement; // Element tree root
byName: Map<string, ElementState>; // Element lookup by name
selection: ReplaySubject<ElementState[]>; // Current selection
moved: Subject<number>; // Drag/resize events
connections: Connections; // Connection manager
moveable?: Moveable; // Drag/resize handler
selecto?: Selecto; // Selection handler
infiniteViewer?: InfiniteViewer; // Pan/zoom (feature-toggled)
context: DimensionContext; // Data dimension resolver
// ... many more properties
}
```
### ElementState (`runtime/element.tsx`)
Represents a single canvas element's runtime state.
**Responsibilities:**
- Element positioning and sizing via CSS
- Constraint-based layout calculations
- Data-driven styling (background, border, text)
- Event handling (click, hover, drag, resize, rotate)
- Link and action execution
- Tooltip management
**Key Methods:**
- `applyLayoutStylesToDiv()` - Apply CSS positioning
- `setPlacementFromConstraint()` - Calculate position from constraints
- `updateData()` - Update element from data context
- `applyDrag()`, `applyResize()`, `applyRotate()` - Moveable event handlers
- `renderElement()` - React render method
### FrameState (`runtime/frame.tsx`)
Container for grouping multiple elements.
**Responsibilities:**
- Child element management
- Layer reordering
- Duplicate/delete operations
- Recursive data updates
- Save model aggregation
### RootElement (`runtime/root.tsx`)
Special frame that serves as the canvas root.
**Key Differences from FrameState:**
- Always 100% width/height
- No placement/constraint options saved
- Direct scene reference
- Change callback for save propagation
---
## External Dependencies
### Moveable
**Package:** `moveable`
**Purpose:** Drag, resize, and rotate functionality
Moveable provides the core manipulation capabilities:
- Draggable elements
- Resizable elements with handles
- Rotatable elements
- Snapping to other elements
- Custom "ables" for dimension/constraint overlays
### Selecto
**Package:** `selecto`
**Purpose:** Element selection handling
Selecto manages:
- Click-to-select
- Marquee/box selection
- Multi-select with shift key
- Selection state coordination with Moveable
### InfiniteViewer
**Package:** `infinite-viewer`
**Purpose:** Pan and zoom functionality (feature-toggled)
When `canvasPanelPanZoom` feature toggle is enabled:
- Mouse wheel zoom
- Drag to pan
- Zoom to fit content
- Middle-click/Ctrl+right-click panning
### RxJS
**Package:** `rxjs`
**Purpose:** Reactive state management
Used for:
- Selection state (`ReplaySubject`)
- Edit mode state (`BehaviorSubject`)
- Move events (`Subject`)
- Subscription management
---
## Configuration Schema
### Options Interface
```typescript
interface Options {
inlineEditing: boolean; // Enable direct manipulation
panZoom: boolean; // Enable pan and zoom
zoomToContent: boolean; // Auto-zoom to fit
showAdvancedTypes: boolean; // Show experimental elements
tooltip: CanvasTooltip; // Tooltip configuration
root: { // Element tree
name: string;
type: 'frame';
elements: CanvasElementOptions[];
};
}
```
### Element Options
```typescript
interface CanvasElementOptions {
name: string; // Unique element name
type: string; // Element type ID
config?: unknown; // Type-specific config
placement?: Placement; // Position and size
constraint?: Constraint; // Responsive behavior
background?: BackgroundConfig; // Background styling
border?: LineConfig; // Border styling
connections?: CanvasConnection[]; // Outgoing connections
links?: DataLink[]; // Data links
actions?: Action[]; // Clickable actions
}
```
### Constraint System
```typescript
enum HorizontalConstraint {
Left = 'left',
Right = 'right',
LeftRight = 'leftright', // Stretch
Center = 'center',
Scale = 'scale', // Percentage-based
}
enum VerticalConstraint {
Top = 'top',
Bottom = 'bottom',
TopBottom = 'topbottom', // Stretch
Center = 'center',
Scale = 'scale', // Percentage-based
}
```
---
## Element System
### Element Registry
Elements are registered in `features/canvas/registry.ts`:
**Default Elements:**
- `metricValue` - Display field values with formatting
- `text` - Static or dynamic text
- `ellipse` - Circle/ellipse shape
- `rectangle` - Rectangle shape
- `icon` - SVG icons from Grafana icon library
- `server` - Server visualization with status indicators
- `triangle` - Triangle shape
- `cloud` - Cloud shape
- `parallelogram` - Parallelogram shape
**Advanced/Experimental Elements:**
- `button` - Clickable button with API actions
- `windTurbine` - Animated wind turbine
- `droneTop`, `droneFront`, `droneSide` - Drone visualizations
### Creating Custom Elements
Elements implement the `CanvasElementItem` interface:
```typescript
interface CanvasElementItem<TConfig, TData> {
id: string;
name: string;
description: string;
display: ComponentType<CanvasElementProps<TConfig, TData>>;
defaultSize?: Placement;
hasEditMode?: boolean;
getNewOptions: (options?) => Omit<CanvasElementOptions<TConfig>, 'type' | 'name'>;
prepareData?: (ctx: DimensionContext, options: CanvasElementOptions<TConfig>) => TData;
registerOptionsUI?: PanelOptionsSupplier<CanvasElementOptions<TConfig>>;
customConnectionAnchors?: Array<{x: number; y: number}>;
standardEditorConfig?: StandardEditorConfig;
}
```
---
## Connection System
Connections allow visual links between elements with the following features:
- **Source/Target Anchors:** Normalized coordinates (-1 to 1) from element center
- **Vertex Support:** Add intermediate points to create custom paths
- **Styling:** Color, width, dash style, animation
- **Direction Arrows:** Forward, reverse, both, or none
- **Data Binding:** Dynamic colors and sizes from data
### Connection Data Structure
```typescript
interface CanvasConnection {
source: ConnectionCoordinates; // Source anchor point
target: ConnectionCoordinates; // Target anchor point
targetName?: string; // Target element name
path: ConnectionPath; // Currently only 'straight'
color?: ColorDimensionConfig; // Line color
size?: ScaleDimensionConfig; // Line width
lineStyle?: LineStyleConfig; // Solid/dashed/dotted
vertices?: ConnectionCoordinates[]; // Intermediate points
direction?: DirectionDimensionConfig;
radius?: ScaleDimensionConfig; // Corner radius
}
```
---
## Editing System
### Inline Editor
The inline editor provides direct manipulation without opening the panel editor:
- **Draggable/Resizable window** persisted to localStorage
- **Tab-based interface:** Element management, Selected element, Selected connection
- **Tree navigation** for element hierarchy
- **Quick access** to element properties
### Context Menu
Right-click context menu provides:
- Add element
- Duplicate selected
- Delete selected
- Move to top/bottom of layer
- Open inline editor
- Set background
### Element Selection
Selection handling coordinates between:
- Selecto (click/marquee selection)
- Moveable (manipulation targets)
- Scene selection subject (state propagation)
- Panel options editor (property display)
---
## Performance Considerations
### Optimization Strategies
1. **Revision IDs:** Elements use `revId` counters to trigger targeted re-renders instead of full tree updates
2. **Mutable State:** Position and style changes update DOM directly via `applyLayoutStylesToDiv()` rather than through React state
3. **Data Update Gating:** `ignoreDataUpdate` flag prevents redundant data processing during drag operations
4. **Selective Rendering:** Connection updates only trigger when affected elements move (`connectionsNeedUpdate()`)
5. **Lazy Initialization:** Moveable/Selecto are initialized after DOM elements are ready via `setTimeout`
### Known Performance Concerns
1. **Large Element Counts:** The constraint calculation system recalculates positions for all elements on resize
2. **Streaming Data:** Frequent data updates can cause excessive re-renders; elements should debounce when appropriate
3. **Connection Rendering:** SVG connection paths are recalculated on every move event
4. **Feature Toggle Impact:** Pan/zoom mode (`canvasPanelPanZoom`) adds InfiniteViewer overhead
---
## Current Limitations and TODOs
### From Code Analysis
#### Scene/Runtime TODOs:
- **Dashboard Scenes Migration:** "TODO: Will need to update this approach for dashboard scenes migration (new dashboard edit experience)" - `scene.tsx:117`
- **Style Application Workarounds:** Multiple TODOs about workarounds for applying styles after size updates - `scene.tsx:234-240`
- **Connection Anchor Stacking:** "Remove this after dealing with the connection anchors stacking context issue" - `scene.tsx:240`
#### Element TODOs:
- **SVG Element Handling:** "TODO: This is a hack, we should have a better way to handle this" - `element.tsx:242, 368`
- **Rotation Constraints:** "TODO: Fix behavior for top+bottom, left+right, center, and scale constraints" for rotated elements - `element.tsx:415`
- **Action Variables:** "TODO: implement actionVars" in confirmation modal - `element.tsx:1047`
#### Connection TODOs:
- **Vertex Removal:** "TODO for vertex removal, clear out originals?" - `Connections.tsx:444`, `Connections2.tsx:414`
- **Coordinate Conversion:** "TODO: Break this out into util function and add tests" - `Connections.tsx:245`
#### Editor TODOs:
- **Element-Specific Icons:** "TODO: Implement element specific icons" in tree navigation - `TreeNavigationEditor.tsx:100`
- **Frame Functionality:** "TODO: This functionality is currently kinda broken / no way to decouple / delete created frames" - `TreeNavigationEditor.tsx:128`
- **Non-Root Navigation:** "TODO: the non-root nav option" - `layerEditor.tsx:69`
#### Utility TODOs:
- **Division by Zero:** "TODO look into a better way to avoid division by zero" - `utils.ts:194`
- **Style Parsing:** "TODO: there sould be a better way than parseFloat" - `utils.ts:243`
- **Row Index:** "@TODO revisit, currently returning last row index for field" - `utils.ts:325`
- **Color Migration:** "@TODO Remove after v10.x" for color string migration - `utils.ts:117`
#### Accessibility TODOs:
- **Reduced Motion:** "TODO: figure out what styles to apply when prefers-reduced-motion is set" for drone/turbine animations - `droneTop.tsx:184, droneSide.tsx:125, droneFront.tsx:126`
### Known Limitations
1. **Frame Duplication:** Cannot duplicate frame elements (nested groups)
2. **Connection Path Types:** Only straight line connections supported (no curved/orthogonal)
3. **Element Nesting:** Frame nesting is feature-flagged and partially implemented
4. **Rotation + Constraints:** Rotation behaves unexpectedly with certain constraint combinations
5. **Pan/Zoom + Editing:** Some editing interactions conflict with pan/zoom gestures
---
## Migration System
The canvas panel includes a migration handler (`migrations.ts`) for backward compatibility:
### Migration History
| Version | Migration |
|---------|-----------|
| Initial | Rename `text-box` type to `rectangle` |
| 11.0 | Ellipse refactor: Move element-specific background/border to standard config |
| ≤11.3 | Actions: Move `action.options` to `action.fetch` |
| ≤11.6 | One-click: Migrate `oneClickMode` to first link/action's `oneClick` property |
| ≤12.2 | Connection direction: Convert string direction to dimension config format |
---
## Evolution History
### 2021 - Foundation
- **September 2021:** Initial alpha canvas panel with basic interfaces (#37279)
- **October 2021:** Element movement/resize, layer editor, multi-layer support
- **November 2021:** Button element with onClick support
- **December 2021:** Name-based element UIDs
### 2022 - Core Features
- **April 2022:** Major constraint system overhaul, scale + center constraints
- **May 2022:** Inline editing, context menu, frames (replacing "groups")
- **July 2022:** Tree view navigation, improved context menu UX
- **August 2022:** Metric value element, inline element settings
- **September-November 2022:** Root context menu, selection fixes
### 2023 - Connections & Polish
- **January 2023:** Connection positioning improvements, tooltip for data links
- **March-April 2023:** Connection properties based on data, schema migration
- **May 2023:** File restructuring, panel edit mode fixes
### 2024 - Advanced Features
- **January 2024:** Pan and zoom functionality (#76705)
- **March 2024:** Infinite pan/zoom, element rotation (#83295, #84968)
- **April-May 2024:** New basic shapes (triangle, cloud, parallelogram), vertex control for connections
- **June 2024:** Improved tooltips, scene refactoring
- **August 2024:** Connection line animation, direction options
### 2025 - Refinement
- **February 2025:** One-click links and actions (#99616)
- **July-August 2025:** Pan/zoom improvements, tooltip options, dynamic connection direction
- **September 2025:** Infinity authentication for actions
- **November 2025:** Component refactoring, accessibility improvements
### Key Architectural Changes
1. **Groups → Frames (May 2022):** Renamed internal "group" concept to "frame" for clarity
2. **Constraint System Overhaul (April 2022):** Complete rewrite of responsive layout system
3. **Schema Migration (May 2023):** Moved to CUE-based schema with generated TypeScript
4. **Pan/Zoom Architecture (2024):** Added InfiniteViewer with parallel implementation (`Connections2.tsx`, etc.)
5. **Actions System (2024-2025):** Added support for API actions with one-click execution
---
## Additional Resources
- [Official Canvas Documentation](https://grafana.com/docs/grafana/latest/panels-visualizations/visualizations/canvas/)
- [GitHub Issues - Canvas](https://github.com/grafana/grafana/issues?q=is%3Aissue+label%3Aarea%2Fpanel%2Fcanvas)
- [Feature Request Template](https://github.com/grafana/grafana/issues/new?assignees=&labels=type%2Ffeature-request,area%2Fpanel%2Fcanvas&title=Canvas:&projects=grafana-dataviz&template=1-feature_requests.md)