js-draw
Version:
Draw pictures using a pen, touchscreen, or mouse! JS-draw is a drawing library for JavaScript and TypeScript.
239 lines (238 loc) • 10.9 kB
JavaScript
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const math_1 = require("@js-draw/math");
const PanZoom_1 = __importStar(require("../../tools/PanZoom"));
const types_1 = require("../../types");
const Viewport_1 = __importDefault(require("../../Viewport"));
const constants_1 = require("../constants");
const BaseToolWidget_1 = __importDefault(require("./BaseToolWidget"));
const BaseWidget_1 = __importDefault(require("./BaseWidget"));
const makeSeparator_1 = __importDefault(require("./components/makeSeparator"));
const makeZoomControl = (localizationTable, editor, helpDisplay) => {
const zoomLevelRow = document.createElement('div');
const increaseButton = document.createElement('button');
const decreaseButton = document.createElement('button');
const resetViewButton = document.createElement('button');
const zoomLevelDisplay = document.createElement('span');
increaseButton.innerText = '+';
decreaseButton.innerText = '-';
resetViewButton.innerText = localizationTable.resetView;
zoomLevelRow.replaceChildren(zoomLevelDisplay, increaseButton, decreaseButton, resetViewButton);
zoomLevelRow.classList.add(`${constants_1.toolbarCSSPrefix}zoomLevelEditor`);
zoomLevelDisplay.classList.add('zoomDisplay');
let lastZoom;
const updateZoomDisplay = () => {
let zoomLevel = editor.viewport.getScaleFactor() * 100;
if (zoomLevel > 0.1) {
zoomLevel = Math.round(zoomLevel * 10) / 10;
}
else {
zoomLevel = Math.round(zoomLevel * 1000) / 1000;
}
if (zoomLevel !== lastZoom) {
zoomLevelDisplay.textContent = localizationTable.zoomLevel(zoomLevel);
lastZoom = zoomLevel;
}
};
updateZoomDisplay();
editor.notifier.on(types_1.EditorEventType.ViewportChanged, (event) => {
if (event.kind === types_1.EditorEventType.ViewportChanged) {
updateZoomDisplay();
// Can't reset if already reset.
resetViewButton.disabled = event.newTransform.eq(math_1.Mat33.identity);
}
});
const zoomBy = (factor) => {
const screenCenter = editor.viewport.visibleRect.center;
const transformUpdate = math_1.Mat33.scaling2D(factor, screenCenter);
editor.dispatch(Viewport_1.default.transformBy(transformUpdate), false);
};
increaseButton.onclick = () => {
zoomBy(5.0 / 4);
};
decreaseButton.onclick = () => {
zoomBy(4.0 / 5);
};
resetViewButton.onclick = () => {
const addToHistory = false;
editor.dispatch(Viewport_1.default.transformBy(editor.viewport.canvasToScreenTransform.inverse()), addToHistory);
};
helpDisplay?.registerTextHelpForElement(increaseButton, localizationTable.handDropdown__zoomInHelpText);
helpDisplay?.registerTextHelpForElement(decreaseButton, localizationTable.handDropdown__zoomOutHelpText);
helpDisplay?.registerTextHelpForElement(resetViewButton, localizationTable.handDropdown__resetViewHelpText);
helpDisplay?.registerTextHelpForElement(zoomLevelDisplay, localizationTable.handDropdown__zoomDisplayHelpText);
return zoomLevelRow;
};
class HandModeWidget extends BaseWidget_1.default {
constructor(editor, tool, flag, makeIcon, title, helpText, localizationTable) {
super(editor, `pan-mode-${flag}`, localizationTable);
this.tool = tool;
this.flag = flag;
this.makeIcon = makeIcon;
this.title = title;
this.helpText = helpText;
editor.notifier.on(types_1.EditorEventType.ToolUpdated, (toolEvt) => {
if (toolEvt.kind === types_1.EditorEventType.ToolUpdated && toolEvt.tool === tool) {
const allEnabled = !!(tool.getMode() & PanZoom_1.PanZoomMode.SinglePointerGestures);
this.setSelected(!!(tool.getMode() & flag) || allEnabled);
// Unless this widget toggles all single pointer gestures, toggling while
// single pointer gestures are enabled should have no effect
this.setDisabled(allEnabled && flag !== PanZoom_1.PanZoomMode.SinglePointerGestures);
}
});
this.setSelected(false);
}
shouldAutoDisableInReadOnlyEditor() {
return false;
}
setModeFlag(enabled) {
this.tool.setModeEnabled(this.flag, enabled);
}
handleClick() {
this.setModeFlag(!this.isSelected());
}
getTitle() {
return this.title;
}
createIcon() {
return this.makeIcon();
}
fillDropdown(_dropdown) {
return false;
}
getHelpText() {
return this.helpText;
}
}
/** This toolbar widget allows controlling the editor's {@link PanZoom} tool(s). */
class HandToolWidget extends BaseToolWidget_1.default {
constructor(editor,
// Can either be the primary pan/zoom tool (in the primary tools list) or
// the override pan/zoom tool.
// If the override pan/zoom tool, the primary will be gotten from the editor's
// tool controller.
// If the primary, the override will be gotten from the editor's tool controller.
tool, localizationTable) {
const isGivenToolPrimary = editor.toolController.getPrimaryTools().includes(tool);
const primaryTool = (isGivenToolPrimary ? tool : HandToolWidget.getPrimaryHandTool(editor.toolController)) ??
tool;
super(editor, primaryTool, 'hand-tool-widget', localizationTable);
this.overridePanZoomTool =
(isGivenToolPrimary ? HandToolWidget.getOverrideHandTool(editor.toolController) : tool) ??
tool;
// Only allow toggling a hand tool if we're using the primary hand tool and not the override
// hand tool for this button.
this.allowTogglingBaseTool = primaryTool !== null;
// Allow showing/hiding the dropdown, even if `overridePanZoomTool` isn't enabled.
if (!this.allowTogglingBaseTool) {
this.container.classList.add('dropdownShowable');
}
// Controls for the overriding hand tool.
const touchPanningWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoom_1.PanZoomMode.OneFingerTouchGestures, () => this.editor.icons.makeTouchPanningIcon(), localizationTable.touchPanning, localizationTable.handDropdown__touchPanningHelpText, localizationTable);
const rotationLockWidget = new HandModeWidget(editor, this.overridePanZoomTool, PanZoom_1.PanZoomMode.RotationLocked, () => this.editor.icons.makeRotationLockIcon(), localizationTable.lockRotation, localizationTable.handDropdown__lockRotationHelpText, localizationTable);
this.addSubWidget(touchPanningWidget);
this.addSubWidget(rotationLockWidget);
}
static getPrimaryHandTool(toolController) {
const primaryPanZoomToolList = toolController
.getPrimaryTools()
.filter((tool) => tool instanceof PanZoom_1.default);
const primaryPanZoomTool = primaryPanZoomToolList[0];
return primaryPanZoomTool;
}
static getOverrideHandTool(toolController) {
const panZoomToolList = toolController.getMatchingTools(PanZoom_1.default);
const panZoomTool = panZoomToolList[0];
return panZoomTool;
}
shouldAutoDisableInReadOnlyEditor() {
return false;
}
getTitle() {
return this.localizationTable.handTool;
}
createIcon() {
return this.editor.icons.makeHandToolIcon();
}
handleClick() {
if (this.allowTogglingBaseTool) {
super.handleClick();
}
else {
this.setDropdownVisible(!this.isDropdownVisible());
}
}
getHelpText() {
return this.localizationTable.handDropdown__baseHelpText;
}
fillDropdown(dropdown, helpDisplay) {
super.fillDropdown(dropdown, helpDisplay);
// The container for all actions that come after the toolbar buttons.
const nonbuttonActionContainer = document.createElement('div');
nonbuttonActionContainer.classList.add(`${constants_1.toolbarCSSPrefix}nonbutton-controls-main-list`);
(0, makeSeparator_1.default)().addTo(nonbuttonActionContainer);
const zoomControl = makeZoomControl(this.localizationTable, this.editor, helpDisplay);
nonbuttonActionContainer.appendChild(zoomControl);
dropdown.appendChild(nonbuttonActionContainer);
return true;
}
setSelected(selected) {
if (this.allowTogglingBaseTool) {
super.setSelected(selected);
}
}
serializeState() {
const toolMode = this.overridePanZoomTool.getMode();
return {
...super.serializeState(),
touchPanning: toolMode & PanZoom_1.PanZoomMode.OneFingerTouchGestures,
rotationLocked: toolMode & PanZoom_1.PanZoomMode.RotationLocked,
};
}
deserializeFrom(state) {
if (state.touchPanning !== undefined) {
this.overridePanZoomTool.setModeEnabled(PanZoom_1.PanZoomMode.OneFingerTouchGestures, !!state.touchPanning);
}
if (state.rotationLocked !== undefined) {
this.overridePanZoomTool.setModeEnabled(PanZoom_1.PanZoomMode.RotationLocked, !!state.rotationLocked);
}
super.deserializeFrom(state);
}
}
exports.default = HandToolWidget;
;