Skip to content

Commit 9f4c19d

Browse files
AmirMohammad CheraghaliAmirMohammad Cheraghali
authored andcommitted
fix: implement definitive V6 Live Resize for PNG export to resolve clipping and data sync
1 parent 93dc4c1 commit 9f4c19d

1 file changed

Lines changed: 41 additions & 47 deletions

File tree

src/components/dashboard/InlineChart.tsx

Lines changed: 41 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -180,87 +180,77 @@ const InlineChartComponent = ({ node, updateAttributes, deleteNode }: any) => {
180180
if (!chartRef.current) return;
181181

182182
setIsExporting(true);
183+
const originalStyle = chartRef.current.getAttribute('style') || '';
184+
183185
try {
186+
// 1. LIVE RESIZE: Force the chart to 1000px off-screen in the actual DOM
187+
// This allows Recharts to recalculate the ResponsiveContainer BEFORE capture
188+
chartRef.current.style.position = 'fixed';
189+
chartRef.current.style.left = '-5000px';
190+
chartRef.current.style.top = '0';
191+
chartRef.current.style.width = '1000px';
192+
chartRef.current.style.zIndex = '-9999';
193+
chartRef.current.style.visibility = 'visible';
194+
chartRef.current.style.opacity = '1';
195+
196+
// 2. WAIT FOR LAYOUT: Give Recharts 800ms to re-render SVG at 1000px
197+
await new Promise(resolve => setTimeout(resolve, 800));
198+
184199
const elementToCapture = chartRef.current;
185200

186-
// Use html2canvas with Clean-Room Reparenting strategy
201+
// 3. CAPTURE WITH ONCLONE ISOLATION
187202
const canvas = await html2canvas(elementToCapture, {
188203
scale: 2,
189204
backgroundColor: isDark ? '#171717' : '#ffffff',
190205
useCORS: true,
191206
logging: false,
192207
onclone: (clonedDoc) => {
193-
// 1. CLEAN-ROOM REPARENTING: Find our target chart in the clone
194-
// We need to find the specific element that matches our chartRef
195-
const chartInClone = clonedDoc.querySelector('.inline-chart-wrapper');
196-
if (!chartInClone) return;
197-
198-
// 2. NUCLEAR STRIP: Remove EVERYTHING from the cloned body
199-
clonedDoc.body.innerHTML = '';
200-
201-
// 3. REPARENT: Put the chart directly into the body
202-
clonedDoc.body.appendChild(chartInClone);
203-
204-
// 4. STYLE ISOLATION: Remove all project-wide styles and inject safe ones
208+
// NUCLEAR STRIP: Remove modern color crashes
205209
const styles = clonedDoc.querySelectorAll('style, link[rel="stylesheet"]');
206210
styles.forEach(s => s.remove());
207211

208212
const safeStyles = clonedDoc.createElement('style');
209213
safeStyles.innerHTML = `
210-
* { box-sizing: border-box; -webkit-print-color-adjust: exact; }
211-
body {
212-
background: ${isDark ? '#0a0a0a' : '#ffffff'} !important;
213-
width: 1100px !important;
214-
height: auto !important;
215-
margin: 0 !important;
216-
padding: 60px !important;
217-
display: flex !important;
218-
justify-content: center !important;
219-
align-items: flex-start !important;
220-
overflow: visible !important;
221-
font-family: -apple-system, system-ui, sans-serif !important;
222-
}
214+
* { box-sizing: border-box; }
223215
.inline-chart-wrapper {
224216
width: 1000px !important;
225-
display: block !important;
226-
background: transparent !important;
227-
opacity: 1 !important;
228-
visibility: visible !important;
229-
transform: none !important;
217+
padding: 40px !important;
218+
background: ${isDark ? '#171717' : '#ffffff'} !important;
219+
display: block !important;
220+
font-family: -apple-system, sans-serif !important;
230221
}
231222
.bg-\\[var\\(--bg-sidebar\\)\\] {
232-
background: ${isDark ? '#171717' : '#ffffff'} !important;
233-
border-radius: 24px !important;
234-
padding: 56px !important;
235-
border: 1px solid ${isDark ? '#262626' : '#e5e5e5'} !important;
236-
box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25) !important;
223+
background: ${isDark ? '#171717' : '#ffffff'} !important;
224+
border-radius: 24px !important;
225+
padding: 48px !important;
226+
border: 1px solid ${isDark ? '#262626' : '#e5e5e5'} !important;
237227
width: 100% !important;
238228
}
239229
.text-\\[var\\(--text-primary\\)\\] { color: ${isDark ? '#f5f5f5' : '#171717'} !important; }
240230
.text-\\[var\\(--text-muted\\)\\] { color: #888888 !important; }
241-
.h-72 { width: 100% !important; height: 450px !important; margin-top: 32px !important; }
242-
.text-xl { font-size: 36px !important; font-weight: 800 !important; margin: 0 !important; color: ${isDark ? '#f5f5f5' : '#171717'} !important; }
243-
.text-xs { font-size: 16px !important; margin-top: 8px !important; color: #888888 !important; }
231+
.h-72 { width: 100% !important; height: 400px !important; margin-top: 32px !important; }
232+
.text-xl { font-size: 32px !important; font-weight: 800 !important; margin: 0 !important; }
233+
.text-xs { font-size: 14px !important; margin-top: 6px !important; }
244234
.flex { display: flex !important; }
245235
.items-center { align-items: center !important; }
246236
.items-start { align-items: flex-start !important; }
247237
.justify-between { justify-content: space-between !important; }
248-
.mb-6 { margin-bottom: 32px !important; }
249-
.gap-3 { gap: 16px !important; }
250-
.capture-hide { display: none !important; visibility: hidden !important; }
238+
.mb-6 { margin-bottom: 24px !important; }
239+
.gap-3 { gap: 12px !important; }
240+
.capture-hide { display: none !important; }
251241
.recharts-responsive-container { width: 100% !important; height: 100% !important; }
252242
svg { width: 100% !important; height: 100% !important; display: block; }
253-
.recharts-text { fill: #888888 !important; font-size: 13px !important; font-weight: 600 !important; }
243+
.recharts-text { fill: #888888 !important; font-size: 12px !important; font-weight: 600 !important; }
254244
.recharts-legend-item-text { fill: #888888 !important; font-weight: 600 !important; }
255245
.recharts-cartesian-grid-line { stroke: ${isDark ? '#262626' : '#e5e5e5'} !important; }
256246
`;
257247
clonedDoc.head.appendChild(safeStyles);
258248

259-
// 5. SCRUB INLINE OKLAB COLORS
249+
// SCRUB INLINE OKLAB COLORS
260250
clonedDoc.querySelectorAll('*').forEach(el => {
261251
if (el instanceof HTMLElement) {
262-
const inlineStyle = el.getAttribute('style') || '';
263-
if (inlineStyle.includes('okl')) {
252+
const s = el.getAttribute('style') || '';
253+
if (s.includes('okl')) {
264254
el.style.color = '';
265255
el.style.backgroundColor = '';
266256
el.style.borderColor = '';
@@ -276,8 +266,12 @@ const InlineChartComponent = ({ node, updateAttributes, deleteNode }: any) => {
276266
link.click();
277267
} catch (err: any) {
278268
console.error('Export Error:', err);
279-
alert(`Export error: ${err.message || 'Unknown failure'}`);
269+
alert(`Export failed: ${err.message || 'Unknown failure'}`);
280270
} finally {
271+
// 4. RESTORE ORIGINAL STATE
272+
if (chartRef.current) {
273+
chartRef.current.setAttribute('style', originalStyle);
274+
}
281275
setIsExporting(false);
282276
}
283277
}}

0 commit comments

Comments
 (0)