import { Editor } from 'js-draw'; const container = document.body; // Create an editor const editor = new Editor(container, { // 2e-10 and 1e12 are the default values for minimum/maximum zoom. minZoom: 2e-10, maxZoom: 1e12, }); // Add the default toolbar const toolbar = editor.addToolbar(); const createCustomIcon = () => { // Create/return an icon here. }; // Add a custom button toolbar.addActionButton({ label: 'Custom Button' icon: createCustomIcon(), }, () => { // Do something here });
Manages drawing surfaces/AbstractRenderers.
Handles undo/redo.
Readonly
iconsReadonly
imageData structure for adding/removing/querying objects in the image.
import { Editor, Stroke, Path, Color4, pathToRenderable } from 'js-draw'; const editor = new Editor(document.body); // Create a path. const stroke = new Stroke([ pathToRenderable(Path.fromString('M0,0 L100,100 L300,30 z'), { fill: Color4.red }), ]); const addElementCommand = editor.image.addElement(stroke); // Add the stroke to the editor editor.dispatch(addElementCommand);
Readonly
notifierGlobal event dispatcher/subscriber.
import { Editor, EditorEventType, SerializableCommand } from 'js-draw'; // Create a minimal editor const editor = new Editor(document.body); editor.addToolbar(); // Create a place to show text output const log = document.createElement('textarea'); document.body.appendChild(log); log.style.width = '100%'; log.style.height = '200px'; // Listen for CommandDone events (there's also a CommandUndone) editor.notifier.on(EditorEventType.CommandDone, event => { // Type narrowing for TypeScript -- event will always be of kind CommandDone, // but TypeScript doesn't know this. if (event.kind !== EditorEventType.CommandDone) return; log.value = `Command done ${event.command.description(editor, editor.localization)}\n`; if (event.command instanceof SerializableCommand) { log.value += `serializes to: ${JSON.stringify(event.command.serialize())}`; } }); // Dispatch an initial command to trigger the event listener for the first time editor.dispatch(editor.image.setAutoresizeEnabled(true));
Readonly
toolControls the list of tools. See the custom tool example for more.
Readonly
viewportAllows transforming the view and querying information about what is currently visible.
Adds all components in components
such that they are in the center of the screen.
This is a convenience method that creates and applies a single command.
If selectComponents
is true (the default), the components are selected.
actionDescription
, if given, should be a screenreader-friendly description of the
reason components were added (e.g. "pasted").
Optional
actionDescription: stringCreates a toolbar. If defaultLayout
is true, default buttons are used.
a reference to the toolbar.
Apply a large transformation in chunks.
If apply
is false
, the commands are unapplied.
Triggers a re-render after each updateChunkSize
-sized group of commands
has been applied.
Creates an element that will be positioned on top of the dry/wet ink renderers.
So as not to change the position of other overlays, overlay
should either
be styled to have 0 height or have position: absolute
.
This is useful for displaying content on top of the rendered content (e.g. a selection box).
apply
a command. command
will be announced for accessibility.
Example:
import { Editor, EditorImage, Stroke, pathToRenderable. Path, Color4, } from 'js-draw'; const editor = new Editor(document.body); const stroke = new Stroke([ pathToRenderable(Path.fromString('m0,0 l100,100 l0,-10 z'), { fill: Color4.red }), ]); editor.dispatch(EditorImage.addElement(stroke));
Dispatches a command without announcing it. By default, does not add to history.
Use this to show finalized commands that don't need to have announceForAccessibility
called.
If addToHistory
is false
, this is equivalent to command.apply(editor)
.
Draws the given path onto the wet ink renderer. The given path will be displayed on top of the main image.
Rest
...path: RenderablePathSpec[]a shallow copy of the current settings of the editor.
Do not modify.
Adds event listners for keypresses (and drop events) on elem
and forwards those
events to the editor.
If the given filter
returns false
for an event, the event is ignored and not
passed to the editor.
Like handlePointerEventsFrom except ignores short input gestures like clicks.
filter
is called once per event, before doing any other processing. If filter
returns true
the event is
forwarded to the editor.
otherEventsFilter
is passed unmodified to handlePointerEventsFrom
.
Optional
filter: HTMLPointerEventFilterOptional
otherEventsFilter: ((eventName: string, event: Event) => boolean)Remove all event listeners registered by this function.
Forward pointer events from elem
to this editor. Such that right-click/right-click drag
events are also forwarded, elem
's contextmenu is disabled.
filter
is called once per pointer event, before doing any other processing. If filter
returns true
the event is
forwarded to the editor.
Note: otherEventsFilter
is like filter
, but is called for other pointer-related
events that could also be forwarded to the editor. To forward just pointer events,
for example, otherEventsFilter
could be given as ()=>false
.
Optional
filter: HTMLPointerEventFilterOptional
otherEventsFilter: ((eventName: string, event: Event) => boolean)Remove all event listeners registered by this function.
Load editor data from an ImageLoader
(e.g. an SVGLoader).
Alias for loadFrom(SVGLoader.fromString)
.
import {Editor} from 'js-draw'; const editor = new Editor(document.body); ---visible--- await editor.loadFromSVG(` <svg viewBox="5 23 52 30" width="52" height="16" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg"> <text style=" transform: matrix(0.181846, 0.1, 0, 0.181846, 11.4, 33.2); font-family: serif; font-size: 32px; fill: rgb(100, 140, 61); ">An SVG image!</text> </svg> `);
Dispatch a keyboard event to the currently selected tool. Intended for unit testing.
If shiftKey
is undefined, it is guessed from key
.
At present, the key code dispatched is guessed from the given key and, while this works for ASCII alphanumeric characters, this does not work for most non-alphanumeric keys.
Because guessing the key code from key
is problematic, only use this for testing.
Dispatch a pen event to the currently selected tool. Intended primarially for unit tests.
Optional
allPointers: Pointer[]Set the background color of the image.
This is a convenience method for adding or updating the BackgroundComponent for the current image.
This is a convenience method for adding or updating the BackgroundComponent and EditorImage.setAutoresizeEnabled for the current image.
If there are multiple BackgroundComponents in the image, this only modifies the topmost such element.
Example:
import { Editor, Color4, BackgroundComponentBackgroundType } from 'js-draw'; const editor = new Editor(document.body); editor.dispatch(editor.setBackgroundStyle({ color: Color4.orange, type: BackgroundComponentBackgroundType.Grid, autoresize: true, }));
To change the background size, see EditorImage.setImportExportRect.
Optional
autoresize?: booleanOptional
color?: Color4Optional
type?: BackgroundComponentBackgroundTypeGet a data URL (e.g. as produced by HTMLCanvasElement::toDataURL
).
If format
is not image/png
, a PNG image URL may still be returned (as in the
case of HTMLCanvasElement::toDataURL
).
The export resolution is the same as the size of the drawing canvas, unless outputSize
is given.
Example:
import { Editor, ImageComponent, Mat33 } from 'js-draw'; const editor = new Editor(document.body); // // Adding an image // const myHtmlImage = new Image(); myHtmlImage.src = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAQAAAACCAYAAAB/qH1jAAAAKklEQVQIW2Ns022zZGRgfPnz8s8HDQwN/xgZgKBDu0PuL8tf5d8/fz8FAOiDD1H2gfpGAAAAAElFTkSuQmCC'; const rotated45Degrees = Mat33.zRotation(Math.PI / 4); // A 45 degree = pi/4 radian rotation const scaledByFactorOf100 = Mat33.scaling2D(100); // Scale **and** rotate const transform = rotated45Degrees.rightMul(scaledByFactorOf100); const imageComponent = await ImageComponent.fromImage(myHtmlImage, transform); await editor.dispatch(editor.image.addElement(imageComponent)); // // Make a new image from the editor itself (with editor.toDataURL) // const toolbar = editor.addToolbar(); toolbar.addActionButton('From editor', async () => { const dataUrl = editor.toDataURL(); const htmlImage = new Image(); htmlImage.src = dataUrl; const imageComponent = await ImageComponent.fromImage(htmlImage, Mat33.identity); await editor.addAndCenterComponents([ imageComponent ]); });
Optional
outputSize: Vec3Converts the editor's content into an SVG image in an asynchronous, but potentially lossy way.
Warning: If the image is being edited during an async rendering, edited components may not be rendered.
Like toSVG, but can be configured to briefly pause after processing every
pauseAfterCount
items. This can prevent the editor from becoming unresponsive
when saving very large images.
Optional
minOptional
onReturns false to cancel the render. Note that totalToProcess is the total for the currently-being-processed layer.
Optional
pauseNumber of components to process before pausing
The main entrypoint for the full editor.
Example
To create an editor with a toolbar,
See also
examples.md
.