You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by ru...@apache.org on 2026/07/01 05:48:50 UTC
(superset) branch master updated: fix(point-cluster-map): guard invalid point radii (#40393)
This is an automated email from the ASF dual-hosted git repository.
rusackas 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 3e88b487b32 fix(point-cluster-map): guard invalid point radii (#40393)
3e88b487b32 is described below
commit 3e88b487b32d2721f7e419225d91572488365a2a
Author: Imamatdin <im...@gmail.com>
AuthorDate: Wed Jul 1 10:48:43 2026 +0500
fix(point-cluster-map): guard invalid point radii (#40393)
Co-authored-by: Imamatdin <20...@users.noreply.github.com>
---
.../src/components/ScatterPlotOverlay.tsx | 8 +++-
.../test/ScatterPlotOverlay.test.tsx | 52 +++++++++++++++++++++-
2 files changed, 57 insertions(+), 3 deletions(-)
diff --git a/superset-frontend/plugins/plugin-chart-point-cluster-map/src/components/ScatterPlotOverlay.tsx b/superset-frontend/plugins/plugin-chart-point-cluster-map/src/components/ScatterPlotOverlay.tsx
index 5c94a69b514..b14da848e45 100644
--- a/superset-frontend/plugins/plugin-chart-point-cluster-map/src/components/ScatterPlotOverlay.tsx
+++ b/superset-frontend/plugins/plugin-chart-point-cluster-map/src/components/ScatterPlotOverlay.tsx
@@ -26,6 +26,9 @@ import luminanceFromRGB from '../utils/luminanceFromRGB';
export const MIN_CLUSTER_RADIUS_RATIO = 1 / 6;
export const MAX_POINT_RADIUS_RATIO = 1 / 3;
+export const isValidCanvasRadius = (value: number) =>
+ Number.isFinite(value) && value > 0;
+
interface GeoJSONLocation {
geometry: {
coordinates: [number, number];
@@ -352,8 +355,11 @@ function ScatterPlotOverlay({
: String(pointMetric);
}
- if (!pointRadius) {
+ if (!isValidCanvasRadius(pointRadius)) {
pointRadius = defaultRadius;
+ if (pointMetric === null) {
+ pointLabel = undefined;
+ }
}
ctx.arc(
diff --git a/superset-frontend/plugins/plugin-chart-point-cluster-map/test/ScatterPlotOverlay.test.tsx b/superset-frontend/plugins/plugin-chart-point-cluster-map/test/ScatterPlotOverlay.test.tsx
index cafa91aaeba..634fc8e208b 100644
--- a/superset-frontend/plugins/plugin-chart-point-cluster-map/test/ScatterPlotOverlay.test.tsx
+++ b/superset-frontend/plugins/plugin-chart-point-cluster-map/test/ScatterPlotOverlay.test.tsx
@@ -18,8 +18,8 @@
*/
import { render } from '@testing-library/react';
-import ScatterPlotOverlay from '../src/components/ScatterPlotOverlay';
-import {
+import ScatterPlotOverlay, {
+ isValidCanvasRadius,
MIN_CLUSTER_RADIUS_RATIO,
MAX_POINT_RADIUS_RATIO,
} from '../src/components/ScatterPlotOverlay';
@@ -158,6 +158,18 @@ const MIN_VISIBLE_POINT_RADIUS =
const MAX_VISIBLE_POINT_RADIUS =
defaultProps.dotRadius * MAX_POINT_RADIUS_RATIO;
+test.each([
+ [1, true],
+ [0.1, true],
+ [0, false],
+ [-1, false],
+ [NaN, false],
+ [Infinity, false],
+ [-Infinity, false],
+])('validates canvas radius value %p', (value, expected) => {
+ expect(isValidCanvasRadius(value)).toBe(expected);
+});
+
test('renders map with varying radius values in Pixels mode', () => {
const locations = [
createLocation([100, 100], { radius: 10, cluster: false }),
@@ -373,6 +385,42 @@ test('renders map with Miles mode', () => {
}).not.toThrow();
});
+test.each(['Kilometers', 'Miles'])(
+ 'falls back to default radius for non-positive %s values',
+ pointRadiusUnit => {
+ const locations = [
+ createLocation([100, 50], { radius: -5, cluster: false }),
+ createLocation([200, 50], { radius: 0, cluster: false }),
+ createLocation([300, 50], { radius: 10, cluster: false }),
+ ];
+
+ render(
+ <ScatterPlotOverlay
+ {...defaultProps}
+ locations={locations}
+ pointRadiusUnit={pointRadiusUnit}
+ zoom={10}
+ />,
+ );
+ const redrawParams = triggerRedraw();
+
+ const arcCalls = redrawParams.ctx.arc.mock.calls;
+
+ arcCalls.forEach(call => {
+ expect(Number.isFinite(call[2])).toBe(true);
+ expect(call[2]).toBeGreaterThan(0);
+ });
+ expect(arcCalls[0][2]).toBe(MIN_VISIBLE_POINT_RADIUS);
+ expect(arcCalls[1][2]).toBe(MIN_VISIBLE_POINT_RADIUS);
+ expect(arcCalls[2][2]).toBeGreaterThan(MIN_VISIBLE_POINT_RADIUS);
+
+ const expectedLabel = pointRadiusUnit === 'Miles' ? '10mi' : '10km';
+ expect(redrawParams.ctx.fillText.mock.calls.map(call => call[0])).toEqual([
+ expectedLabel,
+ ]);
+ },
+);
+
test('displays metric property labels on points', () => {
const locations = [
createLocation([100, 100], { radius: 50, metric: 123.456, cluster: false }),