kritzel-stencil 0.3.16 → 0.3.17
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/LICENSE.md +50 -0
- package/dist/cjs/index-Xav9JFHg.js +2 -2
- package/dist/cjs/index.cjs.js +7 -1
- package/dist/cjs/{kritzel-active-users_42.cjs.entry.js → kritzel-active-users_44.cjs.entry.js} +710 -145
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/cjs/{schema.constants-DJQTjcy7.js → schema.constants-DrHO_CYF.js} +1169 -171
- package/dist/cjs/stencil.cjs.js +1 -1
- package/dist/collection/classes/core/core.class.js +24 -0
- package/dist/collection/classes/handlers/context-menu.handler.js +24 -2
- package/dist/collection/classes/managers/license.manager.js +285 -0
- package/dist/collection/classes/managers/localization.manager.js +189 -0
- package/dist/collection/classes/objects/custom-element.class.js +2 -0
- package/dist/collection/classes/objects/group.class.js +7 -2
- package/dist/collection/classes/objects/image.class.js +10 -7
- package/dist/collection/classes/objects/line.class.js +3 -0
- package/dist/collection/classes/objects/path.class.js +13 -12
- package/dist/collection/classes/objects/selection-group.class.js +7 -2
- package/dist/collection/classes/objects/shape.class.js +3 -0
- package/dist/collection/classes/objects/text.class.js +4 -1
- package/dist/collection/classes/registries/icon-registry.class.js +1 -0
- package/dist/collection/classes/tools/brush-tool.class.js +1 -1
- package/dist/collection/collection-manifest.json +3 -1
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.css +16 -0
- package/dist/collection/components/core/kritzel-editor/kritzel-editor.js +462 -60
- package/dist/collection/components/core/kritzel-engine/kritzel-engine.js +446 -16
- package/dist/collection/components/core/kritzel-watermark/kritzel-watermark.css +29 -0
- package/dist/collection/components/core/kritzel-watermark/kritzel-watermark.js +83 -0
- package/dist/collection/components/shared/kritzel-avatar/kritzel-avatar.js +3 -3
- package/dist/collection/components/shared/kritzel-button/kritzel-button.js +2 -2
- package/dist/collection/components/shared/kritzel-color/kritzel-color.js +2 -2
- package/dist/collection/components/shared/kritzel-color-palette/kritzel-color-palette.js +1 -1
- package/dist/collection/components/shared/kritzel-font/kritzel-font.js +1 -1
- package/dist/collection/components/shared/kritzel-font-size/kritzel-font-size.js +2 -1
- package/dist/collection/components/shared/kritzel-input/kritzel-input.js +1 -1
- package/dist/collection/components/shared/kritzel-master-detail/kritzel-master-detail.js +3 -3
- package/dist/collection/components/shared/kritzel-menu/kritzel-menu.js +1 -1
- package/dist/collection/components/shared/kritzel-menu-item/kritzel-menu-item.js +2 -2
- package/dist/collection/components/shared/kritzel-numeric-input/kritzel-numeric-input.js +1 -1
- package/dist/collection/components/shared/kritzel-opacity-slider/kritzel-opacity-slider.js +1 -1
- package/dist/collection/components/shared/kritzel-portal/kritzel-portal.js +1 -1
- package/dist/collection/components/shared/kritzel-slide-toggle/kritzel-slide-toggle.js +1 -1
- package/dist/collection/components/shared/kritzel-split-button/kritzel-split-button.js +1 -1
- package/dist/collection/components/shared/kritzel-stroke-size/kritzel-stroke-size.js +2 -1
- package/dist/collection/components/shared/kritzel-tooltip/kritzel-tooltip.js +2 -2
- package/dist/collection/components/ui/kritzel-back-to-content/kritzel-back-to-content.js +1 -1
- package/dist/collection/components/ui/kritzel-controls/kritzel-controls.js +41 -6
- package/dist/collection/components/ui/kritzel-current-user/kritzel-current-user.js +36 -1
- package/dist/collection/components/ui/kritzel-current-user-dialog/kritzel-current-user-dialog.js +36 -1
- package/dist/collection/components/ui/kritzel-export/kritzel-export.js +44 -7
- package/dist/collection/components/ui/kritzel-login-dialog/kritzel-login-dialog.js +1 -1
- package/dist/collection/components/ui/kritzel-more-menu/kritzel-more-menu.js +36 -1
- package/dist/collection/components/ui/kritzel-settings/kritzel-settings.js +108 -14
- package/dist/collection/components/ui/kritzel-share-dialog/kritzel-share-dialog.js +38 -3
- package/dist/collection/components/ui/kritzel-tool-config/kritzel-tool-config.js +38 -3
- package/dist/collection/components/ui/kritzel-utility-panel/kritzel-utility-panel.js +36 -1
- package/dist/collection/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.js +38 -3
- package/dist/collection/components/ui/kritzel-zoom-panel/kritzel-zoom-panel.css +72 -0
- package/dist/collection/components/ui/kritzel-zoom-panel/kritzel-zoom-panel.js +173 -0
- package/dist/collection/constants/engine.constants.js +2 -0
- package/dist/collection/constants/license.constants.js +25 -0
- package/dist/collection/constants/version.js +1 -1
- package/dist/collection/helpers/localization.helper.js +25 -0
- package/dist/collection/helpers/math.helper.js +3 -0
- package/dist/collection/helpers/svg-export.helper.js +223 -26
- package/dist/collection/index.js +13 -0
- package/dist/collection/interfaces/localization.interface.js +1 -0
- package/dist/collection/locales/de-locale.js +119 -0
- package/dist/collection/locales/en-locale.js +120 -0
- package/dist/collection/locales/fr-locale.js +119 -0
- package/dist/collection/themes/dark-theme.js +18 -0
- package/dist/collection/themes/light-theme.js +18 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +1 -1
- package/dist/components/kritzel-active-users.js +1 -1
- package/dist/components/kritzel-avatar.js +1 -1
- package/dist/components/kritzel-awareness-cursors.js +1 -1
- package/dist/components/kritzel-back-to-content.js +1 -1
- package/dist/components/kritzel-brush-style.js +1 -1
- package/dist/components/kritzel-button.js +1 -1
- package/dist/components/kritzel-color-palette.js +1 -1
- package/dist/components/kritzel-color.js +1 -1
- package/dist/components/kritzel-context-menu.js +1 -1
- package/dist/components/kritzel-controls.js +1 -1
- package/dist/components/kritzel-current-user-dialog.js +1 -1
- package/dist/components/kritzel-current-user.js +1 -1
- package/dist/components/kritzel-editor.js +1 -1
- package/dist/components/kritzel-engine.js +1 -1
- package/dist/components/kritzel-export.js +1 -1
- package/dist/components/kritzel-font-size.js +1 -1
- package/dist/components/kritzel-font.js +1 -1
- package/dist/components/kritzel-icon.js +1 -1
- package/dist/components/kritzel-input.js +1 -1
- package/dist/components/kritzel-login-dialog.js +1 -1
- package/dist/components/kritzel-master-detail.js +1 -1
- package/dist/components/kritzel-menu-item.js +1 -1
- package/dist/components/kritzel-menu.js +1 -1
- package/dist/components/kritzel-more-menu.js +1 -1
- package/dist/components/kritzel-numeric-input.js +1 -1
- package/dist/components/kritzel-opacity-slider.js +1 -1
- package/dist/components/kritzel-pill-tabs.js +1 -1
- package/dist/components/kritzel-portal.js +1 -1
- package/dist/components/kritzel-settings.js +1 -1
- package/dist/components/kritzel-share-dialog.js +1 -1
- package/dist/components/kritzel-slide-toggle.js +1 -1
- package/dist/components/kritzel-split-button.js +1 -1
- package/dist/components/kritzel-stroke-size.js +1 -1
- package/dist/components/kritzel-tool-config.js +1 -1
- package/dist/components/kritzel-tooltip.js +1 -1
- package/dist/components/kritzel-utility-panel.js +1 -1
- package/dist/components/kritzel-watermark.d.ts +11 -0
- package/dist/components/kritzel-watermark.js +1 -0
- package/dist/components/kritzel-workspace-manager.js +1 -1
- package/dist/components/kritzel-zoom-panel.d.ts +11 -0
- package/dist/components/kritzel-zoom-panel.js +1 -0
- package/dist/components/{p-B5xxfwKF.js → p-3HxnBrCM.js} +1 -1
- package/dist/components/p-6RjeGuvH.js +1 -0
- package/dist/components/p-7NsK0uHu.js +1 -0
- package/dist/components/{p-dcAernE1.js → p-BCNyR5Sw.js} +1 -1
- package/dist/components/{p-C2SX-XRr.js → p-BG6hOSrm.js} +1 -1
- package/dist/components/p-BKJSh8qQ.js +1 -0
- package/dist/components/{p-SptaSMno.js → p-BKvHg9cv.js} +1 -1
- package/dist/components/p-Bc55X65h.js +1 -0
- package/dist/components/p-BpnIvNvq.js +1 -0
- package/dist/components/p-BvRrA4hN.js +1 -0
- package/dist/components/{p-B2w8X7vn.js → p-BxpKq94F.js} +1 -1
- package/dist/components/{p-BFoK4W--.js → p-Bzv9Px8v.js} +1 -1
- package/dist/components/{p-COLHjboZ.js → p-C9HGoDHE.js} +1 -1
- package/dist/components/p-CEnEDaix.js +1 -0
- package/dist/components/p-CIcLzcfA.js +1 -0
- package/dist/components/p-CPtDfadX.js +1 -0
- package/dist/components/p-C_fKgKHu.js +9 -0
- package/dist/components/p-CdR76C4L.js +1 -0
- package/dist/components/p-Cu9KYyoq.js +1 -0
- package/dist/components/p-CyqRcqsO.js +1 -0
- package/dist/components/{p-UoPj5QjH.js → p-DDkmsPpV.js} +1 -1
- package/dist/components/{p-D-sRVAbQ.js → p-DI4vQRE3.js} +1 -1
- package/dist/components/{p-CJOhfMU5.js → p-DNdXJp8F.js} +1 -1
- package/dist/components/p-DX5K8xnh.js +1 -0
- package/dist/components/{p-DEy7zJCe.js → p-DZdgXCAx.js} +1 -1
- package/dist/components/p-DdH1cKED.js +1 -0
- package/dist/components/p-DdsSSqFY.js +1 -0
- package/dist/components/p-DgmtCdnL.js +1 -0
- package/dist/components/{p-BzYU3-MJ.js → p-DmWSRsjK.js} +1 -1
- package/dist/components/{p-Bj2laX89.js → p-Dz-Ti24X.js} +1 -1
- package/dist/components/{p-BiG1dxPS.js → p-F5_X4dZG.js} +1 -1
- package/dist/components/{p-x6doYeiI.js → p-IpoC5EEY.js} +1 -1
- package/dist/components/p-Jn6TNdfe.js +1 -0
- package/dist/components/{p-BfNHpqQ8.js → p-NuLP1xHe.js} +1 -1
- package/dist/components/{p-skWUIStn.js → p-SDZNC8GF.js} +1 -1
- package/dist/components/{p-BYmp9Ovv.js → p-U4oawa1x.js} +1 -1
- package/dist/components/{p-DM11KXUT.js → p-f8aW1ye7.js} +1 -1
- package/dist/components/p-v7dxxrL5.js +1 -0
- package/dist/components/p-vAeiXe6c.js +1 -0
- package/dist/esm/index-Dhio9uis.js +2 -2
- package/dist/esm/index.js +2 -2
- package/dist/esm/{kritzel-active-users_42.entry.js → kritzel-active-users_44.entry.js} +709 -146
- package/dist/esm/loader.js +1 -1
- package/dist/esm/{schema.constants-DiCnmIYK.js → schema.constants-DchTXG3V.js} +1163 -172
- package/dist/esm/stencil.js +1 -1
- package/dist/stencil/index.esm.js +1 -1
- package/dist/stencil/p-DchTXG3V.js +1 -0
- package/dist/stencil/p-c9a3807b.entry.js +9 -0
- package/dist/stencil/stencil.esm.js +1 -1
- package/dist/types/classes/core/core.class.d.ts +16 -0
- package/dist/types/classes/handlers/context-menu.handler.d.ts +13 -0
- package/dist/types/classes/managers/license.manager.d.ts +141 -0
- package/dist/types/classes/managers/localization.manager.d.ts +121 -0
- package/dist/types/classes/objects/custom-element.class.d.ts +2 -0
- package/dist/types/classes/objects/group.class.d.ts +6 -1
- package/dist/types/classes/objects/image.class.d.ts +1 -1
- package/dist/types/classes/objects/path.class.d.ts +3 -2
- package/dist/types/classes/objects/selection-group.class.d.ts +6 -1
- package/dist/types/classes/objects/shape.class.d.ts +2 -0
- package/dist/types/classes/objects/text.class.d.ts +2 -1
- package/dist/types/classes/tools/brush-tool.class.d.ts +1 -1
- package/dist/types/components/core/kritzel-editor/kritzel-editor.d.ts +53 -1
- package/dist/types/components/core/kritzel-engine/kritzel-engine.d.ts +55 -3
- package/dist/types/components/core/kritzel-watermark/kritzel-watermark.d.ts +20 -0
- package/dist/types/components/ui/kritzel-controls/kritzel-controls.d.ts +3 -0
- package/dist/types/components/ui/kritzel-current-user/kritzel-current-user.d.ts +3 -0
- package/dist/types/components/ui/kritzel-current-user-dialog/kritzel-current-user-dialog.d.ts +3 -0
- package/dist/types/components/ui/kritzel-export/kritzel-export.d.ts +4 -1
- package/dist/types/components/ui/kritzel-more-menu/kritzel-more-menu.d.ts +3 -0
- package/dist/types/components/ui/kritzel-settings/kritzel-settings.d.ts +16 -0
- package/dist/types/components/ui/kritzel-share-dialog/kritzel-share-dialog.d.ts +3 -0
- package/dist/types/components/ui/kritzel-tool-config/kritzel-tool-config.d.ts +3 -0
- package/dist/types/components/ui/kritzel-utility-panel/kritzel-utility-panel.d.ts +3 -0
- package/dist/types/components/ui/kritzel-workspace-manager/kritzel-workspace-manager.d.ts +3 -0
- package/dist/types/components/ui/kritzel-zoom-panel/kritzel-zoom-panel.d.ts +20 -0
- package/dist/types/components.d.ts +445 -26
- package/dist/types/constants/engine.constants.d.ts +2 -0
- package/dist/types/constants/license.constants.d.ts +25 -0
- package/dist/types/constants/version.d.ts +1 -1
- package/dist/types/helpers/localization.helper.d.ts +18 -0
- package/dist/types/helpers/math.helper.d.ts +1 -0
- package/dist/types/helpers/svg-export.helper.d.ts +81 -7
- package/dist/types/index.d.ts +13 -0
- package/dist/types/interfaces/context-menu-item.interface.d.ts +7 -1
- package/dist/types/interfaces/line-options.interface.d.ts +2 -0
- package/dist/types/interfaces/localization.interface.d.ts +143 -0
- package/dist/types/interfaces/path-options.interface.d.ts +2 -0
- package/dist/types/interfaces/settings.interface.d.ts +3 -0
- package/dist/types/interfaces/theme.interface.d.ts +27 -2
- package/dist/types/locales/de-locale.d.ts +5 -0
- package/dist/types/locales/en-locale.d.ts +6 -0
- package/dist/types/locales/fr-locale.d.ts +5 -0
- package/package.json +4 -7
- package/dist/components/p-2xYAGd0I.js +0 -1
- package/dist/components/p-B2Os1ya_.js +0 -1
- package/dist/components/p-BTEV1WwT.js +0 -1
- package/dist/components/p-BbactVA0.js +0 -1
- package/dist/components/p-BqwqGFQY.js +0 -1
- package/dist/components/p-C0TN5IAi.js +0 -1
- package/dist/components/p-CFgkUYoO.js +0 -1
- package/dist/components/p-COgo9OWy.js +0 -1
- package/dist/components/p-CUPYGT8c.js +0 -1
- package/dist/components/p-CcyIAi9S.js +0 -1
- package/dist/components/p-Cj78L1Kk.js +0 -1
- package/dist/components/p-CkAVEdDw.js +0 -9
- package/dist/components/p-CmuNn1Tc.js +0 -1
- package/dist/components/p-DDYoDSrm.js +0 -1
- package/dist/components/p-DbB730vO.js +0 -1
- package/dist/components/p-DlwYHzSj.js +0 -1
- package/dist/components/p-FK7b3BGt.js +0 -1
- package/dist/components/p-J9_SwObO.js +0 -1
- package/dist/stencil/p-67775031.entry.js +0 -9
- package/dist/stencil/p-DiCnmIYK.js +0 -1
|
@@ -41,7 +41,7 @@ export class KritzelSvgExportHelper {
|
|
|
41
41
|
* @returns SVG document string
|
|
42
42
|
*/
|
|
43
43
|
static generateSvg(objects, options = {}) {
|
|
44
|
-
const { theme, padding = 0, includeXmlDeclaration = true } = options;
|
|
44
|
+
const { theme, padding = 0, includeXmlDeclaration = true, rasterSafeForCanvas = false, imageDataUrls } = options;
|
|
45
45
|
if (!objects || objects.length === 0) {
|
|
46
46
|
return '';
|
|
47
47
|
}
|
|
@@ -61,7 +61,7 @@ export class KritzelSvgExportHelper {
|
|
|
61
61
|
// Generate SVG elements for each object
|
|
62
62
|
const elements = objects
|
|
63
63
|
.sort((a, b) => a.zIndex - b.zIndex)
|
|
64
|
-
.map(obj => this.objectToSvgElement(obj, theme))
|
|
64
|
+
.map(obj => this.objectToSvgElement(obj, theme, imageDataUrls, rasterSafeForCanvas))
|
|
65
65
|
.filter(Boolean)
|
|
66
66
|
.join('\n ');
|
|
67
67
|
const xmlDecl = includeXmlDeclaration ? '<?xml version="1.0" encoding="UTF-8"?>\n' : '';
|
|
@@ -87,6 +87,102 @@ export class KritzelSvgExportHelper {
|
|
|
87
87
|
}
|
|
88
88
|
return result;
|
|
89
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolves every image referenced by the given objects (including those
|
|
92
|
+
* nested inside groups) to an inlined `data:` URL, keyed by object id.
|
|
93
|
+
*
|
|
94
|
+
* This is required for export flows that rasterize the SVG (e.g. PNG
|
|
95
|
+
* export): an SVG loaded into an `<img>` element will NOT load external
|
|
96
|
+
* or `blob:` resources, so a `<image href="blob:...">` renders as a
|
|
97
|
+
* broken-image placeholder. Embedding the bytes as a base64 `data:` URL
|
|
98
|
+
* makes the image self-contained and survive rasterization.
|
|
99
|
+
*
|
|
100
|
+
* Resolution is best-effort: images that fail to resolve are simply
|
|
101
|
+
* omitted from the map, and the SVG falls back to whatever `href` the
|
|
102
|
+
* synchronous path would have produced.
|
|
103
|
+
* @param objects - Objects to inline images for
|
|
104
|
+
* @param assetResolver - Resolver used to fetch asset bytes; optional
|
|
105
|
+
* @returns Map of image object id -> inlined `data:` URL
|
|
106
|
+
*/
|
|
107
|
+
static async resolveImageDataUrls(objects, assetResolver) {
|
|
108
|
+
const dataUrls = new Map();
|
|
109
|
+
if (!objects || objects.length === 0) {
|
|
110
|
+
return dataUrls;
|
|
111
|
+
}
|
|
112
|
+
const images = this.flattenObjects(objects).filter((obj) => KritzelClassHelper.isInstanceOf(obj, 'KritzelImage'));
|
|
113
|
+
await Promise.all(images.map(async (image) => {
|
|
114
|
+
// Legacy inline data URL is already embeddable as-is.
|
|
115
|
+
if (image.src?.startsWith('data:')) {
|
|
116
|
+
dataUrls.set(image.id, image.src);
|
|
117
|
+
return;
|
|
118
|
+
}
|
|
119
|
+
// A resolvedSrc that is itself a data URL can be embedded directly.
|
|
120
|
+
if (image.resolvedSrc?.startsWith('data:')) {
|
|
121
|
+
dataUrls.set(image.id, image.resolvedSrc);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
if (!image.assetId || !assetResolver) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const blob = await assetResolver.fetchBlob(image.assetId);
|
|
129
|
+
dataUrls.set(image.id, await this.blobToDataUrl(blob));
|
|
130
|
+
}
|
|
131
|
+
catch (err) {
|
|
132
|
+
console.warn(`[KritzelSvgExportHelper] Failed to inline image asset ${image.assetId} for export:`, err);
|
|
133
|
+
}
|
|
134
|
+
}));
|
|
135
|
+
return dataUrls;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Reads a Blob into a base64 `data:` URL.
|
|
139
|
+
* @param blob - The blob to encode
|
|
140
|
+
* @returns Promise resolving to the data URL string
|
|
141
|
+
*/
|
|
142
|
+
static async blobToDataUrl(blob) {
|
|
143
|
+
// Prefer FileReader in browser-like runtimes for efficiency.
|
|
144
|
+
const hasFileReader = typeof FileReader !== 'undefined';
|
|
145
|
+
if (hasFileReader) {
|
|
146
|
+
try {
|
|
147
|
+
return await new Promise((resolve, reject) => {
|
|
148
|
+
const reader = new FileReader();
|
|
149
|
+
reader.onload = () => {
|
|
150
|
+
if (typeof reader.result === 'string') {
|
|
151
|
+
resolve(reader.result);
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
reject(new Error('FileReader result is not a string'));
|
|
155
|
+
};
|
|
156
|
+
reader.onerror = () => reject(reader.error ?? new Error('Failed to read blob as data URL'));
|
|
157
|
+
reader.readAsDataURL(blob);
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
catch {
|
|
161
|
+
// Fall through to the ArrayBuffer-based encoder.
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const bytes = new Uint8Array(await blob.arrayBuffer());
|
|
165
|
+
const mimeType = blob.type || 'application/octet-stream';
|
|
166
|
+
return `data:${mimeType};base64,${this.uint8ToBase64(bytes)}`;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Encodes a byte array to base64 across browser and Node-like runtimes.
|
|
170
|
+
*/
|
|
171
|
+
static uint8ToBase64(bytes) {
|
|
172
|
+
if (typeof Buffer !== 'undefined') {
|
|
173
|
+
return Buffer.from(bytes).toString('base64');
|
|
174
|
+
}
|
|
175
|
+
let binary = '';
|
|
176
|
+
const chunkSize = 0x8000;
|
|
177
|
+
for (let i = 0; i < bytes.length; i += chunkSize) {
|
|
178
|
+
const chunk = bytes.subarray(i, Math.min(i + chunkSize, bytes.length));
|
|
179
|
+
binary += String.fromCharCode(...chunk);
|
|
180
|
+
}
|
|
181
|
+
if (typeof btoa === 'function') {
|
|
182
|
+
return btoa(binary);
|
|
183
|
+
}
|
|
184
|
+
throw new Error('No base64 encoder available in this runtime');
|
|
185
|
+
}
|
|
90
186
|
/**
|
|
91
187
|
* Collects SVG defs (markers, patterns, etc.) needed by the objects.
|
|
92
188
|
* @param objects - Objects to collect defs for
|
|
@@ -131,9 +227,10 @@ export class KritzelSvgExportHelper {
|
|
|
131
227
|
* Converts a Kritzel object to its SVG element representation.
|
|
132
228
|
* @param object - The object to convert
|
|
133
229
|
* @param theme - Theme for color resolution
|
|
230
|
+
* @param imageDataUrls - Optional map of image id -> inlined data URL
|
|
134
231
|
* @returns SVG element string, or empty string if object type is not supported
|
|
135
232
|
*/
|
|
136
|
-
static objectToSvgElement(object, theme) {
|
|
233
|
+
static objectToSvgElement(object, theme, imageDataUrls, rasterSafeForCanvas = false) {
|
|
137
234
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelPath')) {
|
|
138
235
|
return this.pathToSvg(object, theme);
|
|
139
236
|
}
|
|
@@ -144,13 +241,13 @@ export class KritzelSvgExportHelper {
|
|
|
144
241
|
return this.shapeToSvg(object, theme);
|
|
145
242
|
}
|
|
146
243
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelText')) {
|
|
147
|
-
return this.textToSvg(object, theme);
|
|
244
|
+
return this.textToSvg(object, theme, rasterSafeForCanvas);
|
|
148
245
|
}
|
|
149
246
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelImage')) {
|
|
150
|
-
return this.imageToSvg(object);
|
|
247
|
+
return this.imageToSvg(object, imageDataUrls);
|
|
151
248
|
}
|
|
152
249
|
if (KritzelClassHelper.isInstanceOf(object, 'KritzelGroup')) {
|
|
153
|
-
return this.groupToSvg(object, theme);
|
|
250
|
+
return this.groupToSvg(object, theme, imageDataUrls, rasterSafeForCanvas);
|
|
154
251
|
}
|
|
155
252
|
return '';
|
|
156
253
|
}
|
|
@@ -165,9 +262,10 @@ export class KritzelSvgExportHelper {
|
|
|
165
262
|
const fill = KritzelColorHelper.resolveThemeColor(path.fill, theme);
|
|
166
263
|
const stroke = KritzelColorHelper.resolveThemeColor(path.stroke, theme);
|
|
167
264
|
const opacity = path.opacity !== 1 ? ` opacity="${path.opacity}"` : '';
|
|
265
|
+
const scale = this.getObjectScale(path);
|
|
168
266
|
// Path needs to be wrapped in a g with translation since path.d uses local coordinates
|
|
169
267
|
return `<g transform="${transform}"${opacity}>
|
|
170
|
-
<svg viewBox="${path.viewBox}" width="${path.totalWidth /
|
|
268
|
+
<svg viewBox="${path.viewBox}" width="${path.totalWidth / scale}" height="${path.totalHeight / scale}" overflow="visible">
|
|
171
269
|
<path d="${path.d}" fill="${fill || 'none'}" stroke="${stroke || 'none'}"${path.strokeWidth ? ` stroke-width="${path.strokeWidth}"` : ''}/>
|
|
172
270
|
</svg>
|
|
173
271
|
</g>`;
|
|
@@ -182,10 +280,11 @@ export class KritzelSvgExportHelper {
|
|
|
182
280
|
const transform = this.buildTransform(line);
|
|
183
281
|
const stroke = KritzelColorHelper.resolveThemeColor(line.stroke, theme);
|
|
184
282
|
const opacity = line.opacity !== 1 ? ` opacity="${line.opacity}"` : '';
|
|
283
|
+
const scale = this.getObjectScale(line);
|
|
185
284
|
const markerStart = line.hasStartArrow ? ` marker-start="url(#${line.startMarkerId})"` : '';
|
|
186
285
|
const markerEnd = line.hasEndArrow ? ` marker-end="url(#${line.endMarkerId})"` : '';
|
|
187
286
|
return `<g transform="${transform}"${opacity}>
|
|
188
|
-
<svg viewBox="${line.viewBox}" width="${line.totalWidth /
|
|
287
|
+
<svg viewBox="${line.viewBox}" width="${line.totalWidth / scale}" height="${line.totalHeight / scale}" overflow="visible">
|
|
189
288
|
<path d="${line.d}" fill="none" stroke="${stroke}" stroke-width="${line.strokeWidth}" stroke-linecap="round"${markerStart}${markerEnd}/>
|
|
190
289
|
</svg>
|
|
191
290
|
</g>`;
|
|
@@ -201,6 +300,7 @@ export class KritzelSvgExportHelper {
|
|
|
201
300
|
const fill = KritzelColorHelper.resolveThemeColor(shape.fillColor, theme);
|
|
202
301
|
const stroke = KritzelColorHelper.resolveThemeColor(shape.strokeColor, theme);
|
|
203
302
|
const opacity = shape.opacity !== 1 ? ` opacity="${shape.opacity}"` : '';
|
|
303
|
+
const scale = this.getObjectScale(shape);
|
|
204
304
|
// Get the SVG path for the shape
|
|
205
305
|
const pathD = shape.getSvgPath();
|
|
206
306
|
// Handle text content if present
|
|
@@ -221,7 +321,7 @@ export class KritzelSvgExportHelper {
|
|
|
221
321
|
}
|
|
222
322
|
}
|
|
223
323
|
return `<g transform="${transform}"${opacity}>
|
|
224
|
-
<svg viewBox="${shape.viewBox}" width="${shape.totalWidth /
|
|
324
|
+
<svg viewBox="${shape.viewBox}" width="${shape.totalWidth / scale}" height="${shape.totalHeight / scale}" overflow="visible" preserveAspectRatio="none">
|
|
225
325
|
<path d="${pathD}" fill="${fill || 'transparent'}" stroke="${stroke}" stroke-width="${shape.strokeWidth}"/>${textContent}
|
|
226
326
|
</svg>
|
|
227
327
|
</g>`;
|
|
@@ -232,45 +332,85 @@ export class KritzelSvgExportHelper {
|
|
|
232
332
|
* @param theme - Theme for color resolution
|
|
233
333
|
* @returns SVG element string
|
|
234
334
|
*/
|
|
235
|
-
static textToSvg(text, theme) {
|
|
335
|
+
static textToSvg(text, theme, rasterSafeForCanvas = false) {
|
|
336
|
+
if (rasterSafeForCanvas) {
|
|
337
|
+
return this.textToSvgRasterSafe(text, theme);
|
|
338
|
+
}
|
|
236
339
|
const transform = this.buildTransform(text);
|
|
237
340
|
const opacity = text.opacity !== 1 ? ` opacity="${text.opacity}"` : '';
|
|
238
341
|
const fontColor = KritzelColorHelper.resolveThemeColor(text.fontColor, theme);
|
|
239
342
|
const bgColor = KritzelColorHelper.resolveThemeColor(text.backgroundColor, theme);
|
|
343
|
+
const scale = this.getObjectScale(text);
|
|
240
344
|
// Convert ProseMirror content to HTML
|
|
241
345
|
const htmlContent = this.prosemirrorToHtml(text.content, text, theme);
|
|
242
346
|
// Calculate dimensions accounting for scale
|
|
243
|
-
const width = text.totalWidth /
|
|
244
|
-
const height = text.totalHeight /
|
|
347
|
+
const width = text.totalWidth / scale;
|
|
348
|
+
const height = text.totalHeight / scale;
|
|
245
349
|
return `<g transform="${transform}"${opacity}>
|
|
246
350
|
<foreignObject x="0" y="0" width="${width}" height="${height}">
|
|
247
351
|
<div xmlns="http://www.w3.org/1999/xhtml" style="font-family: ${text.fontFamily}; font-size: ${text.fontSize}pt; color: ${fontColor}; background-color: ${bgColor || 'transparent'}; transform: scale(${text.scaleFactor}); transform-origin: top left; white-space: pre-wrap; word-wrap: break-word;">
|
|
248
352
|
${htmlContent}
|
|
249
353
|
</div>
|
|
250
354
|
</foreignObject>
|
|
355
|
+
</g>`;
|
|
356
|
+
}
|
|
357
|
+
/**
|
|
358
|
+
* Converts a KritzelText to SVG using pure SVG text primitives.
|
|
359
|
+
* This path avoids `<foreignObject>`, which taints canvases when the
|
|
360
|
+
* generated SVG is rasterized through `<img>` and `drawImage`.
|
|
361
|
+
*/
|
|
362
|
+
static textToSvgRasterSafe(text, theme) {
|
|
363
|
+
const transform = this.buildTransform(text);
|
|
364
|
+
const opacity = text.opacity !== 1 ? ` opacity="${text.opacity}"` : '';
|
|
365
|
+
const fontColor = KritzelColorHelper.resolveThemeColor(text.fontColor, theme);
|
|
366
|
+
const bgColor = KritzelColorHelper.resolveThemeColor(text.backgroundColor, theme);
|
|
367
|
+
const scale = this.getObjectScale(text);
|
|
368
|
+
const width = text.totalWidth / scale;
|
|
369
|
+
const height = text.totalHeight / scale;
|
|
370
|
+
const lines = this.prosemirrorToPlainTextLines(text.content);
|
|
371
|
+
const resolvedLines = lines.length > 0 ? lines : [''];
|
|
372
|
+
const resolvedFontSize = Math.max(1, text.fontSize * (text.scaleFactor || 1));
|
|
373
|
+
const lineHeight = resolvedFontSize * 1.2;
|
|
374
|
+
const startY = resolvedFontSize;
|
|
375
|
+
const bgRect = bgColor && bgColor !== 'transparent'
|
|
376
|
+
? `<rect x="0" y="0" width="${width}" height="${height}" fill="${bgColor}"/>`
|
|
377
|
+
: '';
|
|
378
|
+
const tspans = resolvedLines
|
|
379
|
+
.map((line, index) => {
|
|
380
|
+
const y = startY + index * lineHeight;
|
|
381
|
+
return `<tspan x="0" y="${y}" xml:space="preserve">${this.escapeHtml(line)}</tspan>`;
|
|
382
|
+
})
|
|
383
|
+
.join('');
|
|
384
|
+
return `<g transform="${transform}"${opacity}>
|
|
385
|
+
${bgRect}
|
|
386
|
+
<text font-family="${this.escapeHtml(text.fontFamily)}" font-size="${resolvedFontSize}" fill="${fontColor}">${tspans}</text>
|
|
251
387
|
</g>`;
|
|
252
388
|
}
|
|
253
389
|
/**
|
|
254
390
|
* Converts a KritzelImage to SVG.
|
|
255
391
|
*
|
|
256
|
-
*
|
|
257
|
-
*
|
|
392
|
+
* Prefers an inlined `data:` URL from `imageDataUrls` (keyed by object
|
|
393
|
+
* id) when provided, so the embedded bytes survive rasterization to
|
|
394
|
+
* PNG. Falls back to `resolvedSrc` (populated by the renderer via the
|
|
395
|
+
* asset resolver) and finally the legacy inline `src` field for
|
|
258
396
|
* documents persisted before the asset layer existed.
|
|
259
397
|
*
|
|
260
|
-
* Note:
|
|
261
|
-
*
|
|
262
|
-
*
|
|
263
|
-
* `
|
|
398
|
+
* Note: a `blob:` `resolvedSrc` renders correctly on-canvas but becomes
|
|
399
|
+
* a broken-image placeholder once the SVG is loaded into an `<img>` and
|
|
400
|
+
* drawn to a canvas. Callers that rasterize the SVG must pass
|
|
401
|
+
* `imageDataUrls` (see {@link KritzelSvgExportHelper.resolveImageDataUrls}).
|
|
264
402
|
* @param image - The image object
|
|
403
|
+
* @param imageDataUrls - Optional map of image id -> inlined data URL
|
|
265
404
|
* @returns SVG element string
|
|
266
405
|
*/
|
|
267
|
-
static imageToSvg(image) {
|
|
406
|
+
static imageToSvg(image, imageDataUrls) {
|
|
268
407
|
const transform = this.buildTransform(image);
|
|
269
408
|
const opacity = image.opacity !== 1 ? ` opacity="${image.opacity}"` : '';
|
|
409
|
+
const scale = this.getObjectScale(image);
|
|
270
410
|
// Calculate dimensions
|
|
271
|
-
const width = image.totalWidth /
|
|
272
|
-
const height = image.totalHeight /
|
|
273
|
-
const href = image.resolvedSrc || image.src || '';
|
|
411
|
+
const width = image.totalWidth / scale;
|
|
412
|
+
const height = image.totalHeight / scale;
|
|
413
|
+
const href = imageDataUrls?.get(image.id) || image.resolvedSrc || image.src || '';
|
|
274
414
|
return `<g transform="${transform}"${opacity}>
|
|
275
415
|
<image href="${href}" x="0" y="0" width="${width}" height="${height}" preserveAspectRatio="xMidYMid meet"/>
|
|
276
416
|
</g>`;
|
|
@@ -279,12 +419,13 @@ export class KritzelSvgExportHelper {
|
|
|
279
419
|
* Converts a KritzelGroup to SVG by recursively converting children.
|
|
280
420
|
* @param group - The group object
|
|
281
421
|
* @param theme - Theme for color resolution
|
|
422
|
+
* @param imageDataUrls - Optional map of image id -> inlined data URL
|
|
282
423
|
* @returns SVG element string
|
|
283
424
|
*/
|
|
284
|
-
static groupToSvg(group, theme) {
|
|
425
|
+
static groupToSvg(group, theme, imageDataUrls, rasterSafeForCanvas = false) {
|
|
285
426
|
const children = group.children
|
|
286
427
|
.sort((a, b) => a.zIndex - b.zIndex)
|
|
287
|
-
.map(child => this.objectToSvgElement(child, theme))
|
|
428
|
+
.map(child => this.objectToSvgElement(child, theme, imageDataUrls, rasterSafeForCanvas))
|
|
288
429
|
.filter(Boolean)
|
|
289
430
|
.join('\n ');
|
|
290
431
|
if (!children) {
|
|
@@ -303,17 +444,25 @@ export class KritzelSvgExportHelper {
|
|
|
303
444
|
*/
|
|
304
445
|
static buildTransform(object) {
|
|
305
446
|
const transforms = [];
|
|
447
|
+
const scale = this.getObjectScale(object);
|
|
306
448
|
// Translation
|
|
307
449
|
transforms.push(`translate(${object.translateX}, ${object.translateY})`);
|
|
308
450
|
// Rotation around center
|
|
309
451
|
if (object.rotation !== 0) {
|
|
310
|
-
const centerX = object.totalWidth / 2 /
|
|
311
|
-
const centerY = object.totalHeight / 2 /
|
|
452
|
+
const centerX = object.totalWidth / 2 / scale;
|
|
453
|
+
const centerY = object.totalHeight / 2 / scale;
|
|
312
454
|
const degrees = object.rotation * (180 / Math.PI);
|
|
313
455
|
transforms.push(`rotate(${degrees}, ${centerX}, ${centerY})`);
|
|
314
456
|
}
|
|
315
457
|
return transforms.join(' ');
|
|
316
458
|
}
|
|
459
|
+
/**
|
|
460
|
+
* Returns a safe non-zero scale for export geometry calculations.
|
|
461
|
+
*/
|
|
462
|
+
static getObjectScale(object) {
|
|
463
|
+
const scale = object.scale ?? 1;
|
|
464
|
+
return scale === 0 ? 1 : scale;
|
|
465
|
+
}
|
|
317
466
|
/**
|
|
318
467
|
* Converts ProseMirror JSON content to HTML string.
|
|
319
468
|
* @param content - ProseMirror document JSON
|
|
@@ -369,6 +518,54 @@ export class KritzelSvgExportHelper {
|
|
|
369
518
|
return '';
|
|
370
519
|
}
|
|
371
520
|
}
|
|
521
|
+
/**
|
|
522
|
+
* Converts ProseMirror JSON content to plain-text lines.
|
|
523
|
+
* Used by raster-safe SVG export, which cannot depend on HTML/foreignObject.
|
|
524
|
+
*/
|
|
525
|
+
static prosemirrorToPlainTextLines(content) {
|
|
526
|
+
if (!content || !Array.isArray(content.content)) {
|
|
527
|
+
return [];
|
|
528
|
+
}
|
|
529
|
+
const plainText = content.content
|
|
530
|
+
.map((node) => this.nodeToPlainText(node))
|
|
531
|
+
.join('')
|
|
532
|
+
.replace(/\r\n/g, '\n')
|
|
533
|
+
.replace(/\n+$/, '');
|
|
534
|
+
if (!plainText) {
|
|
535
|
+
return [];
|
|
536
|
+
}
|
|
537
|
+
return plainText.split('\n');
|
|
538
|
+
}
|
|
539
|
+
/**
|
|
540
|
+
* Converts a ProseMirror node tree into plain text.
|
|
541
|
+
*/
|
|
542
|
+
static nodeToPlainText(node) {
|
|
543
|
+
if (!node) {
|
|
544
|
+
return '';
|
|
545
|
+
}
|
|
546
|
+
switch (node.type) {
|
|
547
|
+
case 'text':
|
|
548
|
+
return node.text || '';
|
|
549
|
+
case 'hard_break':
|
|
550
|
+
return '\n';
|
|
551
|
+
case 'paragraph': {
|
|
552
|
+
const paragraph = Array.isArray(node.content)
|
|
553
|
+
? node.content.map((child) => this.nodeToPlainText(child)).join('')
|
|
554
|
+
: '';
|
|
555
|
+
return `${paragraph}\n`;
|
|
556
|
+
}
|
|
557
|
+
case 'list_item': {
|
|
558
|
+
const item = Array.isArray(node.content)
|
|
559
|
+
? node.content.map((child) => this.nodeToPlainText(child)).join('')
|
|
560
|
+
: '';
|
|
561
|
+
return `- ${item.trim()}\n`;
|
|
562
|
+
}
|
|
563
|
+
default:
|
|
564
|
+
return Array.isArray(node.content)
|
|
565
|
+
? node.content.map((child) => this.nodeToPlainText(child)).join('')
|
|
566
|
+
: '';
|
|
567
|
+
}
|
|
568
|
+
}
|
|
372
569
|
/**
|
|
373
570
|
* Applies a ProseMirror mark to text.
|
|
374
571
|
* @param text - The text to wrap
|
package/dist/collection/index.js
CHANGED
|
@@ -14,6 +14,7 @@ export * from './classes/objects/image.class';
|
|
|
14
14
|
export * from './classes/objects/line.class';
|
|
15
15
|
export * from './classes/objects/group.class';
|
|
16
16
|
export * from './classes/objects/shape.class';
|
|
17
|
+
export * from './classes/tools/base-tool.class';
|
|
17
18
|
export * from './classes/tools/brush-tool.class';
|
|
18
19
|
export * from './classes/tools/line-tool.class';
|
|
19
20
|
export * from './classes/tools/eraser-tool.class';
|
|
@@ -34,6 +35,8 @@ export * from './classes/providers/assets/presigned-asset-provider.class';
|
|
|
34
35
|
export * from './classes/core/workspace.class';
|
|
35
36
|
export * from './classes/managers/anchor.manager';
|
|
36
37
|
export * from './classes/managers/theme.manager';
|
|
38
|
+
export * from './classes/managers/localization.manager';
|
|
39
|
+
export * from './classes/managers/license.manager';
|
|
37
40
|
export * from './interfaces/toolbar-control.interface';
|
|
38
41
|
export * from './interfaces/menu-item.interface';
|
|
39
42
|
export * from './interfaces/object-change-event.interface';
|
|
@@ -48,13 +51,23 @@ export * from './interfaces/anchor.interface';
|
|
|
48
51
|
export * from './interfaces/viewport-state.interface';
|
|
49
52
|
export * from './interfaces/user.interface';
|
|
50
53
|
export * from './interfaces/theme.interface';
|
|
54
|
+
export * from './interfaces/localization.interface';
|
|
51
55
|
export * from './interfaces/shortcut.interface';
|
|
56
|
+
export * from './interfaces/undo-state.interface';
|
|
57
|
+
export * from './interfaces/share.interface';
|
|
58
|
+
export * from './interfaces/engine-state.interface';
|
|
59
|
+
export * from './interfaces/debug-info.interface';
|
|
60
|
+
export * from './interfaces/bounding-box.interface';
|
|
61
|
+
export * from './interfaces/polygon.interface';
|
|
52
62
|
export * from './configs/default-brush-tool.config';
|
|
53
63
|
export * from './configs/default-text-tool.config';
|
|
54
64
|
export * from './configs/default-line-tool.config';
|
|
55
65
|
export * from './configs/default-asset-storage.config';
|
|
56
66
|
export * from './themes/light-theme';
|
|
57
67
|
export * from './themes/dark-theme';
|
|
68
|
+
export * from './locales/en-locale';
|
|
69
|
+
export * from './locales/de-locale';
|
|
70
|
+
export * from './locales/fr-locale';
|
|
58
71
|
export * from './enums/alignment.enum';
|
|
59
72
|
export * from './enums/shape-type.enum';
|
|
60
73
|
export * from './interfaces/migration.interface';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in German locale.
|
|
3
|
+
*/
|
|
4
|
+
export const DE_LOCALE = {
|
|
5
|
+
code: 'de',
|
|
6
|
+
label: 'Deutsch',
|
|
7
|
+
terms: {
|
|
8
|
+
// Context menu
|
|
9
|
+
'menu.copy': 'Kopieren',
|
|
10
|
+
'menu.cut': 'Ausschneiden',
|
|
11
|
+
'menu.paste': 'Einfügen',
|
|
12
|
+
'menu.selectAll': 'Alles auswählen',
|
|
13
|
+
'menu.order': 'Anordnen',
|
|
14
|
+
'menu.bringToFront': 'In den Vordergrund',
|
|
15
|
+
'menu.sendToBack': 'In den Hintergrund',
|
|
16
|
+
'menu.moveUp': 'Nach vorne',
|
|
17
|
+
'menu.moveDown': 'Nach hinten',
|
|
18
|
+
'menu.align': 'Ausrichten',
|
|
19
|
+
'menu.alignLeft': 'Linksbündig ausrichten',
|
|
20
|
+
'menu.alignCenterHorizontal': 'Horizontal zentrieren',
|
|
21
|
+
'menu.alignRight': 'Rechtsbündig ausrichten',
|
|
22
|
+
'menu.alignTop': 'Oben ausrichten',
|
|
23
|
+
'menu.alignCenterVertical': 'Vertikal zentrieren',
|
|
24
|
+
'menu.alignBottom': 'Unten ausrichten',
|
|
25
|
+
'menu.group': 'Gruppieren',
|
|
26
|
+
'menu.ungroup': 'Gruppierung aufheben',
|
|
27
|
+
'menu.export': 'Exportieren',
|
|
28
|
+
'menu.exportAsSvg': 'Als SVG exportieren',
|
|
29
|
+
'menu.exportAsPng': 'Als PNG exportieren',
|
|
30
|
+
'menu.delete': 'Löschen',
|
|
31
|
+
// More menu
|
|
32
|
+
'menu.share': 'Teilen',
|
|
33
|
+
'menu.import': 'Importieren',
|
|
34
|
+
'menu.settings': 'Einstellungen',
|
|
35
|
+
'menu.logout': 'Abmelden',
|
|
36
|
+
// Settings dialog
|
|
37
|
+
'settings.dialogTitle': 'Einstellungen',
|
|
38
|
+
'settings.categories.general': 'Allgemein',
|
|
39
|
+
'settings.categories.viewport': 'Ansichtsfenster',
|
|
40
|
+
'settings.categories.shortcuts': 'Tastenkürzel',
|
|
41
|
+
'settings.categories.developer': 'Entwickleroptionen',
|
|
42
|
+
'settings.categories.about': 'Über',
|
|
43
|
+
'settings.general.title': 'Allgemeine Einstellungen',
|
|
44
|
+
'settings.general.theme.label': 'Design',
|
|
45
|
+
'settings.general.theme.description': 'Wählen Sie ein registriertes Farbdesign für die Editor-Oberfläche.',
|
|
46
|
+
'settings.general.language.label': 'Sprache',
|
|
47
|
+
'settings.general.language.description': 'Wählen Sie die Anzeigesprache für die Editor-Oberfläche.',
|
|
48
|
+
'settings.general.lockDrawingScale.label': 'Zeichenskalierung sperren',
|
|
49
|
+
'settings.general.lockDrawingScale.description': 'Wenn aktiviert, behalten gezeichnete Objekte unabhängig von der aktuellen Zoomstufe eine feste visuelle Größe.',
|
|
50
|
+
'settings.viewport.title': 'Ansichtsfenster-Einstellungen',
|
|
51
|
+
'settings.viewport.minZoom.label': 'Minimale Zoomstufe',
|
|
52
|
+
'settings.viewport.minZoom.description': 'Legt die minimale Zoomstufe fest. Niedrigere Werte ermöglichen weiteres Herauszoomen, um mehr von der Zeichenfläche zu sehen.',
|
|
53
|
+
'settings.viewport.maxZoom.label': 'Maximale Zoomstufe',
|
|
54
|
+
'settings.viewport.maxZoom.description': 'Legt die maximale Zoomstufe fest. Höhere Werte ermöglichen näheres Heranzoomen für Detailarbeit.',
|
|
55
|
+
'settings.viewport.boundaryLeft.label': 'Ansichtsfenster-Grenze links',
|
|
56
|
+
'settings.viewport.boundaryLeft.description': 'Linke Grenze in Weltkoordinaten. Legen Sie fest, wie weit das Ansichtsfenster nach links verschoben werden kann.',
|
|
57
|
+
'settings.viewport.boundaryRight.label': 'Ansichtsfenster-Grenze rechts',
|
|
58
|
+
'settings.viewport.boundaryRight.description': 'Rechte Grenze in Weltkoordinaten. Legen Sie fest, wie weit das Ansichtsfenster nach rechts verschoben werden kann.',
|
|
59
|
+
'settings.viewport.boundaryTop.label': 'Ansichtsfenster-Grenze oben',
|
|
60
|
+
'settings.viewport.boundaryTop.description': 'Obere Grenze in Weltkoordinaten. Legen Sie fest, wie weit das Ansichtsfenster nach oben verschoben werden kann.',
|
|
61
|
+
'settings.viewport.boundaryBottom.label': 'Ansichtsfenster-Grenze unten',
|
|
62
|
+
'settings.viewport.boundaryBottom.description': 'Untere Grenze in Weltkoordinaten. Legen Sie fest, wie weit das Ansichtsfenster nach unten verschoben werden kann.',
|
|
63
|
+
'settings.viewport.boundaryPlaceholder': 'Unendlich',
|
|
64
|
+
'settings.shortcuts.title': 'Tastenkürzel',
|
|
65
|
+
'settings.developer.title': 'Entwickleroptionen',
|
|
66
|
+
'settings.developer.showViewportInfo.label': 'Ansichtsfenster-Infos anzeigen',
|
|
67
|
+
'settings.developer.showViewportInfo.description': 'Zeigt Debug-Informationen zum Ansichtsfenster an, z. B. Position, Zoomstufe und Grenzen.',
|
|
68
|
+
'settings.developer.showObjectInfo.label': 'Objekt-Infos anzeigen',
|
|
69
|
+
'settings.developer.showObjectInfo.description': 'Zeigt Debug-Informationen zu Objekten auf der Zeichenfläche an.',
|
|
70
|
+
'settings.developer.showSyncProviderInfo.label': 'Sync-Provider-Infos anzeigen',
|
|
71
|
+
'settings.developer.showSyncProviderInfo.description': 'Zeigt Debug-Informationen zum Verbindungsstatus des Sync-Providers an.',
|
|
72
|
+
'settings.developer.showMigrationInfo.label': 'Migrations-Infos anzeigen',
|
|
73
|
+
'settings.developer.showMigrationInfo.description': 'Zeigt Debug-Informationen zu Datenmigrationen an.',
|
|
74
|
+
'settings.about.title': 'Über',
|
|
75
|
+
'settings.about.description': 'Kritzel – Eine Zeichenanwendung',
|
|
76
|
+
// Export dialog
|
|
77
|
+
'export.dialogTitle': 'Exportieren',
|
|
78
|
+
'export.tabs.viewport': 'Ansichtsfenster exportieren',
|
|
79
|
+
'export.tabs.workspace': 'Arbeitsbereich exportieren',
|
|
80
|
+
'export.format.label': 'Format',
|
|
81
|
+
'export.filename.label': 'Dateiname',
|
|
82
|
+
'export.filename.placeholder': 'Dateiname eingeben',
|
|
83
|
+
'export.exportButton': 'Exportieren',
|
|
84
|
+
// Workspace manager
|
|
85
|
+
'workspace.sharedTooltip': 'Geteilter Arbeitsbereich',
|
|
86
|
+
'workspace.rename': 'Umbenennen',
|
|
87
|
+
'workspace.delete': 'Löschen',
|
|
88
|
+
// Zoom panel
|
|
89
|
+
'zoom.zoomIn': 'Vergrößern',
|
|
90
|
+
'zoom.zoomOut': 'Verkleinern',
|
|
91
|
+
// Utility panel
|
|
92
|
+
'utility.undo': 'Rückgängig',
|
|
93
|
+
'utility.redo': 'Wiederholen',
|
|
94
|
+
'utility.delete': 'Ausgewählte Elemente löschen',
|
|
95
|
+
// Share dialog
|
|
96
|
+
'share.dialogTitle': 'Arbeitsbereich teilen',
|
|
97
|
+
'share.linkSharing.label': 'Link-Freigabe',
|
|
98
|
+
'share.linkSharing.enabledDescription': 'Jeder mit dem Link kann auf diesen Arbeitsbereich zugreifen.',
|
|
99
|
+
'share.linkSharing.disabledDescription': 'Die Link-Freigabe ist deaktiviert. Nur Sie können auf diesen Arbeitsbereich zugreifen.',
|
|
100
|
+
'share.linkSharing.toggleLabel': 'Link-Freigabe aktivieren',
|
|
101
|
+
'share.copyLink.title': 'Link kopieren',
|
|
102
|
+
'share.copyLink.copied': 'Kopiert!',
|
|
103
|
+
// Login dialog
|
|
104
|
+
'login.dialogTitle': 'Anmelden',
|
|
105
|
+
// Current user dialog
|
|
106
|
+
'currentUser.dialogTitle': 'Konto',
|
|
107
|
+
// Back to content
|
|
108
|
+
'backToContent.label': 'Zurück zum Inhalt',
|
|
109
|
+
// Tool config
|
|
110
|
+
'toolConfig.collapse': 'Einklappen',
|
|
111
|
+
'toolConfig.expand': 'Ausklappen',
|
|
112
|
+
// More menu button
|
|
113
|
+
'moreMenu.ariaLabel': 'Weitere Optionen',
|
|
114
|
+
// Engine
|
|
115
|
+
'engine.loading': 'Wird geladen...',
|
|
116
|
+
// Watermark
|
|
117
|
+
'watermark.poweredBy': 'Bereitgestellt von Kritzel',
|
|
118
|
+
},
|
|
119
|
+
};
|