Skip to main content

Streamlit Drawable Konva

Usage demo — tool picker, draw, spline, crop, and image comparison

Live demo: drawable-konva-demo.streamlit.app

Streamlit custom component (Components v2) that provides a sketching canvas using Konva.js / react-konva.

The public Python API is intentionally compatible with streamlit-drawable-canvas-fix (st_canvas → CanvasResult(image_data, json_data)). Object JSON uses Konva-oriented fields (x/y/points/…), not Fabric.js schemas.

Features

  • Freehand, line, rect, circle, point, polygon, spline (Catmull-Rom through clicks) drawing
  • In-canvas tool picker (0.6) — tools=[…] allow-list + display_tool_picker=True
  • Rect crop — single crop region with dimmed overlay (rect_crop mode)
  • Image comparison — st_image_comparison before/after slider companion
  • Interaction locks & groups — per-object locked, groupId, axis dragConstraint, transform_options
  • Transform mode (move / scale / rotate); double-click to delete
  • Viewport zoom, pan, and tilt (display-only; see below)
  • Background color or image
  • Realtime or on-demand updates to Streamlit
  • Undo / redo / clear toolbar
  • Returns RGBA image_data and scene json_data
  • Host-agnostic mount — standalone.js / DrawableKonvaCanvas.mount for Violit embeds

Viewport: zoom / pan / tilt

Enabled by default (enable_viewport_controls=True). These change how the canvas is viewed, not the stored object coordinates or exported image_data.

Control How
Zoom Mouse wheel, or toolbar Zoom + / −
Pan drawing_mode="pan" and drag; or Alt+drag; or middle-mouse drag
Tilt Toolbar Tilt ↶ / ↷ (view rotation, ±15°)
Reset Toolbar Reset view

Try them in the demo page Zoom / pan / tilt.

Why Konva.js (vs Fabric.js)?

Konva is not universally “better” than Fabric — both are mature 2D canvas libraries. For this Streamlit component, Konva is the better fit.

Concern Konva Fabric
React integration First-class via react-konva (declarative scene tree) Imperative fabric.Canvas; React wrappers are thinner / more brittle
Mental model Stage → Layer → Shape (clear export boundaries) Single canvas object model; background vs drawing export needs extra care
Bundle / focus Leaner, scene-graph oriented Heavier; strong textile/image-editing heritage
Transforms Built-in Transformer for select / scale / rotate Excellent selection UX; historically the gold standard for editors
Ecosystem Strong for interactive UIs and annotation tools Huge installed base; many Fabric JSON examples in the wild

Why we chose Konva here

  1. React + Streamlit Components v2 — the official CCv2 React template maps cleanly onto react-konva. Drawing state stays in React; updates go out via setStateValue without fighting an imperative canvas singleton.
  2. Layered export — background images can live on a non-exported layer while strokes/shapes export cleanly to image_data, matching the upstream “background is not round-tripped” behavior with less glue code.
  3. Maintainability — freerdraw / shapes / polygon / transform are ordinary React event handlers and Konva nodes, which is easier to evolve next to a modern Vite + TypeScript frontend than a Fabric-centric CRA-era stack.
  4. Performance for annotation UIs — Konva’s layer/stage model scales well for ROI / sketching workloads typical in Streamlit apps.

When Fabric may still win

  • You need byte-compatible Fabric JSON (existing pipelines, demos, or tutorials that assume left/top/path Fabric schemas).
  • You want Fabric’s mature free-transform / skew / complex text editing out of the box without reimplementing edge cases.

This package keeps a compatible Python API (st_canvas → CanvasResult) so apps can migrate from streamlit-drawable-canvas-fix, while accepting that json_data is Konva-oriented rather than a Fabric dump.

Install (uv)

uv sync

Build the frontend once (required before first Streamlit run):

cd streamlit_drawable_konva/frontend
npm install
npm run build
cd ../../

Editable install is handled by uv sync via the local pyproject.toml.

Demo

uv run streamlit run app.py

Development

CCv2 watches a production-style build into frontend/build (no separate webpack dev server URL). Use two terminals:

Terminal A — frontend watch build

cd streamlit_drawable_konva/frontend
npm install
npm run dev

Terminal B — Streamlit

uv sync
uv run streamlit run app.py

Refresh the browser after frontend rebuilds.

API

from streamlit_drawable_konva import st_canvas

result = st_canvas(
    fill_color="rgba(255, 165, 0, 0.3)",
    stroke_width=3,
    stroke_color="#000000",
    background_color="#eee",
    background_image=None,
    update_streamlit=True,
    height=400,
    width=600,
    drawing_mode="freedraw",  # freedraw|line|rect|rect_crop|circle|point|polygon|spline|transform|pan
    initial_drawing=None,
    display_toolbar=True,
    # Optional: restrict modes and/or show an in-canvas tool row
    tools=["freedraw", "line", "rect", "polygon", "transform", "pan"],
    display_tool_picker=True,
    point_display_radius=3,
    enable_viewport_controls=True,
    key="canvas",
)

# result.image_data -> np.ndarray | None
# result.json_data  -> dict | None

Image comparison (st_image_comparison)

Before/after slider companion (same package; also available on Violit as vl_image_comparison):

from streamlit_drawable_konva import st_image_comparison

st_image_comparison(
    img1,  # PIL / path / ndarray / data URL
    img2,
    label1="Before",
    label2="After",
    width=700,
    starting_position=50,
)

Crop controls (rect_crop)

  • Draw one rectangle; a new draw replaces the previous crop
  • Drag the box or use handles to move / resize
  • Double-click the crop box to remove it
  • Read coordinates with crop_box_from_json(result.json_data) → (x, y, width, height)
  • Crop overlay is excluded from exported image_data

Spline data (spline)

json_data stores control points only — the clicks you placed:

from streamlit_drawable_konva import splines_from_json, spline_control_points, sample_spline

splines = splines_from_json(result.json_data)
control = spline_control_points(splines[0])   # [(x, y), ...] from JSON
dense = sample_spline(splines[0], samples_per_segment=16)  # interpolated polyline

Each spline object looks like:

{"id": "...", "type": "spline", "points": [x1, y1, x2, y2, ...], "tension": 0.5}

The smooth curve is not in JSON; use sample_spline() (Catmull-Rom, same tension) when you need a dense path for masking, metrics, or export.

Interaction locks, groups, handles (0.3)

Object fields (in initial_drawing / json_data):

  • locked: true — visible, not interactive in transform mode
  • groupId + optional type: "group" descriptor — move/rotate together
  • dragConstraint: { type: "axis", axis: {x, y}, min, max } — constrained handle drag
  • Per-object: draggable, selectable, scalable, rotatable, deletable

Python kwarg:

st_canvas(..., transform_options={"allow_scale": False})

Polygon controls

  • Left-click: add point
  • Right-click: close polygon
  • Double-click: remove latest point

Transform controls

  • Click object to select
  • Drag / resize / rotate with the transformer
  • Double-click selected object to delete

Viewport controls

  • Wheel / Zoom ±: zoom toward cursor (wheel) or canvas center (buttons)
  • Pan mode / Alt-drag / middle-mouse: move the view
  • Tilt ↶↷: rotate the view
  • Reset view: 100% zoom, 0° tilt, centered pan

Migrating from Fabric drawable canvas

See MIGRATION.md for import renames, JSON field mapping, and behavioral differences vs streamlit-drawable-canvas / -fix.

Packaging notes

  • Registered as streamlit-drawable-konva.st_canvas and streamlit-drawable-konva.st_image_comparison via the in-package streamlit_drawable_konva/pyproject.toml manifest (asset_dir = frontend/build).
  • Requires Streamlit >= 1.51 (Components v2).
  • Frontend toolchain targets Node >= 18 (Vite 6).
  • Host-agnostic mount: frontend/build/standalone.js exposes window.DrawableKonvaCanvas.mount and window.DrawableKonvaCanvas.mountImageComparison for non-Streamlit hosts (e.g. Violit). Streamlit uses build/index.js and build/comparison.js.

Step-by-step instructions: PUBLISHING.md (includes updating GitHub / PyPI / Streamlit Cloud / gallery after the first release).

Current version: 0.6.0.

Order: push to GitHub → publish to PyPI → deploy app.py on Community Cloud → submit gallery/streamlit-drawable-konva.json as a PR to streamlit/gallery.

License

MIT

Metadata

Release files for streamlit-drawable-konva 0.6.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for streamlit-drawable-konva 0.6.0
File Size Uploaded
streamlit_drawable_konva-0.6.0.tar.gz 381.4 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for streamlit-drawable-konva 0.6.0
File Interpreter ABI Platform
streamlit_drawable_konva-0.6.0-py3-none-any.whl Python 3 none any Details

Total release size: 762.4 kB

Release files / streamlit_drawable_konva-0.6.0.tar.gz

Download URL streamlit_drawable_konva-0.6.0.tar.gz
Size 381.4 kB
Tags Source
SHA-256 checksum
How to use checksums
262ef580908124e15f97b85489950336448c4b37c22bca1ca20079f35d78cc0d
BLAKE2b-256 checksum
How to use checksums
ed1df941b002edfb609d64a10ecdecd4d93c380621e94918fdb2842468020c80
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / streamlit_drawable_konva-0.6.0-py3-none-any.whl

Download URL streamlit_drawable_konva-0.6.0-py3-none-any.whl
Size 381.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2b3c8a662e3adba4f1d9b9fa157bae282f6ea0905799aca3460d8798e613dde3
BLAKE2b-256 checksum
How to use checksums
2ad774b208e33e22b46b40e36655dcea1679465ecba721db411652330cce6576
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.21 {"installer":{"name":"uv","version":"0.12.21","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"CachyOS Linux","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

0.7.0

2 release files

This release

0.6.0 This release

2 release files

0.5.0

2 release files

0.4.0

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.2

2 release files

0.2.1

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page