diff --git a/CHANGELOG.md b/CHANGELOG.md index c806701068..b67f94b12d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ This project adheres to [Semantic Versioning](https://semver.org/). - [#3765](https://github.com/plotly/dash/pull/3765) Add opt-in partial pattern matching for callback `Input`, `Output`, and `State` dependencies via `partial_pattern=True`. Dictionary ID patterns can now match component IDs containing additional keys, and partial patterns can be combined with `ALL` and `MATCH` wildcards. Fixes [#3764](https://github.com/plotly/dash/issues/3764). - [#3646](https://github.com/plotly/dash/pull/3646) Experimental support for React 19. The default is still React 18.3.1; to use React 19 set the environment variable `REACT_VERSION=19.2.4` before running your app, or call `dash._dash_renderer._set_react_version("19.2.4")` inside the app. React 19 has no official UMD builds, so Dash serves the [`umd-react`](https://www.npmjs.com/package/umd-react) package, together with a compatibility shim loaded after react-dom and before any component package. The shim keeps component libraries built against React <=18 (e.g. dash-bootstrap-components, dash-mantine-components) working under React 19: it stubs the removed `ReactCurrentOwner` internals, redirects the legacy element `$$typeof` symbol so pre-bundled React 18 jsx-runtimes produce elements React 19 accepts (error #525), and exposes a global `react/jsx-runtime` (`window.ReactJSXRuntime`) that Dash's own component bundles externalize to. Component library authors adopting this convention should copy the defensive `jsxRuntimeExternal` webpack external from `components/dash-core-components/webpack.config.js` rather than a bare `'ReactJSXRuntime'` string: it falls back to a `React.createElement`-based runtime when the global is missing, so the same build also works on Dash versions older than this release. - [#3925](https://github.com/plotly/dash/pull/3925) Add optional callback request payload compression for server-side callbacks via `compress_payload` and `compress_threshold` callback parameters (default threshold: 5,000 bytes). When enabled and the request body exceeds the threshold, the renderer sends gzip-compressed binary payloads with `Content-Encoding: gzip`, and Dash transparently decompresses on the server (Flask, FastAPI, and Quart). This can significantly reduce callback roundtrip times for large client-to-server payloads. Fixes [#3924](https://github.com/plotly/dash/issues/3924). +- [#3961](https://github.com/plotly/dash/pull/3961) Added cursor position data (`xPixel`, `yPixel`) to `dcc.Graph` `hoverData` and `clickData` when `hoveranywhere` or `clickanywhere` is enabled in the figure. ### Removed - [#3646](https://github.com/plotly/dash/pull/3646) Remove React 16 support (`16.14.0` is no longer an accepted value for `REACT_VERSION` / `_set_react_version`). diff --git a/components/dash-core-components/src/fragments/Graph.react.js b/components/dash-core-components/src/fragments/Graph.react.js index 8fae4f7189..694bf5404e 100644 --- a/components/dash-core-components/src/fragments/Graph.react.js +++ b/components/dash-core-components/src/fragments/Graph.react.js @@ -125,13 +125,11 @@ const filterEventData = (gd, eventData, event) => { (event === 'click' && gd._fullLayout.clickanywhere === true); if (includeXYVals) { - if (has('xvals', eventData)) { - filteredEventData.xvals = eventData.xvals; - } - - if (has('yvals', eventData)) { - filteredEventData.yvals = eventData.yvals; - } + ['xvals', 'yvals', 'xPixel', 'yPixel'].forEach(key => { + if (has(key, eventData)) { + filteredEventData[key] = eventData[key]; + } + }); if (has('xaxes', eventData)) { filteredEventData.xaxes_id = eventData.xaxes[0]._id; diff --git a/components/dash-core-components/tests/integration/graph/test_graph_basics.py b/components/dash-core-components/tests/integration/graph/test_graph_basics.py index efe32383d2..f268c1edd5 100644 --- a/components/dash-core-components/tests/integration/graph/test_graph_basics.py +++ b/components/dash-core-components/tests/integration/graph/test_graph_basics.py @@ -559,7 +559,10 @@ def show_figure_state(figure): def test_grbs011_clickanywhere_hoveranywhere(dash_dcc): - """When clickanywhere and hoveranywhere are enabled, clickData and hoverData include xvals and yvals""" + """ + When clickanywhere and hoveranywhere are enabled, clickData and hoverData include xvals and yvals + Note - xPixel and yPixel requires Plotly>=7 + """ app = Dash(__name__) app.layout = html.Div( @@ -587,6 +590,10 @@ def on_event(click_data, hover_data): "click_y": (click_data or {}).get("yvals", [None])[0], "hover_x": (hover_data or {}).get("xvals", [None])[0], "hover_y": (hover_data or {}).get("yvals", [None])[0], + "click_xPixel": (click_data or {}).get("xPixel"), + "click_yPixel": (click_data or {}).get("yPixel"), + "hover_xPixel": (hover_data or {}).get("xPixel"), + "hover_yPixel": (hover_data or {}).get("yPixel"), } return json.dumps(result) @@ -600,11 +607,18 @@ def on_event(click_data, hover_data): out = json.loads(dash_dcc.find_element("#output").text) - # click anywhere should produce coordinates - assert out["click_x"] is not None - assert out["click_y"] is not None - assert out["hover_x"] is not None - assert out["hover_y"] is not None + # click/hover anywhere should produce coordinates + for key in ( + "click_x", + "click_y", + "hover_x", + "hover_y", + "click_xPixel", + "click_yPixel", + "hover_xPixel", + "hover_yPixel", + ): + assert out[key] is not None def test_grbs012_graph_patch_keeps_relayout_ranges(dash_dcc):