Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion src/component/toolbox/feature/SaveAsImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,25 @@ export interface ToolboxSaveAsImageFeatureOption extends ToolboxFeatureOption {
lang?: string[]
}

interface ProxyWindow extends Window {
rawWindow?: Window
}

function pickEventView(): Window {
try {
void new MouseEvent("click", { view: (window as ProxyWindow)?.rawWindow || window });
return (window as ProxyWindow)?.rawWindow || window;
} catch {
if (document.defaultView) {
try {
void new MouseEvent("click", { view: document.defaultView });
return document.defaultView;
} catch {}
}
return window;
}
}

class SaveAsImage extends ToolboxFeature<ToolboxSaveAsImageFeatureOption> {

onclick(ecModel: GlobalModel, api: ExtensionAPI) {
Expand All @@ -66,7 +85,7 @@ class SaveAsImage extends ToolboxFeature<ToolboxSaveAsImageFeatureOption> {
$a.href = url;
const evt = new MouseEvent('click', {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not familiar with the micro-frontend framework. Instead of dispatching a click event, does $a.click() work in that environment?

Copy link
Author

@YaoKaiPeng YaoKaiPeng Nov 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi, happy to discuss this further!

In micro-frontend environments, window is often a proxy object (e.g., in qiankun, Micro-app, etc.), which can cause issues when creating MouseEvent with new MouseEvent(..., { view: window }) — for example, throwing errors or behaving unexpectedly.

I believe the key point isn't whether to use element.click() or dispatchEvent, but rather: which actual window object should be used as the view when creating the event.

That’s why this PR replaces document.defaultView with pickEventView() — a safe utility that:

  1. Tries to use window.rawWindow (available in frameworks like Micro-app, where window.proxy holds the real rawWindow).
  2. Falls back to document.defaultView if that’s accessible.
  3. Finally defaults to window if all else fails.

This ensures the MouseEvent always has a valid, real window as its view, regardless of whether window is a proxy — making the event creation robust in micro-frontend setups.

Importantly, this change doesn’t alter how events are dispatched (we still use dispatchEvent), but it significantly improves reliability by ensuring the correct view context is used.

This makes ECharts more resilient in micro-frontend applications without introducing any behavioral changes.

Thanks for raising this question — happy to discuss further! 😊

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your explanation. I mean, we can try using $a.click() rather than manually creating and dispatching a click event, since $a.click() doesn't need to pass the window object. If this works in micro-frontend frameworks, I think we can remove this code block.

// some micro front-end framework, window maybe is a Proxy
view: document.defaultView,
view: pickEventView(),
bubbles: true,
cancelable: false
});
Expand Down