All examples
This page contains an index of all runnable examples in the main documentation. Additional examples can be found on GitHub.
Part of the goal of this page is to easily find broken examples.
Example 1
From page: documents/Guides.Customizing_existing_tools.html
import { Editor, PenTool, Color4 } from 'js-draw'; import 'js-draw/styles'; const editor = new Editor(document.body, { wheelEventsEnabled: 'only-if-focused', }); // The toolbar can be added either before or after changing the tool. editor.addToolbar(); // Get all tools of type PenTool (we could also do this with an EraserTool). const penTools = editor.toolController.getMatchingTools(PenTool); // Get the second pen tool (somewhat fragile -- js-draw might change // the default toolbar configuration in a future major release). const secondPen = penTools[1]; secondPen.setThickness(200); secondPen.setColor(Color4.red);
Example 2
From page: documents/Guides.Customizing_existing_tools.html
import { Editor, PenTool, Color4, makeOutlinedCircleBuilder, } from 'js-draw'; import 'js-draw/styles'; const editor = new Editor(document.body, { wheelEventsEnabled: 'only-if-focused', }); const toolController = editor.toolController; const originalPenTools = toolController.getMatchingTools(PenTool); // Add a new pen after the existing const penStyle: PenStyle = { color: Color4.red, // Draw circles by default factory: makeOutlinedCircleBuilder, thickness: 4, }; const newPen = new PenTool(editor, 'My custom pen', penStyle); // Add after the first pre-existing pen tool toolController.insertToolsAfter(originalPenTools[0], [ newPen ]); // Remove the previous pen tools toolController.removeAndDestroyTools(originalPenTools); // Make the new pen a primary tool -- it disables other primary tools // when the user first enables it (like the default eraser/text tool/pens) toolController.addPrimaryTool(newPen); // Must be done after changing the tools: editor.addToolbar();
Example 3
From page: documents/Guides.Customizing_existing_tools.html
import { Editor, makePolylineBuilder, makeOutlinedCircleBuilder, ComponentBuilderFactory } from 'js-draw'; // A pen factory's job is to return a ComponentBuilder when starting a new stroke. // Below, we randomly choose between a circle ComponentBuilder and a polyline pen ComponentBuilder. // // Parameters: // startPoint - the first point on the stroke. // viewport - information about the current rotation/scale of the drawing canvas. const customPenFactory: ComponentBuilderFactory = (startPoint, viewport) => { // Randomly choose either a polyline or a circle for this stroke. if (Math.random() < 0.5) { return makePolylineBuilder(startPoint, viewport); } else { return makeOutlinedCircleBuilder(startPoint, viewport); } }; const editor = new Editor(document.body, { pens: { // The polyline is already present by default -- additionalPenTypes: [{ name: 'Polyline pen', id: 'custom-polyline', factory: customPenFactory, // The pen doesn't create fixed shapes (e.g. squares, rectangles, etc) // and so should go under the "pens" section. isShapeBuilder: false, }], }, }); editor.addToolbar();
Example 4
From page: documents/Guides.Customizing_existing_tools.html
---use-previous--- ---visible--- import { PenTool } from 'js-draw'; const firstPen = editor.toolController.getMatchingTools(PenTool)[0]; firstPen.setStrokeFactory(customPenFactory);
Example 5
From page: documents/Guides.Customizing_existing_tools.html
import { pathToRenderable, Path, Stroke, ComponentBuilderFactory, Point2, Vec2, Rect2, Color4, Viewport, StrokeDataPoint, RenderingStyle, PathCommandType, ComponentBuilder, AbstractRenderer } from 'js-draw'; /// /// The custom ComponentBuilder /// /// This class handles conversion between input data (for example, as generated /// by a mouse) and AbstractComponents that will be added to the drawing. /// class CustomBuilder implements ComponentBuilder { private path: Path; private renderingStyle: RenderingStyle; private lastPoint: Point2; public constructor( startPoint: StrokeDataPoint, // We'll use sizeOfScreenPixelOnCanvas later, to round points // based on the current zoom level. private sizeOfScreenPixelOnCanvas: number ) { // Round points based on the current zoom to prevent the saved SVG // from having large decimals. const startPosition = this.roundPoint(startPoint.pos); // Initially, just a point: this.path = new Path(startPosition, []); this.renderingStyle = { // No fill fill: Color4.transparent, stroke: { color: startPoint.color, // For now, the custom pen has a constant width based on the first // point. width: startPoint.width, }, }; this.lastPoint = startPosition; } // Returns the bounding box of the stroke drawn so far. This box should contain // all points in the stroke. public getBBox(): Rect2 { return this.path.bbox; } // Called to build the final version of the stroke. public build(): Stroke { return new Stroke([ pathToRenderable(this.path, this.renderingStyle) ]); } // Called while building the stroke. This is separate from .build() to // allow for greater efficiency (.build creates the final version, .preview // can be a fast preview). public preview(renderer: AbstractRenderer) { // For simplicity, use the same final shape as the preview. const stroke = this.build(); stroke.render(renderer); } private roundPoint(point: Point2): Point2 { // Because js-draw supports a very large zoom range, we round differently // at different zoom levels. sizeOfScreenPixelOnCanvas is based on the current zoom level. return Viewport.roundPoint(point, this.sizeOfScreenPixelOnCanvas); } // .addPoint is called when a new point of input data has been received. // newPoint contains color, pressure, and position information. public addPoint(newPoint: StrokeDataPoint) { // Create a new point based on the input data, plus some randomness! const size = newPoint.width * 4; const newPos = newPoint.pos.plus( Vec2.of(Math.random() * size - size/2, Math.random() * size - size/2) ); // Round the point to prevent long decimal values when saving to SVG. const roundedPoint = this.roundPoint(newPos); this.path = new Path(this.path.startPoint, [ ...this.path.parts, { kind: PathCommandType.LineTo, point: roundedPoint, }, ]); } } /// /// The custom ComponentBuilderFactory /// // A ComponentBuilderFactory is responsible for creating instances of a // ComponentBuilder. It's what we'll provide to js-draw. export const makeCustomBuilder: ComponentBuilderFactory = (initialPoint: StrokeDataPoint, viewport: Viewport) => { const sizeOfScreenPixelOnCanvas = viewport.getSizeOfPixelOnCanvas(); return new CustomBuilder(initialPoint, sizeOfScreenPixelOnCanvas); }; /// /// The editor /// import { Editor } from 'js-draw'; const editor = new Editor(document.body, { pens: { additionalPenTypes: [{ name: 'Wavy pen', id: 'wavy-lines', factory: makeCustomBuilder, // Put under the "pens" section. isShapeBuilder: false, }], }, }); editor.addToolbar(); /// /// Select our custom pen by default. /// import { PenTool } from 'js-draw'; const firstPen = editor.toolController.getMatchingTools(PenTool)[0]; firstPen.setStrokeFactory(makeCustomBuilder);
Example 6
From page: documents/Guides.Migrating_to_version_1.html
: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();
Example 7
From page: documents/Guides.Migrating_to_version_1.html
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();
Example 8
From page: documents/Guides.Migrating_to_version_1.html
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();
Example 9
From page: documents/Guides.Positioning_an_element_above_the_editor.html
import { Editor } from 'js-draw'; // Adds the editor to document.body: const editor = new Editor(document.body); // 1 editor.addToolbar();
Example 10
From page: documents/Guides.Positioning_an_element_above_the_editor.html
---use-previous--- ---visible--- const button = document.createElement('button'); button.textContent = 'Example!'; button.style.position = 'absolute';
Example 11
From page: documents/Guides.Positioning_an_element_above_the_editor.html
---use-previous--- ---visible--- import { Mat33, Vec2 } from '@js-draw/math'; const positioning = Mat33.translation(Vec2.of(10, 20)); const anchor = editor.anchorElementToCanvas(button, positioning);
Example 12
From page: documents/Guides.Positioning_an_element_above_the_editor.html
---use-previous--- ---visible--- button.onclick = () => { anchor.remove(); };
Example 13
From page: documents/Guides.Updating_the_viewport.html
import { Editor, Viewport, Mat33 } from 'js-draw'; const editor = new Editor(document.body); // 1 editor.addToolbar(); const command = Viewport.transformBy(Mat33.scaling2D(1/4)); // 2 editor.dispatch(command); // 3
Example 14
From page: documents/Guides.Updating_the_viewport.html
import { Editor, Viewport, Mat33 } from 'js-draw'; const editor = new Editor(document.body); // 1 editor.addToolbar(); ---visible--- const command = Viewport.transformBy(Mat33.scaling2D(1/4)); // 2 editor.dispatch(command, false); // false: Don't add to history // Alternatively, // command.apply(editor);
Example 15
From page: documents/Guides.Updating_the_viewport.html
import { Editor } from 'js-draw'; // Create an editor with a toolbar: const editor = new Editor(document.body); editor.addToolbar();
Example 16
From page: documents/Guides.Updating_the_viewport.html
---use-previous--- ---visible--- import { Color4, BackgroundComponentBackgroundType } from 'js-draw'; editor.dispatch( editor.setBackgroundStyle({ color: Color4.orange, type: BackgroundComponentBackgroundType.Grid, // Make the background autoresize so that it's always // visible: autoresize: true, }), );
Example 17
From page: documents/Guides.Updating_the_viewport.html
---use-previous--- ---visible--- import { Viewport } from 'js-draw'; import { Mat33, Vec2 } from '@js-draw/math'; // When moveLeftUpdate is applied to the viewport, it moves the // viewport to the left by 1 unit. const moveLeftUpdate = Mat33.translation(Vec2.of(-1, 0)); function update() { const moveLeftCommand = Viewport.transformBy(moveLeftUpdate); moveLeftCommand.apply(editor); requestAnimationFrame(update); } update();
Example 18
From page: documents/Guides.Updating_the_viewport.html
import { Editor } from 'js-draw'; import { Color4, BackgroundComponentBackgroundType } from 'js-draw'; const editor = new Editor(document.body); editor.addToolbar(); editor.dispatch( editor.setBackgroundStyle({ color: Color4.orange, type: BackgroundComponentBackgroundType.Grid, autoresize: true, }), ); ---visible--- import { Viewport } from 'js-draw'; import { Mat33, Vec2 } from '@js-draw/math'; let lastTime = performance.now(); function update() { // Get how long many milliseconds have elapsed since the last update. const nowTime = performance.now(); const millisecondsElapsed = nowTime - lastTime; const seconds = millisecondsElapsed / 1000; lastTime = nowTime; const moveLeftRate = -10; // units/second const moveLeftAmount = Vec2.of(moveLeftRate * seconds, 0); const moveLeftUpdate = Mat33.translation(moveLeftAmount); const moveLeftCommand = Viewport.transformBy( moveLeftUpdate ); moveLeftCommand.apply(editor); requestAnimationFrame(update); } update();
Example 19
From page: documents/Guides.Writing_a_theme.html
/* A yellowish theme! */ :root .imageEditorContainer { /* Try changing the below values and clicking run again! */ /* Unselected buttons and dialog text. */ --background-color-1: #ffff77; --foreground-color-1: black; /* Some menu/toolbar backgrounds. */ --background-color-2: #ffff99; --foreground-color-2: #111; /* menu/toolbar backgrounds. */ --background-color-3: #ffffaa; --foreground-color-3: #121100; /* Used for selected buttons. */ --selection-background-color: #9f7; --selection-foreground-color: #00f; /* Used for dialog backgrounds */ --background-color-transparent: rgba(0, 0, 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: #f00; /* Use light mode for controls. */ color-scheme: light; } ---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', }); // Template generated with https://js-draw.web.app/ 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"> <g class="js-draw-image-background js-draw-image-background-grid js-draw-image-background-grid-25"> <path d="M500,500L500,0L0,0L0,500L500,500" fill="#f1ffa4"></path> <path d="M0,0L500,0M0,25L500,25M0,50L500,50M0,75L500,75M0,100L500,100M0,125L500,125M0,150L500,150M0,175L500,175M0,200L500,200M0,225L500,225M0,250L500,250M0,275L500,275M0,300L500,300M0,325L500,325M0,350L500,350M0,375L500,375M0,400L500,400M0,425L500,425M0,450L500,450M0,475L500,475M0,500L500,500M0,0L0,500M25,0L25,500M50,0L50,500M75,0L75,500M100,0L100,500M125,0L125,500M150,0L150,500M175,0L175,500M200,0L200,500M225,0L225,500M250,0L250,500M275,0L275,500M300,0L300,500M325,0L325,500M350,0L350,500M375,0L375,500M400,0L400,500M425,0L425,500M450,0L450,500M475,0L475,500M500,0L500,500" fill="none" stroke="#0e005b33" stroke-width=".7"></path> </g> </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();
Example 20
From page: modules/js-draw.html
import { Editor, Vec3, Mat33, EditorSettings, ShortcutManager } from 'js-draw'; // Use the Material Icon pack. import { MaterialIconProvider } from '@js-draw/material-icons'; // Apply js-draw CSS import 'js-draw/styles'; // If your bundler doesn't support the above, try // import 'js-draw/bundledStyles'; (async () => { // All settings are optional! Try commenting them out. const settings: EditorSettings = { // Use a non-default set of icons iconProvider: new MaterialIconProvider(), // Only capture mouse wheel events if the editor has focus. This is useful // when the editor is part of a larger, scrolling page. wheelEventsEnabled: 'only-if-focused', }; // Create the editor! const editor = new Editor(document.body, settings); // Adds the defualt toolbar const toolbar = editor.addToolbar(); // Increases the minimum height of the editor editor.getRootElement().style.height = '600px'; // 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" > <path d="M500,500L500,0L0,0L0,500L500,500" fill="#aaa" class="js-draw-image-background" /> <text style="transform: matrix(1, 0, 0, 1, 57, 192); font-family: serif; font-size: 32px; fill: #111;" >Testing...</text> </svg> `); // Adding tags to a toolbar button allows different styles to be applied. // Also see addActionButton. toolbar.addSaveButton(() => { const saveData = editor.toSVG().outerHTML; // Do something with saveData alert('Saved data!\n\n' + saveData); }); toolbar.addExitButton(() => { // Save/confirm exiting here? editor.remove(); }); })();
Example 21
From page: modules/js-draw.html
import { Editor, RenderingStyle, Erase, Stroke, pathToRenderable } from 'js-draw'; import { Path, Color4, Point2, Vec2, Rect2 } from '@js-draw/math'; const editor = new Editor(document.body); // //////////////// // // Helper functions // // //////////////// // function addStroke(path: Path, style: RenderingStyle) { const stroke = new Stroke([ pathToRenderable(path, style) ]); // Create a command that adds the stroke to the image // (but don't apply it yet). const command = editor.image.addElement(stroke); // Actually apply the command. editor.dispatch(command); } function addBoxAt(point: Point2, color: Color4) { // Create a 10x10 square at the given point: const box = new Rect2(point.x, point.y, 10, 10); addStroke( Path.fromRect(box), { fill: color }, ); } function makeTrashIcon() { const container = document.createElement('div'); container.textContent = '🗑️'; return container; } // //////////////////// // // End helper functions // // //////////////////// // // Add some components to the image: addBoxAt(Vec2.of(0, 0), Color4.green); addBoxAt(Vec2.of(20, 0), Color4.orange); addBoxAt(Vec2.of(20, 20), Color4.blue); // Get the components in a small rectangle near (0, 0) const components = editor.image.getElementsIntersectingRegion( new Rect2(0, 0, 5, 5), // a 5x5 square with top left (0, 0) ); // Add a button that removes the components const toolbar = editor.addToolbar(); toolbar.addActionButton({ icon: makeTrashIcon(), label: 'remove near (0,0)', }, () => { const deleteCommand = new Erase(components); editor.dispatch(deleteCommand); });
Example 22
From page: classes/js-draw.AbstractToolbar.html
import { Editor } from 'js-draw'; const editor = new Editor(document.body); const toolbar = editor.addToolbar(); function makeTrashIcon() { const container = document.createElement('div'); container.textContent = '🗑️'; return container; } toolbar.addActionButton({ icon: makeTrashIcon(), // can be any Element not in the DOM label: 'Delete all', }, () => { alert('to-do!');
Example 23
From page: classes/js-draw.AbstractToolbar.html
import { Editor, makeDropdownToolbar } from 'js-draw'; const editor = new Editor(document.body); const toolbar = makeDropdownToolbar(editor); toolbar.addDefaults(); toolbar.addSaveButton(() => alert('save clicked!'));
Example 24
From page: classes/js-draw.CanvasRenderer.html
import {Editor,CanvasRenderer} from 'js-draw'; // Create an editor and load initial data -- don't add to the body (hidden editor). const editor = new Editor(document.createElement('div')); await editor.loadFromSVG('<svg><path d="m0,0 l100,5 l-50,60 l30,20 z" fill="green"/></svg>'); ---visible--- // Given some editor. // Set up the canvas to be drawn onto. const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // Ensure that the canvas can fit the entire rendering const viewport = editor.image.getImportExportViewport(); canvas.width = viewport.getScreenRectSize().x; canvas.height = viewport.getScreenRectSize().y; // Render editor.image onto the renderer const renderer = new CanvasRenderer(ctx, viewport); editor.image.render(renderer, viewport); // Add the rendered canvas to the document. document.body.appendChild(canvas);
Example 25
From page: classes/js-draw.Editor.html
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... });
Example 26
From page: classes/js-draw.Editor.html
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 });
Example 27
From page: classes/js-draw.Editor.html
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);
Example 28
From page: classes/js-draw.Editor.html
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));
Example 29
From page: classes/js-draw.Editor.html
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));
Example 30
From page: classes/js-draw.Editor.html
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> `);
Example 31
From page: classes/js-draw.Editor.html
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, }));
Example 32
From page: classes/js-draw.Editor.html
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 ]); });
Example 33
From page: classes/js-draw.EditorImage.html
import {Editor,CanvasRenderer} from 'js-draw'; // Create an editor and load initial data -- don't add to the body (hidden editor). const editor = new Editor(document.createElement('div')); await editor.loadFromSVG('<svg><path d="m0,0 l100,5 l-50,60 l30,20 z" fill="green"/></svg>'); ---visible--- // Given some editor. // Set up the canvas to be drawn onto. const canvas = document.createElement('canvas'); const ctx = canvas.getContext('2d'); // Ensure that the canvas can fit the entire rendering const viewport = editor.image.getImportExportViewport(); canvas.width = viewport.getScreenRectSize().x; canvas.height = viewport.getScreenRectSize().y; // Render editor.image onto the renderer const renderer = new CanvasRenderer(ctx, viewport); editor.image.render(renderer, viewport); // Add the rendered canvas to the document. document.body.appendChild(canvas);
Example 34
From page: classes/js-draw.EditorImage.html
import { Editor } from 'js-draw'; const editor = new Editor(document.body); const toolbar = editor.addToolbar(); // Add a save button to demonstrate what the output looks like // (it should change size to fit whatever was drawn) toolbar.addSaveButton(() => { document.body.replaceChildren(editor.toSVG({ sanitize: true })); }); // Actually using setAutoresizeEnabled: // // To set autoresize without announcing for accessibility/making undoable const addToHistory = false; editor.dispatchNoAnnounce(editor.image.setAutoresizeEnabled(true), addToHistory); // Add to undo history **and** announce for accessibility //editor.dispatch(editor.image.setAutoresizeEnabled(true), true);
Example 35
From page: classes/js-draw.EditorImage.html
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));
Example 36
From page: classes/js-draw.Erase.html
import { Editor, Erase, uniteCommands, Color4, Path, Stroke, Rect2, pathToRenderable } from 'js-draw'; const editor = new Editor(document.body); editor.addToolbar(); // Add a large number of strokes const commands = []; for (let x = -20; x < 20; x++) { for (let y = 0; y < 60; y++) { const stroke = new Stroke([ pathToRenderable( Path.fromString(`m${x * 5},${y * 5}l1,1`), { fill: Color4.transparent, stroke: {width: 2, color: Color4.ofRGB(x / 10, y / 10, 0.5)}} ) ]); commands.push(editor.image.addElement(stroke)); } } await editor.dispatch(uniteCommands(commands, 100)); ---visible--- // Given some editor... // Find all elements intersecting the rectangle with top left (-10,-30) and // (width,height)=(50,100). const elems = editor.image.getElementsIntersectingRegion( new Rect2(-10, -30, 50, 100) ); // Create a command that erases [elems] when applied const eraseElemsCmd = new Erase(elems); // Apply the command (and make it undoable) editor.dispatch(eraseElemsCmd);
Example 37
From page: classes/js-draw.IconProvider.html
import * as jsdraw from 'js-draw'; class CustomIconProvider extends jsdraw.IconProvider { // Use '☺' instead of the default dropdown symbol. public override makeDropdownIcon() { const icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg'); icon.innerHTML = ` <text x='5' y='55' style='fill: var(--icon-color); font-size: 50pt;'>☺</text> `; icon.setAttribute('viewBox', '0 0 100 100'); return icon; } } const icons = new CustomIconProvider(); const editor = new jsdraw.Editor(document.body, { // The icon pack to use is specified through the editor's initial // configuration object: iconProvider: icons, }); // Add a toolbar that uses these icons jsdraw.makeDropdownToolbar(editor).addDefaults();
Example 38
From page: classes/js-draw.ImageComponent.html
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 ]); });
Example 39
From page: classes/js-draw.InsertImageWidget.html
import { Editor, makeEdgeToolbar, InsertImageWidget } from 'js-draw'; const editor = new Editor(document.body); const toolbar = makeEdgeToolbar(editor); toolbar.addWidget(new InsertImageWidget(editor));
Example 40
From page: classes/js-draw.PanZoomTool.html
import { Editor, PanZoomTool, PanZoomMode } from 'js-draw'; const editor = new Editor(document.body); // By default, there are multiple PanZoom tools that handle different events. // This gets all PanZoomTools. const panZoomToolList = editor.toolController.getMatchingTools(PanZoomTool); // The first PanZoomTool is the highest priority -- by default, // this tool is responsible for handling multi-finger touch gestures. // // Lower-priority PanZoomTools handle one-finger touch gestures and // key-presses. const panZoomTool = panZoomToolList[0]; // Lock rotation for multi-finger touch gestures. panZoomTool.setModeEnabled(PanZoomMode.RotationLocked, true);
Example 41
From page: classes/js-draw.PenTool.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 42
From page: classes/js-draw.Stroke.html
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));
Example 43
From page: classes/js-draw.TextComponent.html
import { Editor, TextComponent, Mat33, Vec2, Color4, TextRenderingStyle } from 'js-draw'; const editor = new Editor(document.body); editor.dispatch(editor.setBackgroundStyle({ color: Color4.black, autoresize: true )); ---visible--- /// Adding a simple TextComponent ///------------------------------ const positioning1 = Mat33.translation(Vec2.of(10, 10)); const style: TextRenderingStyle = { fontFamily: 'sans', size: 12, renderingStyle: { fill: Color4.green }, }; editor.dispatch( editor.image.addElement(new TextComponent(['Hello, world'], positioning1, style)), ); /// Adding nested TextComponents ///----------------------------- // Add another TextComponent that contains text and a TextComponent. Observe that '[Test]' // is placed directly after 'Test'. const positioning2 = Mat33.translation(Vec2.of(10, 50)); editor.dispatch( editor.image.addElement( new TextComponent([ new TextComponent(['Test'], positioning1, style), '[Test]' ], positioning2, style) ), );
Example 44
From page: interfaces/js-draw.EditorSettings.html
import { EditorSettings, Editor, KeyBinding, makeEdgeToolbar } from 'js-draw'; import { MaterialIconProvider } from '@js-draw/material-icons'; // All settings are optional! Try commenting them out. const settings: EditorSettings = { // Use a non-default set of icons iconProvider: new MaterialIconProvider(), // Only capture mouse wheel events if the editor has focus. This is useful // when the editor is part of a larger, scrolling page. wheelEventsEnabled: 'only-if-focused', // The default minimum zoom is 2e-10... minZoom: 2e-10, // and the maximum default zoom is 1e12 maxZoom: 1e12, // Override some keyboard shortcuts! keyboardShortcutOverrides: { // The ID for the save action 'jsdraw.toolbar.SaveActionWidget.save': [ // "Meta" = the command key on MacOS KeyBinding.fromString('ctrlOrMeta+s'), // Also map ctrl+M to save! KeyBinding.fromString('ctrl+m'), ], }, }; // Create the editor! const editor = new Editor(document.body, settings); // Selects a specific toolbar type. See also makeDropdownToolbar const toolbar = makeEdgeToolbar(editor); toolbar.addDefaults(); // Add the action button that is triggered by the save keyboard shortcuts above. toolbar.addSaveButton(() => { const saveData = editor.toSVG().outerHTML; // Do something with saveData alert('Saved data:\n\n' + saveData); });
Example 45
From page: interfaces/js-draw.EditorSettings.html
import { Editor, makePolylineBuilder } from 'js-draw'; const editor = new Editor(document.body, { pens: { additionalPenTypes: [{ name: 'Polyline (For debugging)', id: 'custom-polyline', factory: makePolylineBuilder, // The pen doesn't create fixed shapes (e.g. squares, rectangles, etc) // and so should go under the "pens" section. isShapeBuilder: false, }], }, }); editor.addToolbar();
Example 46
From page: interfaces/js-draw.EditorSettings.html
import {Editor} from 'js-draw'; const editor = new Editor(document.body, { // Only allow selecting the polyline pen from the toolbar. pens: { filterPenTypes: p => p.id === 'polyline-pen' }, }); editor.addToolbar();
Example 47
From page: functions/js-draw.adjustEditorThemeForContrast.html
import { Editor, adjustEditorThemeForContrast } from 'js-draw'; const editor = new Editor(document.body); editor.addToolbar(); const css = ` :root .imageEditorContainer { --background-color-1: #ffff77; --foreground-color-1: #fff; --background-color-2: #ffff99; --foreground-color-2: #ffff88; --background-color-3: #ddffff; --foreground-color-3: #eeffff; --selection-background-color: #9f7; --selection-foreground-color: #98f; } @media screen and (prefers-color-scheme: dark) { :root .imageEditorContainer { --background-color-1: black; } } `; editor.addStyleSheet(css); adjustEditorThemeForContrast(editor); // Because adjustEditorThemeForContrast overrides the current theme, it should be called again // to allow the editor to switch between light/dark themes. window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', () => { adjustEditorThemeForContrast(editor); }); window.matchMedia('print').addEventListener('change', () => { adjustEditorThemeForContrast(editor); });
Example 48
From page: functions/js-draw.makeArrowBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 49
From page: functions/js-draw.makeDropdownToolbar.html
import { makeDropdownToolbar, Editor } from 'js-draw'; const editor = new Editor(document.body); const toolbar = makeDropdownToolbar(editor); toolbar.addDefaults(); toolbar.addExitButton(editor => { // TODO }); toolbar.addSaveButton(editor => { // TODO });
Example 50
From page: functions/js-draw.makeEdgeToolbar.html
import { makeEdgeToolbar, Editor } from 'js-draw'; const editor = new Editor(document.body); const toolbar = makeEdgeToolbar(editor); toolbar.addDefaults(); toolbar.addSaveButton(editor => { // TODO }); toolbar.addExitButton(editor => { // TODO });
Example 51
From page: functions/js-draw.makeFilledRectangleBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 52
From page: functions/js-draw.makeFreehandLineBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 53
From page: functions/js-draw.makeLineBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 54
From page: functions/js-draw.makeOutlinedCircleBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 55
From page: functions/js-draw.makeOutlinedRectangleBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 56
From page: functions/js-draw.makePolylineBuilder.html
import { Editor, PenTool, makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, InputEvtType, sendPenEvent, } from 'js-draw'; import { Color4, Vec2 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Different pen types that build strokes in different ways. This is a list of some of the // default ones: const strokeBuilders = [ makePolylineBuilder, makeOutlinedCircleBuilder, makeOutlinedRectangleBuilder, makeArrowBuilder, makePressureSensitiveFreehandLineBuilder, makeFreehandLineBuilder, ]; // Get the first pen const pen = editor.toolController.getMatchingTools(PenTool)[0]; // If using a different pen (e.g. the second), be sure to select it! // pen.setEnabled(true); // Draw something with each style for (const factory of strokeBuilders) { // Make the pen use a certain style. pen.setStrokeFactory(factory); // What happens if the following line is uncommented? // pen.setStrokeFactory(makeArrowBuilder); // Select a random pen color const penColor = Color4.ofRGB(Math.random(), Math.random(), Math.random()); pen.setColor(penColor); // Draw something! const imageSize = editor.getImportExportRect().size; const startPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); const endPos = Vec2.of(Math.random() * imageSize.x, Math.random() * imageSize.y); sendPenEvent(editor, InputEvtType.PointerDownEvt, startPos); sendPenEvent(editor, InputEvtType.PointerMoveEvt, startPos.lerp(endPos, 0.5)); sendPenEvent(editor, InputEvtType.PointerUpEvt, endPos); }
Example 57
From page: functions/js-draw.uniteCommands.html
import { Editor, pathToRenderable, Stroke, uniteCommands } from 'js-draw'; import { Path, Color4 } from '@js-draw/math'; const editor = new Editor(document.body); editor.addToolbar(); // Create strokes! const strokes = []; for (let i = 0; i < 10; i++) { const renderablePath = pathToRenderable( Path.fromString(`M0,${i * 10} L100,100 L300,30 z`), { fill: Color4.transparent, stroke: { color: Color4.red, width: 1, } } ); strokes.push(new Stroke([ renderablePath ])); } // Convert to commands const addStrokesCommands = strokes.map(stroke => editor.image.addElement(stroke)); // Apply all as a single undoable command (try applying each in a loop instead!) await editor.dispatch(uniteCommands(addStrokesCommands)); // The second parameter to uniteCommands is for very large numbers of commands, when // applying them shouldn't be done all at once (which would block the UI). // The second parameter to uniteCommands is for very large numbers of commands, when // applying them shouldn't be done all at once (which would block the UI).
Example 58
From page: modules/_js-draw_material-icons.html
import { Editor, makeEdgeToolbar } from 'js-draw'; import { MaterialIconProvider } from '@js-draw/material-icons'; // Apply js-draw CSS import 'js-draw/styles'; const editor = new Editor(document.body, { iconProvider: new MaterialIconProvider(), }); // Ensure that there is enough room for the toolbar editor.getRootElement().style.minHeight = '500px'; // Add a toolbar const toolbar = makeEdgeToolbar(editor); // ...with the default elements toolbar.addDefaults();
Example 59
From page: functions/_js-draw_material-icons.makeMaterialIconProviderClass.html
import * as jsdraw from 'js-draw'; import { makeMaterialIconProviderClass } from '@js-draw/material-icons'; const MaterialIconProvider = makeMaterialIconProviderClass(jsdraw); (new jsdraw.Editor( document.body, { iconProvider: new MaterialIconProvider() }, )).addToolbar();
Example 60
From page: modules/_js-draw_math.html
import { Vec2, Mat33, Rect2 } from '@js-draw/math'; // Example: Rotate a vector 90 degrees about the z-axis const rotate90Degrees = Mat33.zRotation(Math.PI/2); // π/2 radians = 90 deg const moveUp = Mat33.translation(Vec2.of(1, 0)); const moveUpThenRotate = rotate90Degrees.rightMul(moveUp); console.log(moveUpThenRotate.transformVec2(Vec2.of(1, 2))); // Example: Bounding box of some points console.log(Rect2.bboxOf([ Vec2.of(1, 2), Vec2.of(3, 4), Vec2.of(-100, 1000), ]));
Example 61
From page: modules/_js-draw_math.Vec2.html
import { Vec2 } from '@js-draw/math'; const v = Vec2.of(1, 2); console.log('a Vec2:', v); console.log('x component:', v.x); console.log('z component:', v.z);
Example 62
From page: functions/_js-draw_math.Vec2.of.html
import { Vec2 } from '@js-draw/math'; const v = Vec2.of(3, 4); // x=3, y=4.
Example 63
From page: functions/_js-draw_math.Vec2.ofXY.html
import { Vec2 } from '@js-draw/math'; const v1 = Vec2.ofXY({ x: 3, y: 4.5 }); const v2 = Vec2.ofXY({ x: -123.4, y: 1 });
Example 64
From page: functions/_js-draw_math.Vec3.of.html
import { Vec3 } from '@js-draw/math'; const v1 = Vec3.of(1, 2, 3); console.log(v1.plus(Vec3.of(0, 100, 0)));
Example 65
From page: classes/_js-draw_math.Color4.html
import { Color4 } from '@js-draw/math'; console.log('Red:', Color4.fromString('#f00')); console.log('Also red:', Color4.ofRGB(1, 0, 0), Color4.red); console.log('Mixing red and blue:', Color4.red.mix(Color4.blue, 0.5)); console.log('To string:', Color4.orange.toHexString());
Example 66
From page: classes/_js-draw_math.Color4.html
import { Color4 } from '@js-draw/math'; console.log(Color4.fromHex('#ff0'));
Example 67
From page: classes/_js-draw_math.LineSegment2.html
import {LineSegment2, Vec2} from '@js-draw/math'; const l = new LineSegment2(Vec2.of(1, 1), Vec2.of(2, 2)); console.log('length: ', l.length); console.log('direction: ', l.direction); console.log('bounding box: ', l.bbox);
Example 68
From page: classes/_js-draw_math.LineSegment2.html
import {LineSegment2, Vec2} from '@js-draw/math'; console.log(LineSegment2.ofSmallestContainingPoints([Vec2.of(1, 0), Vec2.of(0, 1)]));
Example 69
From page: classes/_js-draw_math.Mat33.html
import {Mat33, Vec2} from '@js-draw/math'; const moveLeftAndUp = Mat33.translation(Vec2.of(5, 6)); console.log(moveLeftAndUp);
Example 70
From page: classes/_js-draw_math.Mat33.html
---use-previous--- ---visible--- console.log(moveLeftAndUp.transformVec2(Vec2.of(1, 1))); console.log(moveLeftAndUp.transformVec2(Vec2.of(-1, 2)));
Example 71
From page: classes/_js-draw_math.Mat33.html
---use-previous--- ---visible--- // Create a matrix by right multiplying. const scaleThenRotate = // The resultant matrix first scales by a factor of two Mat33.scaling2D(2).rightMul( // ...then rotates by pi/2 radians = 90 degrees. Mat33.zRotation(Math.PI / 2) ); console.log(scaleThenRotate); // Use scaleThenRotate to scale then rotate a vector. console.log(scaleThenRotate.transformVec2(Vec2.unitX));
Example 72
From page: classes/_js-draw_math.Mat33.html
import {Mat33, Vec2} from '@js-draw/math'; console.log(Mat33.identity.rightMul(Mat33.identity)); // Create a matrix by right multiplying. const scaleThenRotate = // The resultant matrix first scales by a factor of two Mat33.scaling2D(2).rightMul( // ...then rotates by pi/4 radians = 45 degrees. Mat33.zRotation(Math.PI / 4) ); console.log(scaleThenRotate); // Use scaleThenRotate to scale then rotate a vector. console.log(scaleThenRotate.transformVec2(Vec2.unitX));
Example 73
From page: classes/_js-draw_math.Mat33.html
import { Mat33 } from '@js-draw/math'; console.log( new Mat33( 1, 2, 3, 4, 5, 6, 7, 8, 9, ) );
Example 74
From page: classes/_js-draw_math.Mat33.html
import { Mat33 } from '@js-draw/math'; console.log(Mat33.identity.toString());
Example 75
From page: classes/_js-draw_math.Mat33.html
import { Mat33, Vec2 } from '@js-draw/math'; const halfCircle = Math.PI; // PI radians = 180 degrees = 1/2 circle const center = Vec2.of(1, 1); // The point (1,1) const rotationMatrix = Mat33.zRotation(halfCircle, center); console.log( 'Rotating (0,0) 180deg about', center, 'results in', // Rotates (0,0) rotationMatrix.transformVec2(Vec2.zero), );
Example 76
From page: classes/_js-draw_math.Path.html
import {Path, Mat33, Vec2, LineSegment2} from '@js-draw/math'; // Creates a path from an SVG path string. // In this case, // 1. Move to (0,0) // 2. Line to (100,0) const path = Path.fromString('M0,0 L100,0'); // Logs the distance from (10,0) to the curve 1 unit // away from path. This curve forms a stroke with the path at // its center. const strokeRadius = 1; console.log(path.signedDistance(Vec2.of(10,0), strokeRadius)); // Log a version of the path that's scaled by a factor of 4. console.log(path.transformedBy(Mat33.scaling2D(4)).toString()); // Log all intersections of a stroked version of the path with // a vertical line segment. // (Try removing the `strokeRadius` parameter). const segment = new LineSegment2(Vec2.of(5, -100), Vec2.of(5, 100)); console.log(path.intersection(segment, strokeRadius).map(i => i.point));
Example 77
From page: classes/_js-draw_math.Path.html
import {Path} from '@js-draw/math'; console.log(Path.fromString('m0,0l1,1').reversed()); // -> M1,1 L0,0
Example 78
From page: classes/_js-draw_math.Path.html
import {Path, Vec2} from '@js-draw/math'; console.log(Path.fromString('m0,0 L100,0').signedDistance(Vec2.zero, 1));
Example 79
From page: classes/_js-draw_math.Path.html
import { Path } from '@js-draw/math'; const path = Path.fromString('m0,0l100,100'); console.log(path.toString(true)); // true: Prefer relative to absolute path commands
Example 80
From page: classes/_js-draw_math.QuadraticBezier.html
import { QuadraticBezier, Vec2 } from '@js-draw/math'; const startPoint = Vec2.of(4, 3); const controlPoint = Vec2.of(1, 1); const endPoint = Vec2.of(1, 3); const curve = new QuadraticBezier( startPoint, controlPoint, endPoint, ); console.log('Curve:', curve);
Example 81
From page: classes/_js-draw_math.Rect2.html
import { Rect2, Vec2 } from '@js-draw/math'; const rect = Rect2.fromCorners( Vec2.of(0, 0), Vec2.of(10, 10), ); console.log('area', rect.area); console.log('topLeft', rect.topLeft);
Example 82
From page: interfaces/_js-draw_math.Vec3-1.html
import { Vec3 } from '@js-draw/math'; console.log('Vector addition:', Vec3.of(1, 2, 3).plus(Vec3.of(0, 1, 0))); console.log('Scalar multiplication:', Vec3.of(1, 2, 3).times(2)); console.log('Cross products:', Vec3.unitX.cross(Vec3.unitY)); console.log('Magnitude:', Vec3.of(1, 2, 3).length(), 'or', Vec3.of(1, 2, 3).magnitude()); console.log('Square Magnitude:', Vec3.of(1, 2, 3).magnitudeSquared()); console.log('As an array:', Vec3.unitZ.asArray());
Example 83
From page: interfaces/_js-draw_math.Vec3-1.html
import { Vec2 } from '@js-draw/math'; console.log(Vec2.of(-1, -0).angle()); // atan2(-0, -1) console.log(Vec2.of(-1, 0).angle()); // atan2(0, -1)
Example 84
From page: interfaces/_js-draw_math.Vec3-1.html
import { Vec3 } from '@js-draw/math'; console.log(Vec3.of(1, 2, 3).map(val => val + 1)); // → Vec(2, 3, 4)
Example 85
From page: interfaces/_js-draw_math.Vec3-1.html
import { Vec3 } from '@js-draw/math'; console.log(Vec3.of(-1, -10, 8).maximumEntryMagnitude()); // -> 10
Example 86
From page: functions/_js-draw_math.toRoundedString.html
import { toRoundedString } from '@js-draw/math'; console.log('Rounded: ', toRoundedString(1.000000011));