Migrating to version 1

Version 1 of the js-draw library introduces many new features and several breaking changes. This guide summarizes the breaking API changes and major UI adjustments.

The CSS variables used to customize js-draw's theme have changed.

Comparison between old and new CSS variables

Old CSS variables:

  • --primary-background-color: Background color of the editor, toolbar, and menus
  • --primary-foreground-color: Text/icon color of the content of the toolbar and menus
  • --secondary-background-color: Background color of selected items
  • --secondary-foreground-color: Text/icon color of selected items
  • --primary-shadow-color: Color of shadows

New CSS variables:

  • --background-color-1: Background color of the editor and some dialogs
  • --foreground-color-1: Text/icon color of the editor and some dialogs
  • --background-color-2: Background color of the main toolbar content
  • --foreground-color-2: Text/icon color of the main toolbar content
  • --background-color-3: Background color of action buttons in the toolbar and some toolbar widgets
  • --foreground-color-3: Text/icon color of action buttons in the toolbar
  • --selection-background-color: Background color of selected content
  • --selection-foreground-color: Foreground color of selected content
  • --shadow-color: Color used for shadows
  • --background-color-transparent: A partially-transparent background color used for overlays
  • --primary-action-foreground-color: Color used for inputs/action buttons in the toolbar (e.g. a submit button).

Try the different CSS variables below:

:root .imageEditorContainer {
    /* Used for unselected buttons and dialog text. */
	--background-color-1: white;
	--foreground-color-1: black;

	/* Used for some menu/toolbar backgrounds. */
	--background-color-2: #f5f5f5;
	--foreground-color-2: #2c303a;

	/* Used for other menu/toolbar backgrounds. */
	--background-color-3: #e5e5e5;
	--foreground-color-3: #1c202a;

	/* Used for selected buttons. */
	--selection-background-color: #cbdaf1;
	--selection-foreground-color: #2c303a;

	/* Used for dialog backgrounds */
	--background-color-transparent: rgba(105, 100, 100, 0.5);

	/* Used for shadows */
	--shadow-color: rgba(0, 0, 0, 0.5);

	/* Color used for some button/input foregrounds */
	--primary-action-foreground-color: #15b;
}

---ts---
import { Editor, makeEdgeToolbar, makeDropdownToolbar } from 'js-draw';
import 'js-draw/styles';
import { MaterialIconProvider } from '@js-draw/material-icons';



const makeToolbar = (newToolbar: boolean, editor: Editor) => {
	const toolbar = newToolbar ? makeEdgeToolbar(editor) : makeDropdownToolbar(editor);
	toolbar.addDefaults();

	toolbar.addExitButton(() => {
		alert('Not implemented for this editor!');
	});

	toolbar.addSaveButton(() => {
		const saveData = editor.toSVG().outerHTML;

		// Do something with saveData
		alert('Not implemented for this editor!');
	});

	return toolbar;
};

const makeEditor = async () => {
	const editor = new Editor(document.body, {
		iconProvider: new MaterialIconProvider(),
    	wheelEventsEnabled: 'only-if-focused',
	});

	// Loads from SVG data
	await editor.loadFromSVG(`
		<svg viewBox="0 0 500 500" width="500" height="500" version="1.1" baseProfile="full" xmlns="http://www.w3.org/2000/svg">
			<style id="js-draw-style-sheet">path{stroke-linecap:round;stroke-linejoin:round;}text{white-space:pre;}</style>
			<path d="M500,500L500,0L0,0L0,500L500,500" fill="#e3e3e3" class="js-draw-image-background"></path>
			<text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: sans-serif; font-size: 32px; fill: rgb(0, 0, 0);">Testing...</text>
		</svg>
	`);

	let isNewToolbar = true;
	let toolbar = makeToolbar(isNewToolbar, editor);



	const toolbarSelector = document.createElement('button');
	toolbarSelector.innerText = 'Change toolbar type';
	document.body.appendChild(toolbarSelector);

	toolbarSelector.onclick = () => {
		isNewToolbar = !isNewToolbar;
		toolbar.remove();

		toolbar = makeToolbar(isNewToolbar, editor);
	};
};

makeEditor();

The toolbar added by .addToolbar() has changed. A version of the original toolbar is still available.

This runnable code block shows how to specify which toolbar should be used and how to switch between them:

import {
	Editor, makeEdgeToolbar, makeDropdownToolbar, AbstractToolbar
} from 'js-draw';
import 'js-draw/styles';

// Also use the new icon pack:
import { MaterialIconProvider } from '@js-draw/material-icons';

let toolbar: AbstractToolbar|null = null
let isDropdownToolbar: boolean = true;

const makeToolbar = (editor: Editor) => {
	// Remove the old toolbar (if any).
	if (toolbar) {
		toolbar.remove();
	}

	// Create the new toolbar
	if (isDropdownToolbar) {
		toolbar = makeDropdownToolbar(editor);
	} else {
		toolbar = makeEdgeToolbar(editor);
	}

	// Add the default action buttons to the toolbar
	toolbar.addDefaults();

	// Add a toggle button
	toolbar.addActionButton({
		// An icon that looks similar to an arrow:
		icon: editor.icons.makeDropdownIcon(),
		label: 'Change toolbar type'
	}, () => {
		isDropdownToolbar = !isDropdownToolbar;
		makeToolbar(editor);
	});

	// Optional: Add save/exit buttons:
	// toolbar.addExitButton(() => { });
	// toolbar.addSaveButton(() => { });

	return toolbar;
};

// Creates the edior and adds it to the document
const makeEditor = () => {
	const editor = new Editor(document.body, {
		iconProvider: new MaterialIconProvider(),
    	wheelEventsEnabled: 'only-if-focused',
	});

	makeToolbar(editor);
};

makeEditor();

In summary, the makeDropdownToolbar and makeEdgeToolbar functions can be imported from js-draw to create different types of toolbars.

Even in the dropdown toolbar, the behavior/appearance of many toolbar widgets are different.

The constructor for the PenTool has changed — rather than accepting the pen's default stroke factory as a separate argument, the factory is a part of the style parameter.

The following demo shows how to create a pen tool:

import {
	Editor, PenTool, PenStyle, Color4,
	makeOutlinedCircleBuilder, makeFreehandLineBuilder
} from 'js-draw';
import 'js-draw/styles';

const editor = new Editor(document.body, {
    wheelEventsEnabled: 'only-if-focused',
});

const penStyle: PenStyle = {
	color: Color4.red,
	// Try changing this to makeFreehandLineBuilder
	factory: makeOutlinedCircleBuilder,
	thickness: 4,
};

editor.toolController.addPrimaryTool(
	new PenTool(editor, 'Some description here', penStyle),
);


// Add the toolbar **after** adding the new tool.
editor.addToolbar();

Timestamps attached to events internal to the editor now use performance.now() rather than Date.now(). As such, these timestamps

  • are relative to performance.timeOrigin, not the UNIX epoch
  • are not integers (but are still in milliseconds).
OpenSource licenses