diff --git a/web/client/components/charts/WidgetChart.jsx b/web/client/components/charts/WidgetChart.jsx index 0578f1b264..5eed2f3979 100644 --- a/web/client/components/charts/WidgetChart.jsx +++ b/web/client/components/charts/WidgetChart.jsx @@ -20,7 +20,7 @@ import { enableBarChartStack, FONT } from '../../utils/WidgetsUtils'; - +import withLegendScrollHandler from './withLegendScrollHandler'; const Plot = React.lazy(() => import('./PlotlyChart')); const processDataProperties = (formula, key, data) => { @@ -698,4 +698,4 @@ function WidgetChart({ ); } -export default withClassifyGeoJSONSync(WidgetChart); +export default withLegendScrollHandler(withClassifyGeoJSONSync(WidgetChart)); diff --git a/web/client/components/charts/withLegendScrollHandler.jsx b/web/client/components/charts/withLegendScrollHandler.jsx new file mode 100644 index 0000000000..9885026544 --- /dev/null +++ b/web/client/components/charts/withLegendScrollHandler.jsx @@ -0,0 +1,61 @@ + +import React from 'react'; +import isNil from 'lodash/isNil'; + +/** + * Handler to deal with legend mouse wheel sensitivity issue + * with chart widget has multiple legend items + * NOTE: This is a workaround for issue in plotly.js https://github.com/plotly/plotly.js/issues/6737 + * until fix on plotly is implemented + */ +const withLegendScrollHandler = (WrappedComponent) => { + return (props) => { + /** + * Event listener captures mouse wheel event of legend element + * and modifies the deltaY such that the sensitivity is exhibited in a controlled manner + */ + const legendMouseWheelEventHandler = (graphDiv) => { + const legend = graphDiv.querySelector('.infolayer .legend'); + if (legend) { + const legendBg = legend.querySelector('.bg'); + + // add listener in capture mode + legend.addEventListener('wheel', function(event) { + if (!event.isTrusted) return; + event.preventDefault(); + event.stopPropagation(); + + const maxScrollDistance = legend.getBBox()?.height; + const scrollHeight = legendBg?.getBBox()?.height; + + let deltaY = 0.30; // fallback fixed value + if (!isNil(scrollHeight) && !isNil(maxScrollDistance)) { + deltaY = (scrollHeight / maxScrollDistance) * 100; + } + if (Number(event.deltaY) < 0) { + deltaY *= -1; // negate on upward scroll + } + const newEvent = new WheelEvent('wheel', { + clientX: event.clientX, + clientY: event.clientY, + deltaY, + view: window, + bubbles: true, + cancelable: true + }); + event.target.dispatchEvent(newEvent); + }, true); + } + }; + return ( + { + legendMouseWheelEventHandler(graphDiv); + props.onInitialized(figure, graphDiv); + }} + />); + }; +}; + +export default withLegendScrollHandler;