js-draw 1.3.1 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/Editor.css +55 -13
- package/dist/bundle.js +2 -2
- package/dist/bundledStyles.js +1 -1
- package/dist/cjs/Editor.d.ts +36 -3
- package/dist/cjs/Editor.js +63 -26
- package/dist/cjs/commands/Erase.js +1 -1
- package/dist/cjs/commands/UnresolvedCommand.d.ts +1 -1
- package/dist/cjs/components/AbstractComponent.d.ts +1 -1
- package/dist/cjs/components/AbstractComponent.js +1 -1
- package/dist/cjs/components/BackgroundComponent.d.ts +1 -1
- package/dist/cjs/components/BackgroundComponent.js +13 -7
- package/dist/cjs/components/SVGGlobalAttributesObject.d.ts +2 -2
- package/dist/cjs/components/SVGGlobalAttributesObject.js +10 -14
- package/dist/cjs/{EditorImage.d.ts → image/EditorImage.d.ts} +30 -8
- package/dist/cjs/{EditorImage.js → image/EditorImage.js} +51 -7
- package/dist/cjs/image/export/adjustExportedSVGSize.d.ts +6 -0
- package/dist/cjs/image/export/adjustExportedSVGSize.js +22 -0
- package/dist/cjs/image/export/editorImageToSVG.d.ts +8 -0
- package/dist/cjs/image/export/editorImageToSVG.js +63 -0
- package/dist/cjs/image/lib.d.ts +1 -0
- package/dist/cjs/image/lib.js +8 -0
- package/dist/cjs/lib.d.ts +1 -1
- package/dist/cjs/lib.js +2 -3
- package/dist/cjs/localizations/comments.d.ts +6 -0
- package/dist/cjs/localizations/comments.js +10 -0
- package/dist/cjs/localizations/es.js +68 -48
- package/dist/cjs/rendering/caching/RenderingCache.d.ts +1 -1
- package/dist/cjs/rendering/caching/RenderingCacheNode.d.ts +1 -1
- package/dist/cjs/rendering/caching/RenderingCacheNode.js +4 -3
- package/dist/cjs/rendering/renderers/AbstractRenderer.d.ts +1 -0
- package/dist/cjs/rendering/renderers/AbstractRenderer.js +8 -0
- package/dist/cjs/rendering/renderers/SVGRenderer.d.ts +28 -1
- package/dist/cjs/rendering/renderers/SVGRenderer.js +58 -7
- package/dist/cjs/toolbar/AbstractToolbar.d.ts +11 -3
- package/dist/cjs/toolbar/AbstractToolbar.js +20 -6
- package/dist/cjs/toolbar/EdgeToolbar.js +5 -6
- package/dist/cjs/toolbar/IconProvider.d.ts +1 -0
- package/dist/cjs/toolbar/IconProvider.js +43 -0
- package/dist/cjs/toolbar/widgets/ActionButtonWidget.d.ts +3 -1
- package/dist/cjs/toolbar/widgets/ActionButtonWidget.js +19 -1
- package/dist/cjs/toolbar/widgets/BaseToolWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/BaseToolWidget.js +3 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.d.ts +5 -0
- package/dist/cjs/toolbar/widgets/BaseWidget.js +30 -2
- package/dist/cjs/toolbar/widgets/DocumentPropertiesWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/HandToolWidget.js +6 -0
- package/dist/cjs/toolbar/widgets/InsertImageWidget.js +1 -1
- package/dist/cjs/toolbar/widgets/OverflowWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/OverflowWidget.js +3 -0
- package/dist/cjs/toolbar/widgets/SaveActionWidget.d.ts +1 -0
- package/dist/cjs/toolbar/widgets/SaveActionWidget.js +3 -0
- package/dist/cjs/tools/BaseTool.d.ts +3 -0
- package/dist/cjs/tools/BaseTool.js +13 -2
- package/dist/cjs/tools/FindTool.d.ts +1 -0
- package/dist/cjs/tools/FindTool.js +4 -1
- package/dist/cjs/tools/PanZoom.d.ts +1 -0
- package/dist/cjs/tools/PanZoom.js +4 -0
- package/dist/cjs/tools/Pen.d.ts +0 -1
- package/dist/cjs/tools/Pen.js +1 -4
- package/dist/cjs/tools/PipetteTool.d.ts +1 -0
- package/dist/cjs/tools/PipetteTool.js +3 -0
- package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +1 -0
- package/dist/cjs/tools/SelectionTool/SelectAllShortcutHandler.js +3 -0
- package/dist/cjs/tools/SelectionTool/Selection.d.ts +2 -0
- package/dist/cjs/tools/SelectionTool/Selection.js +44 -8
- package/dist/cjs/tools/SelectionTool/SelectionHandle.d.ts +14 -6
- package/dist/cjs/tools/SelectionTool/SelectionHandle.js +26 -8
- package/dist/cjs/tools/SelectionTool/SelectionTool.js +5 -0
- package/dist/cjs/tools/SoundUITool.d.ts +1 -0
- package/dist/cjs/tools/SoundUITool.js +4 -1
- package/dist/cjs/tools/TextTool.js +2 -2
- package/dist/cjs/tools/ToolController.d.ts +2 -0
- package/dist/cjs/tools/ToolController.js +13 -2
- package/dist/cjs/tools/ToolSwitcherShortcut.d.ts +1 -0
- package/dist/cjs/tools/ToolSwitcherShortcut.js +3 -0
- package/dist/cjs/types.d.ts +9 -4
- package/dist/cjs/types.js +4 -3
- package/dist/cjs/util/ReactiveValue.d.ts +1 -1
- package/dist/cjs/util/ReactiveValue.js +2 -2
- package/dist/cjs/version.js +1 -1
- package/dist/mjs/Editor.d.ts +36 -3
- package/dist/mjs/Editor.mjs +64 -27
- package/dist/mjs/Editor.toSVGAsync.test.d.ts +1 -0
- package/dist/mjs/commands/Erase.mjs +1 -1
- package/dist/mjs/commands/UnresolvedCommand.d.ts +1 -1
- package/dist/mjs/components/AbstractComponent.d.ts +1 -1
- package/dist/mjs/components/AbstractComponent.mjs +1 -1
- package/dist/mjs/components/BackgroundComponent.d.ts +1 -1
- package/dist/mjs/components/BackgroundComponent.mjs +13 -7
- package/dist/mjs/components/SVGGlobalAttributesObject.d.ts +2 -2
- package/dist/mjs/components/SVGGlobalAttributesObject.mjs +10 -14
- package/dist/mjs/{EditorImage.d.ts → image/EditorImage.d.ts} +30 -8
- package/dist/mjs/{EditorImage.mjs → image/EditorImage.mjs} +51 -7
- package/dist/mjs/image/EditorImage.test.d.ts +1 -0
- package/dist/mjs/image/export/adjustExportedSVGSize.d.ts +6 -0
- package/dist/mjs/image/export/adjustExportedSVGSize.mjs +20 -0
- package/dist/mjs/image/export/editorImageToSVG.d.ts +8 -0
- package/dist/mjs/image/export/editorImageToSVG.mjs +55 -0
- package/dist/mjs/image/lib.d.ts +1 -0
- package/dist/mjs/image/lib.mjs +1 -0
- package/dist/mjs/lib.d.ts +1 -1
- package/dist/mjs/lib.mjs +1 -1
- package/dist/mjs/localizations/comments.d.ts +6 -0
- package/dist/mjs/localizations/comments.mjs +8 -0
- package/dist/mjs/localizations/es.mjs +68 -48
- package/dist/mjs/rendering/caching/RenderingCache.d.ts +1 -1
- package/dist/mjs/rendering/caching/RenderingCacheNode.d.ts +1 -1
- package/dist/mjs/rendering/caching/RenderingCacheNode.mjs +4 -3
- package/dist/mjs/rendering/renderers/AbstractRenderer.d.ts +1 -0
- package/dist/mjs/rendering/renderers/AbstractRenderer.mjs +8 -0
- package/dist/mjs/rendering/renderers/SVGRenderer.d.ts +28 -1
- package/dist/mjs/rendering/renderers/SVGRenderer.mjs +58 -7
- package/dist/mjs/toolbar/AbstractToolbar.d.ts +11 -3
- package/dist/mjs/toolbar/AbstractToolbar.mjs +20 -6
- package/dist/mjs/toolbar/EdgeToolbar.mjs +5 -6
- package/dist/mjs/toolbar/IconProvider.d.ts +1 -0
- package/dist/mjs/toolbar/IconProvider.mjs +43 -0
- package/dist/mjs/toolbar/widgets/ActionButtonWidget.d.ts +3 -1
- package/dist/mjs/toolbar/widgets/ActionButtonWidget.mjs +21 -2
- package/dist/mjs/toolbar/widgets/BaseToolWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/BaseToolWidget.mjs +3 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.d.ts +5 -0
- package/dist/mjs/toolbar/widgets/BaseWidget.mjs +30 -2
- package/dist/mjs/toolbar/widgets/DocumentPropertiesWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/HandToolWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/HandToolWidget.mjs +6 -0
- package/dist/mjs/toolbar/widgets/InsertImageWidget.mjs +1 -1
- package/dist/mjs/toolbar/widgets/OverflowWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/OverflowWidget.mjs +3 -0
- package/dist/mjs/toolbar/widgets/SaveActionWidget.d.ts +1 -0
- package/dist/mjs/toolbar/widgets/SaveActionWidget.mjs +3 -0
- package/dist/mjs/tools/BaseTool.d.ts +3 -0
- package/dist/mjs/tools/BaseTool.mjs +13 -2
- package/dist/mjs/tools/FindTool.d.ts +1 -0
- package/dist/mjs/tools/FindTool.mjs +4 -1
- package/dist/mjs/tools/PanZoom.d.ts +1 -0
- package/dist/mjs/tools/PanZoom.mjs +4 -0
- package/dist/mjs/tools/Pen.d.ts +0 -1
- package/dist/mjs/tools/Pen.mjs +1 -4
- package/dist/mjs/tools/PipetteTool.d.ts +1 -0
- package/dist/mjs/tools/PipetteTool.mjs +3 -0
- package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.d.ts +1 -0
- package/dist/mjs/tools/SelectionTool/SelectAllShortcutHandler.mjs +3 -0
- package/dist/mjs/tools/SelectionTool/Selection.d.ts +2 -0
- package/dist/mjs/tools/SelectionTool/Selection.mjs +45 -9
- package/dist/mjs/tools/SelectionTool/SelectionHandle.d.ts +14 -6
- package/dist/mjs/tools/SelectionTool/SelectionHandle.mjs +25 -7
- package/dist/mjs/tools/SelectionTool/SelectionTool.mjs +5 -0
- package/dist/mjs/tools/SoundUITool.d.ts +1 -0
- package/dist/mjs/tools/SoundUITool.mjs +4 -1
- package/dist/mjs/tools/TextTool.mjs +2 -2
- package/dist/mjs/tools/ToolController.d.ts +2 -0
- package/dist/mjs/tools/ToolController.mjs +13 -2
- package/dist/mjs/tools/ToolSwitcherShortcut.d.ts +1 -0
- package/dist/mjs/tools/ToolSwitcherShortcut.mjs +3 -0
- package/dist/mjs/types.d.ts +9 -4
- package/dist/mjs/types.mjs +4 -3
- package/dist/mjs/util/ReactiveValue.d.ts +1 -1
- package/dist/mjs/util/ReactiveValue.mjs +2 -2
- package/dist/mjs/version.mjs +1 -1
- package/package.json +5 -5
- package/src/Editor.scss +6 -0
- package/src/toolbar/EdgeToolbar.scss +19 -2
- package/src/tools/SelectionTool/SelectionTool.scss +74 -0
- package/src/tools/tools.scss +1 -1
- package/src/tools/SelectionTool/SelectionTool.css +0 -35
- /package/dist/cjs/{EditorImage.test.d.ts → Editor.toSVGAsync.test.d.ts} +0 -0
- /package/dist/{mjs → cjs/image}/EditorImage.test.d.ts +0 -0
@@ -1,68 +1,88 @@
|
|
1
1
|
import { defaultEditorLocalization } from '../localization.mjs';
|
2
|
-
// A partial Spanish localization.
|
2
|
+
// A partial Spanish localization, created with /scripts/markdownTranslationFormToTs.ts
|
3
3
|
const localization = {
|
4
4
|
...defaultEditorLocalization,
|
5
|
-
// Strings for the main editor interface
|
6
|
-
// (see src/localization.ts)
|
7
|
-
loading: (percentage) => `Cargando: ${percentage}%...`,
|
8
|
-
imageEditor: 'Editor de dibujos',
|
9
|
-
undoAnnouncement: (commandDescription) => `${commandDescription} fue deshecho`,
|
10
|
-
redoAnnouncement: (commandDescription) => `${commandDescription} fue rehecho`,
|
11
|
-
undo: 'Deshace',
|
12
|
-
redo: 'Rehace',
|
13
|
-
// Strings for the toolbar
|
14
|
-
// (see src/toolbar/localization.ts)
|
15
5
|
pen: 'Lapiz',
|
16
6
|
eraser: 'Borrador',
|
17
7
|
select: 'Selecciona',
|
18
|
-
thicknessLabel: 'Tamaño',
|
19
|
-
colorLabel: 'Color',
|
20
|
-
doneLoading: 'El cargado terminó',
|
21
|
-
fontLabel: 'Fuente: ',
|
22
|
-
anyDevicePanning: 'Mover la pantalla con todo dispotivo',
|
23
|
-
touchPanning: 'Mover la pantalla con un dedo',
|
24
|
-
touchPanTool: 'Instrumento de mover la pantalla con un dedo',
|
25
|
-
outlinedRectanglePen: 'Rectángulo con nada más que un borde',
|
26
|
-
filledRectanglePen: 'Rectángulo sin borde',
|
27
|
-
linePen: 'Línea',
|
28
|
-
arrowPen: 'Flecha',
|
29
|
-
roundedTipPen: 'Lapiz Redondeado',
|
30
|
-
selectPenTip: 'Forma de dibuja',
|
31
8
|
handTool: 'Mover',
|
32
|
-
|
9
|
+
image: 'Imagen',
|
10
|
+
chooseFile: 'Seleccionar archivo',
|
11
|
+
cancel: 'Cancelar',
|
33
12
|
resetView: 'Reiniciar vista',
|
13
|
+
thicknessLabel: 'Tamaño',
|
14
|
+
fontLabel: 'Fuente:',
|
15
|
+
textSize: 'Tamaño',
|
34
16
|
resizeImageToSelection: 'Redimensionar la imagen a lo que está seleccionado',
|
35
17
|
deleteSelection: 'Borra la selección',
|
36
18
|
duplicateSelection: 'Duplica la selección',
|
19
|
+
exit: 'Salir',
|
20
|
+
save: 'Guardar',
|
21
|
+
undo: 'Deshace',
|
22
|
+
redo: 'Rehace',
|
23
|
+
selectPenTip: 'Punta',
|
24
|
+
selectShape: 'Forma',
|
37
25
|
pickColorFromScreen: 'Selecciona un color de la pantalla',
|
38
26
|
clickToPickColorAnnouncement: 'Haga un clic en la pantalla para seleccionar un color',
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
27
|
+
documentProperties: 'Fondo',
|
28
|
+
backgroundColor: 'Color de fondo',
|
29
|
+
imageWidthOption: 'Ancho',
|
30
|
+
imageHeightOption: 'Alto',
|
31
|
+
toggleOverflow: 'Más',
|
32
|
+
touchPanning: 'Mover la pantalla con un dedo',
|
33
|
+
roundedTipPen: 'Lapiz Redondeado',
|
34
|
+
arrowPen: 'Flecha',
|
35
|
+
linePen: 'Línea',
|
36
|
+
outlinedRectanglePen: 'Rectángulo delineado',
|
37
|
+
filledRectanglePen: 'Rectángulo sin borde',
|
38
|
+
lockRotation: 'Bloquea rotación',
|
39
|
+
paste: 'Pegar',
|
40
|
+
closeSidebar: (toolName) => `Close sidebar for ${toolName}`,
|
41
|
+
dropdownShown: (toolName) => `Menú por ${toolName} es visible`,
|
42
|
+
dropdownHidden: (toolName) => { return `Menú por ${toolName} fue ocultado`; },
|
43
|
+
zoomLevel: (zoomPercent) => `Zoom: ${zoomPercent}%`,
|
44
|
+
colorChangedAnnouncement: (color) => { return `Color fue cambiado a ${color}`; },
|
45
|
+
imageSize: (size, units) => `Tamaño del imagen: ${size} ${units}`,
|
46
|
+
imageLoadError: (message) => `Error cargando imagen: ${message}`,
|
47
|
+
penTool: (penId) => { return `Lapiz ${penId}`; },
|
52
48
|
selectionTool: 'Selecciona',
|
53
49
|
eraserTool: 'Borrador',
|
50
|
+
touchPanTool: 'Instrumento de mover la pantalla con un dedo',
|
51
|
+
pipetteTool: 'Seleccione un color de la pantalla',
|
52
|
+
keyboardPanZoom: 'Mover la pantalla con el teclado',
|
54
53
|
textTool: 'Texto',
|
55
54
|
enterTextToInsert: 'Entra texto',
|
56
|
-
|
55
|
+
findLabel: 'Buscar',
|
56
|
+
toNextMatch: 'Próxima',
|
57
|
+
closeDialog: 'Cerrar',
|
58
|
+
focusedFoundText: (matchIdx, totalMatches) => `Viewing match ${matchIdx} of ${totalMatches}`,
|
59
|
+
anyDevicePanning: 'Mover la pantalla con todo dispotivo',
|
60
|
+
copied: (count, description) => `Copied ${count} ${description}`,
|
61
|
+
pasted: (count, description) => `Pasted ${count} ${description}`,
|
62
|
+
toolEnabledAnnouncement: (toolName) => `${toolName} enabled`,
|
63
|
+
toolDisabledAnnouncement: (toolName) => `${toolName} disabled`,
|
64
|
+
transformedElements: (elemCount) => `Transformed ${elemCount} element${elemCount === 1 ? '' : 's'}`,
|
65
|
+
resizeOutputCommand: (newSize) => `Resized image to ${newSize.w}x${newSize.h}`,
|
66
|
+
addElementAction: (componentDescription) => `Added ${componentDescription}`,
|
67
|
+
eraseAction: (componentDescription, numElems) => `Erased ${numElems} ${componentDescription}`,
|
68
|
+
duplicateAction: (componentDescription, numElems) => `Duplicated ${numElems} ${componentDescription}`,
|
69
|
+
unionOf: (actionDescription, actionCount) => `Union: ${actionCount} ${actionDescription}`,
|
70
|
+
inverseOf: (actionDescription) => `Inverse of ${actionDescription}`,
|
71
|
+
rotatedBy: (degrees) => `Rotated by ${Math.abs(degrees)} degrees ${degrees < 0 ? 'clockwise' : 'counter-clockwise'}`,
|
72
|
+
selectedElements: (count) => `Selected ${count} element${count === 1 ? '' : 's'}`,
|
73
|
+
filledBackgroundWithColor: (color) => `Filled background (${color})`,
|
74
|
+
text: (text) => `Text object: ${text}`,
|
75
|
+
imageNode: (label) => `Image: ${label}`,
|
76
|
+
restyledElement: (elementDescription) => `Restyled ${elementDescription}`,
|
77
|
+
pathNodeCount: (count) => `There are ${count} visible path objects.`,
|
78
|
+
textNodeCount: (count) => `There are ${count} visible text nodes.`,
|
79
|
+
imageNodeCount: (nodeCount) => `There are ${nodeCount} visible image nodes.`,
|
80
|
+
textNode: (content) => `Text: ${content}`,
|
57
81
|
rerenderAsText: 'Redibuja la pantalla al texto',
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
documentProperties: 'Fondo',
|
64
|
-
imageWidthOption: 'Ancho',
|
65
|
-
imageHeightOption: 'Alto',
|
66
|
-
backgroundColor: 'Color de fondo: '
|
82
|
+
loading: (percentage) => `Cargando: ${percentage}%...`,
|
83
|
+
imageEditor: 'Editor de dibujos',
|
84
|
+
doneLoading: 'El cargado terminó',
|
85
|
+
undoAnnouncement: (commandDescription) => `${commandDescription} fue deshecho`,
|
86
|
+
redoAnnouncement: (commandDescription) => `${commandDescription} fue rehecho`,
|
67
87
|
};
|
68
88
|
export default localization;
|
@@ -1,5 +1,5 @@
|
|
1
1
|
// A cache record with sub-nodes.
|
2
|
-
import { sortLeavesByZIndex } from '../../EditorImage.mjs';
|
2
|
+
import { sortLeavesByZIndex } from '../../image/EditorImage.mjs';
|
3
3
|
import { Rect2, Color4 } from '@js-draw/math';
|
4
4
|
// 3x3 divisions for each node.
|
5
5
|
const cacheDivisionSize = 3;
|
@@ -42,11 +42,12 @@ export default class RenderingCacheNode {
|
|
42
42
|
// Generates children, if missing.
|
43
43
|
generateChildren() {
|
44
44
|
if (this.instantiatedChildren.length === 0) {
|
45
|
-
|
46
|
-
if (this.region.size.x === 0 || this.region.size.y === 0) {
|
45
|
+
if (this.region.size.x / cacheDivisionSize === 0 || this.region.size.y / cacheDivisionSize === 0) {
|
47
46
|
console.warn('Cache element has zero size! Not generating children.');
|
48
47
|
return;
|
49
48
|
}
|
49
|
+
const childRects = this.region.divideIntoGrid(cacheDivisionSize, cacheDivisionSize);
|
50
|
+
console.assert(childRects.length === cacheDivisionSize * cacheDivisionSize, 'Warning: divideIntoGrid created the wrong number of subrectangles!');
|
50
51
|
for (const rect of childRects) {
|
51
52
|
const child = new RenderingCacheNode(rect, this.cacheState);
|
52
53
|
child.parent = this;
|
@@ -158,4 +158,12 @@ export default class AbstractRenderer {
|
|
158
158
|
getSizeOfCanvasPixelOnScreen() {
|
159
159
|
return this.getCanvasToScreenTransform().transformVec3(Vec2.unitX).length();
|
160
160
|
}
|
161
|
+
// Returns the region in canvas space that is visible within the viewport this
|
162
|
+
// canvas is rendering to.
|
163
|
+
//
|
164
|
+
// Note that in some cases this might not be the same as the `visibleRect` given
|
165
|
+
// to components in their `render` method.
|
166
|
+
getVisibleRect() {
|
167
|
+
return this.viewport.visibleRect;
|
168
|
+
}
|
161
169
|
}
|
@@ -6,6 +6,15 @@ import TextRenderingStyle from '../TextRenderingStyle';
|
|
6
6
|
import AbstractRenderer, { RenderableImage } from './AbstractRenderer';
|
7
7
|
import RenderablePathSpec from '../RenderablePathSpec';
|
8
8
|
export declare const renderedStylesheetId = "js-draw-style-sheet";
|
9
|
+
type FromViewportOptions = {
|
10
|
+
sanitize?: boolean;
|
11
|
+
/**
|
12
|
+
* Rather than having the top left of the `viewBox` set to (0, 0),
|
13
|
+
* if `useViewBoxForPositioning` is `true`, the `viewBox`'s top left
|
14
|
+
* is based on the top left of the rendering viewport's `visibleRect`.
|
15
|
+
*/
|
16
|
+
useViewBoxForPositioning?: boolean;
|
17
|
+
};
|
9
18
|
/**
|
10
19
|
* Renders onto an `SVGElement`.
|
11
20
|
*
|
@@ -50,8 +59,26 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
50
59
|
drawPoints(...points: Point2[]): void;
|
51
60
|
drawSVGElem(elem: SVGElement): void;
|
52
61
|
isTooSmallToRender(_rect: Rect2): boolean;
|
53
|
-
|
62
|
+
private visibleRectOverride;
|
63
|
+
/**
|
64
|
+
* Overrides the visible region returned by `getVisibleRect`.
|
65
|
+
*
|
66
|
+
* This is useful when the `viewport`'s transform has been modified,
|
67
|
+
* for example, to compensate for storing part of the image's
|
68
|
+
* transformation in an SVG property.
|
69
|
+
*/
|
70
|
+
private overrideVisibleRect;
|
71
|
+
getVisibleRect(): Rect2;
|
72
|
+
/**
|
73
|
+
* Creates a new SVG element and `SVGRenerer` with `width`, `height`, `viewBox`,
|
74
|
+
* and other metadata attributes set for the given `Viewport`.
|
75
|
+
*
|
76
|
+
* If `options` is a `boolean`, it is interpreted as whether to sanitize (not add unknown
|
77
|
+
* SVG entities to) the output.
|
78
|
+
*/
|
79
|
+
static fromViewport(viewport: Viewport, options?: FromViewportOptions | boolean): {
|
54
80
|
element: SVGSVGElement;
|
55
81
|
renderer: SVGRenderer;
|
56
82
|
};
|
57
83
|
}
|
84
|
+
export {};
|
@@ -36,6 +36,7 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
36
36
|
this.textContainer = null;
|
37
37
|
this.textContainerTransform = null;
|
38
38
|
this.textParentStyle = defaultTextStyle;
|
39
|
+
this.visibleRectOverride = null;
|
39
40
|
this.clear();
|
40
41
|
this.addStyleSheet();
|
41
42
|
}
|
@@ -338,20 +339,70 @@ export default class SVGRenderer extends AbstractRenderer {
|
|
338
339
|
isTooSmallToRender(_rect) {
|
339
340
|
return false;
|
340
341
|
}
|
341
|
-
|
342
|
-
|
342
|
+
/**
|
343
|
+
* Overrides the visible region returned by `getVisibleRect`.
|
344
|
+
*
|
345
|
+
* This is useful when the `viewport`'s transform has been modified,
|
346
|
+
* for example, to compensate for storing part of the image's
|
347
|
+
* transformation in an SVG property.
|
348
|
+
*/
|
349
|
+
overrideVisibleRect(newRect) {
|
350
|
+
this.visibleRectOverride = newRect;
|
351
|
+
}
|
352
|
+
getVisibleRect() {
|
353
|
+
return this.visibleRectOverride ?? super.getVisibleRect();
|
354
|
+
}
|
355
|
+
/**
|
356
|
+
* Creates a new SVG element and `SVGRenerer` with `width`, `height`, `viewBox`,
|
357
|
+
* and other metadata attributes set for the given `Viewport`.
|
358
|
+
*
|
359
|
+
* If `options` is a `boolean`, it is interpreted as whether to sanitize (not add unknown
|
360
|
+
* SVG entities to) the output.
|
361
|
+
*/
|
362
|
+
static fromViewport(viewport, options = true) {
|
363
|
+
let sanitize;
|
364
|
+
let useViewBoxForPositioning;
|
365
|
+
if (typeof options === 'boolean') {
|
366
|
+
sanitize = options;
|
367
|
+
useViewBoxForPositioning = false;
|
368
|
+
}
|
369
|
+
else {
|
370
|
+
sanitize = options.sanitize ?? true;
|
371
|
+
useViewBoxForPositioning = options.useViewBoxForPositioning ?? false;
|
372
|
+
}
|
343
373
|
const svgNameSpace = 'http://www.w3.org/2000/svg';
|
344
374
|
const result = document.createElementNS(svgNameSpace, 'svg');
|
345
|
-
const
|
375
|
+
const screenRectSize = viewport.getScreenRectSize();
|
376
|
+
const visibleRect = viewport.visibleRect;
|
377
|
+
let viewBoxComponents;
|
378
|
+
if (useViewBoxForPositioning) {
|
379
|
+
const exportRect = viewport.visibleRect;
|
380
|
+
viewBoxComponents = [
|
381
|
+
exportRect.x, exportRect.y, exportRect.w, exportRect.h,
|
382
|
+
];
|
383
|
+
// Replace the viewport with a copy that has a modified transform.
|
384
|
+
// (Avoids modifying the original viewport).
|
385
|
+
viewport = viewport.getTemporaryClone();
|
386
|
+
// TODO: This currently discards any rotation information.
|
387
|
+
// Render with (0,0) at (0,0) -- the translation is handled by the viewBox.
|
388
|
+
viewport.resetTransform(Mat33.identity);
|
389
|
+
}
|
390
|
+
else {
|
391
|
+
viewBoxComponents = [0, 0, screenRectSize.x, screenRectSize.y];
|
392
|
+
}
|
346
393
|
// rect.x -> size of rect in x direction, rect.y -> size of rect in y direction.
|
347
|
-
result.setAttribute('viewBox',
|
348
|
-
result.setAttribute('width', toRoundedString(
|
349
|
-
result.setAttribute('height', toRoundedString(
|
394
|
+
result.setAttribute('viewBox', viewBoxComponents.map(part => toRoundedString(part)).join(' '));
|
395
|
+
result.setAttribute('width', toRoundedString(screenRectSize.x));
|
396
|
+
result.setAttribute('height', toRoundedString(screenRectSize.y));
|
350
397
|
// Ensure the image can be identified as an SVG if downloaded.
|
351
398
|
// See https://jwatt.org/svg/authoring/
|
352
399
|
result.setAttribute('version', '1.1');
|
353
400
|
result.setAttribute('baseProfile', 'full');
|
354
401
|
result.setAttribute('xmlns', svgNameSpace);
|
355
|
-
|
402
|
+
const renderer = new SVGRenderer(result, viewport, sanitize);
|
403
|
+
if (!visibleRect.eq(viewport.visibleRect)) {
|
404
|
+
renderer.overrideVisibleRect(visibleRect);
|
405
|
+
}
|
406
|
+
return { element: result, renderer };
|
356
407
|
}
|
357
408
|
}
|
@@ -8,6 +8,10 @@ export interface SpacerOptions {
|
|
8
8
|
minSize: string;
|
9
9
|
maxSize: string;
|
10
10
|
}
|
11
|
+
export type ToolbarActionButtonOptions = {
|
12
|
+
mustBeToplevel?: boolean;
|
13
|
+
autoDisableInReadOnlyEditors?: boolean;
|
14
|
+
};
|
11
15
|
export default abstract class AbstractToolbar {
|
12
16
|
#private;
|
13
17
|
protected editor: Editor;
|
@@ -91,18 +95,22 @@ export default abstract class AbstractToolbar {
|
|
91
95
|
* @see
|
92
96
|
* {@link addActionButton}
|
93
97
|
*/
|
94
|
-
protected makeActionButton(title: string | ActionButtonIcon, command: () => void,
|
98
|
+
protected makeActionButton(title: string | ActionButtonIcon, command: () => void, options?: ToolbarActionButtonOptions | boolean): BaseWidget;
|
95
99
|
/**
|
96
100
|
* Adds an action button with `title` to this toolbar (or to the given `parent` element).
|
97
101
|
*
|
102
|
+
* `options` can either be an object with properties `mustBeToplevel` and/or
|
103
|
+
* `autoDisableInReadOnlyEditors` or a boolean value. If a boolean, it is interpreted
|
104
|
+
* as being the value of `mustBeToplevel`.
|
105
|
+
*
|
98
106
|
* @return The added button.
|
99
107
|
*/
|
100
|
-
addActionButton(title: string | ActionButtonIcon, command: () => void,
|
108
|
+
addActionButton(title: string | ActionButtonIcon, command: () => void, options?: ToolbarActionButtonOptions | boolean): BaseWidget;
|
101
109
|
/**
|
102
110
|
* Like {@link addActionButton}, except associates `tags` with the button that allow
|
103
111
|
* different toolbar styles to give the button tag-dependent styles.
|
104
112
|
*/
|
105
|
-
addTaggedActionButton(tags: (ToolbarWidgetTag | string)[], title: string | ActionButtonIcon, command: () => void,
|
113
|
+
addTaggedActionButton(tags: (ToolbarWidgetTag | string)[], title: string | ActionButtonIcon, command: () => void, options?: ToolbarActionButtonOptions | boolean): BaseWidget;
|
106
114
|
/**
|
107
115
|
* Adds a save button that, when clicked, calls `saveCallback`.
|
108
116
|
*
|
@@ -230,7 +230,15 @@ class AbstractToolbar {
|
|
230
230
|
* @see
|
231
231
|
* {@link addActionButton}
|
232
232
|
*/
|
233
|
-
makeActionButton(title, command,
|
233
|
+
makeActionButton(title, command, options = true) {
|
234
|
+
// Parse options
|
235
|
+
if (typeof options === 'boolean') {
|
236
|
+
options = {
|
237
|
+
mustBeToplevel: options,
|
238
|
+
};
|
239
|
+
}
|
240
|
+
const mustBeToplevel = options.mustBeToplevel ?? true;
|
241
|
+
const autoDisableInReadOnlyEditors = options.autoDisableInReadOnlyEditors ?? true;
|
234
242
|
const titleString = typeof title === 'string' ? title : title.label;
|
235
243
|
const widgetId = 'action-button';
|
236
244
|
const makeIcon = () => {
|
@@ -239,16 +247,20 @@ class AbstractToolbar {
|
|
239
247
|
}
|
240
248
|
return title.icon;
|
241
249
|
};
|
242
|
-
const widget = new ActionButtonWidget(this.editor, widgetId, makeIcon, titleString, command, this.editor.localization, mustBeToplevel);
|
250
|
+
const widget = new ActionButtonWidget(this.editor, widgetId, makeIcon, titleString, command, this.editor.localization, mustBeToplevel, autoDisableInReadOnlyEditors);
|
243
251
|
return widget;
|
244
252
|
}
|
245
253
|
/**
|
246
254
|
* Adds an action button with `title` to this toolbar (or to the given `parent` element).
|
247
255
|
*
|
256
|
+
* `options` can either be an object with properties `mustBeToplevel` and/or
|
257
|
+
* `autoDisableInReadOnlyEditors` or a boolean value. If a boolean, it is interpreted
|
258
|
+
* as being the value of `mustBeToplevel`.
|
259
|
+
*
|
248
260
|
* @return The added button.
|
249
261
|
*/
|
250
|
-
addActionButton(title, command,
|
251
|
-
const widget = this.makeActionButton(title, command,
|
262
|
+
addActionButton(title, command, options = true) {
|
263
|
+
const widget = this.makeActionButton(title, command, options);
|
252
264
|
this.addWidget(widget);
|
253
265
|
return widget;
|
254
266
|
}
|
@@ -256,8 +268,8 @@ class AbstractToolbar {
|
|
256
268
|
* Like {@link addActionButton}, except associates `tags` with the button that allow
|
257
269
|
* different toolbar styles to give the button tag-dependent styles.
|
258
270
|
*/
|
259
|
-
addTaggedActionButton(tags, title, command,
|
260
|
-
const widget = this.makeActionButton(title, command,
|
271
|
+
addTaggedActionButton(tags, title, command, options = true) {
|
272
|
+
const widget = this.makeActionButton(title, command, options);
|
261
273
|
widget.setTags(tags);
|
262
274
|
this.addWidget(widget);
|
263
275
|
return widget;
|
@@ -303,6 +315,8 @@ class AbstractToolbar {
|
|
303
315
|
icon: this.editor.icons.makeCloseIcon(),
|
304
316
|
}, () => {
|
305
317
|
exitCallback();
|
318
|
+
}, {
|
319
|
+
autoDisableInReadOnlyEditors: false,
|
306
320
|
});
|
307
321
|
}
|
308
322
|
/**
|
@@ -191,7 +191,6 @@ export default class EdgeToolbar extends AbstractToolbar {
|
|
191
191
|
};
|
192
192
|
const actionRowBBox = this.toolbarActionRow.getBoundingClientRect();
|
193
193
|
const toolbarRowBBox = this.toolbarToolRow.getBoundingClientRect();
|
194
|
-
const inSameRow = actionRowBBox.y === toolbarRowBBox.y;
|
195
194
|
const onDifferentRows = actionRowBBox.y + actionRowBBox.height <= toolbarRowBBox.y;
|
196
195
|
if (onDifferentRows) {
|
197
196
|
this.toolbarContainer.classList.remove('one-row');
|
@@ -201,11 +200,11 @@ export default class EdgeToolbar extends AbstractToolbar {
|
|
201
200
|
}
|
202
201
|
if (this.toolbarToolRow.clientWidth < this.toolbarToolRow.scrollWidth) {
|
203
202
|
this.toolbarToolRow.classList.add('has-scroll');
|
204
|
-
//
|
205
|
-
//
|
206
|
-
|
207
|
-
|
208
|
-
|
203
|
+
// Note: This can potentially change the size of the tool row.
|
204
|
+
// Because this is run inside of a ResizeObserver callback, special
|
205
|
+
// care must be taken to ensure that this change doesn't re-trigger
|
206
|
+
// the resize observer.
|
207
|
+
setExtraPadding();
|
209
208
|
}
|
210
209
|
else {
|
211
210
|
this.toolbarToolRow.classList.remove('has-scroll', 'extra-padding');
|
@@ -38,6 +38,7 @@ export default class IconProvider {
|
|
38
38
|
makeDropdownIcon(): IconElemType;
|
39
39
|
makeEraserIcon(eraserSize?: number): IconElemType;
|
40
40
|
makeSelectionIcon(): IconElemType;
|
41
|
+
makeRotateIcon(): IconElemType;
|
41
42
|
makeHandToolIcon(): IconElemType;
|
42
43
|
makeTouchPanningIcon(): IconElemType;
|
43
44
|
/** Unused by js-draw. @deprecated */
|
@@ -164,6 +164,49 @@ class IconProvider {
|
|
164
164
|
icon.setAttribute('viewBox', '0 0 100 100');
|
165
165
|
return icon;
|
166
166
|
}
|
167
|
+
makeRotateIcon() {
|
168
|
+
const icon = document.createElementNS(svgNamespace, 'svg');
|
169
|
+
icon.innerHTML = `
|
170
|
+
<defs>
|
171
|
+
<marker
|
172
|
+
id="arrow-marker"
|
173
|
+
viewBox="0 0 10 10"
|
174
|
+
refX="3" refY="5"
|
175
|
+
markerWidth="3" markerHeight="3"
|
176
|
+
orient="auto-start-reverse"
|
177
|
+
>
|
178
|
+
<path
|
179
|
+
d="M0,0 L8,5 L0,10z"
|
180
|
+
fill="var(--icon-color)"
|
181
|
+
/>
|
182
|
+
</marker>
|
183
|
+
</defs>
|
184
|
+
|
185
|
+
<path
|
186
|
+
marker-start="url(#arrow-marker)"
|
187
|
+
d="
|
188
|
+
M20,20
|
189
|
+
A30,30 0 1 1 80 80
|
190
|
+
"
|
191
|
+
fill="none"
|
192
|
+
stroke="var(--icon-color)"
|
193
|
+
stroke-width="12"
|
194
|
+
/>
|
195
|
+
<path
|
196
|
+
d="
|
197
|
+
M80,80
|
198
|
+
A30,30 0 1 1 20 20
|
199
|
+
"
|
200
|
+
fill="none"
|
201
|
+
stroke="var(--icon-color)"
|
202
|
+
stroke-width="12"
|
203
|
+
stroke-dasharray="30 10 20 10 20 10 10"
|
204
|
+
style="stroke-linecap: butt;"
|
205
|
+
/>
|
206
|
+
`;
|
207
|
+
icon.setAttribute('viewBox', '-5 -5 110 110');
|
208
|
+
return icon;
|
209
|
+
}
|
167
210
|
makeHandToolIcon() {
|
168
211
|
const fill = 'none';
|
169
212
|
const strokeColor = 'var(--icon-color)';
|
@@ -2,11 +2,13 @@ import Editor from '../../Editor';
|
|
2
2
|
import { ToolbarLocalization } from '../localization';
|
3
3
|
import BaseWidget from './BaseWidget';
|
4
4
|
export default class ActionButtonWidget extends BaseWidget {
|
5
|
+
#private;
|
5
6
|
protected makeIcon: () => Element | null;
|
6
7
|
protected title: string;
|
7
8
|
protected clickAction: () => void;
|
8
9
|
protected mustBeToplevel: boolean;
|
9
|
-
constructor(editor: Editor, id: string, makeIcon: () => Element | null, title: string, clickAction: () => void, localizationTable?: ToolbarLocalization, mustBeToplevel?: boolean);
|
10
|
+
constructor(editor: Editor, id: string, makeIcon: () => Element | null, title: string, clickAction: () => void, localizationTable?: ToolbarLocalization, mustBeToplevel?: boolean, autoDisableInReadOnlyEditors?: boolean);
|
11
|
+
protected shouldAutoDisableInReadOnlyEditor(): boolean;
|
10
12
|
protected handleClick(): void;
|
11
13
|
protected getTitle(): string;
|
12
14
|
protected createIcon(): Element | null;
|
@@ -1,11 +1,28 @@
|
|
1
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
2
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
3
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
4
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
5
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
6
|
+
};
|
7
|
+
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
|
8
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
|
9
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
10
|
+
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
11
|
+
};
|
12
|
+
var _ActionButtonWidget_autoDisableInReadOnlyEditors;
|
1
13
|
import BaseWidget from './BaseWidget.mjs';
|
2
|
-
|
3
|
-
constructor(editor, id, makeIcon, title, clickAction, localizationTable, mustBeToplevel = false) {
|
14
|
+
class ActionButtonWidget extends BaseWidget {
|
15
|
+
constructor(editor, id, makeIcon, title, clickAction, localizationTable, mustBeToplevel = false, autoDisableInReadOnlyEditors = true) {
|
4
16
|
super(editor, id, localizationTable);
|
5
17
|
this.makeIcon = makeIcon;
|
6
18
|
this.title = title;
|
7
19
|
this.clickAction = clickAction;
|
8
20
|
this.mustBeToplevel = mustBeToplevel;
|
21
|
+
_ActionButtonWidget_autoDisableInReadOnlyEditors.set(this, void 0);
|
22
|
+
__classPrivateFieldSet(this, _ActionButtonWidget_autoDisableInReadOnlyEditors, autoDisableInReadOnlyEditors, "f");
|
23
|
+
}
|
24
|
+
shouldAutoDisableInReadOnlyEditor() {
|
25
|
+
return __classPrivateFieldGet(this, _ActionButtonWidget_autoDisableInReadOnlyEditors, "f");
|
9
26
|
}
|
10
27
|
handleClick() {
|
11
28
|
this.clickAction();
|
@@ -23,3 +40,5 @@ export default class ActionButtonWidget extends BaseWidget {
|
|
23
40
|
return this.mustBeToplevel;
|
24
41
|
}
|
25
42
|
}
|
43
|
+
_ActionButtonWidget_autoDisableInReadOnlyEditors = new WeakMap();
|
44
|
+
export default ActionButtonWidget;
|
@@ -6,6 +6,7 @@ import BaseWidget from './BaseWidget';
|
|
6
6
|
export default abstract class BaseToolWidget extends BaseWidget {
|
7
7
|
protected targetTool: BaseTool;
|
8
8
|
constructor(editor: Editor, targetTool: BaseTool, id: string, localizationTable?: ToolbarLocalization);
|
9
|
+
protected shouldAutoDisableInReadOnlyEditor(): boolean;
|
9
10
|
protected handleClick(): void;
|
10
11
|
protected onKeyPress(event: KeyPressEvent): boolean;
|
11
12
|
addTo(parent: HTMLElement): HTMLElement;
|
@@ -34,6 +34,9 @@ export default class BaseToolWidget extends BaseWidget {
|
|
34
34
|
}
|
35
35
|
});
|
36
36
|
}
|
37
|
+
shouldAutoDisableInReadOnlyEditor() {
|
38
|
+
return !this.targetTool.canReceiveInputInReadOnlyEditor();
|
39
|
+
}
|
37
40
|
handleClick() {
|
38
41
|
if (this.hasDropdown) {
|
39
42
|
if (!this.targetTool.isEnabled()) {
|
@@ -29,6 +29,11 @@ export default abstract class BaseWidget {
|
|
29
29
|
private toplevel;
|
30
30
|
protected readonly localizationTable: ToolbarLocalization;
|
31
31
|
constructor(editor: Editor, id: string, localizationTable?: ToolbarLocalization);
|
32
|
+
/**
|
33
|
+
* Should return a constant true or false value. If true (the default),
|
34
|
+
* this widget must be automatically disabled when its editor is read-only.
|
35
|
+
*/
|
36
|
+
protected shouldAutoDisableInReadOnlyEditor(): boolean;
|
32
37
|
getId(): string;
|
33
38
|
/**
|
34
39
|
* Note: Tags should be set *before* a tool widget is added to a toolbar.
|