Socket
Socket
Sign inDemoInstall

js-draw

Package Overview
Dependencies
Maintainers
1
Versions
117
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

js-draw - npm Package Compare versions

Comparing version 0.2.3 to 0.3.0

dist/src/toolbar/lib.d.ts

4

CHANGELOG.md

@@ -0,1 +1,5 @@

# 0.3.0
* Pen-related bug fixes
* API: Allow creating custom tools and tool widgets.
# 0.2.3

@@ -2,0 +6,0 @@ * Fix lines with thickness set to small numbers self-intersecting many times.

2

dist/src/components/builders/FreehandLineBuilder.js

@@ -126,3 +126,3 @@ import { Bezier } from 'bezier-js';

roundPoint(point) {
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth);
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth / 2);
if (minFit < 1e-10) {

@@ -129,0 +129,0 @@ minFit = this.minFitAllowed;

@@ -0,1 +1,3 @@

export * from './builders/types';
export { makeFreehandLineBuilder } from './builders/FreehandLineBuilder';
import AbstractComponent from './AbstractComponent';

@@ -2,0 +4,0 @@ import Stroke from './Stroke';

@@ -0,1 +1,3 @@

export * from './builders/types';
export { makeFreehandLineBuilder } from './builders/FreehandLineBuilder';
import AbstractComponent from './AbstractComponent';

@@ -2,0 +4,0 @@ import Stroke from './Stroke';

@@ -305,3 +305,2 @@ var _a;

render(renderer, visibleRect) {
// Don't render components that are < 0.1% of the viewport.
const leaves = this.getLeavesIntersectingRegion(visibleRect, rect => renderer.isTooSmallToRender(rect));

@@ -308,0 +307,0 @@ sortLeavesByZIndex(leaves);

@@ -16,3 +16,4 @@ /**

import Editor from './Editor';
export { EditorEventType } from './types';
export { default as EditorImage } from './EditorImage';
export * from './types';
export { default as getLocalizationTable } from './localizations/getLocalizationTable';

@@ -24,4 +25,7 @@ export * from './localization';

export * from './commands/lib';
export * from './tools/lib';
export * from './toolbar/lib';
export { default as Pointer, PointerDevice } from './Pointer';
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
export { Editor };
export default Editor;

@@ -16,3 +16,4 @@ /**

import Editor from './Editor';
export { EditorEventType } from './types';
export { default as EditorImage } from './EditorImage';
export * from './types';
export { default as getLocalizationTable } from './localizations/getLocalizationTable';

@@ -24,4 +25,7 @@ export * from './localization';

export * from './commands/lib';
export * from './tools/lib';
export * from './toolbar/lib';
export { default as Pointer, PointerDevice } from './Pointer';
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';
export { Editor };
export default Editor;

@@ -180,5 +180,6 @@ // A cache record with sub-nodes.

// Determine whether we already have rendered the items
const tooSmallToRender = (rect) => rect.w / this.region.w < 1 / this.cacheState.props.blockResolution.x;
const leaves = [];
for (const item of items) {
leaves.push(...item.getLeavesIntersectingRegion(this.region, rect => rect.w / this.region.w < 2 / this.cacheState.props.blockResolution.x));
leaves.push(...item.getLeavesIntersectingRegion(this.region, tooSmallToRender));
}

@@ -185,0 +186,0 @@ sortLeavesByZIndex(leaves);

@@ -74,4 +74,4 @@ /**

blockResolution: cacheBlockResolution,
cacheSize: 500 * 500 * 4 * 150,
maxScale: 1.5,
cacheSize: 600 * 600 * 4 * 120,
maxScale: 1.4,
minComponentsPerCache: 45,

@@ -78,0 +78,0 @@ minComponentsToUseCache: 105,

@@ -40,10 +40,10 @@ import Color4 from '../../Color4';

if (draftMode) {
this.minSquareCurveApproxDist = 64;
this.minRenderSizeBothDimens = 8;
this.minRenderSizeAnyDimen = 2;
this.minSquareCurveApproxDist = 9;
this.minRenderSizeBothDimens = 2;
this.minRenderSizeAnyDimen = 0.5;
}
else {
this.minSquareCurveApproxDist = 1;
this.minRenderSizeBothDimens = 0.5;
this.minRenderSizeAnyDimen = 0;
this.minSquareCurveApproxDist = 0.5;
this.minRenderSizeBothDimens = 0.3;
this.minRenderSizeAnyDimen = 1e-5;
}

@@ -50,0 +50,0 @@ }

import Editor from '../Editor';
import { ToolbarLocalization } from './localization';
import { ActionButtonIcon } from './types';
import BaseWidget from './widgets/BaseWidget';
export declare const toolbarCSSPrefix = "toolbar-";

@@ -10,8 +11,10 @@ export default class HTMLToolbar {

private static colorisStarted;
private updateColoris;
constructor(editor: Editor, parent: HTMLElement, localizationTable?: ToolbarLocalization);
setupColorPickers(): void;
addWidget(widget: BaseWidget): void;
addActionButton(title: string | ActionButtonIcon, command: () => void, parent?: Element): HTMLButtonElement;
private addUndoRedoButtons;
addUndoRedoButtons(): void;
addDefaultToolWidgets(): void;
addDefaultActionButtons(): void;
}

@@ -1,7 +0,4 @@

import { ToolType } from '../tools/ToolController';
import { EditorEventType } from '../types';
import { coloris, init as colorisInit } from '@melloware/coloris';
import Color4 from '../Color4';
import Pen from '../tools/Pen';
import Eraser from '../tools/Eraser';
import SelectionTool from '../tools/SelectionTool';

@@ -12,7 +9,8 @@ import { defaultToolbarLocalization } from './localization';

import TextTool from '../tools/TextTool';
import PenWidget from './widgets/PenWidget';
import EraserWidget from './widgets/EraserWidget';
import { SelectionWidget } from './widgets/SelectionWidget';
import PenToolWidget from './widgets/PenToolWidget';
import EraserWidget from './widgets/EraserToolWidget';
import SelectionToolWidget from './widgets/SelectionToolWidget';
import TextToolWidget from './widgets/TextToolWidget';
import HandToolWidget from './widgets/HandToolWidget';
import { EraserTool, PenTool } from '../tools/lib';
export const toolbarCSSPrefix = 'toolbar-';

@@ -23,2 +21,3 @@ export default class HTMLToolbar {

this.localizationTable = localizationTable;
this.updateColoris = null;
this.container = document.createElement('div');

@@ -36,2 +35,7 @@ this.container.classList.add(`${toolbarCSSPrefix}root`);

setupColorPickers() {
// Much of the setup only needs to be done once.
if (this.updateColoris) {
this.updateColoris();
return;
}
const closePickerOverlay = document.createElement('div');

@@ -62,2 +66,3 @@ closePickerOverlay.className = `${toolbarCSSPrefix}closeColorPickerOverlay`;

initColoris();
this.updateColoris = initColoris;
const addColorToSwatch = (newColor) => {

@@ -93,2 +98,8 @@ let alreadyPresent = false;

}
// Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent
// (i.e. its `addTo` method should not have been called).
addWidget(widget) {
widget.addTo(this.container);
this.setupColorPickers();
}
addActionButton(title, command, parent) {

@@ -141,32 +152,19 @@ const button = document.createElement('button');

const toolController = this.editor.toolController;
for (const tool of toolController.getMatchingTools(ToolType.Pen)) {
if (!(tool instanceof Pen)) {
throw new Error('All `Pen` tools must have kind === ToolType.Pen');
}
const widget = new PenWidget(this.editor, tool, this.localizationTable);
widget.addTo(this.container);
for (const tool of toolController.getMatchingTools(PenTool)) {
const widget = new PenToolWidget(this.editor, tool, this.localizationTable);
this.addWidget(widget);
}
for (const tool of toolController.getMatchingTools(ToolType.Eraser)) {
if (!(tool instanceof Eraser)) {
throw new Error('All Erasers must have kind === ToolType.Eraser!');
}
(new EraserWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
for (const tool of toolController.getMatchingTools(EraserTool)) {
this.addWidget(new EraserWidget(this.editor, tool, this.localizationTable));
}
for (const tool of toolController.getMatchingTools(ToolType.Selection)) {
if (!(tool instanceof SelectionTool)) {
throw new Error('All SelectionTools must have kind === ToolType.Selection');
}
(new SelectionWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
for (const tool of toolController.getMatchingTools(SelectionTool)) {
this.addWidget(new SelectionToolWidget(this.editor, tool, this.localizationTable));
}
for (const tool of toolController.getMatchingTools(ToolType.Text)) {
if (!(tool instanceof TextTool)) {
throw new Error('All text tools must have kind === ToolType.Text');
}
(new TextToolWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
for (const tool of toolController.getMatchingTools(TextTool)) {
this.addWidget(new TextToolWidget(this.editor, tool, this.localizationTable));
}
const panZoomTool = toolController.getMatchingTools(ToolType.PanZoom)[0];
if (panZoomTool && panZoomTool instanceof PanZoom) {
(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)).addTo(this.container);
const panZoomTool = toolController.getMatchingTools(PanZoom)[0];
if (panZoomTool) {
this.addWidget(new HandToolWidget(this.editor, panZoomTool, this.localizationTable));
}
this.setupColorPickers();
}

@@ -173,0 +171,0 @@ addDefaultActionButtons() {

@@ -15,3 +15,3 @@ import Color4 from '../Color4';

export declare const makeTextIcon: (textStyle: TextStyle) => SVGSVGElement;
export declare const makePenIcon: (tipThickness: number, color: string) => SVGSVGElement;
export declare const makePenIcon: (tipThickness: number, color: string | Color4) => SVGSVGElement;
export declare const makeIconFromFactory: (pen: Pen, factory: ComponentBuilderFactory) => SVGSVGElement;

@@ -18,0 +18,0 @@ export declare const makePipetteIcon: (color?: Color4) => SVGSVGElement;

@@ -0,1 +1,2 @@

import Color4 from '../Color4';
import EventDispatcher from '../EventDispatcher';

@@ -254,2 +255,5 @@ import { Vec2 } from '../math/Vec2';

export const makePenIcon = (tipThickness, color) => {
if (color instanceof Color4) {
color = color.toHexString();
}
const icon = document.createElementNS(svgNamespace, 'svg');

@@ -256,0 +260,0 @@ icon.setAttribute('viewBox', '0 0 100 100');

import Color4 from '../Color4';
import { ToolType } from '../tools/ToolController';
import PipetteTool from '../tools/PipetteTool';
import { EditorEventType } from '../types';

@@ -62,3 +62,3 @@ import { makePipetteIcon } from './icons';

updatePipetteIcon();
const pipetteTool = editor.toolController.getMatchingTools(ToolType.Pipette)[0];
const pipetteTool = editor.toolController.getMatchingTools(PipetteTool)[0];
const endColorSelectMode = () => {

@@ -65,0 +65,0 @@ pipetteTool === null || pipetteTool === void 0 ? void 0 : pipetteTool.clearColorListener();

@@ -1,5 +0,1 @@

export declare enum ToolbarButtonType {
ToggleButton = 0,
ActionButton = 1
}
export interface ActionButtonIcon {

@@ -6,0 +2,0 @@ icon: Element;

@@ -1,5 +0,1 @@

export var ToolbarButtonType;
(function (ToolbarButtonType) {
ToolbarButtonType[ToolbarButtonType["ToggleButton"] = 0] = "ToggleButton";
ToolbarButtonType[ToolbarButtonType["ActionButton"] = 1] = "ActionButton";
})(ToolbarButtonType || (ToolbarButtonType = {}));
export {};
import { PointerEvtListener, WheelEvt, PointerEvt, EditorNotifier, KeyPressEvent, KeyUpEvent } from '../types';
import { ToolType } from './ToolController';
import ToolEnabledGroup from './ToolEnabledGroup';

@@ -13,3 +12,2 @@ export default abstract class BaseTool implements PointerEvtListener {

onGestureCancel(): void;
abstract readonly kind: ToolType;
protected constructor(notifier: EditorNotifier, description: string);

@@ -16,0 +14,0 @@ onWheel(_event: WheelEvt): boolean;

import { PointerEvt } from '../types';
import BaseTool from './BaseTool';
import Editor from '../Editor';
import { ToolType } from './ToolController';
export default class Eraser extends BaseTool {

@@ -9,3 +8,2 @@ private editor;

private command;
kind: ToolType;
private toRemove;

@@ -12,0 +10,0 @@ constructor(editor: Editor, description: string);

import BaseTool from './BaseTool';
import LineSegment2 from '../math/LineSegment2';
import Erase from '../commands/Erase';
import { ToolType } from './ToolController';
import { PointerDevice } from '../Pointer';

@@ -11,3 +10,2 @@ export default class Eraser extends BaseTool {

this.command = null;
this.kind = ToolType.Eraser;
}

@@ -14,0 +12,0 @@ onPointerDown(event) {

@@ -6,3 +6,2 @@ import { Editor } from '../Editor';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
interface PinchData {

@@ -24,3 +23,2 @@ canvasCenter: Point2;

private mode;
readonly kind: ToolType.PanZoom;
private transform;

@@ -27,0 +25,0 @@ private lastAngle;

@@ -8,3 +8,2 @@ import Mat33 from '../math/Mat33';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
export var PanZoomMode;

@@ -23,3 +22,2 @@ (function (PanZoomMode) {

this.mode = mode;
this.kind = ToolType.PanZoom;
this.transform = null;

@@ -26,0 +24,0 @@ }

import Color4 from '../Color4';
import Editor from '../Editor';
import { PointerEvt } from '../types';
import Pointer from '../Pointer';
import { PointerEvt, StrokeDataPoint } from '../types';
import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
import { ComponentBuilderFactory } from '../components/builders/types';
import { ComponentBuilder, ComponentBuilderFactory } from '../components/builders/types';
export interface PenStyle {

@@ -14,11 +14,10 @@ color: Color4;

private style;
private builder;
private builderFactory;
protected builder: ComponentBuilder | null;
protected builderFactory: ComponentBuilderFactory;
private lastPoint;
readonly kind: ToolType;
constructor(editor: Editor, description: string, style: PenStyle);
private getPressureMultiplier;
private getStrokePoint;
private previewStroke;
private addPointToStroke;
protected toStrokePoint(pointer: Pointer): StrokeDataPoint;
protected previewStroke(): void;
protected addPointToStroke(point: StrokeDataPoint): void;
onPointerDown({ current, allPointers }: PointerEvt): boolean;

@@ -25,0 +24,0 @@ onPointerMove({ current }: PointerEvt): void;

@@ -6,3 +6,2 @@ import EditorImage from '../EditorImage';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
export default class Pen extends BaseTool {

@@ -16,3 +15,2 @@ constructor(editor, description, style) {

this.lastPoint = null;
this.kind = ToolType.Pen;
}

@@ -22,3 +20,4 @@ getPressureMultiplier() {

}
getStrokePoint(pointer) {
// Converts a `pointer` to a `StrokeDataPoint`.
toStrokePoint(pointer) {
var _a;

@@ -41,2 +40,3 @@ const minPressure = 0.3;

}
// Displays the stroke that is currently being built with the display's `wetInkRenderer`.
previewStroke() {

@@ -47,2 +47,3 @@ var _a;

}
// Throws if no stroke builder exists.
addPointToStroke(point) {

@@ -66,3 +67,3 @@ if (!this.builder) {

if ((allPointers.length === 1 && !isEraser) || anyDeviceIsStylus) {
this.builder = this.builderFactory(this.getStrokePoint(current), this.editor.viewport);
this.builder = this.builderFactory(this.toStrokePoint(current), this.editor.viewport);
return true;

@@ -73,3 +74,3 @@ }

onPointerMove({ current }) {
this.addPointToStroke(this.getStrokePoint(current));
this.addPointToStroke(this.toStrokePoint(current));
}

@@ -82,3 +83,3 @@ onPointerUp({ current }) {

// onPointerUp events can have zero pressure. Use the last pressure instead.
const currentPoint = this.getStrokePoint(current);
const currentPoint = this.toStrokePoint(current);
const strokePoint = Object.assign(Object.assign({}, currentPoint), { width: (_b = (_a = this.lastPoint) === null || _a === void 0 ? void 0 : _a.width) !== null && _b !== void 0 ? _b : currentPoint.width });

@@ -85,0 +86,0 @@ this.addPointToStroke(strokePoint);

@@ -5,7 +5,5 @@ import Color4 from '../Color4';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
declare type ColorListener = (color: Color4 | null) => void;
export default class PipetteTool extends BaseTool {
private editor;
kind: ToolType;
private colorPreviewListener;

@@ -12,0 +10,0 @@ private colorSelectListener;

// @internal @packageDocumentation
import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
export default class PipetteTool extends BaseTool {

@@ -8,3 +7,2 @@ constructor(editor, description) {

this.editor = editor;
this.kind = ToolType.Pipette;
this.colorPreviewListener = null;

@@ -11,0 +9,0 @@ this.colorSelectListener = null;

@@ -8,3 +8,2 @@ import Command from '../commands/Command';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
declare class Selection {

@@ -47,3 +46,2 @@ startPoint: Point2;

private selectionBox;
readonly kind: ToolType;
constructor(editor: Editor, description: string);

@@ -50,0 +48,0 @@ onPointerDown(event: PointerEvt): boolean;

@@ -0,1 +1,4 @@

// Allows users to select/transform portions of the `EditorImage`.
// With respect to `extend`ing, `SelectionTool` is not stable.
// @packageDocumentation
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {

@@ -14,3 +17,2 @@ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }

import Mat33 from '../math/Mat33';
// import Mat33 from "../geometry/Mat33";
import Rect2 from '../math/Rect2';

@@ -21,3 +23,2 @@ import { Vec2 } from '../math/Vec2';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
import SerializableCommand from '../commands/SerializableCommand';

@@ -414,2 +415,3 @@ const handleScreenSize = 30;

};
// {@inheritDoc SelectionTool!}
export default class SelectionTool extends BaseTool {

@@ -419,3 +421,2 @@ constructor(editor, description) {

this.editor = editor;
this.kind = ToolType.Selection;
this.handleOverlay = document.createElement('div');

@@ -422,0 +423,0 @@ editor.createHTMLOverlay(this.handleOverlay);

@@ -7,7 +7,5 @@ import Color4 from '../Color4';

import { ToolLocalization } from './localization';
import { ToolType } from './ToolController';
export default class TextTool extends BaseTool {
private editor;
private localizationTable;
kind: ToolType;
private textStyle;

@@ -14,0 +12,0 @@ private textEditOverlay;

@@ -8,3 +8,2 @@ import Color4 from '../Color4';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
const overlayCssClass = 'textEditorOverlay';

@@ -16,3 +15,2 @@ export default class TextTool extends BaseTool {

this.localizationTable = localizationTable;
this.kind = ToolType.Text;
this.textInputElem = null;

@@ -19,0 +17,0 @@ this.textTargetPosition = null;

import { InputEvt } from '../types';
import Editor from '../Editor';
import BaseTool from './BaseTool';
import ToolEnabledGroup from './ToolEnabledGroup';
import { ToolLocalization } from './localization';
export declare enum ToolType {
Pen = 0,
Selection = 1,
Eraser = 2,
PanZoom = 3,
Text = 4,
UndoRedoShortcut = 5,
Pipette = 6,
Other = 7
}
export default class ToolController {
private tools;
private activeTool;
private primaryToolGroup;
/** @internal */
constructor(editor: Editor, localization: ToolLocalization);
setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup): void;
addPrimaryTool(tool: BaseTool): void;
addTool(tool: BaseTool): void;
dispatchInputEvent(event: InputEvt): boolean;
getMatchingTools(kind: ToolType): BaseTool[];
getMatchingTools<Type extends BaseTool>(type: new (...args: any[]) => Type): Type[];
}

@@ -11,16 +11,8 @@ import { InputEvtType, EditorEventType } from '../types';

import PipetteTool from './PipetteTool';
export var ToolType;
(function (ToolType) {
ToolType[ToolType["Pen"] = 0] = "Pen";
ToolType[ToolType["Selection"] = 1] = "Selection";
ToolType[ToolType["Eraser"] = 2] = "Eraser";
ToolType[ToolType["PanZoom"] = 3] = "PanZoom";
ToolType[ToolType["Text"] = 4] = "Text";
ToolType[ToolType["UndoRedoShortcut"] = 5] = "UndoRedoShortcut";
ToolType[ToolType["Pipette"] = 6] = "Pipette";
ToolType[ToolType["Other"] = 7] = "Other";
})(ToolType || (ToolType = {}));
export default class ToolController {
/** @internal */
constructor(editor, localization) {
const primaryToolEnabledGroup = new ToolEnabledGroup();
this.activeTool = null;
const primaryToolGroup = new ToolEnabledGroup();
this.primaryToolGroup = primaryToolGroup;
const panZoomTool = new PanZoom(editor, PanZoomMode.TwoFingerTouchGestures | PanZoomMode.RightClickDrags, localization.touchPanTool);

@@ -34,3 +26,3 @@ const keyboardPanZoomTool = new PanZoom(editor, PanZoomMode.Keyboard, localization.keyboardPanZoom);

primaryPenTool,
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 8 }),
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 4 }),
// Highlighter-like pen with width=64

@@ -47,3 +39,3 @@ new Pen(editor, localization.penTool(3), { color: Color4.ofRGBA(1, 1, 0, 0.5), thickness: 64 }),

];
primaryTools.forEach(tool => tool.setToolGroup(primaryToolEnabledGroup));
primaryTools.forEach(tool => tool.setToolGroup(primaryToolGroup));
panZoomTool.setEnabled(true);

@@ -63,2 +55,22 @@ primaryPenTool.setEnabled(true);

}
// Replaces the current set of tools with `tools`. This should only be done before
// the creation of the app's toolbar (if using `HTMLToolbar`).
setTools(tools, primaryToolGroup) {
this.tools = tools;
this.primaryToolGroup = primaryToolGroup !== null && primaryToolGroup !== void 0 ? primaryToolGroup : new ToolEnabledGroup();
}
// Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
// This should be called before creating the app's toolbar.
addPrimaryTool(tool) {
tool.setToolGroup(this.primaryToolGroup);
if (tool.isEnabled()) {
this.primaryToolGroup.notifyEnabled(tool);
}
this.addTool(tool);
}
// Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
// This should be called before creating the app's toolbar.
addTool(tool) {
this.tools.push(tool);
}
// Returns true if the event was handled

@@ -123,5 +135,5 @@ dispatchInputEvent(event) {

}
getMatchingTools(kind) {
return this.tools.filter(tool => tool.kind === kind);
getMatchingTools(type) {
return this.tools.filter(tool => tool instanceof type);
}
}

@@ -1,2 +0,2 @@

// Connects a group of tools -- at most one tool in the group must be enabled.
// Connects a group of tools -- at most one tool in the group can be enabled.
export default class ToolEnabledGroup {

@@ -3,0 +3,0 @@ constructor() { }

import Editor from '../Editor';
import { KeyPressEvent } from '../types';
import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
export default class UndoRedoShortcut extends BaseTool {
private editor;
kind: ToolType.UndoRedoShortcut;
constructor(editor: Editor);
onKeyPress({ key, ctrlKey }: KeyPressEvent): boolean;
}

@@ -0,3 +1,5 @@

// Handles ctrl+Z, ctrl+Shift+Z keyboard shortcuts.
// @packageDocumentation
import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
// {@inheritDoc UndoRedoShortcut!}
export default class UndoRedoShortcut extends BaseTool {

@@ -7,3 +9,2 @@ constructor(editor) {

this.editor = editor;
this.kind = ToolType.UndoRedoShortcut;
}

@@ -10,0 +11,0 @@ // Activate undo/redo

{
"name": "js-draw",
"version": "0.2.3",
"version": "0.3.0",
"description": "Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript. ",

@@ -5,0 +5,0 @@ "main": "./dist/src/lib.d.ts",

@@ -183,3 +183,3 @@ import { Bezier } from 'bezier-js';

private roundPoint(point: Point2): Point2 {
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth);
let minFit = Math.min(this.minFitAllowed, this.curveStartWidth / 2);

@@ -186,0 +186,0 @@ if (minFit < 1e-10) {

@@ -0,1 +1,4 @@

export * from './builders/types';
export { makeFreehandLineBuilder } from './builders/FreehandLineBuilder';
import AbstractComponent from './AbstractComponent';

@@ -2,0 +5,0 @@ import Stroke from './Stroke';

@@ -391,3 +391,2 @@ import Editor from './Editor';

public render(renderer: AbstractRenderer, visibleRect: Rect2) {
// Don't render components that are < 0.1% of the viewport.
const leaves = this.getLeavesIntersectingRegion(visibleRect, rect => renderer.isTooSmallToRender(rect));

@@ -394,0 +393,0 @@ sortLeavesByZIndex(leaves);

@@ -17,3 +17,4 @@ /**

import Editor from './Editor';
export { EditorEventType } from './types';
export { default as EditorImage } from './EditorImage';
export * from './types';
export { default as getLocalizationTable } from './localizations/getLocalizationTable';

@@ -26,2 +27,5 @@ export * from './localization';

export * from './commands/lib';
export * from './tools/lib';
export * from './toolbar/lib';
export { default as Pointer, PointerDevice } from './Pointer';
export { default as HTMLToolbar } from './toolbar/HTMLToolbar';

@@ -28,0 +32,0 @@

@@ -224,2 +224,4 @@

// Determine whether we already have rendered the items
const tooSmallToRender = (rect: Rect2) => rect.w / this.region.w < 1 / this.cacheState.props.blockResolution.x;
const leaves = [];

@@ -229,3 +231,3 @@ for (const item of items) {

...item.getLeavesIntersectingRegion(
this.region, rect => rect.w / this.region.w < 2 / this.cacheState.props.blockResolution.x,
this.region, tooSmallToRender,
)

@@ -232,0 +234,0 @@ );

@@ -79,4 +79,4 @@ /**

blockResolution: cacheBlockResolution,
cacheSize: 500 * 500 * 4 * 150,
maxScale: 1.5,
cacheSize: 600 * 600 * 4 * 120,
maxScale: 1.4,
minComponentsPerCache: 45,

@@ -83,0 +83,0 @@ minComponentsToUseCache: 105,

@@ -62,9 +62,9 @@ import Color4 from '../../Color4';

if (draftMode) {
this.minSquareCurveApproxDist = 64;
this.minRenderSizeBothDimens = 8;
this.minRenderSizeAnyDimen = 2;
this.minSquareCurveApproxDist = 9;
this.minRenderSizeBothDimens = 2;
this.minRenderSizeAnyDimen = 0.5;
} else {
this.minSquareCurveApproxDist = 1;
this.minRenderSizeBothDimens = 0.5;
this.minRenderSizeAnyDimen = 0;
this.minSquareCurveApproxDist = 0.5;
this.minRenderSizeBothDimens = 0.3;
this.minRenderSizeAnyDimen = 1e-5;
}

@@ -71,0 +71,0 @@ }

import Editor from '../Editor';
import { ToolType } from '../tools/ToolController';
import { EditorEventType } from '../types';

@@ -7,4 +6,2 @@

import Color4 from '../Color4';
import Pen from '../tools/Pen';
import Eraser from '../tools/Eraser';
import SelectionTool from '../tools/SelectionTool';

@@ -16,7 +13,9 @@ import { defaultToolbarLocalization, ToolbarLocalization } from './localization';

import TextTool from '../tools/TextTool';
import PenWidget from './widgets/PenWidget';
import EraserWidget from './widgets/EraserWidget';
import { SelectionWidget } from './widgets/SelectionWidget';
import PenToolWidget from './widgets/PenToolWidget';
import EraserWidget from './widgets/EraserToolWidget';
import SelectionToolWidget from './widgets/SelectionToolWidget';
import TextToolWidget from './widgets/TextToolWidget';
import HandToolWidget from './widgets/HandToolWidget';
import BaseWidget from './widgets/BaseWidget';
import { EraserTool, PenTool } from '../tools/lib';

@@ -26,2 +25,3 @@

type UpdateColorisCallback = ()=>void;

@@ -32,2 +32,3 @@ export default class HTMLToolbar {

private static colorisStarted: boolean = false;
private updateColoris: UpdateColorisCallback|null = null;

@@ -52,2 +53,8 @@ public constructor(

public setupColorPickers() {
// Much of the setup only needs to be done once.
if (this.updateColoris) {
this.updateColoris();
return;
}
const closePickerOverlay = document.createElement('div');

@@ -81,2 +88,3 @@ closePickerOverlay.className = `${toolbarCSSPrefix}closeColorPickerOverlay`;

initColoris();
this.updateColoris = initColoris;

@@ -119,2 +127,9 @@ const addColorToSwatch = (newColor: string) => {

// Adds an `ActionButtonWidget` or `BaseToolWidget`. The widget should not have already have a parent
// (i.e. its `addTo` method should not have been called).
public addWidget(widget: BaseWidget) {
widget.addTo(this.container);
this.setupColorPickers();
}
public addActionButton(title: string|ActionButtonIcon, command: ()=> void, parent?: Element) {

@@ -144,3 +159,3 @@ const button = document.createElement('button');

private addUndoRedoButtons() {
public addUndoRedoButtons() {
const undoRedoGroup = document.createElement('div');

@@ -177,43 +192,25 @@ undoRedoGroup.classList.add(`${toolbarCSSPrefix}buttonGroup`);

const toolController = this.editor.toolController;
for (const tool of toolController.getMatchingTools(ToolType.Pen)) {
if (!(tool instanceof Pen)) {
throw new Error('All `Pen` tools must have kind === ToolType.Pen');
}
const widget = new PenWidget(
for (const tool of toolController.getMatchingTools(PenTool)) {
const widget = new PenToolWidget(
this.editor, tool, this.localizationTable,
);
widget.addTo(this.container);
this.addWidget(widget);
}
for (const tool of toolController.getMatchingTools(ToolType.Eraser)) {
if (!(tool instanceof Eraser)) {
throw new Error('All Erasers must have kind === ToolType.Eraser!');
}
(new EraserWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
for (const tool of toolController.getMatchingTools(EraserTool)) {
this.addWidget(new EraserWidget(this.editor, tool, this.localizationTable));
}
for (const tool of toolController.getMatchingTools(ToolType.Selection)) {
if (!(tool instanceof SelectionTool)) {
throw new Error('All SelectionTools must have kind === ToolType.Selection');
}
(new SelectionWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
for (const tool of toolController.getMatchingTools(SelectionTool)) {
this.addWidget(new SelectionToolWidget(this.editor, tool, this.localizationTable));
}
for (const tool of toolController.getMatchingTools(ToolType.Text)) {
if (!(tool instanceof TextTool)) {
throw new Error('All text tools must have kind === ToolType.Text');
}
(new TextToolWidget(this.editor, tool, this.localizationTable)).addTo(this.container);
for (const tool of toolController.getMatchingTools(TextTool)) {
this.addWidget(new TextToolWidget(this.editor, tool, this.localizationTable));
}
const panZoomTool = toolController.getMatchingTools(ToolType.PanZoom)[0];
if (panZoomTool && panZoomTool instanceof PanZoom) {
(new HandToolWidget(this.editor, panZoomTool, this.localizationTable)).addTo(this.container);
const panZoomTool = toolController.getMatchingTools(PanZoom)[0];
if (panZoomTool) {
this.addWidget(new HandToolWidget(this.editor, panZoomTool, this.localizationTable));
}
this.setupColorPickers();
}

@@ -220,0 +217,0 @@

@@ -290,3 +290,7 @@ import Color4 from '../Color4';

export const makePenIcon = (tipThickness: number, color: string) => {
export const makePenIcon = (tipThickness: number, color: string|Color4) => {
if (color instanceof Color4) {
color = color.toHexString();
}
const icon = document.createElementNS(svgNamespace, 'svg');

@@ -293,0 +297,0 @@ icon.setAttribute('viewBox', '0 0 100 100');

import Color4 from '../Color4';
import Editor from '../Editor';
import PipetteTool from '../tools/PipetteTool';
import { ToolType } from '../tools/ToolController';
import { EditorEventType } from '../types';

@@ -80,3 +79,3 @@ import { makePipetteIcon } from './icons';

const pipetteTool: PipetteTool|undefined = editor.toolController.getMatchingTools(ToolType.Pipette)[0] as PipetteTool|undefined;
const pipetteTool: PipetteTool|undefined = editor.toolController.getMatchingTools(PipetteTool)[0];
const endColorSelectMode = () => {

@@ -83,0 +82,0 @@ pipetteTool?.clearColorListener();

@@ -1,5 +0,1 @@

export enum ToolbarButtonType {
ToggleButton,
ActionButton,
}

@@ -6,0 +2,0 @@ export interface ActionButtonIcon {

import { PointerEvtListener, WheelEvt, PointerEvt, EditorNotifier, EditorEventType, KeyPressEvent, KeyUpEvent } from '../types';
import { ToolType } from './ToolController';
import ToolEnabledGroup from './ToolEnabledGroup';

@@ -14,4 +13,2 @@

public abstract readonly kind: ToolType;
protected constructor(private notifier: EditorNotifier, public readonly description: string) {

@@ -18,0 +15,0 @@ }

@@ -7,3 +7,2 @@ import { PointerEvt } from '../types';

import Erase from '../commands/Erase';
import { ToolType } from './ToolController';
import AbstractComponent from '../components/AbstractComponent';

@@ -15,3 +14,2 @@ import { PointerDevice } from '../Pointer';

private command: Erase|null = null;
public kind: ToolType = ToolType.Eraser;
private toRemove: AbstractComponent[];

@@ -18,0 +16,0 @@

@@ -10,3 +10,2 @@

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';

@@ -29,3 +28,2 @@ interface PinchData {

export default class PanZoom extends BaseTool {
public readonly kind: ToolType.PanZoom = ToolType.PanZoom;
private transform: ViewportTransform|null = null;

@@ -32,0 +30,0 @@

@@ -8,3 +8,2 @@ import Color4 from '../Color4';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
import { ComponentBuilder, ComponentBuilderFactory } from '../components/builders/types';

@@ -18,8 +17,6 @@

export default class Pen extends BaseTool {
private builder: ComponentBuilder|null = null;
private builderFactory: ComponentBuilderFactory = makeFreehandLineBuilder;
protected builder: ComponentBuilder|null = null;
protected builderFactory: ComponentBuilderFactory = makeFreehandLineBuilder;
private lastPoint: StrokeDataPoint|null = null;
public readonly kind: ToolType = ToolType.Pen;
public constructor(

@@ -37,3 +34,4 @@ private editor: Editor,

private getStrokePoint(pointer: Pointer): StrokeDataPoint {
// Converts a `pointer` to a `StrokeDataPoint`.
protected toStrokePoint(pointer: Pointer): StrokeDataPoint {
const minPressure = 0.3;

@@ -58,3 +56,4 @@ let pressure = Math.max(pointer.pressure ?? 1.0, minPressure);

private previewStroke() {
// Displays the stroke that is currently being built with the display's `wetInkRenderer`.
protected previewStroke() {
this.editor.clearWetInk();

@@ -64,3 +63,4 @@ this.builder?.preview(this.editor.display.getWetInkRenderer());

private addPointToStroke(point: StrokeDataPoint) {
// Throws if no stroke builder exists.
protected addPointToStroke(point: StrokeDataPoint) {
if (!this.builder) {

@@ -86,3 +86,3 @@ throw new Error('No stroke is currently being generated.');

if ((allPointers.length === 1 && !isEraser) || anyDeviceIsStylus) {
this.builder = this.builderFactory(this.getStrokePoint(current), this.editor.viewport);
this.builder = this.builderFactory(this.toStrokePoint(current), this.editor.viewport);
return true;

@@ -95,3 +95,3 @@ }

public onPointerMove({ current }: PointerEvt): void {
this.addPointToStroke(this.getStrokePoint(current));
this.addPointToStroke(this.toStrokePoint(current));
}

@@ -105,3 +105,3 @@

// onPointerUp events can have zero pressure. Use the last pressure instead.
const currentPoint = this.getStrokePoint(current);
const currentPoint = this.toStrokePoint(current);
const strokePoint = {

@@ -129,3 +129,3 @@ ...currentPoint,

public onGestureCancel(): void {
public onGestureCancel() {
this.editor.clearWetInk();

@@ -132,0 +132,0 @@ }

@@ -7,3 +7,2 @@ // @internal @packageDocumentation

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';

@@ -13,4 +12,2 @@ type ColorListener = (color: Color4|null)=>void;

export default class PipetteTool extends BaseTool {
public kind: ToolType = ToolType.Pipette;
private colorPreviewListener: ColorListener|null = null;

@@ -17,0 +14,0 @@ private colorSelectListener: ColorListener|null = null;

@@ -9,7 +9,6 @@ import Color4 from '../Color4';

import SelectionTool from './SelectionTool';
import { ToolType } from './ToolController';
import createEditor from '../testing/createEditor';
const getSelectionTool = (editor: Editor): SelectionTool => {
return editor.toolController.getMatchingTools(ToolType.Selection)[0] as SelectionTool;
return editor.toolController.getMatchingTools(SelectionTool)[0];
};

@@ -16,0 +15,0 @@

@@ -0,1 +1,5 @@

// Allows users to select/transform portions of the `EditorImage`.
// With respect to `extend`ing, `SelectionTool` is not stable.
// @packageDocumentation
import Command from '../commands/Command';

@@ -7,3 +11,2 @@ import Duplicate from '../commands/Duplicate';

import Mat33 from '../math/Mat33';
// import Mat33 from "../geometry/Mat33";
import Rect2 from '../math/Rect2';

@@ -15,3 +18,2 @@ import { Point2, Vec2 } from '../math/Vec2';

import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
import SerializableCommand from '../commands/SerializableCommand';

@@ -507,2 +509,3 @@

// {@inheritDoc SelectionTool!}
export default class SelectionTool extends BaseTool {

@@ -512,3 +515,2 @@ private handleOverlay: HTMLElement;

private selectionBox: Selection|null;
public readonly kind: ToolType = ToolType.Selection;

@@ -515,0 +517,0 @@ public constructor(private editor: Editor, description: string) {

@@ -11,7 +11,5 @@ import Color4 from '../Color4';

import { ToolLocalization } from './localization';
import { ToolType } from './ToolController';
const overlayCssClass = 'textEditorOverlay';
export default class TextTool extends BaseTool {
public kind: ToolType = ToolType.Text;
private textStyle: TextStyle;

@@ -18,0 +16,0 @@

@@ -15,19 +15,12 @@ import { InputEvtType, InputEvt, EditorEventType } from '../types';

export enum ToolType {
Pen,
Selection,
Eraser,
PanZoom,
Text,
UndoRedoShortcut,
Pipette,
Other,
}
export default class ToolController {
private tools: BaseTool[];
private activeTool: BaseTool|null;
private activeTool: BaseTool|null = null;
private primaryToolGroup: ToolEnabledGroup;
/** @internal */
public constructor(editor: Editor, localization: ToolLocalization) {
const primaryToolEnabledGroup = new ToolEnabledGroup();
const primaryToolGroup = new ToolEnabledGroup();
this.primaryToolGroup = primaryToolGroup;
const panZoomTool = new PanZoom(editor, PanZoomMode.TwoFingerTouchGestures | PanZoomMode.RightClickDrags, localization.touchPanTool);

@@ -42,3 +35,3 @@ const keyboardPanZoomTool = new PanZoom(editor, PanZoomMode.Keyboard, localization.keyboardPanZoom);

primaryPenTool,
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 8 }),
new Pen(editor, localization.penTool(2), { color: Color4.clay, thickness: 4 }),

@@ -57,3 +50,3 @@ // Highlighter-like pen with width=64

];
primaryTools.forEach(tool => tool.setToolGroup(primaryToolEnabledGroup));
primaryTools.forEach(tool => tool.setToolGroup(primaryToolGroup));
panZoomTool.setEnabled(true);

@@ -76,2 +69,26 @@ primaryPenTool.setEnabled(true);

// Replaces the current set of tools with `tools`. This should only be done before
// the creation of the app's toolbar (if using `HTMLToolbar`).
public setTools(tools: BaseTool[], primaryToolGroup?: ToolEnabledGroup) {
this.tools = tools;
this.primaryToolGroup = primaryToolGroup ?? new ToolEnabledGroup();
}
// Add a tool that acts like one of the primary tools (only one primary tool can be enabled at a time).
// This should be called before creating the app's toolbar.
public addPrimaryTool(tool: BaseTool) {
tool.setToolGroup(this.primaryToolGroup);
if (tool.isEnabled()) {
this.primaryToolGroup.notifyEnabled(tool);
}
this.addTool(tool);
}
// Add a tool to the end of this' tool list (the added tool receives events after tools already added to this).
// This should be called before creating the app's toolbar.
public addTool(tool: BaseTool) {
this.tools.push(tool);
}
// Returns true if the event was handled

@@ -139,6 +156,6 @@ public dispatchInputEvent(event: InputEvt): boolean {

public getMatchingTools(kind: ToolType): BaseTool[] {
return this.tools.filter(tool => tool.kind === kind);
public getMatchingTools<Type extends BaseTool>(type: new (...args: any[])=>Type): Type[] {
return this.tools.filter(tool => tool instanceof type) as Type[];
}
}
import BaseTool from './BaseTool';
// Connects a group of tools -- at most one tool in the group must be enabled.
// Connects a group of tools -- at most one tool in the group can be enabled.
export default class ToolEnabledGroup {

@@ -5,0 +5,0 @@ private activeTool: BaseTool|null;

@@ -0,10 +1,10 @@

// Handles ctrl+Z, ctrl+Shift+Z keyboard shortcuts.
// @packageDocumentation
import Editor from '../Editor';
import { KeyPressEvent } from '../types';
import BaseTool from './BaseTool';
import { ToolType } from './ToolController';
// {@inheritDoc UndoRedoShortcut!}
export default class UndoRedoShortcut extends BaseTool {
public kind: ToolType.UndoRedoShortcut = ToolType.UndoRedoShortcut;
public constructor(private editor: Editor) {

@@ -11,0 +11,0 @@ super(editor.notifier, editor.localization.undoRedoTool);

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc