This is an automated email from the ASF dual-hosted git repository.

EnxDev pushed a commit to branch fix/timeshift-line-chart-report-render
in repository https://gitbox.apache.org/repos/asf/superset.git

commit 3e70b4472c47030ed4a6990fd70f731504d40e7d
Author: Enzo Martellucci <[email protected]>
AuthorDate: Mon Jul 13 17:43:46 2026 +0200

    fix(chart-echarts): disable animation for report screenshots so time-shift 
lines render fully
---
 .../src/components/Echart.test.tsx                 | 53 +++++++++++++++++++++-
 .../plugin-chart-echarts/src/components/Echart.tsx | 30 +++++++++---
 2 files changed, 75 insertions(+), 8 deletions(-)

diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.test.tsx 
b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.test.tsx
index 110b4214fd6..f353fd2532d 100644
--- 
a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.test.tsx
+++ 
b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.test.tsx
@@ -18,7 +18,7 @@
  */
 import { render, waitFor } from '../../../../spec/helpers/testing-library';
 import type { EChartsCoreOption } from 'echarts/core';
-import Echart from './Echart';
+import Echart, { isReportScreenshotMode } from './Echart';
 import type { EchartsProps } from '../types';
 
 type Handler = (params: unknown) => void;
@@ -130,6 +130,20 @@ const trigger = (name: string) => {
   (listeners[name] || []).forEach(listener => listener.handler({}));
 };
 
+const originalLocation = 
`${window.location.pathname}${window.location.search}`;
+
+const setStandalone = (standalone?: string) => {
+  window.history.replaceState(
+    {},
+    '',
+    standalone === undefined ? '/' : `/?standalone=${standalone}`,
+  );
+};
+
+afterEach(() => {
+  window.history.replaceState({}, '', originalLocation);
+});
+
 beforeEach(() => {
   Object.keys(listeners).forEach(name => {
     delete listeners[name];
@@ -221,3 +235,40 @@ test('replaces stale query event handlers without clearing 
regular event handler
   expect(firstQueryHandler).not.toHaveBeenCalled();
   expect(secondQueryHandler).not.toHaveBeenCalled();
 });
+
+test.each([
+  // Report/thumbnail screenshots render in standalone "true" (charts) or 3 
(reports)
+  ['true', true],
+  ['3', true],
+  // Live embeds use 1/2 and must keep animation
+  ['1', false],
+  ['2', false],
+  ['0', false],
+  [undefined, false],
+])(
+  'isReportScreenshotMode() is %p for standalone=%p',
+  (standalone, expected) => {
+    setStandalone(standalone);
+    expect(isReportScreenshotMode()).toBe(expected);
+  },
+);
+
+test('disables animation when rendering in report screenshot mode', async () 
=> {
+  setStandalone('true');
+  render(renderEchart(), { initialState, useRedux: true });
+
+  await waitFor(() => expect(mockChart.setOption).toHaveBeenCalled());
+
+  const lastOptions = mockChart.setOption.mock.calls.at(-1)?.[0];
+  expect(lastOptions.animation).toBe(false);
+});
+
+test('keeps animation enabled when not in report screenshot mode', async () => 
{
+  setStandalone(undefined);
+  render(renderEchart(), { initialState, useRedux: true });
+
+  await waitFor(() => expect(mockChart.setOption).toHaveBeenCalled());
+
+  const lastOptions = mockChart.setOption.mock.calls.at(-1)?.[0];
+  expect(lastOptions.animation).not.toBe(false);
+});
diff --git 
a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx 
b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx
index 52111fd4f86..43fc7bf2bb0 100644
--- a/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx
+++ b/superset-frontend/plugins/plugin-chart-echarts/src/components/Echart.tsx
@@ -131,6 +131,19 @@ const loadLocale = async (locale: string) => {
   return lang?.default;
 };
 
+// Report/thumbnail screenshots use standalone="true" (charts) or 3 (reports);
+// live embeds use 1/2 and keep animation. See superset/utils/screenshots.py.
+export function isReportScreenshotMode(): boolean {
+  try {
+    const standalone = new URLSearchParams(window.location.search).get(
+      'standalone',
+    );
+    return standalone === 'true' || standalone === '3';
+  } catch {
+    return false;
+  }
+}
+
 function Echart(
   {
     width,
@@ -278,13 +291,16 @@ function Echart(
         ? theme.echartsOptionsOverridesByChartType?.[vizType] || {}
         : {};
 
-      // Disable animations during auto-refresh to reduce visual noise
-      const animationOverride = isDashboardRefreshing
-        ? {
-            animation: false,
-            animationDuration: 0,
-          }
-        : {};
+      // Disable animation on auto-refresh and screenshots. Screenshots have no
+      // "render finished" signal, so a running draw can be captured mid-frame,
+      // producing partial/blank charts.
+      const animationOverride =
+        isDashboardRefreshing || isReportScreenshotMode()
+          ? {
+              animation: false,
+              animationDuration: 0,
+            }
+          : {};
 
       const themedEchartOptions = mergeEchartsThemeOverrides(
         baseTheme,

Reply via email to