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.
ReadonlyiconsReadonlyimageData 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 addComponentCommand = editor.image.addComponent(stroke);
// Add the stroke to the editor
editor.dispatch(addComponentCommand);
ReadonlynotifierGlobal 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));
ReadonlytoolControls the list of tools. See the custom tool example for more.
ReadonlyviewportAllows 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").
OptionalactionDescription: stringCreates a toolbar. If defaultLayout is true, default buttons are used.
a reference to the toolbar.
Anchors the given element to the canvas with a given position/transformation in canvas space.
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, Path, Color4,
} from 'js-draw';
const editor = new Editor(document.body);
const stroke = Stroke.fromFilled(
	Path.fromString('m0,0 l100,100 l0,-10 z'),
	Color4.red,
);
editor.dispatch(EditorImage.addComponent(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.
a shallow copy of the current settings of the editor.
Do not modify.
Dispatches a PointerEvent to the editor. The target element for evt must have the same top left
as the content of the editor.
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.
Optionalfilter: HTMLPointerEventFilterOptionalotherEventsFilter: (eventName: string, event: Event) => booleanRemove 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.
Optionalfilter: HTMLPointerEventFilterOptionalotherEventsFilter: (eventName: string, event: Event) => booleanRemove 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.
OptionalallPointers: 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.
Get 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.addComponent(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 ]);
});
OptionaloutputSize: 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.
OptionalminDimension?: numberOptionalonProgress?: (Returns false to cancel the render. Note that totalToProcess is the total for the currently-being-processed layer.
OptionalpauseAfterCount?: numberNumber of components to process before pausing
The main entrypoint for the full editor.
Example
To create an editor with a toolbar,
import { Editor } from 'js-draw'; const editor = new Editor(document.body); const toolbar = editor.addToolbar(); toolbar.addSaveButton(() => { const saveData = editor.toSVG().outerHTML; // Do something with saveData... });See also
examples.md.