Skip to content

Commit 800c427

Browse files
committed
Fix regression that doesnt reset origial translate
1 parent d151da1 commit 800c427

1 file changed

Lines changed: 88 additions & 80 deletions

File tree

src/core/capture.js

Lines changed: 88 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,10 @@ export async function captureDOM(element, options) {
132132
const TOTAL = matrixFromComputed(measure);
133133
document.documentElement.removeChild(measure);
134134

135+
// -- NUEVO: extraigo la traslación total (px) para cancelarla en el container
136+
const e = TOTAL.e ?? TOTAL.m41 ?? 0; // translateX total
137+
const f = TOTAL.f ?? TOTAL.m42 ?? 0; // translateY total
138+
135139
// 4) bbox proyectado (sin traslación) sobre el tamaño w,h
136140
const M2D = TOTAL.is2D ? matrix2DNoTranslate(TOTAL) : matrix2DNoTranslate(new DOMMatrix(TOTAL.toString()));
137141
const bb = bboxFromMatrix(w, h, M2D);
@@ -158,22 +162,26 @@ export async function captureDOM(element, options) {
158162
classCSS;
159163
fo.appendChild(styleTag);
160164

161-
// 6) contenedor para el re-escalado por width/height (si aplica)
165+
// 6) contenedor para el re-escalado y la cancelación de translate
162166
const container = document.createElement("div");
163167
container.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
164168
container.style.width = `${w}px`;
165169
container.style.height = `${h}px`;
166170
container.style.overflow = "visible";
167171
container.style.transformOrigin = "0 0";
168172

173+
// armamos la transform del container empezando por CANCELAR la traslación total
174+
const cancels = [`translate(${-e}px, ${-f}px)`];
175+
176+
// luego tu lógica de escalado de salida
169177
if (!hasScale && (hasW || hasH)) {
170-
// escalo solo por petición de output w/h
171178
const sxWH = rect.width ? (w / rect.width) : 1;
172179
const syWH = rect.height ? (h / rect.height) : 1;
173-
container.style.transform = `scale(${sxWH}, ${syWH})`;
180+
cancels.push(`scale(${sxWH}, ${syWH})`);
174181
} else if (hasScale) {
175-
container.style.transform = `scale(${scaleOpt})`;
182+
cancels.push(`scale(${scaleOpt})`);
176183
}
184+
container.style.transform = cancels.join(" ");
177185

178186
// 7) aplicar al clone EXACTAMENTE lo que tenía el elemento
179187
clone.setAttribute("xmlns", "http://www.w3.org/1999/xhtml");
@@ -210,83 +218,83 @@ export async function captureDOM(element, options) {
210218
return dataURL;
211219
}
212220

213-
// helpers -----------------------------------------------------------------------
214-
function getNaturalBorderBoxSize(el) {
215-
const cs = getComputedStyle(el);
216-
const px = (v) => parseFloat(v) || 0;
217-
let w = px(cs.width);
218-
let h = px(cs.height);
219-
if (cs.boxSizing === "content-box") {
220-
w += px(cs.paddingLeft) + px(cs.paddingRight) + px(cs.borderLeftWidth) + px(cs.borderRightWidth);
221-
h += px(cs.paddingTop) + px(cs.paddingBottom) + px(cs.borderTopWidth) + px(cs.borderBottomWidth);
222-
}
223-
return { width: w, height: h };
224-
}
221+
// helpers -----------------------------------------------------------------------
222+
function getNaturalBorderBoxSize(el) {
223+
const cs = getComputedStyle(el);
224+
const px = (v) => parseFloat(v) || 0;
225+
let w = px(cs.width);
226+
let h = px(cs.height);
227+
if (cs.boxSizing === "content-box") {
228+
w += px(cs.paddingLeft) + px(cs.paddingRight) + px(cs.borderLeftWidth) + px(cs.borderRightWidth);
229+
h += px(cs.paddingTop) + px(cs.paddingBottom) + px(cs.borderTopWidth) + px(cs.borderBottomWidth);
230+
}
231+
return { width: w, height: h };
232+
}
225233

226-
function matrixFromComputed(el) {
227-
const tr = getComputedStyle(el).transform;
228-
if (!tr || tr === "none") return new DOMMatrix(); // identidad
229-
try { return new DOMMatrix(tr); }
230-
catch { return new WebKitCSSMatrix(tr); } // fallback WebKit
231-
}
234+
function matrixFromComputed(el) {
235+
const tr = getComputedStyle(el).transform;
236+
if (!tr || tr === "none") return new DOMMatrix(); // identidad
237+
try { return new DOMMatrix(tr); }
238+
catch { return new WebKitCSSMatrix(tr); } // fallback WebKit
239+
}
232240

233-
function matrix2DNoTranslate(M) {
234-
// devuelvo solo a,b,c,d y cero e,f para bbox
235-
return new DOMMatrix([M.a, M.b, M.c, M.d, 0, 0]);
236-
}
241+
function matrix2DNoTranslate(M) {
242+
// devuelvo solo a,b,c,d y cero e,f para bbox
243+
return new DOMMatrix([M.a, M.b, M.c, M.d, 0, 0]);
244+
}
237245

238-
function bboxFromMatrix(w, h, M2D) {
239-
const pts = [
240-
{ x: 0, y: 0 },
241-
{ x: w, y: 0 },
242-
{ x: 0, y: h },
243-
{ x: w, y: h },
244-
];
245-
const t = pts.map(p => ({
246-
x: M2D.a * p.x + M2D.c * p.y,
247-
y: M2D.b * p.x + M2D.d * p.y,
248-
}));
249-
const minX = Math.min(...t.map(p => p.x));
250-
const maxX = Math.max(...t.map(p => p.x));
251-
const minY = Math.min(...t.map(p => p.y));
252-
const maxY = Math.max(...t.map(p => p.y));
253-
return { minX, minY, width: maxX - minX, height: maxY - minY };
254-
}
246+
function bboxFromMatrix(w, h, M2D) {
247+
const pts = [
248+
{ x: 0, y: 0 },
249+
{ x: w, y: 0 },
250+
{ x: 0, y: h },
251+
{ x: w, y: h },
252+
];
253+
const t = pts.map(p => ({
254+
x: M2D.a * p.x + M2D.c * p.y,
255+
y: M2D.b * p.x + M2D.d * p.y,
256+
}));
257+
const minX = Math.min(...t.map(p => p.x));
258+
const maxX = Math.max(...t.map(p => p.x));
259+
const minY = Math.min(...t.map(p => p.y));
260+
const maxY = Math.max(...t.map(p => p.y));
261+
return { minX, minY, width: maxX - minX, height: maxY - minY };
262+
}
255263

256-
// lectura de typed OM (cuando existe)
257-
function readIndividualTransforms(el) {
258-
const out = { rotate: "0deg", scale: null, translate: null };
259-
const map = el.computedStyleMap?.();
260-
if (map) {
261-
const rot = map.get("rotate");
262-
if (rot) {
263-
const ang = rot.angle ?? rot;
264-
if (ang && "unit" in ang) {
265-
out.rotate = ang.unit === "rad" ? (ang.value * 180 / Math.PI) + "deg" : ang.value + ang.unit;
266-
} else {
267-
out.rotate = String(rot);
268-
}
269-
}
270-
const sc = map.get("scale");
271-
if (sc && sc.length) {
272-
const sx = sc[0]?.value ?? 1;
273-
const sy = sc[1]?.value ?? sx;
274-
out.scale = `${sx} ${sy}`;
275-
}
276-
const tr = map.get("translate");
277-
if (tr && tr.length) {
278-
const tx = tr[0]?.value ?? 0;
279-
const ty = tr[1]?.value ?? 0;
280-
const ux = tr[0]?.unit ?? "px";
281-
const uy = tr[1]?.unit ?? "px";
282-
out.translate = `${tx}${ux} ${ty}${uy}`;
283-
}
284-
return out;
285-
}
286-
// fallbacks por si no hay Typed OM
287-
const cs = getComputedStyle(el);
288-
out.rotate = cs.rotate && cs.rotate !== "none" ? cs.rotate : "0deg";
289-
out.scale = cs.scale && cs.scale !== "none" ? cs.scale : null;
290-
out.translate = cs.translate && cs.translate !== "none" ? cs.translate : null;
291-
return out;
292-
}
264+
// lectura de typed OM (cuando existe)
265+
function readIndividualTransforms(el) {
266+
const out = { rotate: "0deg", scale: null, translate: null };
267+
const map = el.computedStyleMap?.();
268+
if (map) {
269+
const rot = map.get("rotate");
270+
if (rot) {
271+
const ang = rot.angle ?? rot;
272+
if (ang && "unit" in ang) {
273+
out.rotate = ang.unit === "rad" ? (ang.value * 180 / Math.PI) + "deg" : ang.value + ang.unit;
274+
} else {
275+
out.rotate = String(rot);
276+
}
277+
}
278+
const sc = map.get("scale");
279+
if (sc && sc.length) {
280+
const sx = sc[0]?.value ?? 1;
281+
const sy = sc[1]?.value ?? sx;
282+
out.scale = `${sx} ${sy}`;
283+
}
284+
const tr = map.get("translate");
285+
if (tr && tr.length) {
286+
const tx = tr[0]?.value ?? 0;
287+
const ty = tr[1]?.value ?? 0;
288+
const ux = tr[0]?.unit ?? "px";
289+
const uy = tr[1]?.unit ?? "px";
290+
out.translate = `${tx}${ux} ${ty}${uy}`;
291+
}
292+
return out;
293+
}
294+
// fallbacks por si no hay Typed OM
295+
const cs = getComputedStyle(el);
296+
out.rotate = cs.rotate && cs.rotate !== "none" ? cs.rotate : "0deg";
297+
out.scale = cs.scale && cs.scale !== "none" ? cs.scale : null;
298+
out.translate = cs.translate && cs.translate !== "none" ? cs.translate : null;
299+
return out;
300+
}

0 commit comments

Comments
 (0)