This is an automated email from the ASF dual-hosted git repository.
EnxDev pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/superset.git
The following commit(s) were added to refs/heads/master by this push:
new 5dd060b714a fix(chart-echarts): disable animation for report
screenshots so time-shift lines render fully (#42003)
5dd060b714a is described below
commit 5dd060b714a19828037c67258474934e2e0dd92d
Author: Enzo Martellucci <[email protected]>
AuthorDate: Mon Jul 13 19:02:45 2026 +0200
fix(chart-echarts): disable animation for report screenshots so time-shift
lines render fully (#42003)
---
.../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,