web-to-print 0.1.0
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 +21 -0
- package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
- package/dist/cjs/canvas-helpers-A6rp5rPD.js +765 -0
- package/dist/cjs/index-IFGFRm-i.js +1649 -0
- package/dist/cjs/index.cjs.js +232 -0
- package/dist/cjs/loader.cjs.js +13 -0
- package/dist/cjs/logo-BUX-b45R.js +18 -0
- package/dist/cjs/web-to-print.cjs.js +25 -0
- package/dist/cjs/wtp-editor_2.cjs.entry.js +12386 -0
- package/dist/cjs/wtp-logo-renderer.cjs.entry.js +353 -0
- package/dist/cjs/wtp-print-area-editor.cjs.entry.js +431 -0
- package/dist/collection/collection-manifest.json +16 -0
- package/dist/collection/components/wtp-editor/wtp-editor.css +124 -0
- package/dist/collection/components/wtp-editor/wtp-editor.js +1114 -0
- package/dist/collection/components/wtp-logo-renderer/wtp-logo-renderer.css +30 -0
- package/dist/collection/components/wtp-logo-renderer/wtp-logo-renderer.js +455 -0
- package/dist/collection/components/wtp-logo-upload/wtp-logo-upload.css +428 -0
- package/dist/collection/components/wtp-logo-upload/wtp-logo-upload.js +573 -0
- package/dist/collection/components/wtp-print-area-editor/wtp-print-area-editor.css +20 -0
- package/dist/collection/components/wtp-print-area-editor/wtp-print-area-editor.js +600 -0
- package/dist/collection/examples/schaeffler--big.svg +1 -0
- package/dist/collection/index.js +8 -0
- package/dist/collection/types/editor.js +1 -0
- package/dist/collection/types/index.js +2 -0
- package/dist/collection/types/labels.js +30 -0
- package/dist/collection/types/logo.js +13 -0
- package/dist/collection/utils/background-removal.js +717 -0
- package/dist/collection/utils/canvas-helpers.js +380 -0
- package/dist/collection/utils/format-detection.js +48 -0
- package/dist/collection/utils/html-render-helpers.js +106 -0
- package/dist/collection/utils/image-preview.js +54 -0
- package/dist/collection/utils/logo-validation.js +141 -0
- package/dist/collection/utils/pdf-export.js +224 -0
- package/dist/components/index.d.ts +35 -0
- package/dist/components/index.js +1 -0
- package/dist/components/p-5qCsRzlt.js +1 -0
- package/dist/components/p-Bn9gR_8e.js +1 -0
- package/dist/components/p-D8pVJRuX.js +1 -0
- package/dist/components/wtp-editor.d.ts +11 -0
- package/dist/components/wtp-editor.js +1 -0
- package/dist/components/wtp-logo-renderer.d.ts +11 -0
- package/dist/components/wtp-logo-renderer.js +1 -0
- package/dist/components/wtp-logo-upload.d.ts +11 -0
- package/dist/components/wtp-logo-upload.js +1 -0
- package/dist/components/wtp-print-area-editor.d.ts +11 -0
- package/dist/components/wtp-print-area-editor.js +1 -0
- package/dist/esm/app-globals-DQuL1Twl.js +3 -0
- package/dist/esm/canvas-helpers-CK8OAq2J.js +748 -0
- package/dist/esm/index-CUetmLbL.js +1641 -0
- package/dist/esm/index.js +228 -0
- package/dist/esm/loader.js +11 -0
- package/dist/esm/logo-D8pVJRuX.js +15 -0
- package/dist/esm/web-to-print.js +21 -0
- package/dist/esm/wtp-editor_2.entry.js +12383 -0
- package/dist/esm/wtp-logo-renderer.entry.js +351 -0
- package/dist/esm/wtp-print-area-editor.entry.js +429 -0
- package/dist/index.cjs.js +1 -0
- package/dist/index.js +1 -0
- package/dist/types/components/wtp-editor/wtp-editor.d.ts +101 -0
- package/dist/types/components/wtp-logo-renderer/wtp-logo-renderer.d.ts +55 -0
- package/dist/types/components/wtp-logo-upload/wtp-logo-upload.d.ts +76 -0
- package/dist/types/components/wtp-print-area-editor/wtp-print-area-editor.d.ts +43 -0
- package/dist/types/components.d.ts +507 -0
- package/dist/types/index.d.ts +11 -0
- package/dist/types/stencil-public-runtime.d.ts +1860 -0
- package/dist/types/types/editor.d.ts +79 -0
- package/dist/types/types/index.d.ts +5 -0
- package/dist/types/types/labels.d.ts +30 -0
- package/dist/types/types/logo.d.ts +47 -0
- package/dist/types/utils/background-removal.d.ts +95 -0
- package/dist/types/utils/canvas-helpers.d.ts +60 -0
- package/dist/types/utils/format-detection.d.ts +4 -0
- package/dist/types/utils/html-render-helpers.d.ts +44 -0
- package/dist/types/utils/image-preview.d.ts +13 -0
- package/dist/types/utils/logo-validation.d.ts +2 -0
- package/dist/types/utils/pdf-export.d.ts +32 -0
- package/dist/web-to-print/index.esm.js +1 -0
- package/dist/web-to-print/p-611ec561.entry.js +1 -0
- package/dist/web-to-print/p-703e4c52.entry.js +1 -0
- package/dist/web-to-print/p-CK8OAq2J.js +1 -0
- package/dist/web-to-print/p-CUetmLbL.js +2 -0
- package/dist/web-to-print/p-D8pVJRuX.js +1 -0
- package/dist/web-to-print/p-DQuL1Twl.js +1 -0
- package/dist/web-to-print/p-b532777b.entry.js +1 -0
- package/dist/web-to-print/web-to-print.esm.js +1 -0
- package/loader/cdn.js +1 -0
- package/loader/index.cjs.js +1 -0
- package/loader/index.d.ts +24 -0
- package/loader/index.es2017.js +1 -0
- package/loader/index.js +2 -0
- package/package.json +68 -0
- package/readme.md +490 -0
|
@@ -0,0 +1,351 @@
|
|
|
1
|
+
import { r as registerInstance, c as createEvent, g as getElement, h } from './index-CUetmLbL.js';
|
|
2
|
+
import { u as upscaleSvgDataUrl, b as warpImageForBulge, f as fitLogoToPrintArea, p as printAreaToPixelCorners } from './canvas-helpers-CK8OAq2J.js';
|
|
3
|
+
|
|
4
|
+
/** Utility functions for the HTML/CSS-based logo renderer and Canvas 2D export. */
|
|
5
|
+
/** Load an image from a URL/data-URL and return the HTMLImageElement once loaded. */
|
|
6
|
+
function loadImage(src) {
|
|
7
|
+
return new Promise((resolve, reject) => {
|
|
8
|
+
const img = new Image();
|
|
9
|
+
img.onload = () => resolve(img);
|
|
10
|
+
img.onerror = () => reject(new Error(`Failed to load image: ${src.slice(0, 80)}`));
|
|
11
|
+
img.src = src;
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
/** Compute contain-fit dimensions (uniform scale to fit inside container). */
|
|
15
|
+
function computeContainFit(containerW, containerH, imgW, imgH) {
|
|
16
|
+
const scale = Math.min(containerW / imgW, containerH / imgH);
|
|
17
|
+
return { fittedW: imgW * scale, fittedH: imgH * scale };
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Convert a Fabric.js center-origin transform to CSS top-left positioning.
|
|
21
|
+
* Fabric.js stores x/y as the center of the object. CSS `transform-origin: center`
|
|
22
|
+
* means the origin is at the center of the unscaled element box, so left/top are
|
|
23
|
+
* computed by subtracting half the *natural* (unscaled) dimensions.
|
|
24
|
+
*/
|
|
25
|
+
function centerOriginToTopLeft(transform, naturalW, naturalH) {
|
|
26
|
+
return {
|
|
27
|
+
left: transform.x - naturalW / 2,
|
|
28
|
+
top: transform.y - naturalH / 2,
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Parse an SVG data URL to extract intrinsic dimensions from viewBox or width/height attributes.
|
|
33
|
+
* Returns null if the data URL is not SVG or dimensions cannot be determined.
|
|
34
|
+
*/
|
|
35
|
+
function getSvgIntrinsicSize(svgDataUrl) {
|
|
36
|
+
if (!svgDataUrl.startsWith('data:image/svg+xml'))
|
|
37
|
+
return null;
|
|
38
|
+
let svgText;
|
|
39
|
+
const base64Idx = svgDataUrl.indexOf(';base64,');
|
|
40
|
+
if (base64Idx !== -1) {
|
|
41
|
+
svgText = atob(svgDataUrl.slice(base64Idx + 8));
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
const commaIdx = svgDataUrl.indexOf(',');
|
|
45
|
+
if (commaIdx === -1)
|
|
46
|
+
return null;
|
|
47
|
+
svgText = decodeURIComponent(svgDataUrl.slice(commaIdx + 1));
|
|
48
|
+
}
|
|
49
|
+
// Use regex instead of DOMParser to avoid JSDOM/mock-doc XML parsing limitations
|
|
50
|
+
const svgMatch = svgText.match(/<svg[^>]*>/i);
|
|
51
|
+
if (svgMatch === null)
|
|
52
|
+
return null;
|
|
53
|
+
const svgTag = svgMatch[0];
|
|
54
|
+
const viewBoxMatch = svgTag.match(/viewBox=["']([^"']+)["']/);
|
|
55
|
+
if (viewBoxMatch !== null) {
|
|
56
|
+
const parts = viewBoxMatch[1].trim().split(/[\s,]+/);
|
|
57
|
+
const vbW = parseFloat(parts[2]);
|
|
58
|
+
const vbH = parseFloat(parts[3]);
|
|
59
|
+
if (vbW > 0 && vbH > 0)
|
|
60
|
+
return { width: vbW, height: vbH };
|
|
61
|
+
}
|
|
62
|
+
const widthMatch = svgTag.match(/\bwidth=["']([^"']+)["']/);
|
|
63
|
+
const heightMatch = svgTag.match(/\bheight=["']([^"']+)["']/);
|
|
64
|
+
if (widthMatch !== null && heightMatch !== null) {
|
|
65
|
+
const svgW = parseFloat(widthMatch[1]);
|
|
66
|
+
const svgH = parseFloat(heightMatch[1]);
|
|
67
|
+
if (svgW > 0 && svgH > 0)
|
|
68
|
+
return { width: svgW, height: svgH };
|
|
69
|
+
}
|
|
70
|
+
return null;
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Canvas 2D export: draw product background + logo layers onto a plain canvas.
|
|
74
|
+
* Returns a data URL string.
|
|
75
|
+
*/
|
|
76
|
+
function renderToCanvas(containerW, containerH, bgColor, productImg, layers, format = 'png', quality = 1) {
|
|
77
|
+
const canvas = document.createElement('canvas');
|
|
78
|
+
canvas.width = containerW;
|
|
79
|
+
canvas.height = containerH;
|
|
80
|
+
const ctx = canvas.getContext('2d');
|
|
81
|
+
// Background color
|
|
82
|
+
ctx.fillStyle = bgColor;
|
|
83
|
+
ctx.fillRect(0, 0, containerW, containerH);
|
|
84
|
+
// Product image (contain-fit, centered)
|
|
85
|
+
if (productImg !== undefined) {
|
|
86
|
+
const { fittedW, fittedH } = computeContainFit(containerW, containerH, productImg.naturalWidth, productImg.naturalHeight);
|
|
87
|
+
const ox = (containerW - fittedW) / 2;
|
|
88
|
+
const oy = (containerH - fittedH) / 2;
|
|
89
|
+
ctx.drawImage(productImg, ox, oy, fittedW, fittedH);
|
|
90
|
+
}
|
|
91
|
+
// Logo layers
|
|
92
|
+
for (const layer of layers) {
|
|
93
|
+
ctx.save();
|
|
94
|
+
// Move to the center of the object (top-left + half natural size, matching CSS transform-origin: center)
|
|
95
|
+
const cx = layer.left + layer.naturalWidth / 2;
|
|
96
|
+
const cy = layer.top + layer.naturalHeight / 2;
|
|
97
|
+
ctx.translate(cx, cy);
|
|
98
|
+
// Apply transforms in Fabric.js order: rotate → skew → scale
|
|
99
|
+
ctx.rotate((layer.angle * Math.PI) / 180);
|
|
100
|
+
const tanSkX = Math.tan((layer.skewX * Math.PI) / 180);
|
|
101
|
+
const tanSkY = Math.tan((layer.skewY * Math.PI) / 180);
|
|
102
|
+
ctx.transform(1, tanSkY, tanSkX, 1, 0, 0);
|
|
103
|
+
ctx.scale(layer.scaleX, layer.scaleY);
|
|
104
|
+
// Draw image centered at origin
|
|
105
|
+
ctx.drawImage(layer.img, -layer.naturalWidth / 2, -layer.naturalHeight / 2, layer.naturalWidth, layer.naturalHeight);
|
|
106
|
+
ctx.restore();
|
|
107
|
+
}
|
|
108
|
+
return canvas.toDataURL(`image/${format}`, quality);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const wtpLogoRendererCss = () => `*.sc-wtp-logo-renderer,*.sc-wtp-logo-renderer::before,*.sc-wtp-logo-renderer::after{box-sizing:border-box}.sc-wtp-logo-renderer-h{font-family:var(--wtp-font-family, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif);color:var(--wtp-color-text, #1e293b);line-height:1.5}.wtp-logo-renderer.sc-wtp-logo-renderer{display:inline-block;position:relative;overflow:hidden;border:1px solid var(--wtp-color-border, #e2e8f0);border-radius:8px}.product-bg.sc-wtp-logo-renderer{display:block;width:100%;height:100%;object-fit:contain}.logo-layer.sc-wtp-logo-renderer{pointer-events:none}`;
|
|
112
|
+
|
|
113
|
+
const WtpLogoRenderer = class {
|
|
114
|
+
constructor(hostRef) {
|
|
115
|
+
registerInstance(this, hostRef);
|
|
116
|
+
this.wtpRenderComplete = createEvent(this, "wtpRenderComplete");
|
|
117
|
+
this.wtpRenderError = createEvent(this, "wtpRenderError");
|
|
118
|
+
}
|
|
119
|
+
get el() { return getElement(this); }
|
|
120
|
+
/** Product background image URL. */
|
|
121
|
+
productImage;
|
|
122
|
+
/** Container width in pixels. */
|
|
123
|
+
width = 600;
|
|
124
|
+
/** Container height in pixels. */
|
|
125
|
+
height = 400;
|
|
126
|
+
/** Array of logos to place on the renderer. */
|
|
127
|
+
logos = [];
|
|
128
|
+
/** Background color. */
|
|
129
|
+
backgroundColor = '#ffffff';
|
|
130
|
+
/** Print area definition for auto-fitting logos (relative 0-1 coordinates). */
|
|
131
|
+
printArea;
|
|
132
|
+
/** Fires when the renderer has finished rendering all logos. */
|
|
133
|
+
wtpRenderComplete;
|
|
134
|
+
/** Fires when a rendering error occurs. */
|
|
135
|
+
wtpRenderError;
|
|
136
|
+
layers = [];
|
|
137
|
+
containerWidth = 0;
|
|
138
|
+
containerHeight = 0;
|
|
139
|
+
productImg;
|
|
140
|
+
componentWillLoad() {
|
|
141
|
+
this.computeLayout();
|
|
142
|
+
}
|
|
143
|
+
onProductImageChange() {
|
|
144
|
+
this.computeLayout();
|
|
145
|
+
}
|
|
146
|
+
onLogosChange() {
|
|
147
|
+
this.computeLayout();
|
|
148
|
+
}
|
|
149
|
+
onPrintAreaChange() {
|
|
150
|
+
this.computeLayout();
|
|
151
|
+
}
|
|
152
|
+
onSizeChange() {
|
|
153
|
+
this.computeLayout();
|
|
154
|
+
}
|
|
155
|
+
onBackgroundColorChange() {
|
|
156
|
+
// Background color is applied via inline style in render(), so Stencil
|
|
157
|
+
// re-renders automatically. We still need to re-emit the export data URL.
|
|
158
|
+
this.emitRenderComplete();
|
|
159
|
+
}
|
|
160
|
+
/** Export the rendered scene as a data URL image. */
|
|
161
|
+
async exportImage(format = 'png', quality = 1) {
|
|
162
|
+
const w = this.containerWidth || this.width;
|
|
163
|
+
const h = this.containerHeight || this.height;
|
|
164
|
+
const exportLayers = this.layers.map(l => ({
|
|
165
|
+
img: l.exportImg,
|
|
166
|
+
naturalWidth: l.naturalWidth,
|
|
167
|
+
naturalHeight: l.naturalHeight,
|
|
168
|
+
left: l.left,
|
|
169
|
+
top: l.top,
|
|
170
|
+
scaleX: l.scaleX,
|
|
171
|
+
scaleY: l.scaleY,
|
|
172
|
+
angle: l.angle,
|
|
173
|
+
skewX: l.skewX,
|
|
174
|
+
skewY: l.skewY,
|
|
175
|
+
}));
|
|
176
|
+
return renderToCanvas(w, h, this.backgroundColor, this.productImg, exportLayers, format, quality);
|
|
177
|
+
}
|
|
178
|
+
async computeLayout() {
|
|
179
|
+
try {
|
|
180
|
+
let cw = this.width;
|
|
181
|
+
let ch = this.height;
|
|
182
|
+
// Load product image and compute contain-fit dimensions
|
|
183
|
+
if (this.productImage !== undefined && this.productImage !== '') {
|
|
184
|
+
const img = await loadImage(this.productImage);
|
|
185
|
+
this.productImg = img;
|
|
186
|
+
const { fittedW, fittedH } = computeContainFit(this.width, this.height, img.naturalWidth, img.naturalHeight);
|
|
187
|
+
cw = fittedW;
|
|
188
|
+
ch = fittedH;
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
this.productImg = undefined;
|
|
192
|
+
}
|
|
193
|
+
this.containerWidth = cw;
|
|
194
|
+
this.containerHeight = ch;
|
|
195
|
+
const newLayers = [];
|
|
196
|
+
for (const logo of this.logos) {
|
|
197
|
+
const displayUrl = logo.previewDataUrl ?? logo.dataUrl;
|
|
198
|
+
if (logo.transform !== undefined) {
|
|
199
|
+
// Explicit transform path
|
|
200
|
+
const exportImg = await loadImage(logo.dataUrl);
|
|
201
|
+
const nw = exportImg.naturalWidth;
|
|
202
|
+
const nh = exportImg.naturalHeight;
|
|
203
|
+
const { left, top } = centerOriginToTopLeft(logo.transform, nw, nh);
|
|
204
|
+
newLayers.push({
|
|
205
|
+
id: logo.id,
|
|
206
|
+
src: displayUrl,
|
|
207
|
+
exportImg,
|
|
208
|
+
naturalWidth: nw,
|
|
209
|
+
naturalHeight: nh,
|
|
210
|
+
left,
|
|
211
|
+
top,
|
|
212
|
+
scaleX: logo.transform.scaleX,
|
|
213
|
+
scaleY: logo.transform.scaleY,
|
|
214
|
+
angle: logo.transform.angle,
|
|
215
|
+
skewX: logo.transform.skewX ?? 0,
|
|
216
|
+
skewY: logo.transform.skewY ?? 0,
|
|
217
|
+
});
|
|
218
|
+
}
|
|
219
|
+
else if (this.printArea !== undefined) {
|
|
220
|
+
// Auto-fit path: determine logo dimensions, fit into print area
|
|
221
|
+
const hasBulge = this.printArea.bulge !== undefined && this.printArea.bulge !== 0;
|
|
222
|
+
let logoW;
|
|
223
|
+
let logoH;
|
|
224
|
+
let displaySrc = displayUrl;
|
|
225
|
+
if (hasBulge) {
|
|
226
|
+
// Bulge path: upscale SVG first (rasters pass through unchanged), then
|
|
227
|
+
// compute fit from actual pixel dimensions — matches the old Fabric.js flow
|
|
228
|
+
// where FabricImage.fromURL loaded the upscaled image before fitLogoToPrintArea.
|
|
229
|
+
const rendererMaxSize = Math.round(Math.max(cw, ch) * 2);
|
|
230
|
+
const { dataUrl: processedUrl } = upscaleSvgDataUrl(logo.dataUrl, rendererMaxSize);
|
|
231
|
+
const warpSrc = await loadImage(processedUrl);
|
|
232
|
+
logoW = warpSrc.naturalWidth;
|
|
233
|
+
logoH = warpSrc.naturalHeight;
|
|
234
|
+
const transform = fitLogoToPrintArea(logoW, logoH, this.printArea, cw, ch);
|
|
235
|
+
const [tl, tr, br, bl] = printAreaToPixelCorners(this.printArea, cw, ch);
|
|
236
|
+
const leftH = Math.hypot(bl.x - tl.x, bl.y - tl.y);
|
|
237
|
+
const rightH = Math.hypot(br.x - tr.x, br.y - tr.y);
|
|
238
|
+
const avgHeight = (leftH + rightH) / 2;
|
|
239
|
+
const warped = warpImageForBulge(warpSrc, this.printArea.bulge, avgHeight, transform.scaleX);
|
|
240
|
+
displaySrc = warped.toDataURL('image/png');
|
|
241
|
+
// Warped canvas may be taller due to displacement padding
|
|
242
|
+
logoW = warped.width;
|
|
243
|
+
logoH = warped.height;
|
|
244
|
+
const exportImg = await loadImage(displaySrc);
|
|
245
|
+
const { left, top } = centerOriginToTopLeft(transform, logoW, logoH);
|
|
246
|
+
newLayers.push({
|
|
247
|
+
id: logo.id,
|
|
248
|
+
src: displaySrc,
|
|
249
|
+
exportImg,
|
|
250
|
+
naturalWidth: logoW,
|
|
251
|
+
naturalHeight: logoH,
|
|
252
|
+
left,
|
|
253
|
+
top,
|
|
254
|
+
scaleX: transform.scaleX,
|
|
255
|
+
scaleY: transform.scaleY,
|
|
256
|
+
angle: transform.angle,
|
|
257
|
+
skewX: 0,
|
|
258
|
+
skewY: 0,
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
// No bulge: use intrinsic SVG dimensions (vector quality in <img>)
|
|
263
|
+
// or raster naturalWidth/Height
|
|
264
|
+
const svgSize = getSvgIntrinsicSize(logo.dataUrl);
|
|
265
|
+
if (svgSize !== null) {
|
|
266
|
+
logoW = svgSize.width;
|
|
267
|
+
logoH = svgSize.height;
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
const tempImg = await loadImage(logo.dataUrl);
|
|
271
|
+
logoW = tempImg.naturalWidth;
|
|
272
|
+
logoH = tempImg.naturalHeight;
|
|
273
|
+
}
|
|
274
|
+
const transform = fitLogoToPrintArea(logoW, logoH, this.printArea, cw, ch);
|
|
275
|
+
const exportImg = await loadImage(displaySrc);
|
|
276
|
+
const { left, top } = centerOriginToTopLeft(transform, logoW, logoH);
|
|
277
|
+
newLayers.push({
|
|
278
|
+
id: logo.id,
|
|
279
|
+
src: displaySrc,
|
|
280
|
+
exportImg,
|
|
281
|
+
naturalWidth: logoW,
|
|
282
|
+
naturalHeight: logoH,
|
|
283
|
+
left,
|
|
284
|
+
top,
|
|
285
|
+
scaleX: transform.scaleX,
|
|
286
|
+
scaleY: transform.scaleY,
|
|
287
|
+
angle: transform.angle,
|
|
288
|
+
skewX: 0,
|
|
289
|
+
skewY: 0,
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
}
|
|
294
|
+
this.layers = newLayers;
|
|
295
|
+
this.emitRenderComplete();
|
|
296
|
+
}
|
|
297
|
+
catch (err) {
|
|
298
|
+
const message = err instanceof Error ? err.message : 'Unknown render error';
|
|
299
|
+
this.wtpRenderError.emit({ message });
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
async emitRenderComplete() {
|
|
303
|
+
try {
|
|
304
|
+
const dataUrl = await this.exportImage('png');
|
|
305
|
+
this.wtpRenderComplete.emit({ dataUrl });
|
|
306
|
+
}
|
|
307
|
+
catch {
|
|
308
|
+
// Export may fail if called before layout is ready; ignore silently
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
render() {
|
|
312
|
+
const renderW = this.containerWidth || this.width;
|
|
313
|
+
const renderH = this.containerHeight || this.height;
|
|
314
|
+
return (h("div", { key: '3a720dae0cd0ab070a90b1f20dff9adb699b0ba5', class: "wtp-logo-renderer", style: {
|
|
315
|
+
width: `${renderW}px`,
|
|
316
|
+
height: `${renderH}px`,
|
|
317
|
+
backgroundColor: this.backgroundColor,
|
|
318
|
+
} }, this.productImage !== undefined && this.productImage !== '' && (h("img", { key: '88b50d0a4fd320a935bd7008ef3ddfee1644cbab', class: "product-bg", src: this.productImage, alt: "" })), this.layers.map(layer => (h("img", { key: layer.id, class: "logo-layer", src: layer.src, alt: "", style: {
|
|
319
|
+
position: 'absolute',
|
|
320
|
+
left: `${layer.left}px`,
|
|
321
|
+
top: `${layer.top}px`,
|
|
322
|
+
width: `${layer.naturalWidth}px`,
|
|
323
|
+
height: `${layer.naturalHeight}px`,
|
|
324
|
+
transformOrigin: 'center',
|
|
325
|
+
transform: `rotate(${layer.angle}deg) skewX(${layer.skewX}deg) skewY(${layer.skewY}deg) scale(${layer.scaleX}, ${layer.scaleY})`,
|
|
326
|
+
} })))));
|
|
327
|
+
}
|
|
328
|
+
static get watchers() { return {
|
|
329
|
+
"productImage": [{
|
|
330
|
+
"onProductImageChange": 0
|
|
331
|
+
}],
|
|
332
|
+
"logos": [{
|
|
333
|
+
"onLogosChange": 0
|
|
334
|
+
}],
|
|
335
|
+
"printArea": [{
|
|
336
|
+
"onPrintAreaChange": 0
|
|
337
|
+
}],
|
|
338
|
+
"width": [{
|
|
339
|
+
"onSizeChange": 0
|
|
340
|
+
}],
|
|
341
|
+
"height": [{
|
|
342
|
+
"onSizeChange": 0
|
|
343
|
+
}],
|
|
344
|
+
"backgroundColor": [{
|
|
345
|
+
"onBackgroundColorChange": 0
|
|
346
|
+
}]
|
|
347
|
+
}; }
|
|
348
|
+
};
|
|
349
|
+
WtpLogoRenderer.style = wtpLogoRendererCss();
|
|
350
|
+
|
|
351
|
+
export { WtpLogoRenderer as wtp_logo_renderer };
|