From 8260b99bc8286d8ebed33dbf5e845811919aafcc Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 27 Apr 2023 10:54:27 +0200 Subject: [PATCH 01/41] Removed dead code --- packages/react-core/src/filters/tileFeaturesGeometries.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/react-core/src/filters/tileFeaturesGeometries.js b/packages/react-core/src/filters/tileFeaturesGeometries.js index 3195c23d4..306aa888e 100644 --- a/packages/react-core/src/filters/tileFeaturesGeometries.js +++ b/packages/react-core/src/filters/tileFeaturesGeometries.js @@ -166,10 +166,6 @@ function createIndicesForPoints(data) { data.pointIndices.value.set([lastFeatureId + 1], featureIds.length); } -export function getGeometryToIntersect(viewport, geometry) { - return geometry ? intersect(bboxPolygon(viewport), geometry) : bboxPolygon(viewport); -} - export default function tileFeaturesGeometries({ tiles, tileFormat, From ebdd99ca5baa8baad2273edf60ff4d8e7f0c7ea1 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 27 Apr 2023 12:06:55 +0200 Subject: [PATCH 02/41] Changed behavior of getGeometryToIntersect --- .../__tests__/filters/tileFeatures.test.js | 114 +++++++++++++++--- .../react-core/src/filters/tileFeatures.d.ts | 4 +- .../react-core/src/filters/tileFeatures.js | 20 ++- 3 files changed, 115 insertions(+), 23 deletions(-) diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index c286032a5..93f7693f4 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -2,10 +2,68 @@ import { TILE_FORMATS } from '@deck.gl/carto'; import { geojsonToBinary } from '@loaders.gl/gis'; import { tileFeatures } from '../../src'; import * as transformToTileCoords from '../../src/utils/transformToTileCoords'; +import { getGeometryToIntersect } from '../../src/filters/tileFeatures'; + +/** @type { import('../../src').Viewport } */ +const viewport = [-10, -10, 10, 10]; // west - south - east - north + +const viewportFeature = { + bbox: viewport, + type: 'Feature', + properties: {}, + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-10, -10], + [10, -10], + [10, 10], + [-10, 10], + [-10, -10] + ] + ] + } +}; + +/** @type { import('geojson').Feature } */ +const geometryFeature = { + type: 'Feature', + geometry: { + type: 'Polygon', + coordinates: [ + [ + [-1, -1], + [1, -1], + [1, 1], + [-1, 1], + [-1, -1] + ] + ] + }, + properties: {} +}; + +describe('getGeometryToIntersect', () => { + test('returns null in case no viewport or geometry is present', () => { + expect(getGeometryToIntersect(null, null)).toStrictEqual(null); + expect(getGeometryToIntersect([], null)).toStrictEqual(null); + }); + + test('returns the viewport as feature', () => { + expect(getGeometryToIntersect(viewport, null)).toStrictEqual(viewportFeature); + }); + + test('returns the geometry as feature', () => { + expect(getGeometryToIntersect(null, geometryFeature)).toStrictEqual(geometryFeature); + expect(getGeometryToIntersect(viewport, geometryFeature)).toStrictEqual( + geometryFeature + ); + }); +}); describe('viewport features with binary mode', () => { - const viewport = [-10, -10, 10, 10]; // west - south - east - north const [west, south, east, north] = viewport; + const tileFormat = TILE_FORMATS.BINARY; describe('return no data', () => { test('tiles are not visible', () => { @@ -13,7 +71,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport + viewport, + tileFormat }); expect(properties).toEqual([]); }); @@ -23,7 +82,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport + viewport, + tileFormat }); expect(properties).toEqual([]); }); @@ -33,7 +93,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport + viewport, + tileFormat }); expect(properties).toEqual([]); }); @@ -43,7 +104,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport + viewport, + tileFormat }); expect(properties).toEqual([]); }); @@ -75,7 +137,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); // prettier-ignore @@ -111,7 +174,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); // prettier-ignore expect(properties).toEqual([ @@ -146,7 +210,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); // prettier-ignore expect(properties).toEqual([ @@ -184,7 +249,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); // prettier-ignore expect(properties).toEqual([ @@ -220,7 +286,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); expect(properties).toEqual([{ cartodb_id: 1, other_prop: 1 }]); }); @@ -250,7 +317,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); expect(properties).toEqual([{ cartodb_id: 1, other_prop: 1 }]); }); @@ -280,7 +348,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); expect(properties).toEqual([{ cartodb_id: 1, other_prop: 1 }]); }); @@ -310,7 +379,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); expect(properties).toEqual([{ cartodb_id: 1, other_prop: 1 }]); }); @@ -343,7 +413,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'cartodb_id' + uniqueIdProperty: 'cartodb_id', + tileFormat }); expect(properties).toEqual([{ cartodb_id: 1, other_prop: 1 }]); }); @@ -389,7 +460,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, viewport, - uniqueIdProperty: undefined + uniqueIdProperty: undefined, + tileFormat }); // prettier-ignore @@ -426,7 +498,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: undefined + uniqueIdProperty: undefined, + tileFormat }); // prettier-ignore expect(properties).toEqual([ @@ -462,7 +535,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: undefined + uniqueIdProperty: undefined, + tileFormat }); // prettier-ignore expect(properties).toEqual([ @@ -497,7 +571,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: undefined + uniqueIdProperty: undefined, + tileFormat }); // prettier-ignore expect(properties).toEqual([ @@ -534,7 +609,8 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, viewport, - uniqueIdProperty: 'user_id' + uniqueIdProperty: 'user_id', + tileFormat }); // prettier-ignore expect(properties).toEqual([ diff --git a/packages/react-core/src/filters/tileFeatures.d.ts b/packages/react-core/src/filters/tileFeatures.d.ts index b30085f20..e668405e9 100644 --- a/packages/react-core/src/filters/tileFeatures.d.ts +++ b/packages/react-core/src/filters/tileFeatures.d.ts @@ -1,5 +1,5 @@ import { TileFeatures, TileFeaturesResponse } from '../types'; -import { Geometry, Feature, Polygon, MultiPolygon } from 'geojson'; +import { Feature, Polygon, MultiPolygon } from 'geojson'; -export function getGeometryToIntersect(viewport: number[], geometry: Geometry | null): Feature | null; +export function getGeometryToIntersect(viewport: number[] | null, geometry: Feature | null): Feature | null; export function tileFeatures(arg: TileFeatures): TileFeaturesResponse; \ No newline at end of file diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index fd352c21a..0321d331d 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -1,10 +1,26 @@ import bboxPolygon from '@turf/bbox-polygon'; -import intersect from '@turf/intersect'; import tileFeaturesGeometries from './tileFeaturesGeometries'; import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; +/** + * Select the geometry to use for widget calculation and data filtering. + * If a geometry (mask) is set, use the mask otherwise use the current viewport. + * Since it's possible that no mask and no viewport is set, return null in this case. + * + * @typedef { import('geojson').Polygon | import('geojson').MultiPolygon } Geometry + * @typedef { import('geojson').Feature } Feature + * @typedef { import('geojson').BBox } BBox + * + * @param { BBox? } viewport viewport [minX, minY, maxX, maxY], if any + * @param { Feature? } geometry the active mask, if any + * @returns { Feature? } the geometry to use for filtering + */ export function getGeometryToIntersect(viewport, geometry) { - return geometry ? intersect(bboxPolygon(viewport), geometry) : bboxPolygon(viewport); + return geometry + ? geometry + : Array.isArray(viewport) && viewport.length === 4 + ? bboxPolygon(viewport) + : null; } export function tileFeatures({ From 61777e8572bfa84cacfd5bf75dea2c70db3caa4f Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 27 Apr 2023 16:36:31 +0200 Subject: [PATCH 03/41] Refactor: reduced unneeded widget calculation --- .../react-api/src/hooks/useCartoLayerProps.js | 8 +-- .../react-api/src/hooks/useGeojsonFeatures.js | 14 ++--- .../react-api/src/hooks/useTileFeatures.js | 14 ++--- .../__tests__/filters/geojsonFeatures.test.js | 23 ++++--- .../__tests__/filters/tileFeatures.test.js | 62 +++++++------------ .../src/filters/geojsonFeatures.d.ts | 7 +-- .../react-core/src/filters/geojsonFeatures.js | 4 +- .../react-core/src/filters/tileFeatures.js | 5 +- packages/react-core/src/index.d.ts | 2 +- packages/react-core/src/index.js | 2 +- packages/react-core/src/types.d.ts | 5 +- .../react-redux/src/slices/cartoSlice.d.ts | 3 +- .../react-workers/__tests__/methods.test.js | 7 ++- packages/react-workers/src/workers/methods.js | 11 ++-- 14 files changed, 69 insertions(+), 98 deletions(-) diff --git a/packages/react-api/src/hooks/useCartoLayerProps.js b/packages/react-api/src/hooks/useCartoLayerProps.js index f78f73739..7d753f03f 100644 --- a/packages/react-api/src/hooks/useCartoLayerProps.js +++ b/packages/react-api/src/hooks/useCartoLayerProps.js @@ -7,6 +7,7 @@ import { getDataFilterExtensionProps } from './dataFilterExtensionUtil'; import { getMaskExtensionProps } from './maskExtensionUtil'; import FeaturesDroppedLoader from './FeaturesDroppedLoader'; import { CLIENT_ID } from '../api/common'; +import { getGeometryToIntersect } from '@carto/react-core'; const LOADERS = [FeaturesDroppedLoader]; @@ -19,19 +20,18 @@ export default function useCartoLayerProps({ }) { const viewport = useSelector((state) => state.carto.viewport); const spatialFilter = useSelector((state) => selectSpatialFilter(state, source?.id)); + const geometryToIntersect = getGeometryToIntersect(viewport, spatialFilter); const [onDataLoadForGeojson] = useGeojsonFeatures({ source, - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty, debounceTimeout: viewporFeaturesDebounceTimeout }); const [onDataLoadForTile, onViewportLoad, fetch] = useTileFeatures({ source, - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty, debounceTimeout: viewporFeaturesDebounceTimeout }); diff --git a/packages/react-api/src/hooks/useGeojsonFeatures.js b/packages/react-api/src/hooks/useGeojsonFeatures.js index cd2a1d15b..263336275 100644 --- a/packages/react-api/src/hooks/useGeojsonFeatures.js +++ b/packages/react-api/src/hooks/useGeojsonFeatures.js @@ -6,8 +6,7 @@ import useFeaturesCommons from './useFeaturesCommons'; export default function useGeojsonFeatures({ source, - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty, debounceTimeout = 250 }) { @@ -23,10 +22,9 @@ export default function useGeojsonFeatures({ const sourceId = source?.id; const computeFeatures = useCallback( - ({ viewport, spatialFilter, uniqueIdProperty }) => { + ({ geometryToIntersect, uniqueIdProperty }) => { executeTask(sourceId, Methods.GEOJSON_FEATURES, { - viewport, - geometry: spatialFilter, + geometryToIntersect, uniqueIdProperty }) .then(() => { @@ -48,14 +46,12 @@ export default function useGeojsonFeatures({ clearDebounce(); setSourceFeaturesReady(false); debounceIdRef.current = debouncedComputeFeatures({ - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty }); } }, [ - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty, sourceId, isGeoJsonLoaded, diff --git a/packages/react-api/src/hooks/useTileFeatures.js b/packages/react-api/src/hooks/useTileFeatures.js index 501594ff6..6e85e6f2f 100644 --- a/packages/react-api/src/hooks/useTileFeatures.js +++ b/packages/react-api/src/hooks/useTileFeatures.js @@ -10,8 +10,7 @@ import { useDispatch } from 'react-redux'; export default function useTileFeatures({ source, - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty, debounceTimeout = 250 }) { @@ -32,7 +31,7 @@ export default function useTileFeatures({ const sourceId = source?.id; const computeFeatures = useCallback( - ({ viewport, spatialFilter, uniqueIdProperty }) => { + ({ geometryToIntersect, uniqueIdProperty }) => { if (!tileFormat) { return null; } @@ -40,8 +39,7 @@ export default function useTileFeatures({ setSourceFeaturesReady(false); executeTask(sourceId, Methods.TILE_FEATURES, { - viewport, - geometry: spatialFilter, + geometryToIntersect, uniqueIdProperty, tileFormat, geoColumName, @@ -101,14 +99,12 @@ export default function useTileFeatures({ clearDebounce(); setSourceFeaturesReady(false); debounceIdRef.current = debouncedComputeFeatures({ - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty }); } }, [ - viewport, - spatialFilter, + geometryToIntersect, uniqueIdProperty, debouncedComputeFeatures, sourceId, diff --git a/packages/react-core/__tests__/filters/geojsonFeatures.test.js b/packages/react-core/__tests__/filters/geojsonFeatures.test.js index 5742ebe83..05806ca1b 100644 --- a/packages/react-core/__tests__/filters/geojsonFeatures.test.js +++ b/packages/react-core/__tests__/filters/geojsonFeatures.test.js @@ -1,7 +1,10 @@ +import bboxPolygon from '@turf/bbox-polygon'; import { geojsonFeatures } from '../../src/filters/geojsonFeatures'; describe('viewport features with geojson data', () => { + /** @type { import('../../src').Viewport } */ const viewport = [-10, -10, 10, 10]; // west - south - east - north + const viewportFeature = bboxPolygon(viewport); describe('return no data', () => { test('should return an empty array if no geojson features present', () => { @@ -12,7 +15,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson, - viewport + geometryToIntersect: viewportFeature }); expect(properties).toEqual([]); @@ -39,7 +42,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: linestrings, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -70,7 +73,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multilinestrings, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -101,7 +104,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: polygons, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -135,7 +138,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multipolygons, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -167,7 +170,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: points, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -193,7 +196,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: linestrings, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -219,7 +222,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multilinestrings, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -245,7 +248,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: polygons, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); @@ -274,7 +277,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multipolygons, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id' }); diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index 93f7693f4..c82f06230 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -3,27 +3,11 @@ import { geojsonToBinary } from '@loaders.gl/gis'; import { tileFeatures } from '../../src'; import * as transformToTileCoords from '../../src/utils/transformToTileCoords'; import { getGeometryToIntersect } from '../../src/filters/tileFeatures'; +import bboxPolygon from '@turf/bbox-polygon'; /** @type { import('../../src').Viewport } */ const viewport = [-10, -10, 10, 10]; // west - south - east - north - -const viewportFeature = { - bbox: viewport, - type: 'Feature', - properties: {}, - geometry: { - type: 'Polygon', - coordinates: [ - [ - [-10, -10], - [10, -10], - [10, 10], - [-10, 10], - [-10, -10] - ] - ] - } -}; +const viewportFeature = bboxPolygon(viewport); /** @type { import('geojson').Feature } */ const geometryFeature = { @@ -71,7 +55,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport, + geometryToIntersect: viewportFeature, tileFormat }); expect(properties).toEqual([]); @@ -82,7 +66,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport, + geometryToIntersect: viewportFeature, tileFormat }); expect(properties).toEqual([]); @@ -93,7 +77,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport, + geometryToIntersect: viewportFeature, tileFormat }); expect(properties).toEqual([]); @@ -104,7 +88,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport, + geometryToIntersect: viewportFeature, tileFormat }); expect(properties).toEqual([]); @@ -136,7 +120,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -173,7 +157,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -209,7 +193,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -248,7 +232,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -285,7 +269,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -316,7 +300,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -347,7 +331,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -378,7 +362,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -412,7 +396,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -459,7 +443,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: undefined, tileFormat }); @@ -497,7 +481,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: undefined, tileFormat }); @@ -534,7 +518,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: undefined, tileFormat }); @@ -570,7 +554,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: undefined, tileFormat }); @@ -608,7 +592,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, uniqueIdProperty: 'user_id', tileFormat }); @@ -643,21 +627,21 @@ describe('viewport features with binary mode', () => { tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, tileFormat: TILE_FORMATS.GEOJSON }); expect(transformToTileCoordsSpy).toHaveBeenCalledTimes(0); tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, tileFormat: TILE_FORMATS.BINARY }); expect(transformToTileCoordsSpy).toHaveBeenCalledTimes(0); tileFeatures({ tiles: mockedTile, - viewport, + geometryToIntersect: viewportFeature, tileFormat: TILE_FORMATS.MVT }); expect(transformToTileCoordsSpy).toHaveBeenCalledTimes(1); diff --git a/packages/react-core/src/filters/geojsonFeatures.d.ts b/packages/react-core/src/filters/geojsonFeatures.d.ts index dc300618e..018641cbb 100644 --- a/packages/react-core/src/filters/geojsonFeatures.d.ts +++ b/packages/react-core/src/filters/geojsonFeatures.d.ts @@ -1,10 +1,9 @@ -import { FeatureCollection, Geometry } from 'geojson'; -import { Viewport, TileFeaturesResponse } from '../types'; +import { FeatureCollection, Feature, Polygon, MultiPolygon } from 'geojson'; +import { TileFeaturesResponse } from '../types'; type GeojsonFeaturesArgs = { geojson: FeatureCollection, - viewport: Viewport, - geometry?: Geometry + geometryToIntersect: Feature | null, uniqueIdProperty?: string } diff --git a/packages/react-core/src/filters/geojsonFeatures.js b/packages/react-core/src/filters/geojsonFeatures.js index 5c7693ddc..355a7e0f9 100644 --- a/packages/react-core/src/filters/geojsonFeatures.js +++ b/packages/react-core/src/filters/geojsonFeatures.js @@ -1,11 +1,9 @@ import intersects from '@turf/boolean-intersects'; -import { getGeometryToIntersect } from './tileFeatures'; -export function geojsonFeatures({ geojson, viewport, geometry, uniqueIdProperty }) { +export function geojsonFeatures({ geojson, geometryToIntersect, uniqueIdProperty }) { let uniqueIdx = 0; // Map is used to cache multi geometries. Only a sucessfull intersect by multipolygon const map = new Map(); - const geometryToIntersect = getGeometryToIntersect(viewport, geometry); if (!geometryToIntersect) { return []; diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index 0321d331d..295b732d3 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -25,15 +25,12 @@ export function getGeometryToIntersect(viewport, geometry) { export function tileFeatures({ tiles, - viewport, - geometry, + geometryToIntersect, uniqueIdProperty, tileFormat, geoColumName, spatialIndex }) { - const geometryToIntersect = getGeometryToIntersect(viewport, geometry); - if (!geometryToIntersect) { return []; } diff --git a/packages/react-core/src/index.d.ts b/packages/react-core/src/index.d.ts index d0e0c8cb9..b89218369 100644 --- a/packages/react-core/src/index.d.ts +++ b/packages/react-core/src/index.d.ts @@ -25,7 +25,7 @@ export { scatterPlot } from './operations/scatterPlot'; export { FilterTypes as _FilterTypes } from './filters/FilterTypes'; -export { tileFeatures } from './filters/tileFeatures'; +export { tileFeatures, getGeometryToIntersect } from './filters/tileFeatures'; export { geojsonFeatures } from './filters/geojsonFeatures'; export { AggregationFunctions, GroupByFeature, HistogramFeature, Viewport, TileFeatures } from './types'; diff --git a/packages/react-core/src/index.js b/packages/react-core/src/index.js index 634e7becb..d55052d3a 100644 --- a/packages/react-core/src/index.js +++ b/packages/react-core/src/index.js @@ -34,7 +34,7 @@ export { applyFilters as _applyFilters } from './filters/Filter'; -export { tileFeatures } from './filters/tileFeatures'; +export { tileFeatures, getGeometryToIntersect } from './filters/tileFeatures'; export { geojsonFeatures } from './filters/geojsonFeatures'; export { GroupDateTypes } from './operations/constants/GroupDateTypes'; diff --git a/packages/react-core/src/types.d.ts b/packages/react-core/src/types.d.ts index 29220e9d2..37d61bc6e 100644 --- a/packages/react-core/src/types.d.ts +++ b/packages/react-core/src/types.d.ts @@ -1,6 +1,6 @@ import { TILE_FORMATS } from '@deck.gl/carto'; import { AggregationTypes } from './operations/constants/AggregationTypes'; -import { Geometry } from 'geojson'; +import { Feature, Polygon, MultiPolygon } from 'geojson'; import { SpatialIndex } from './operations/constants/SpatialIndexTypes'; export type AggregationFunctions = Record< @@ -27,8 +27,7 @@ export type Viewport = [number, number, number, number]; export type TileFeatures = { tiles?: any; // TODO: add proper deck.gl type - viewport: Viewport; - geometry?: Geometry; + geometryToIntersect: Feature | null; uniqueIdProperty?: string; tileFormat: TILE_FORMATS; geoColumName?: string; diff --git a/packages/react-redux/src/slices/cartoSlice.d.ts b/packages/react-redux/src/slices/cartoSlice.d.ts index 7b5103745..68c95f0e0 100644 --- a/packages/react-redux/src/slices/cartoSlice.d.ts +++ b/packages/react-redux/src/slices/cartoSlice.d.ts @@ -4,6 +4,7 @@ import { FiltersLogicalOperators, _FilterTypes } from '@carto/react-core'; import { CartoBasemapsNames, GMapsBasemapsNames } from '@carto/react-basemaps/'; import { InitialCartoState, CartoState, ViewState } from '../types'; import { AnyAction, Reducer } from 'redux'; +import { Feature, Polygon, MultiPolygon } from 'geojson'; type Source = SourceProps & { id: string @@ -158,6 +159,6 @@ export function setFeatureSelectionEnabled(enabled: boolean): { payload: boolean; }; -export function selectSpatialFilter(state: any, sourceId?: string): object | null; +export function selectSpatialFilter(state: any, sourceId?: string): Feature | null; export function selectFeatureSelectionMode(state: any): string | null; diff --git a/packages/react-workers/__tests__/methods.test.js b/packages/react-workers/__tests__/methods.test.js index 6350a2247..93b6eecc3 100644 --- a/packages/react-workers/__tests__/methods.test.js +++ b/packages/react-workers/__tests__/methods.test.js @@ -1,3 +1,4 @@ +import bboxPolygon from '@turf/bbox-polygon'; import { getFormula, getHistogram, @@ -11,10 +12,10 @@ describe('Worker Methods', () => { beforeEach(() => { loadGeoJSONFeatures({ geojson: sampleGeoJson }); getGeojsonFeatures({ - viewport: [ + geometryToIntersect: bboxPolygon([ -119.8541879250893, 19.66738891368218, -61.31673251486329, 54.38309840045979 - ], - geometry: null + ]), + uniqueIdProperty: undefined }); }); describe('getFormula', () => { diff --git a/packages/react-workers/src/workers/methods.js b/packages/react-workers/src/workers/methods.js index 7a3bdd64d..03d44f0a2 100644 --- a/packages/react-workers/src/workers/methods.js +++ b/packages/react-workers/src/workers/methods.js @@ -17,8 +17,7 @@ let currentGeoJSON; let currentTiles; export function getTileFeatures({ - viewport, - geometry, + geometryToIntersect, uniqueIdProperty, tileFormat, geoColumName, @@ -26,8 +25,7 @@ export function getTileFeatures({ }) { currentFeatures = tileFeatures({ tiles: currentTiles, - viewport, - geometry, + geometryToIntersect, uniqueIdProperty, tileFormat, geoColumName, @@ -46,12 +44,11 @@ export function loadGeoJSONFeatures({ geojson }) { return true; } -export function getGeojsonFeatures({ viewport, geometry, uniqueIdProperty }) { +export function getGeojsonFeatures({ geometryToIntersect, uniqueIdProperty }) { if (currentGeoJSON) { currentFeatures = geojsonFeatures({ geojson: currentGeoJSON, - viewport, - geometry, + geometryToIntersect, uniqueIdProperty }); } From bb7cc408ae0b62bd8ea7611fc12417ab92728b49 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:00:51 +0200 Subject: [PATCH 04/41] Refactor: getGeometryToIntersect returns a Geometry --- .../react-api/src/hooks/useGeojsonFeatures.js | 3 +- .../__tests__/filters/geojsonFeatures.test.js | 32 ++++--- .../__tests__/filters/tileFeatures.test.js | 86 +++++++++---------- .../src/filters/geojsonFeatures.d.ts | 4 +- .../react-core/src/filters/tileFeatures.d.ts | 2 +- .../react-core/src/filters/tileFeatures.js | 14 +-- .../src/filters/tileFeaturesGeometries.d.ts | 4 +- .../src/filters/tileFeaturesSpatialIndex.d.ts | 4 +- .../src/filters/tileFeaturesSpatialIndex.js | 6 +- packages/react-core/src/types.d.ts | 4 +- .../react-workers/__tests__/methods.test.js | 2 +- 11 files changed, 84 insertions(+), 77 deletions(-) diff --git a/packages/react-api/src/hooks/useGeojsonFeatures.js b/packages/react-api/src/hooks/useGeojsonFeatures.js index 263336275..e1f2e6abf 100644 --- a/packages/react-api/src/hooks/useGeojsonFeatures.js +++ b/packages/react-api/src/hooks/useGeojsonFeatures.js @@ -25,7 +25,8 @@ export default function useGeojsonFeatures({ ({ geometryToIntersect, uniqueIdProperty }) => { executeTask(sourceId, Methods.GEOJSON_FEATURES, { geometryToIntersect, - uniqueIdProperty + uniqueIdProperty, + tileFormat: undefined }) .then(() => { setSourceFeaturesReady(true); diff --git a/packages/react-core/__tests__/filters/geojsonFeatures.test.js b/packages/react-core/__tests__/filters/geojsonFeatures.test.js index 05806ca1b..361062a10 100644 --- a/packages/react-core/__tests__/filters/geojsonFeatures.test.js +++ b/packages/react-core/__tests__/filters/geojsonFeatures.test.js @@ -4,10 +4,11 @@ import { geojsonFeatures } from '../../src/filters/geojsonFeatures'; describe('viewport features with geojson data', () => { /** @type { import('../../src').Viewport } */ const viewport = [-10, -10, 10, 10]; // west - south - east - north - const viewportFeature = bboxPolygon(viewport); + const viewportGeometry = bboxPolygon(viewport).geometry; describe('return no data', () => { test('should return an empty array if no geojson features present', () => { + /** @type { import('geojson').FeatureCollection } */ const geojson = { type: 'FeatureCollection', features: [] @@ -15,7 +16,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson, - geometryToIntersect: viewportFeature + geometryToIntersect: viewportGeometry }); expect(properties).toEqual([]); @@ -24,6 +25,7 @@ describe('viewport features with geojson data', () => { describe('correctly returns data', () => { test('should handle linestrings correctly fwsf', () => { + /** @type { import('geojson').FeatureCollection } */ const linestrings = { type: 'FeatureCollection', features: [...Array(3)].map((_, i) => ({ @@ -42,7 +44,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: linestrings, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -55,6 +57,7 @@ describe('viewport features with geojson data', () => { }); test('should handle multilinestrings correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const multilinestrings = { type: 'FeatureCollection', features: [...Array(3)].map((_, i) => ({ @@ -73,7 +76,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multilinestrings, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -86,6 +89,7 @@ describe('viewport features with geojson data', () => { }); test('should handle polygons correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const polygons = { type: 'FeatureCollection', features: [...Array(3)].map((_, i) => ({ @@ -104,7 +108,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: polygons, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -117,6 +121,7 @@ describe('viewport features with geojson data', () => { }); test('should handle multilipolygons correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const multipolygons = { type: 'FeatureCollection', features: [...Array(3)].map((_, i) => ({ @@ -138,7 +143,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multipolygons, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -153,6 +158,7 @@ describe('viewport features with geojson data', () => { describe('with repeated features', () => { test('should handle points correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const points = { type: 'FeatureCollection', features: [...Array(4)].map(() => ({ @@ -170,7 +176,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: points, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -178,6 +184,7 @@ describe('viewport features with geojson data', () => { }); test('should handle linestrings correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const linestrings = { type: 'FeatureCollection', features: [...Array(4)].map(() => ({ @@ -196,7 +203,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: linestrings, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -204,6 +211,7 @@ describe('viewport features with geojson data', () => { }); test('should handle multilinestrings correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const multilinestrings = { type: 'FeatureCollection', features: [...Array(4)].map(() => ({ @@ -222,7 +230,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multilinestrings, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -230,6 +238,7 @@ describe('viewport features with geojson data', () => { }); test('should handle polygons correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const polygons = { type: 'FeatureCollection', features: [...Array(4)].map(() => ({ @@ -248,7 +257,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: polygons, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); @@ -256,6 +265,7 @@ describe('viewport features with geojson data', () => { }); test('should handle multipolygons correctly', () => { + /** @type { import('geojson').FeatureCollection } */ const multipolygons = { type: 'FeatureCollection', features: [...Array(4)].map(() => ({ @@ -277,7 +287,7 @@ describe('viewport features with geojson data', () => { const properties = geojsonFeatures({ geojson: multipolygons, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id' }); diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index c82f06230..d2cf4f954 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -7,23 +7,25 @@ import bboxPolygon from '@turf/bbox-polygon'; /** @type { import('../../src').Viewport } */ const viewport = [-10, -10, 10, 10]; // west - south - east - north -const viewportFeature = bboxPolygon(viewport); - +const viewportGeometry = bboxPolygon(viewport).geometry; + +/** @type { import('geojson').Polygon } */ +const filterGeometry = { + type: 'Polygon', + coordinates: [ + [ + [-1, -1], + [1, -1], + [1, 1], + [-1, 1], + [-1, -1] + ] + ] +}; /** @type { import('geojson').Feature } */ -const geometryFeature = { +const filterFeature = { type: 'Feature', - geometry: { - type: 'Polygon', - coordinates: [ - [ - [-1, -1], - [1, -1], - [1, 1], - [-1, 1], - [-1, -1] - ] - ] - }, + geometry: filterGeometry, properties: {} }; @@ -33,15 +35,13 @@ describe('getGeometryToIntersect', () => { expect(getGeometryToIntersect([], null)).toStrictEqual(null); }); - test('returns the viewport as feature', () => { - expect(getGeometryToIntersect(viewport, null)).toStrictEqual(viewportFeature); + test('returns the viewport as geometry', () => { + expect(getGeometryToIntersect(viewport, null)).toStrictEqual(viewportGeometry); }); - test('returns the geometry as feature', () => { - expect(getGeometryToIntersect(null, geometryFeature)).toStrictEqual(geometryFeature); - expect(getGeometryToIntersect(viewport, geometryFeature)).toStrictEqual( - geometryFeature - ); + test('returns the filter as geometry', () => { + expect(getGeometryToIntersect(null, filterFeature)).toStrictEqual(filterGeometry); + expect(getGeometryToIntersect(viewport, filterFeature)).toStrictEqual(filterGeometry); }); }); @@ -55,7 +55,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat }); expect(properties).toEqual([]); @@ -66,7 +66,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat }); expect(properties).toEqual([]); @@ -77,7 +77,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat }); expect(properties).toEqual([]); @@ -88,7 +88,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat }); expect(properties).toEqual([]); @@ -120,7 +120,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -157,7 +157,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -193,7 +193,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -232,7 +232,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -269,7 +269,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -300,7 +300,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -331,7 +331,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -362,7 +362,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -396,7 +396,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'cartodb_id', tileFormat }); @@ -443,7 +443,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTiles, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: undefined, tileFormat }); @@ -481,7 +481,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: undefined, tileFormat }); @@ -518,7 +518,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: undefined, tileFormat }); @@ -554,7 +554,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: undefined, tileFormat }); @@ -592,7 +592,7 @@ describe('viewport features with binary mode', () => { const properties = tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, uniqueIdProperty: 'user_id', tileFormat }); @@ -627,21 +627,21 @@ describe('viewport features with binary mode', () => { tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat: TILE_FORMATS.GEOJSON }); expect(transformToTileCoordsSpy).toHaveBeenCalledTimes(0); tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat: TILE_FORMATS.BINARY }); expect(transformToTileCoordsSpy).toHaveBeenCalledTimes(0); tileFeatures({ tiles: mockedTile, - geometryToIntersect: viewportFeature, + geometryToIntersect: viewportGeometry, tileFormat: TILE_FORMATS.MVT }); expect(transformToTileCoordsSpy).toHaveBeenCalledTimes(1); diff --git a/packages/react-core/src/filters/geojsonFeatures.d.ts b/packages/react-core/src/filters/geojsonFeatures.d.ts index 018641cbb..3a55a2715 100644 --- a/packages/react-core/src/filters/geojsonFeatures.d.ts +++ b/packages/react-core/src/filters/geojsonFeatures.d.ts @@ -1,9 +1,9 @@ -import { FeatureCollection, Feature, Polygon, MultiPolygon } from 'geojson'; +import { FeatureCollection, Polygon, MultiPolygon } from 'geojson'; import { TileFeaturesResponse } from '../types'; type GeojsonFeaturesArgs = { geojson: FeatureCollection, - geometryToIntersect: Feature | null, + geometryToIntersect: Polygon | MultiPolygon | null, uniqueIdProperty?: string } diff --git a/packages/react-core/src/filters/tileFeatures.d.ts b/packages/react-core/src/filters/tileFeatures.d.ts index e668405e9..7a441deb6 100644 --- a/packages/react-core/src/filters/tileFeatures.d.ts +++ b/packages/react-core/src/filters/tileFeatures.d.ts @@ -1,5 +1,5 @@ import { TileFeatures, TileFeaturesResponse } from '../types'; import { Feature, Polygon, MultiPolygon } from 'geojson'; -export function getGeometryToIntersect(viewport: number[] | null, geometry: Feature | null): Feature | null; +export function getGeometryToIntersect(viewport: number[] | null, spatialFilter: Feature | null): Polygon | MultiPolygon | null; export function tileFeatures(arg: TileFeatures): TileFeaturesResponse; \ No newline at end of file diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index 295b732d3..0160b97db 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -4,7 +4,7 @@ import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; /** * Select the geometry to use for widget calculation and data filtering. - * If a geometry (mask) is set, use the mask otherwise use the current viewport. + * If a spatial filter (mask) is set, use the mask otherwise use the current viewport. * Since it's possible that no mask and no viewport is set, return null in this case. * * @typedef { import('geojson').Polygon | import('geojson').MultiPolygon } Geometry @@ -12,14 +12,14 @@ import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; * @typedef { import('geojson').BBox } BBox * * @param { BBox? } viewport viewport [minX, minY, maxX, maxY], if any - * @param { Feature? } geometry the active mask, if any - * @returns { Feature? } the geometry to use for filtering + * @param { Feature? } spatialFilter the active spatial filter (mask), if any + * @returns { Geometry? } the geometry to use for filtering */ -export function getGeometryToIntersect(viewport, geometry) { - return geometry - ? geometry +export function getGeometryToIntersect(viewport, spatialFilter) { + return spatialFilter + ? spatialFilter.geometry : Array.isArray(viewport) && viewport.length === 4 - ? bboxPolygon(viewport) + ? bboxPolygon(viewport).geometry : null; } diff --git a/packages/react-core/src/filters/tileFeaturesGeometries.d.ts b/packages/react-core/src/filters/tileFeaturesGeometries.d.ts index 9a8172dcb..d6f6daf47 100644 --- a/packages/react-core/src/filters/tileFeaturesGeometries.d.ts +++ b/packages/react-core/src/filters/tileFeaturesGeometries.d.ts @@ -1,11 +1,11 @@ import { TILE_FORMATS } from '@deck.gl/carto'; -import { Feature, Polygon, MultiPolygon } from 'geojson'; +import { Polygon, MultiPolygon } from 'geojson'; import { TileFeaturesResponse } from "../types"; export default function tileFeaturesGeometries(arg: { tiles: any; tileFormat: TILE_FORMATS; - geometryToIntersect: Feature; + geometryToIntersect: Polygon | MultiPolygon; uniqueIdProperty?: string; }): TileFeaturesResponse; diff --git a/packages/react-core/src/filters/tileFeaturesSpatialIndex.d.ts b/packages/react-core/src/filters/tileFeaturesSpatialIndex.d.ts index 140d9dbcd..bd46ea865 100644 --- a/packages/react-core/src/filters/tileFeaturesSpatialIndex.d.ts +++ b/packages/react-core/src/filters/tileFeaturesSpatialIndex.d.ts @@ -1,10 +1,10 @@ -import { Feature, Polygon, MultiPolygon } from 'geojson'; +import { Polygon, MultiPolygon } from 'geojson'; import { SpatialIndex } from "../operations/constants/SpatialIndexTypes"; import { TileFeaturesResponse } from "../types"; export default function tileFeaturesSpatialIndex(arg: { tiles: any; - geometryToIntersect: Feature; + geometryToIntersect: Polygon | MultiPolygon; geoColumName: string; spatialIndex: SpatialIndex; }): TileFeaturesResponse; diff --git a/packages/react-core/src/filters/tileFeaturesSpatialIndex.js b/packages/react-core/src/filters/tileFeaturesSpatialIndex.js index b9f2b2756..9913951f2 100644 --- a/packages/react-core/src/filters/tileFeaturesSpatialIndex.js +++ b/packages/react-core/src/filters/tileFeaturesSpatialIndex.js @@ -20,11 +20,7 @@ export default function tileFeaturesSpatialIndex({ if (!resolution) { return []; } - const cells = getCellsCoverGeometry( - geometryToIntersect.geometry, - spatialIndex, - resolution - ); + const cells = getCellsCoverGeometry(geometryToIntersect, spatialIndex, resolution); if (!cells?.length) { return []; diff --git a/packages/react-core/src/types.d.ts b/packages/react-core/src/types.d.ts index 37d61bc6e..c34edc746 100644 --- a/packages/react-core/src/types.d.ts +++ b/packages/react-core/src/types.d.ts @@ -1,6 +1,6 @@ import { TILE_FORMATS } from '@deck.gl/carto'; import { AggregationTypes } from './operations/constants/AggregationTypes'; -import { Feature, Polygon, MultiPolygon } from 'geojson'; +import { Polygon, MultiPolygon } from 'geojson'; import { SpatialIndex } from './operations/constants/SpatialIndexTypes'; export type AggregationFunctions = Record< @@ -27,7 +27,7 @@ export type Viewport = [number, number, number, number]; export type TileFeatures = { tiles?: any; // TODO: add proper deck.gl type - geometryToIntersect: Feature | null; + geometryToIntersect: Polygon | MultiPolygon | null; uniqueIdProperty?: string; tileFormat: TILE_FORMATS; geoColumName?: string; diff --git a/packages/react-workers/__tests__/methods.test.js b/packages/react-workers/__tests__/methods.test.js index 93b6eecc3..3f9c478e5 100644 --- a/packages/react-workers/__tests__/methods.test.js +++ b/packages/react-workers/__tests__/methods.test.js @@ -14,7 +14,7 @@ describe('Worker Methods', () => { getGeojsonFeatures({ geometryToIntersect: bboxPolygon([ -119.8541879250893, 19.66738891368218, -61.31673251486329, 54.38309840045979 - ]), + ]).geometry, uniqueIdProperty: undefined }); }); From a327add10aa20b8a231487c56277f182fb74f7d4 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 05/41] Support for spatialFilter param in API call --- packages/react-api/src/api/model.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/react-api/src/api/model.js b/packages/react-api/src/api/model.js index 3d604420f..f21ac69b8 100644 --- a/packages/react-api/src/api/model.js +++ b/packages/react-api/src/api/model.js @@ -9,10 +9,12 @@ const AVAILABLE_MODELS = ['category', 'histogram', 'formula', 'timeseries', 'ran /** * Execute a SQL model request. * + * @typedef { import('geojson').Polygon | import('geojson').MultiPolygon } SpatialFilter * @param { object } props * @param { string } props.model - widget's model that we want to get the data for * @param { object } props.source - source that owns the column * @param { object } props.params - widget's props + * @param { SpatialFilter= } props.spatialFilter - restrict widget calculation to an area * @param { object= } props.opts - Additional options for the HTTP request */ export function executeModel(props) { @@ -27,7 +29,7 @@ export function executeModel(props) { )}` ); - const { source, model, params, opts } = props; + const { source, model, params, spatialFilter, opts } = props; checkCredentials(source.credentials); @@ -39,6 +41,8 @@ export function executeModel(props) { let url = `${source.credentials.apiBaseUrl}/v3/sql/${source.connection}/model/${model}`; + console.log(url); + const { filters, filtersLogicalOperator, data, type } = source; const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) @@ -52,13 +56,23 @@ export function executeModel(props) { filtersLogicalOperator }; + if (spatialFilter) { + queryParams.spatialFilter = JSON.stringify(spatialFilter); + } + + console.log(JSON.stringify(queryParams)); + const isGet = url.length + JSON.stringify(queryParams).length <= URL_LENGTH; if (isGet) { url += '?' + new URLSearchParams(queryParams).toString(); } else { + // undo the JSON.stringify, @todo find a better pattern queryParams.params = params; queryParams.filters = filters; queryParams.queryParameters = source.queryParameters; + if (spatialFilter) { + queryParams.spatialFilter = spatialFilter; + } } return makeCall({ url, From 04bae81da871f484cac9d49c11121b686cf01e46 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 06/41] Support for remote widgets --- .../react-api/src/hooks/useCartoLayerProps.js | 4 +- .../__tests__/filters/tileFeatures.test.js | 2 + .../react-core/src/filters/tileFeatures.js | 2 +- .../react-redux/src/slices/cartoSlice.d.ts | 4 +- packages/react-redux/src/slices/cartoSlice.js | 7 +++ .../react-widgets/src/hooks/useWidgetFetch.js | 48 ++++++++++++++++--- packages/react-widgets/src/models/utils.js | 20 ++++++-- 7 files changed, 73 insertions(+), 14 deletions(-) diff --git a/packages/react-api/src/hooks/useCartoLayerProps.js b/packages/react-api/src/hooks/useCartoLayerProps.js index 7d753f03f..be9d6a197 100644 --- a/packages/react-api/src/hooks/useCartoLayerProps.js +++ b/packages/react-api/src/hooks/useCartoLayerProps.js @@ -1,6 +1,6 @@ import { useCallback } from 'react'; import { useSelector } from 'react-redux'; -import { selectSpatialFilter } from '@carto/react-redux'; +import { selectSpatialFilter, selectViewport } from '@carto/react-redux'; import useGeojsonFeatures from './useGeojsonFeatures'; import useTileFeatures from './useTileFeatures'; import { getDataFilterExtensionProps } from './dataFilterExtensionUtil'; @@ -18,7 +18,7 @@ export default function useCartoLayerProps({ viewportFeatures = true, viewporFeaturesDebounceTimeout = 250 }) { - const viewport = useSelector((state) => state.carto.viewport); + const viewport = useSelector(selectViewport); const spatialFilter = useSelector((state) => selectSpatialFilter(state, source?.id)); const geometryToIntersect = getGeometryToIntersect(viewport, spatialFilter); diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index d2cf4f954..1a0798373 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -33,6 +33,8 @@ describe('getGeometryToIntersect', () => { test('returns null in case no viewport or geometry is present', () => { expect(getGeometryToIntersect(null, null)).toStrictEqual(null); expect(getGeometryToIntersect([], null)).toStrictEqual(null); + expect(getGeometryToIntersect(null, {})).toStrictEqual(null); + expect(getGeometryToIntersect([], {})).toStrictEqual(null); }); test('returns the viewport as geometry', () => { diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index 0160b97db..40dbf0d79 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -16,7 +16,7 @@ import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; * @returns { Geometry? } the geometry to use for filtering */ export function getGeometryToIntersect(viewport, spatialFilter) { - return spatialFilter + return spatialFilter && spatialFilter.geometry ? spatialFilter.geometry : Array.isArray(viewport) && viewport.length === 4 ? bboxPolygon(viewport).geometry diff --git a/packages/react-redux/src/slices/cartoSlice.d.ts b/packages/react-redux/src/slices/cartoSlice.d.ts index 68c95f0e0..bf562ee4f 100644 --- a/packages/react-redux/src/slices/cartoSlice.d.ts +++ b/packages/react-redux/src/slices/cartoSlice.d.ts @@ -1,6 +1,6 @@ import { Credentials } from '@carto/react-api/'; import { SourceProps } from '@carto/react-api/types'; -import { FiltersLogicalOperators, _FilterTypes } from '@carto/react-core'; +import { FiltersLogicalOperators, Viewport, _FilterTypes } from '@carto/react-core'; import { CartoBasemapsNames, GMapsBasemapsNames } from '@carto/react-basemaps/'; import { InitialCartoState, CartoState, ViewState } from '../types'; import { AnyAction, Reducer } from 'redux'; @@ -159,6 +159,8 @@ export function setFeatureSelectionEnabled(enabled: boolean): { payload: boolean; }; +export function selectViewport(state: any): Viewport | null; + export function selectSpatialFilter(state: any, sourceId?: string): Feature | null; export function selectFeatureSelectionMode(state: any): string | null; diff --git a/packages/react-redux/src/slices/cartoSlice.js b/packages/react-redux/src/slices/cartoSlice.js index 86a5b2f36..91c487ef5 100644 --- a/packages/react-redux/src/slices/cartoSlice.js +++ b/packages/react-redux/src/slices/cartoSlice.js @@ -336,6 +336,13 @@ export const selectSourceById = (state, id) => state.carto.dataSources[id]; export const checkIfSourceIsDroppingFeature = (state, id) => state.carto.dataSources[id]?.isDroppingFeatures; +/** + * Redux selector to select the active viewport + */ +export const selectViewport = (state) => { + return state.carto.viewport ? state.carto.viewport : null; +}; + /** * Redux selector to select the spatial filter of a given sourceId or the root one */ diff --git a/packages/react-widgets/src/hooks/useWidgetFetch.js b/packages/react-widgets/src/hooks/useWidgetFetch.js index 7a2077950..baed33bab 100644 --- a/packages/react-widgets/src/hooks/useWidgetFetch.js +++ b/packages/react-widgets/src/hooks/useWidgetFetch.js @@ -1,25 +1,48 @@ -import { InvalidColumnError } from '@carto/react-core'; -import { selectAreFeaturesReadyForSource } from '@carto/react-redux'; +import { InvalidColumnError, getGeometryToIntersect } from '@carto/react-core'; +import { + selectAreFeaturesReadyForSource, + selectSpatialFilter, + selectViewport +} from '@carto/react-redux'; import { dequal } from 'dequal'; import { useState } from 'react'; import { useSelector } from 'react-redux'; import { DEFAULT_INVALID_COLUMN_ERR } from '../widgets/utils/constants'; import useCustomCompareEffect from './useCustomCompareEffect'; import useWidgetSource from './useWidgetSource'; +import { isRemoteCalculationSupported } from '../models/utils'; export default function useWidgetFetch( modelFn, - { id, dataSource, params, global, onError, enabled = true } + { + id, + dataSource, + params, + global, + onError, + enabled = true, + attemptRemoteCalculation = false + } ) { // State const [data, setData] = useState(); const [isLoading, setIsLoading] = useState(false); const [warning, setWarning] = useState(''); + const source = useWidgetSource({ dataSource, id }); + const remoteCalculation = + attemptRemoteCalculation && isRemoteCalculationSupported({ source }); + const isSourceReady = useSelector( - (state) => global || selectAreFeaturesReadyForSource(state, dataSource) + (state) => + global || remoteCalculation || selectAreFeaturesReadyForSource(state, dataSource) ); - const source = useWidgetSource({ dataSource, id }); + + const viewport = useSelector(selectViewport); + const spatialFilter = useSelector((state) => selectSpatialFilter(state, dataSource)); + const geometryToIntersect = !global + ? getGeometryToIntersect(viewport, spatialFilter) + : null; useCustomCompareEffect( () => { @@ -30,7 +53,9 @@ export default function useWidgetFetch( modelFn({ source, ...params, - global + global, + remoteCalculation, + spatialFilter: geometryToIntersect }) .then((data) => { if (data !== null && data !== undefined) { @@ -49,7 +74,16 @@ export default function useWidgetFetch( }); } }, - [params, source, onError, isSourceReady, global, enabled], + [ + params, + source, + onError, + isSourceReady, + global, + remoteCalculation, + geometryToIntersect, + enabled + ], dequal ); diff --git a/packages/react-widgets/src/models/utils.js b/packages/react-widgets/src/models/utils.js index 62ef405b4..d05c3f0ad 100644 --- a/packages/react-widgets/src/models/utils.js +++ b/packages/react-widgets/src/models/utils.js @@ -1,8 +1,18 @@ import { AggregationTypes, _filtersToSQL } from '@carto/react-core'; import { MAP_TYPES, API_VERSIONS } from '@deck.gl/carto'; +export function isRemoteCalculationSupported(props) { + const { source } = props; + + return ( + source && + source.type !== MAP_TYPES.TILESET && + source.credentials.apiVersion !== API_VERSIONS.V2 + ); +} + export function wrapModelCall(props, fromLocal, fromRemote) { - const { source, global } = props; + const { source, global, remoteCalculation } = props; if (global) { if (source.type === MAP_TYPES.TILESET) @@ -19,9 +29,13 @@ export function wrapModelCall(props, fromLocal, fromRemote) { } return fromRemote(props); + } else if (remoteCalculation && isRemoteCalculationSupported(props)) { + // The widget supports remote calculation, preferred whenever possible + return fromRemote(props); + } else { + // Local calculation, it requires data to be available + return fromLocal(props); } - - return fromLocal(props); } export function formatTableNameWithFilters(props) { From 1d3bfb3100ef9a93881bdf44de1b7ba02eb77d1c Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 07/41] Remote calculation enabled for Formula --- packages/react-widgets/src/models/FormulaModel.js | 3 ++- packages/react-widgets/src/widgets/FormulaWidget.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react-widgets/src/models/FormulaModel.js b/packages/react-widgets/src/models/FormulaModel.js index f8e2352fb..0baced5f1 100644 --- a/packages/react-widgets/src/models/FormulaModel.js +++ b/packages/react-widgets/src/models/FormulaModel.js @@ -21,12 +21,13 @@ function fromLocal(props) { // From remote function fromRemote(props) { - const { source, abortController, ...params } = props; + const { source, spatialFilter, abortController, ...params } = props; const { column, operation } = params; return _executeModel({ model: 'formula', source, + spatialFilter, params: { column: column || '*', operation }, opts: { abortController } }).then((res) => normalizeObjectKeys(res.rows[0])); diff --git a/packages/react-widgets/src/widgets/FormulaWidget.js b/packages/react-widgets/src/widgets/FormulaWidget.js index 14b84bcde..4e2831e4f 100644 --- a/packages/react-widgets/src/widgets/FormulaWidget.js +++ b/packages/react-widgets/src/widgets/FormulaWidget.js @@ -50,7 +50,8 @@ function FormulaWidget({ joinOperation }, global, - onError + onError, + attemptRemoteCalculation: true }); return ( From 863827ddf0c873d8db8266c747b7f499743d9127 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 08/41] Remote calculation enabled for Category --- packages/react-widgets/src/models/CategoryModel.js | 3 ++- packages/react-widgets/src/widgets/CategoryWidget.js | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/react-widgets/src/models/CategoryModel.js b/packages/react-widgets/src/models/CategoryModel.js index 2827795f6..ebde077e9 100644 --- a/packages/react-widgets/src/models/CategoryModel.js +++ b/packages/react-widgets/src/models/CategoryModel.js @@ -22,12 +22,13 @@ function fromLocal(props) { // From remote function fromRemote(props) { - const { source, abortController, ...params } = props; + const { source, spatialFilter, abortController, ...params } = props; const { column, operation, operationColumn } = params; return _executeModel({ model: 'category', source, + spatialFilter, params: { column, operation, diff --git a/packages/react-widgets/src/widgets/CategoryWidget.js b/packages/react-widgets/src/widgets/CategoryWidget.js index 4dab8613b..4d9d6a0b7 100644 --- a/packages/react-widgets/src/widgets/CategoryWidget.js +++ b/packages/react-widgets/src/widgets/CategoryWidget.js @@ -73,7 +73,8 @@ function CategoryWidget(props) { operation }, global, - onError + onError, + attemptRemoteCalculation: true }); const handleSelectedCategoriesChange = useCallback( From 3b8c7e44fb05fb21d128ddb4d4ed4e88347ce472 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 09/41] Remote calculation enabled for Histogram --- packages/react-widgets/src/models/HistogramModel.js | 4 ++-- packages/react-widgets/src/widgets/HistogramWidget.js | 3 ++- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/react-widgets/src/models/HistogramModel.js b/packages/react-widgets/src/models/HistogramModel.js index 327eeec07..96065a06c 100644 --- a/packages/react-widgets/src/models/HistogramModel.js +++ b/packages/react-widgets/src/models/HistogramModel.js @@ -21,13 +21,13 @@ function fromLocal(props) { // From remote async function fromRemote(props) { - const { source, abortController, ...params } = props; - + const { source, spatialFilter, abortController, ...params } = props; const { column, operation, ticks } = params; const data = await _executeModel({ model: 'histogram', source, + spatialFilter, params: { column, operation, ticks }, opts: { abortController } }).then((res) => normalizeObjectKeys(res.rows)); diff --git a/packages/react-widgets/src/widgets/HistogramWidget.js b/packages/react-widgets/src/widgets/HistogramWidget.js index 3ecd7aacf..05414dba9 100644 --- a/packages/react-widgets/src/widgets/HistogramWidget.js +++ b/packages/react-widgets/src/widgets/HistogramWidget.js @@ -112,7 +112,8 @@ function HistogramWidget({ }, global, onError, - enabled: !!ticks.length + enabled: !!ticks.length, + attemptRemoteCalculation: true }); const thresholdsFromFilters = useWidgetFilterValues({ From de93aba884074db5d9a81624ec3f697d076714e0 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 10/41] Remote calculation enabled for Bar --- packages/react-widgets/src/widgets/BarWidget.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-widgets/src/widgets/BarWidget.js b/packages/react-widgets/src/widgets/BarWidget.js index 4b61107c2..ed87556c8 100644 --- a/packages/react-widgets/src/widgets/BarWidget.js +++ b/packages/react-widgets/src/widgets/BarWidget.js @@ -76,7 +76,8 @@ function BarWidget({ operation }, global, - onError + onError, + attemptRemoteCalculation: true }); const sortedData = useMemo(() => { From 8700698393f94556924082bf474cf5d61dcc4609 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 11/41] Remote calculation enabled for Pie --- packages/react-widgets/src/widgets/PieWidget.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-widgets/src/widgets/PieWidget.js b/packages/react-widgets/src/widgets/PieWidget.js index 7a05e2499..0338d6b82 100644 --- a/packages/react-widgets/src/widgets/PieWidget.js +++ b/packages/react-widgets/src/widgets/PieWidget.js @@ -75,7 +75,8 @@ function PieWidget({ operation }, global, - onError + onError, + attemptRemoteCalculation: true }); const handleSelectedCategoriesChange = useCallback( From fb815fe92a8f0b4f3d5bf77de70e29a8e46da027 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 28 Apr 2023 11:43:50 +0200 Subject: [PATCH 12/41] Remote calculation enabled for Range --- packages/react-widgets/src/widgets/RangeWidget.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-widgets/src/widgets/RangeWidget.js b/packages/react-widgets/src/widgets/RangeWidget.js index 61cd11c17..5bed3c738 100644 --- a/packages/react-widgets/src/widgets/RangeWidget.js +++ b/packages/react-widgets/src/widgets/RangeWidget.js @@ -67,7 +67,8 @@ function RangeWidget({ column }, global, - onError + onError, + attemptRemoteCalculation: true }); const handleSelectedRangeChange = useCallback( From b6d02411aa7e67c4f2ab069242f56847c3bcf2b3 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Sat, 29 Apr 2023 13:16:39 +0200 Subject: [PATCH 13/41] Tests --- .../__tests__/hooks/useWidgetFetch.test.js | 107 +++++++++++++++++- .../react-widgets/__tests__/mockReduxHooks.js | 4 + .../__tests__/models/utils.test.js | 33 ++++-- packages/react-widgets/src/models/utils.js | 4 + 4 files changed, 133 insertions(+), 15 deletions(-) diff --git a/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js b/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js index 3412f3e06..9e4618231 100644 --- a/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js +++ b/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js @@ -3,7 +3,9 @@ import { DEFAULT_INVALID_COLUMN_ERR } from '../../src/widgets/utils/constants'; import { act, render, screen } from '@testing-library/react'; import React from 'react'; import useWidgetFetch from '../../src/hooks/useWidgetFetch'; -import { mockReduxHooks } from '../mockReduxHooks'; +import { mockClear, mockReduxHooks, mockSetup } from '../mockReduxHooks'; +import { selectViewport } from '@carto/react-redux'; +import bboxPolygon from '@turf/bbox-polygon'; const PARAMS_MOCK = { column: '__test__' @@ -11,15 +13,37 @@ const PARAMS_MOCK = { const SOURCE_MOCK = { id: 'test', - data: 'testTable' + data: 'testTable', + type: 'table', + credentials: { + apiVersion: 'v3' + } }; +const viewport = [-10, -5, 8, 9]; +const spatialFilter = bboxPolygon([-10, -5, 8, 9]).geometry; + jest.mock('../../src/hooks/useWidgetSource', () => () => SOURCE_MOCK); describe('useWidgetFetch', () => { - mockReduxHooks(); + beforeAll(() => { + const { useDispatch, useSelector } = mockSetup(); + const defaultSelector = jest.fn(); + + useDispatch.mockReturnValue(jest.fn()); + useSelector.mockImplementation((selector) => { + if (selector === selectViewport) { + return viewport; + } + return defaultSelector; + }); + }); - test('should work correctly', async () => { + afterAll(() => { + mockClear(); + }); + + it('should work correctly (no remote attempt)', async () => { const onError = jest.fn(); const modelFn = jest .fn() @@ -35,6 +59,7 @@ describe('useWidgetFetch', () => { dataSource: 'test', params: PARAMS_MOCK, global: false, + attemptRemoteCalculation: false, onError }} /> @@ -44,7 +69,9 @@ describe('useWidgetFetch', () => { expect(modelFn).toBeCalledWith({ source: SOURCE_MOCK, ...PARAMS_MOCK, - global: false + global: false, + remoteCalculation: false, + spatialFilter: spatialFilter }); expect(screen.getByText('loading')).toBeInTheDocument(); @@ -65,6 +92,7 @@ describe('useWidgetFetch', () => { dataSource: 'test', params: PARAMS_MOCK, global: true, + attemptRemoteCalculation: false, onError }} /> @@ -74,7 +102,9 @@ describe('useWidgetFetch', () => { expect(modelFn).toBeCalledWith({ source: SOURCE_MOCK, ...PARAMS_MOCK, - global: true + global: true, + remoteCalculation: false, + spatialFilter: null // never in global mode }); expect(screen.getByText('loading')).toBeInTheDocument(); @@ -93,6 +123,7 @@ describe('useWidgetFetch', () => { dataSource: 'test', params: PARAMS_MOCK, global: false, + remoteCalculation: false, onError }} /> @@ -104,6 +135,70 @@ describe('useWidgetFetch', () => { expect(onError).toBeCalledTimes(1); expect(screen.queryByText(DEFAULT_INVALID_COLUMN_ERR)).toBeInTheDocument(); }); + + it('should work correctly (non-global, remote attempt)', async () => { + const onError = jest.fn(); + const modelFn = jest + .fn() + .mockImplementation( + () => new Promise((resolve) => setTimeout(() => resolve('data'), 100)) + ); + + const { rerender } = render( + + ); + + // Test modelFn is called with the right params + expect(modelFn).toBeCalledWith({ + source: SOURCE_MOCK, + ...PARAMS_MOCK, + global: false, + remoteCalculation: true, + spatialFilter: spatialFilter + }); + }); + + it('should work correctly (global, remote attempt)', async () => { + const onError = jest.fn(); + const modelFn = jest + .fn() + .mockImplementation( + () => new Promise((resolve) => setTimeout(() => resolve('data'), 100)) + ); + + const { rerender } = render( + + ); + + // Test modelFn is called with the right params + expect(modelFn).toBeCalledWith({ + source: SOURCE_MOCK, + ...PARAMS_MOCK, + global: true, + remoteCalculation: true, + spatialFilter: null // no spatial filter for glboal case + }); + }); }); // Aux diff --git a/packages/react-widgets/__tests__/mockReduxHooks.js b/packages/react-widgets/__tests__/mockReduxHooks.js index 726f5c4e7..65e4397ef 100644 --- a/packages/react-widgets/__tests__/mockReduxHooks.js +++ b/packages/react-widgets/__tests__/mockReduxHooks.js @@ -11,6 +11,10 @@ export function mockReduxHooks(dispatchValue, selectorValue) { useSelectorSpy.mockReturnValue(mockSelectorFn); } +export function mockSetup() { + return { useDispatch: useDispatchSpy, useSelector: useSelectorSpy }; +} + export function mockClear() { useDispatchSpy.mockClear(); useSelectorSpy.mockClear(); diff --git a/packages/react-widgets/__tests__/models/utils.test.js b/packages/react-widgets/__tests__/models/utils.test.js index 8a3775f78..91d5fed9a 100644 --- a/packages/react-widgets/__tests__/models/utils.test.js +++ b/packages/react-widgets/__tests__/models/utils.test.js @@ -41,19 +41,34 @@ const fromRemote = jest.fn(); describe('utils', () => { describe('wrapModelCall', () => { - test('should work correctly', () => { - const props = { source: V2_SOURCE, global: false }; - wrapModelCall(props, fromLocal, fromRemote); - expect(fromLocal).toHaveBeenCalledWith(props); + const cases = [ + // source, global, remoteCalculation, expectedFn + [V2_SOURCE, false, false, fromLocal], + [V3_SOURCE, false, false, fromLocal], + [V3_SOURCE, true, false, fromRemote], + [V2_SOURCE, false, true, fromLocal], + [V3_SOURCE, false, true, fromRemote], + [V3_SOURCE, true, true, fromRemote] + ]; + + test.each(cases)( + 'should work correctly', + (source, global, remoteCalculation, expectedFn) => { + const props = { source, global, remoteCalculation }; + wrapModelCall(props, fromLocal, fromRemote); + expect(expectedFn).toHaveBeenCalledWith(props); + } + ); - const props2 = { source: V3_SOURCE, global: true }; - wrapModelCall(props2, fromLocal, fromRemote); - expect(fromRemote).toHaveBeenCalledWith(props2); + test('should throw error if global is true but fromRemote is missing', () => { + expect(() => + wrapModelCall({ source: V3_SOURCE, global: true }, fromLocal) + ).toThrowError(); }); - test('should throw error if global is true but fromRemote is missing', () => { + test('should throw error if remoteCalculation is true but fromRemote is missing', () => { expect(() => - wrapModelCall({ source: V2_SOURCE, global: true }, fromLocal) + wrapModelCall({ source: V3_SOURCE, remoteCalculation: true }, fromLocal) ).toThrowError(); }); diff --git a/packages/react-widgets/src/models/utils.js b/packages/react-widgets/src/models/utils.js index d05c3f0ad..732bf2e52 100644 --- a/packages/react-widgets/src/models/utils.js +++ b/packages/react-widgets/src/models/utils.js @@ -30,6 +30,10 @@ export function wrapModelCall(props, fromLocal, fromRemote) { return fromRemote(props); } else if (remoteCalculation && isRemoteCalculationSupported(props)) { + if (!fromRemote) { + throw new Error(`Remote calculation isn't supported for this widget`); + } + // The widget supports remote calculation, preferred whenever possible return fromRemote(props); } else { From ea023b9a03b9fe7d25ccb883c80f8e8e11f93794 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Wed, 3 May 2023 17:09:22 +0200 Subject: [PATCH 14/41] Remote calculation enabled for TimeSeries --- packages/react-widgets/src/widgets/TimeSeriesWidget.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/react-widgets/src/widgets/TimeSeriesWidget.js b/packages/react-widgets/src/widgets/TimeSeriesWidget.js index ebc6ed455..b96f18571 100644 --- a/packages/react-widgets/src/widgets/TimeSeriesWidget.js +++ b/packages/react-widgets/src/widgets/TimeSeriesWidget.js @@ -135,7 +135,8 @@ function TimeSeriesWidget({ operation }, global, - onError + onError, + attemptRemoteCalculation: true }); const handleTimeWindowUpdate = useCallback( From 32f47cce5638d0f4eb7ec24dc5061e849931ab71 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Wed, 3 May 2023 17:10:16 +0200 Subject: [PATCH 15/41] Remote calculation controlled by Feature Flag --- packages/react-core/src/index.d.ts | 5 ++++- packages/react-core/src/index.js | 1 + packages/react-core/src/utils/featureFlags.d.ts | 3 +++ packages/react-core/src/utils/featureFlags.js | 4 ++++ packages/react-widgets/src/widgets/BarWidget.js | 9 +++++++-- packages/react-widgets/src/widgets/CategoryWidget.js | 9 +++++++-- packages/react-widgets/src/widgets/FormulaWidget.js | 4 ++-- packages/react-widgets/src/widgets/HistogramWidget.js | 9 +++++++-- packages/react-widgets/src/widgets/PieWidget.js | 9 +++++++-- packages/react-widgets/src/widgets/RangeWidget.js | 8 ++++++-- packages/react-widgets/src/widgets/TimeSeriesWidget.js | 6 ++++-- 11 files changed, 52 insertions(+), 15 deletions(-) diff --git a/packages/react-core/src/index.d.ts b/packages/react-core/src/index.d.ts index f067bffd9..191a3f252 100644 --- a/packages/react-core/src/index.d.ts +++ b/packages/react-core/src/index.d.ts @@ -1,3 +1,5 @@ +import { _FeatureFlags } from '.'; + export { getRequest, postRequest, @@ -38,7 +40,8 @@ export { SpatialIndex } from './operations/constants/SpatialIndexTypes' export { FEATURE_SELECTION_MODES, EDIT_MODES, MASK_ID } from './utils/featureSelectionConstants'; export { + Flags as _FeatureFlags, hasFlag as _hasFeatureFlag, setFlags as _setFeatureFlags, clearFlags as _clearFeatureFlags -} from './utils/featureFlags'; \ No newline at end of file +} from './utils/featureFlags'; diff --git a/packages/react-core/src/index.js b/packages/react-core/src/index.js index 31456ac87..39744a0b6 100644 --- a/packages/react-core/src/index.js +++ b/packages/react-core/src/index.js @@ -49,6 +49,7 @@ export { } from './utils/featureSelectionConstants'; export { + Flags as _FeatureFlags, hasFlag as _hasFeatureFlag, setFlags as _setFeatureFlags, clearFlags as _clearFeatureFlags diff --git a/packages/react-core/src/utils/featureFlags.d.ts b/packages/react-core/src/utils/featureFlags.d.ts index 3b18740e9..04872d147 100644 --- a/packages/react-core/src/utils/featureFlags.d.ts +++ b/packages/react-core/src/utils/featureFlags.d.ts @@ -1,3 +1,6 @@ +export enum Flags { + DYNAMIC_TILING_V2 = '2023-dynamic-tiling-v-2' +} export function setFlags(flags: Record | string[]): void export function clearFlags(): void export function hasFlag(flag: string): boolean diff --git a/packages/react-core/src/utils/featureFlags.js b/packages/react-core/src/utils/featureFlags.js index a91489645..48801ef2b 100644 --- a/packages/react-core/src/utils/featureFlags.js +++ b/packages/react-core/src/utils/featureFlags.js @@ -1,5 +1,9 @@ let featureFlags = []; +export const Flags = Object.freeze({ + DYNAMIC_TILING_V2: '2023-dynamic-tiling-v-2' +}); + export function setFlags(flags) { const isValidFlag = (f) => typeof f === 'string' && f; diff --git a/packages/react-widgets/src/widgets/BarWidget.js b/packages/react-widgets/src/widgets/BarWidget.js index ed87556c8..f457af8a0 100644 --- a/packages/react-widgets/src/widgets/BarWidget.js +++ b/packages/react-widgets/src/widgets/BarWidget.js @@ -3,7 +3,12 @@ import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import { addFilter, removeFilter } from '@carto/react-redux'; import { BarWidgetUI, WrapperWidgetUI } from '@carto/react-ui'; -import { _FilterTypes as FilterTypes, AggregationTypes } from '@carto/react-core'; +import { + _FilterTypes as FilterTypes, + AggregationTypes, + _hasFeatureFlag, + _FeatureFlags +} from '@carto/react-core'; import { getCategories } from '../models'; import { useWidgetFilterValues } from '../hooks/useWidgetFilterValues'; import { columnAggregationOn } from './utils/propTypesFns'; @@ -77,7 +82,7 @@ function BarWidget({ }, global, onError, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); const sortedData = useMemo(() => { diff --git a/packages/react-widgets/src/widgets/CategoryWidget.js b/packages/react-widgets/src/widgets/CategoryWidget.js index 4d9d6a0b7..632e43f7f 100644 --- a/packages/react-widgets/src/widgets/CategoryWidget.js +++ b/packages/react-widgets/src/widgets/CategoryWidget.js @@ -3,7 +3,12 @@ import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import { addFilter, removeFilter } from '@carto/react-redux'; import { WrapperWidgetUI, CategoryWidgetUI } from '@carto/react-ui'; -import { _FilterTypes as FilterTypes, AggregationTypes } from '@carto/react-core'; +import { + _FilterTypes as FilterTypes, + AggregationTypes, + _hasFeatureFlag, + _FeatureFlags +} from '@carto/react-core'; import { getCategories } from '../models'; import { useWidgetFilterValues } from '../hooks/useWidgetFilterValues'; import { columnAggregationOn } from './utils/propTypesFns'; @@ -74,7 +79,7 @@ function CategoryWidget(props) { }, global, onError, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); const handleSelectedCategoriesChange = useCallback( diff --git a/packages/react-widgets/src/widgets/FormulaWidget.js b/packages/react-widgets/src/widgets/FormulaWidget.js index 4e2831e4f..11d69f952 100644 --- a/packages/react-widgets/src/widgets/FormulaWidget.js +++ b/packages/react-widgets/src/widgets/FormulaWidget.js @@ -2,7 +2,7 @@ import React from 'react'; import { PropTypes } from 'prop-types'; import { WrapperWidgetUI, FormulaWidgetUI } from '@carto/react-ui'; import { getFormula } from '../models'; -import { AggregationTypes } from '@carto/react-core'; +import { AggregationTypes, _FeatureFlags, _hasFeatureFlag } from '@carto/react-core'; import { checkFormulaColumn, columnAggregationOn } from './utils/propTypesFns'; import useWidgetFetch from '../hooks/useWidgetFetch'; import WidgetWithAlert from './utils/WidgetWithAlert'; @@ -51,7 +51,7 @@ function FormulaWidget({ }, global, onError, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); return ( diff --git a/packages/react-widgets/src/widgets/HistogramWidget.js b/packages/react-widgets/src/widgets/HistogramWidget.js index 05414dba9..580cd06f4 100644 --- a/packages/react-widgets/src/widgets/HistogramWidget.js +++ b/packages/react-widgets/src/widgets/HistogramWidget.js @@ -3,7 +3,12 @@ import { useDispatch } from 'react-redux'; import { PropTypes } from 'prop-types'; import { addFilter, removeFilter } from '@carto/react-redux'; import { WrapperWidgetUI, HistogramWidgetUI } from '@carto/react-ui'; -import { _FilterTypes as FilterTypes, AggregationTypes } from '@carto/react-core'; +import { + _FilterTypes as FilterTypes, + AggregationTypes, + _hasFeatureFlag, + _FeatureFlags +} from '@carto/react-core'; import { getHistogram } from '../models'; import { useWidgetFilterValues } from '../hooks/useWidgetFilterValues'; import useWidgetFetch from '../hooks/useWidgetFetch'; @@ -113,7 +118,7 @@ function HistogramWidget({ global, onError, enabled: !!ticks.length, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); const thresholdsFromFilters = useWidgetFilterValues({ diff --git a/packages/react-widgets/src/widgets/PieWidget.js b/packages/react-widgets/src/widgets/PieWidget.js index 0338d6b82..1d42611e1 100644 --- a/packages/react-widgets/src/widgets/PieWidget.js +++ b/packages/react-widgets/src/widgets/PieWidget.js @@ -3,7 +3,12 @@ import { useDispatch } from 'react-redux'; import PropTypes from 'prop-types'; import { addFilter, removeFilter } from '@carto/react-redux'; import { WrapperWidgetUI, PieWidgetUI } from '@carto/react-ui'; -import { _FilterTypes as FilterTypes, AggregationTypes } from '@carto/react-core'; +import { + _FilterTypes as FilterTypes, + AggregationTypes, + _hasFeatureFlag, + _FeatureFlags +} from '@carto/react-core'; import { getCategories } from '../models'; import { useWidgetFilterValues } from '../hooks/useWidgetFilterValues'; import { columnAggregationOn } from './utils/propTypesFns'; @@ -76,7 +81,7 @@ function PieWidget({ }, global, onError, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); const handleSelectedCategoriesChange = useCallback( diff --git a/packages/react-widgets/src/widgets/RangeWidget.js b/packages/react-widgets/src/widgets/RangeWidget.js index 5bed3c738..39dca5143 100644 --- a/packages/react-widgets/src/widgets/RangeWidget.js +++ b/packages/react-widgets/src/widgets/RangeWidget.js @@ -1,7 +1,11 @@ import React, { useCallback, useEffect, useMemo, useState } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import { PropTypes } from 'prop-types'; -import { _FilterTypes as FilterTypes } from '@carto/react-core'; +import { + _FilterTypes as FilterTypes, + _FeatureFlags, + _hasFeatureFlag +} from '@carto/react-core'; import { WrapperWidgetUI } from '@carto/react-ui'; import { addFilter, selectSourceById } from '@carto/react-redux/'; import { getRange } from '../models/RangeModel'; @@ -68,7 +72,7 @@ function RangeWidget({ }, global, onError, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); const handleSelectedRangeChange = useCallback( diff --git a/packages/react-widgets/src/widgets/TimeSeriesWidget.js b/packages/react-widgets/src/widgets/TimeSeriesWidget.js index b96f18571..0796d1924 100644 --- a/packages/react-widgets/src/widgets/TimeSeriesWidget.js +++ b/packages/react-widgets/src/widgets/TimeSeriesWidget.js @@ -11,7 +11,9 @@ import { import { GroupDateTypes, AggregationTypes, - _FilterTypes as FilterTypes + _FilterTypes as FilterTypes, + _hasFeatureFlag, + _FeatureFlags } from '@carto/react-core'; import { capitalize, Menu, MenuItem, SvgIcon } from '@mui/material'; import { PropTypes } from 'prop-types'; @@ -136,7 +138,7 @@ function TimeSeriesWidget({ }, global, onError, - attemptRemoteCalculation: true + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) }); const handleTimeWindowUpdate = useCallback( From 9cb3f3b0c770cf3fe875650ebcd13ca4e7804220 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 4 May 2023 12:25:55 +0200 Subject: [PATCH 16/41] Removed debug logging --- packages/react-api/src/api/model.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/react-api/src/api/model.js b/packages/react-api/src/api/model.js index f21ac69b8..360e172ef 100644 --- a/packages/react-api/src/api/model.js +++ b/packages/react-api/src/api/model.js @@ -41,8 +41,6 @@ export function executeModel(props) { let url = `${source.credentials.apiBaseUrl}/v3/sql/${source.connection}/model/${model}`; - console.log(url); - const { filters, filtersLogicalOperator, data, type } = source; const queryParameters = source.queryParameters ? JSON.stringify(source.queryParameters) @@ -60,8 +58,6 @@ export function executeModel(props) { queryParams.spatialFilter = JSON.stringify(spatialFilter); } - console.log(JSON.stringify(queryParams)); - const isGet = url.length + JSON.stringify(queryParams).length <= URL_LENGTH; if (isGet) { url += '?' + new URLSearchParams(queryParams).toString(); From 4607396bf3ff6a9c9277752145a99544165a6a4a Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 4 May 2023 12:29:34 +0200 Subject: [PATCH 17/41] Changed the feature flag to `2023-remote-widgets` --- packages/react-core/src/utils/featureFlags.d.ts | 2 +- packages/react-core/src/utils/featureFlags.js | 2 +- packages/react-widgets/src/widgets/BarWidget.js | 2 +- packages/react-widgets/src/widgets/CategoryWidget.js | 2 +- packages/react-widgets/src/widgets/FormulaWidget.js | 2 +- packages/react-widgets/src/widgets/HistogramWidget.js | 2 +- packages/react-widgets/src/widgets/PieWidget.js | 2 +- packages/react-widgets/src/widgets/RangeWidget.js | 2 +- packages/react-widgets/src/widgets/TimeSeriesWidget.js | 2 +- 9 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/react-core/src/utils/featureFlags.d.ts b/packages/react-core/src/utils/featureFlags.d.ts index 04872d147..1beb1280d 100644 --- a/packages/react-core/src/utils/featureFlags.d.ts +++ b/packages/react-core/src/utils/featureFlags.d.ts @@ -1,5 +1,5 @@ export enum Flags { - DYNAMIC_TILING_V2 = '2023-dynamic-tiling-v-2' + REMOTE_WIDGETS = '2023-remote-widgets' } export function setFlags(flags: Record | string[]): void export function clearFlags(): void diff --git a/packages/react-core/src/utils/featureFlags.js b/packages/react-core/src/utils/featureFlags.js index 48801ef2b..79783ee70 100644 --- a/packages/react-core/src/utils/featureFlags.js +++ b/packages/react-core/src/utils/featureFlags.js @@ -1,7 +1,7 @@ let featureFlags = []; export const Flags = Object.freeze({ - DYNAMIC_TILING_V2: '2023-dynamic-tiling-v-2' + REMOTE_WIDGETS: '2023-remote-widgets' }); export function setFlags(flags) { diff --git a/packages/react-widgets/src/widgets/BarWidget.js b/packages/react-widgets/src/widgets/BarWidget.js index f457af8a0..0494b4a79 100644 --- a/packages/react-widgets/src/widgets/BarWidget.js +++ b/packages/react-widgets/src/widgets/BarWidget.js @@ -82,7 +82,7 @@ function BarWidget({ }, global, onError, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); const sortedData = useMemo(() => { diff --git a/packages/react-widgets/src/widgets/CategoryWidget.js b/packages/react-widgets/src/widgets/CategoryWidget.js index 632e43f7f..775b7fa28 100644 --- a/packages/react-widgets/src/widgets/CategoryWidget.js +++ b/packages/react-widgets/src/widgets/CategoryWidget.js @@ -79,7 +79,7 @@ function CategoryWidget(props) { }, global, onError, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); const handleSelectedCategoriesChange = useCallback( diff --git a/packages/react-widgets/src/widgets/FormulaWidget.js b/packages/react-widgets/src/widgets/FormulaWidget.js index 11d69f952..d0387f104 100644 --- a/packages/react-widgets/src/widgets/FormulaWidget.js +++ b/packages/react-widgets/src/widgets/FormulaWidget.js @@ -51,7 +51,7 @@ function FormulaWidget({ }, global, onError, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); return ( diff --git a/packages/react-widgets/src/widgets/HistogramWidget.js b/packages/react-widgets/src/widgets/HistogramWidget.js index 580cd06f4..667a20b22 100644 --- a/packages/react-widgets/src/widgets/HistogramWidget.js +++ b/packages/react-widgets/src/widgets/HistogramWidget.js @@ -118,7 +118,7 @@ function HistogramWidget({ global, onError, enabled: !!ticks.length, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); const thresholdsFromFilters = useWidgetFilterValues({ diff --git a/packages/react-widgets/src/widgets/PieWidget.js b/packages/react-widgets/src/widgets/PieWidget.js index 1d42611e1..1d2091894 100644 --- a/packages/react-widgets/src/widgets/PieWidget.js +++ b/packages/react-widgets/src/widgets/PieWidget.js @@ -81,7 +81,7 @@ function PieWidget({ }, global, onError, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); const handleSelectedCategoriesChange = useCallback( diff --git a/packages/react-widgets/src/widgets/RangeWidget.js b/packages/react-widgets/src/widgets/RangeWidget.js index 39dca5143..6621246b5 100644 --- a/packages/react-widgets/src/widgets/RangeWidget.js +++ b/packages/react-widgets/src/widgets/RangeWidget.js @@ -72,7 +72,7 @@ function RangeWidget({ }, global, onError, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); const handleSelectedRangeChange = useCallback( diff --git a/packages/react-widgets/src/widgets/TimeSeriesWidget.js b/packages/react-widgets/src/widgets/TimeSeriesWidget.js index 0796d1924..f7d860dd4 100644 --- a/packages/react-widgets/src/widgets/TimeSeriesWidget.js +++ b/packages/react-widgets/src/widgets/TimeSeriesWidget.js @@ -138,7 +138,7 @@ function TimeSeriesWidget({ }, global, onError, - attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.DYNAMIC_TILING_V2) + attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); const handleTimeWindowUpdate = useCallback( From 0901ae838812321fac1a8b7c7cc37cd373714a92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Thu, 4 May 2023 17:14:41 +0200 Subject: [PATCH 18/41] Prepare changelog for alpha --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 023dd2813..cf4538b24 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # CHANGELOG +## 2.1 + +## 2.1.0-alpha.0 (2021-05-11) + +- Calculation of widget using maps API #658](https://github.com/CartoDB/carto-react/pull/658) + ## Not released - Changed how widget are calculated when a mask is set: use just the mask, no more intersection between mask and viewport [#661](https://github.com/CartoDB/carto-react/pull/661) From 2fe5fc91c376d47a937ca653deba7c588ac0da74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Thu, 4 May 2023 17:17:25 +0200 Subject: [PATCH 19/41] v2.1.0-alpha.0 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 82240e466..fa0747b8d 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.0.2" + "version": "2.1.0-alpha.0" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 616c2f41d..8604449f4 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 53c6a6a36..e16fbf50d 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index baa3c84e3..bbbeab13d 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 609dbfbe5..9c14e7e0c 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index d14dfb331..d576aa904 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index a548121eb..0eb24427a 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index 9eeff9f47..29023b5c7 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index 25b57b2f3..26580686e 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.0.2", + "version": "2.1.0-alpha.0", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.0.2", + "@carto/react-core": "^2.1.0-alpha.0", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From 5682c114c493e96721c528a48543d12d4ae949b7 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Mon, 8 May 2023 10:24:34 +0200 Subject: [PATCH 20/41] Fix --- packages/react-core/src/filters/tileFeatures.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index 85b4ec40d..140033a43 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -15,7 +15,7 @@ import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; * @returns { Geometry? } the geometry to use for filtering */ export function getGeometryToIntersect(viewport, geometry) { - return geometry + return geometry && geometry.coordinates ? geometry : Array.isArray(viewport) && viewport.length === 4 ? bboxPolygon(viewport).geometry From 18b48376dd921425b67ae6079025c1c865cc16fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Mon, 8 May 2023 10:50:27 +0200 Subject: [PATCH 21/41] v2.1.0-alpha.2 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index d8d1e622a..817758b79 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.1.0-alpha.1" + "version": "2.1.0-alpha.2" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 2a7757e75..bdf7f3888 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index b9c1cbcce..24e82bbb3 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index c70efc128..91d2012af 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index bfe7c189a..c353143ab 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index 851666dca..2a2621e46 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index cd0e4d2b1..166073dbc 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index 98eb936f7..2fd58a35d 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index fa0cb4a1b..7a80ddb36 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.1.0-alpha.1", + "version": "2.1.0-alpha.2", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.1.0-alpha.1", + "@carto/react-core": "^2.1.0-alpha.2", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From d56168dfb2704848a69054d42b1545459c008f7d Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Mon, 8 May 2023 15:38:58 +0200 Subject: [PATCH 22/41] Fix --- packages/react-widgets/src/hooks/useWidgetFetch.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-widgets/src/hooks/useWidgetFetch.js b/packages/react-widgets/src/hooks/useWidgetFetch.js index baed33bab..a191fd202 100644 --- a/packages/react-widgets/src/hooks/useWidgetFetch.js +++ b/packages/react-widgets/src/hooks/useWidgetFetch.js @@ -41,7 +41,7 @@ export default function useWidgetFetch( const viewport = useSelector(selectViewport); const spatialFilter = useSelector((state) => selectSpatialFilter(state, dataSource)); const geometryToIntersect = !global - ? getGeometryToIntersect(viewport, spatialFilter) + ? getGeometryToIntersect(viewport, spatialFilter ? spatialFilter.geometry : null) : null; useCustomCompareEffect( From cdf71ef4b6c647a446d7084dcdb3790efb91bced Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Tue, 9 May 2023 16:41:54 +0200 Subject: [PATCH 23/41] v2.1.0-alpha.3 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 817758b79..0a0234355 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.1.0-alpha.2" + "version": "2.1.0-alpha.3" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index bdf7f3888..13ae56784 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 24e82bbb3..ef050da95 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index 91d2012af..9bbf89144 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index c353143ab..1a6da6ac8 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index 2a2621e46..8641232ec 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 166073dbc..32e3f73f9 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index 2fd58a35d..b335476d7 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index 7a80ddb36..190ce32c7 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.1.0-alpha.2", + "version": "2.1.0-alpha.3", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.1.0-alpha.2", + "@carto/react-core": "^2.1.0-alpha.3", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From 3f14aeb70578aad9ac84589badc591b86b0385eb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20Zag=C3=B3rski?= Date: Thu, 11 May 2023 11:30:05 +0200 Subject: [PATCH 24/41] react-redux: export setViewPort and setViewStateDirect --- .../react-redux/src/slices/cartoSlice.d.ts | 9 +++++++ packages/react-redux/src/slices/cartoSlice.js | 24 ++++++++++++++++++- 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/packages/react-redux/src/slices/cartoSlice.d.ts b/packages/react-redux/src/slices/cartoSlice.d.ts index bf562ee4f..19d0ee729 100644 --- a/packages/react-redux/src/slices/cartoSlice.d.ts +++ b/packages/react-redux/src/slices/cartoSlice.d.ts @@ -139,6 +139,15 @@ export function selectAreFeaturesReadyForSource(state: any, id: string): boolean export function setViewState(viewState: ViewState): Function; +export const setViewStateDirect: (viewState: ViewState) => { + type: 'carto/setViewState'; + payload: ViewState; +}; + +export const setViewPort: () => { + type: 'carto/setViewPort'; +}; + export function setFeaturesReady(data: FeaturesReadyData): { type: CartoActions.SET_FEATURES_READY; payload: FeaturesReadyData; diff --git a/packages/react-redux/src/slices/cartoSlice.js b/packages/react-redux/src/slices/cartoSlice.js index 91c487ef5..f8f206145 100644 --- a/packages/react-redux/src/slices/cartoSlice.js +++ b/packages/react-redux/src/slices/cartoSlice.js @@ -380,7 +380,9 @@ const NOT_ALLOWED_DECK_PROPS = [ ]; /** - * Action to set the current ViewState + * Action to set the current ViewState. + * + * Requires redux-thunk middleware, also invokes debounced `setViewPort`. * @param {Object} viewState */ export const setViewState = (viewState) => { @@ -401,6 +403,26 @@ export const setViewState = (viewState) => { }; }; +/** + * Action to set the current ViewState. + * + * Doesn't refresh widgets immetiately, requires user to call `setViewPort` once all updates are ready. + * @param {Object} viewState + */ +export const setViewStateDirect = (viewState) => ({ + type: 'carto/setViewState', + payload: viewState +}); + +/** + * Sync current viewport state deriving it from `viewState`. + * + * Causes widgets in remote mode to refresh its data. + */ +export const setViewPort = () => ({ + type: 'carto/setViewPort' +}); + /** * Action to set the ready features state of a layer * @param {object} sourceId - the id of the source From 1d0de4a1668bb3dde50b5a271c002c6bc2ccb266 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Zbigniew=20Zag=C3=B3rski?= Date: Thu, 11 May 2023 12:42:55 +0200 Subject: [PATCH 25/41] v2.1.0-alpha.4 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 0a0234355..c7dde2bc7 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.1.0-alpha.3" + "version": "2.1.0-alpha.4" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 13ae56784..d191fff49 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index ef050da95..ff3104c83 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index 9bbf89144..0dbfa9ad4 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 1a6da6ac8..cf44184cd 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index 8641232ec..5fc9be718 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 32e3f73f9..fddf231d0 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index b335476d7..8910a5838 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index 190ce32c7..4455de965 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.1.0-alpha.3", + "version": "2.1.0-alpha.4", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.1.0-alpha.3", + "@carto/react-core": "^2.1.0-alpha.4", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From e211ce5850529c0b204666d8097c3f32b002e211 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 11 May 2023 17:51:49 +0200 Subject: [PATCH 26/41] Fixed "no data available at this zoom level" --- packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js | 2 +- packages/react-widgets/src/hooks/useWidgetFetch.js | 2 +- packages/react-widgets/src/widgets/BarWidget.js | 4 +++- packages/react-widgets/src/widgets/CategoryWidget.js | 4 +++- packages/react-widgets/src/widgets/FormulaWidget.js | 4 +++- packages/react-widgets/src/widgets/HistogramWidget.js | 4 +++- packages/react-widgets/src/widgets/PieWidget.js | 4 +++- packages/react-widgets/src/widgets/TimeSeriesWidget.js | 4 +++- 8 files changed, 20 insertions(+), 8 deletions(-) diff --git a/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js b/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js index 9e4618231..c84e45bbf 100644 --- a/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js +++ b/packages/react-widgets/__tests__/hooks/useWidgetFetch.test.js @@ -3,7 +3,7 @@ import { DEFAULT_INVALID_COLUMN_ERR } from '../../src/widgets/utils/constants'; import { act, render, screen } from '@testing-library/react'; import React from 'react'; import useWidgetFetch from '../../src/hooks/useWidgetFetch'; -import { mockClear, mockReduxHooks, mockSetup } from '../mockReduxHooks'; +import { mockClear, mockSetup } from '../mockReduxHooks'; import { selectViewport } from '@carto/react-redux'; import bboxPolygon from '@turf/bbox-polygon'; diff --git a/packages/react-widgets/src/hooks/useWidgetFetch.js b/packages/react-widgets/src/hooks/useWidgetFetch.js index a191fd202..afe1f3ba5 100644 --- a/packages/react-widgets/src/hooks/useWidgetFetch.js +++ b/packages/react-widgets/src/hooks/useWidgetFetch.js @@ -87,5 +87,5 @@ export default function useWidgetFetch( dequal ); - return { data, isLoading, isSourceReady, source, warning }; + return { data, isLoading, isSourceReady, source, warning, remoteCalculation }; } diff --git a/packages/react-widgets/src/widgets/BarWidget.js b/packages/react-widgets/src/widgets/BarWidget.js index 0494b4a79..68554db08 100644 --- a/packages/react-widgets/src/widgets/BarWidget.js +++ b/packages/react-widgets/src/widgets/BarWidget.js @@ -70,7 +70,8 @@ function BarWidget({ const { data: _data = [], isLoading, - warning + warning, + remoteCalculation } = useWidgetFetch(getCategories, { id, dataSource, @@ -147,6 +148,7 @@ function BarWidget({ global={global} droppingFeaturesAlertProps={droppingFeaturesAlertProps} noDataAlertProps={noDataAlertProps} + showDroppingFeaturesAlert={!remoteCalculation} > {(!!sortedData.length || isLoading) && ( {(!!data.length || isLoading) && ( {(!!data.length || isLoading) && ( {(!!data.length || isLoading) && ( {(!!data.length || isLoading) && ( Date: Thu, 11 May 2023 18:44:24 +0200 Subject: [PATCH 27/41] v2.1.0-alpha.5 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index c7dde2bc7..7785e1157 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.1.0-alpha.4" + "version": "2.1.0-alpha.5" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index e494a3db5..d352d897c 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 5307eb64b..8994b3488 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index dcade0bf0..bbaa04cd3 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index cf44184cd..b4509cc87 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index a39b2d645..e5b51ef6e 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 49a312675..f10cd464a 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index 2f18922b2..a9330ea13 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index 4455de965..9364b320f 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.1.0-alpha.4", + "version": "2.1.0-alpha.5", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.1.0-alpha.4", + "@carto/react-core": "^2.1.0-alpha.5", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From 42e08983b7902ef312a2c5c0258976de62c691f5 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 12 May 2023 18:01:48 +0200 Subject: [PATCH 28/41] Fix normalizeObjectKeys for null/undefined values --- .../__tests__/models/utils.test.js | 28 +++++++++---------- packages/react-widgets/src/models/utils.js | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/react-widgets/__tests__/models/utils.test.js b/packages/react-widgets/__tests__/models/utils.test.js index 91d5fed9a..267e3b9e8 100644 --- a/packages/react-widgets/__tests__/models/utils.test.js +++ b/packages/react-widgets/__tests__/models/utils.test.js @@ -117,20 +117,20 @@ describe('utils', () => { }); describe('normalizeObjectKeys', () => { - test('should work correctly', () => { - const test = { VALUE: 1 }; - const test2 = [{ TICK: 0, VALUE: 1 }]; - const test3 = [{ TICK: [{ VALUE: 0 }], VALUE: 1 }]; - - expect(JSON.stringify(normalizeObjectKeys(test))).toEqual( - JSON.stringify(test).toLowerCase() - ); - expect(JSON.stringify(normalizeObjectKeys(test2))).toEqual( - JSON.stringify(test2).toLowerCase() - ); - expect(JSON.stringify(normalizeObjectKeys(test3))).toEqual( - JSON.stringify(test3).toLowerCase() - ); + const tests = [ + // single objects + { VALUE: 1 }, + { A: null, B: undefined, C: 'hello' }, + { A: { X: null }, B: { X: undefined }, C: 'hello' }, + // array of objects + [{ TICK: 0, VALUE: 1 }], + [{ TICK: [{ VALUE: 0 }], VALUE: 1 }], + [{ A: null, B: undefined, C: 'hello' }], + [{ A: { X: null }, B: { X: undefined }, C: 'hello' }] + ]; + test.each(tests)('should work correctly for %p', (test) => { + const normalized = normalizeObjectKeys(test); + expect(JSON.stringify(normalized)).toEqual(JSON.stringify(test).toLowerCase()); }); }); diff --git a/packages/react-widgets/src/models/utils.js b/packages/react-widgets/src/models/utils.js index 732bf2e52..81aa71e08 100644 --- a/packages/react-widgets/src/models/utils.js +++ b/packages/react-widgets/src/models/utils.js @@ -63,7 +63,7 @@ export function normalizeObjectKeys(el) { return Object.entries(el).reduce((acc, [key, value]) => { acc[key.toLowerCase()] = - typeof value === 'object' ? normalizeObjectKeys(value) : value; + typeof value === 'object' && value ? normalizeObjectKeys(value) : value; return acc; }, {}); } From dca0727d4c32c5b210814e24c2aa9018c6d313ef Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 12 May 2023 18:19:38 +0200 Subject: [PATCH 29/41] Support for NoData in FormulaWidget --- packages/react-widgets/src/widgets/FormulaWidget.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/react-widgets/src/widgets/FormulaWidget.js b/packages/react-widgets/src/widgets/FormulaWidget.js index f9cedc8ad..e6d91d67b 100644 --- a/packages/react-widgets/src/widgets/FormulaWidget.js +++ b/packages/react-widgets/src/widgets/FormulaWidget.js @@ -55,6 +55,8 @@ function FormulaWidget({ attemptRemoteCalculation: _hasFeatureFlag(_FeatureFlags.REMOTE_WIDGETS) }); + const value = Number.isFinite(data?.value) ? data.value : undefined; + return ( - + {value !== undefined && ( + + )} ); From 20332366d94ac9dd7c84a789cc0bd7f5b4e6b94e Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Fri, 12 May 2023 18:23:44 +0200 Subject: [PATCH 30/41] Fix NoData for HistogramWidget --- packages/react-widgets/src/models/HistogramModel.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/react-widgets/src/models/HistogramModel.js b/packages/react-widgets/src/models/HistogramModel.js index 96065a06c..7160a29bb 100644 --- a/packages/react-widgets/src/models/HistogramModel.js +++ b/packages/react-widgets/src/models/HistogramModel.js @@ -32,8 +32,11 @@ async function fromRemote(props) { opts: { abortController } }).then((res) => normalizeObjectKeys(res.rows)); - const result = Array(ticks.length + 1).fill(0); - data.forEach(({ tick, value }) => (result[tick] = value)); + if (data.length) { + const result = Array(ticks.length + 1).fill(0); + data.forEach(({ tick, value }) => (result[tick] = value)); + return result; + } - return result; + return []; } From 354dbe30e92bd82d6f23af3042f38e615e1e9df8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Fri, 12 May 2023 18:45:45 +0200 Subject: [PATCH 31/41] v2.1.0-alpha.7 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 7785e1157..375495bbf 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.1.0-alpha.5" + "version": "2.1.0-alpha.7" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index d352d897c..75674d01d 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 8994b3488..4626bfa62 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index bbaa04cd3..49aed114e 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index b4509cc87..7575c6627 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index e5b51ef6e..67704d7e8 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index f4c85c068..ed5b7f294 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index a9330ea13..e6dc94d05 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index 9364b320f..e9bda1566 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.1.0-alpha.5", + "version": "2.1.0-alpha.7", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.1.0-alpha.5", + "@carto/react-core": "^2.1.0-alpha.7", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From 3ff12ada0a85e08fb618f8c01a3c067e8cfab0ca Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Mon, 15 May 2023 18:09:24 +0200 Subject: [PATCH 32/41] Optimized viewport wrapping the globe (fix 314403) --- .../__tests__/filters/tileFeatures.test.js | 33 ++++++++++++++++++- .../react-core/src/filters/tileFeatures.d.ts | 3 +- .../react-core/src/filters/tileFeatures.js | 31 ++++++++++++++++- packages/react-core/src/index.d.ts | 2 +- packages/react-core/src/index.js | 6 +++- .../react-widgets/src/hooks/useWidgetFetch.js | 13 +++++--- 6 files changed, 79 insertions(+), 9 deletions(-) diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index 65f9ffd8f..5d9c2a4bb 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -2,7 +2,7 @@ import { TILE_FORMATS } from '@deck.gl/carto'; import { geojsonToBinary } from '@loaders.gl/gis'; import { tileFeatures } from '../../src'; import * as transformToTileCoords from '../../src/utils/transformToTileCoords'; -import { getGeometryToIntersect } from '../../src/filters/tileFeatures'; +import { getGeometryToIntersect, isGlobalViewport } from '../../src/filters/tileFeatures'; import bboxPolygon from '@turf/bbox-polygon'; /** @type { import('../../src').Viewport } */ @@ -23,6 +23,29 @@ const filterGeometry = { ] }; +describe('isGlobalViewport', () => { + const normalViewports = [ + { v: null }, + { v: viewport }, + { + v: [-344.2596303029739, -75.05112877980663, 230.26452782294038, 75.05112877980655] + }, + { v: [-125.2596303029739, -85.05112877980663, 230.26452782294038, 85.05112877980655] } + ]; + const globalViewports = [ + { v: [-344.2596303029739, -85.05112877980663, 230.26452782294038, 85.05112877980655] } + ]; + + test.each(normalViewports)('return false for normal viewports', ({ v }) => { + expect(!isGlobalViewport(v)); + }); + + test.each(globalViewports)('return true for global viewports', ({ v }) => { + console.log(viewport); + expect(isGlobalViewport(v)); + }); +}); + describe('getGeometryToIntersect', () => { test('returns null in case no viewport or geometry is present', () => { expect(getGeometryToIntersect(null, null)).toStrictEqual(null); @@ -41,6 +64,14 @@ describe('getGeometryToIntersect', () => { filterGeometry ); }); + + test('resolves viewports wapping across the globe', () => { + const wrapping = [-200, 0, +190, 45]; + const nonWrapping = [-180, 0, +180, 45]; + expect(getGeometryToIntersect(wrapping, null)).toStrictEqual( + bboxPolygon(nonWrapping).geometry + ); + }); }); describe('viewport features with binary mode', () => { diff --git a/packages/react-core/src/filters/tileFeatures.d.ts b/packages/react-core/src/filters/tileFeatures.d.ts index eaf5f0c99..0c62d7faa 100644 --- a/packages/react-core/src/filters/tileFeatures.d.ts +++ b/packages/react-core/src/filters/tileFeatures.d.ts @@ -1,5 +1,6 @@ -import { TileFeatures, TileFeaturesResponse } from '../types'; +import { TileFeatures, TileFeaturesResponse, Viewport } from '../types'; import { Polygon, MultiPolygon } from 'geojson'; export function getGeometryToIntersect(viewport: number[] | null, geometry: Polygon | MultiPolygon | null): Polygon | MultiPolygon | null; +export function isGlobalViewport(viewport: Viewport | null): boolean; export function tileFeatures(arg: TileFeatures): TileFeaturesResponse; \ No newline at end of file diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index 140033a43..3c86629d1 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -2,6 +2,19 @@ import bboxPolygon from '@turf/bbox-polygon'; import tileFeaturesGeometries from './tileFeaturesGeometries'; import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; +function bboxToGeometry(viewport) { + let [minx, miny, maxx, maxy] = viewport; + if (maxx - minx > 360) { + minx = -180; + maxx = +180; + } + if (maxy - miny > 180) { + miny = -90; + maxy = +90; + } + return bboxPolygon([minx, miny, maxx, maxy]).geometry; +} + /** * Select the geometry to use for widget calculation and data filtering. * If a spatial filter (mask) is set, use the mask otherwise use the current viewport. @@ -18,10 +31,26 @@ export function getGeometryToIntersect(viewport, geometry) { return geometry && geometry.coordinates ? geometry : Array.isArray(viewport) && viewport.length === 4 - ? bboxPolygon(viewport).geometry + ? bboxToGeometry(viewport) : null; } +/** + * Check if a viewport is large enough to represent a global coverage. + * In this case the spatial filter parameter for widget calculation + * can be removed. This also normalizes viewports that are too large. + * + * @param { import('../types').Viewport? } viewport + * @returns { boolean } + */ +export function isGlobalViewport(viewport) { + if (viewport) { + const [minx, miny, maxx, maxy] = viewport; + return maxx - minx > 179.5 * 2 && maxy - miny > 85.05 * 2; + } + return false; +} + export function tileFeatures({ tiles, viewport, diff --git a/packages/react-core/src/index.d.ts b/packages/react-core/src/index.d.ts index 191a3f252..7406943af 100644 --- a/packages/react-core/src/index.d.ts +++ b/packages/react-core/src/index.d.ts @@ -27,7 +27,7 @@ export { scatterPlot } from './operations/scatterPlot'; export { FilterTypes as _FilterTypes } from './filters/FilterTypes'; -export { tileFeatures, getGeometryToIntersect } from './filters/tileFeatures'; +export { tileFeatures, getGeometryToIntersect, isGlobalViewport } from './filters/tileFeatures'; export { geojsonFeatures } from './filters/geojsonFeatures'; export { AggregationFunctions, GroupByFeature, HistogramFeature, Viewport, TileFeatures } from './types'; diff --git a/packages/react-core/src/index.js b/packages/react-core/src/index.js index 39744a0b6..51119ec17 100644 --- a/packages/react-core/src/index.js +++ b/packages/react-core/src/index.js @@ -34,7 +34,11 @@ export { applyFilters as _applyFilters } from './filters/Filter'; -export { tileFeatures, getGeometryToIntersect } from './filters/tileFeatures'; +export { + tileFeatures, + getGeometryToIntersect, + isGlobalViewport +} from './filters/tileFeatures'; export { geojsonFeatures } from './filters/geojsonFeatures'; export { GroupDateTypes } from './operations/constants/GroupDateTypes'; diff --git a/packages/react-widgets/src/hooks/useWidgetFetch.js b/packages/react-widgets/src/hooks/useWidgetFetch.js index afe1f3ba5..625552021 100644 --- a/packages/react-widgets/src/hooks/useWidgetFetch.js +++ b/packages/react-widgets/src/hooks/useWidgetFetch.js @@ -1,4 +1,8 @@ -import { InvalidColumnError, getGeometryToIntersect } from '@carto/react-core'; +import { + InvalidColumnError, + getGeometryToIntersect, + isGlobalViewport +} from '@carto/react-core'; import { selectAreFeaturesReadyForSource, selectSpatialFilter, @@ -40,9 +44,10 @@ export default function useWidgetFetch( const viewport = useSelector(selectViewport); const spatialFilter = useSelector((state) => selectSpatialFilter(state, dataSource)); - const geometryToIntersect = !global - ? getGeometryToIntersect(viewport, spatialFilter ? spatialFilter.geometry : null) - : null; + const geometryToIntersect = + global || (!spatialFilter && isGlobalViewport(viewport)) + ? null + : getGeometryToIntersect(viewport, spatialFilter ? spatialFilter.geometry : null); useCustomCompareEffect( () => { From 66a5add363453f7f1213cc124df6fac810478be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Mon, 15 May 2023 20:22:27 +0200 Subject: [PATCH 33/41] v2.0.3-alpha.1 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 375495bbf..1beacd0b9 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.1.0-alpha.7" + "version": "2.0.3-alpha.1" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index 75674d01d..b00acf62a 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 4626bfa62..da5d6b15f 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index 49aed114e..47f838d06 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 7575c6627..7951a6340 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index 67704d7e8..5498e7e45 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index ed5b7f294..5800415a3 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index e6dc94d05..25716bc21 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index e9bda1566..8b40778c1 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.1.0-alpha.7", + "version": "2.0.3-alpha.1", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.1.0-alpha.7", + "@carto/react-core": "^2.0.3-alpha.1", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From 021ccf7822bafa9c5c6b5ee98998fcafcc0b85b1 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Wed, 17 May 2023 19:13:21 +0200 Subject: [PATCH 34/41] Partial revert of wrapping the globe optimization --- .../__tests__/filters/tileFeatures.test.js | 8 -------- packages/react-core/src/filters/tileFeatures.js | 15 +-------------- 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index 5d9c2a4bb..7ba32ddfb 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -64,14 +64,6 @@ describe('getGeometryToIntersect', () => { filterGeometry ); }); - - test('resolves viewports wapping across the globe', () => { - const wrapping = [-200, 0, +190, 45]; - const nonWrapping = [-180, 0, +180, 45]; - expect(getGeometryToIntersect(wrapping, null)).toStrictEqual( - bboxPolygon(nonWrapping).geometry - ); - }); }); describe('viewport features with binary mode', () => { diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index 3c86629d1..feababb70 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -2,19 +2,6 @@ import bboxPolygon from '@turf/bbox-polygon'; import tileFeaturesGeometries from './tileFeaturesGeometries'; import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; -function bboxToGeometry(viewport) { - let [minx, miny, maxx, maxy] = viewport; - if (maxx - minx > 360) { - minx = -180; - maxx = +180; - } - if (maxy - miny > 180) { - miny = -90; - maxy = +90; - } - return bboxPolygon([minx, miny, maxx, maxy]).geometry; -} - /** * Select the geometry to use for widget calculation and data filtering. * If a spatial filter (mask) is set, use the mask otherwise use the current viewport. @@ -31,7 +18,7 @@ export function getGeometryToIntersect(viewport, geometry) { return geometry && geometry.coordinates ? geometry : Array.isArray(viewport) && viewport.length === 4 - ? bboxToGeometry(viewport) + ? bboxPolygon(viewport).geometry : null; } From df14fa41530f7d700c2862b07280c070a2cbf0a4 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Wed, 17 May 2023 19:14:34 +0200 Subject: [PATCH 35/41] Minor optimization --- packages/react-core/src/filters/tileFeaturesSpatialIndex.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-core/src/filters/tileFeaturesSpatialIndex.js b/packages/react-core/src/filters/tileFeaturesSpatialIndex.js index 9913951f2..a3c723ddf 100644 --- a/packages/react-core/src/filters/tileFeaturesSpatialIndex.js +++ b/packages/react-core/src/filters/tileFeaturesSpatialIndex.js @@ -37,7 +37,7 @@ export default function tileFeaturesSpatialIndex({ } tile.data.forEach((d) => { - if (cellsDictionary[d.id]) { + if (d.id in cellsDictionary) { map.set(d.id, { ...d.properties, [spatialIndexIDName]: d.id }); } }); From 3c50889bbdd0c8a51849ad10d5227d6a8b31fd5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Wed, 17 May 2023 20:05:58 +0200 Subject: [PATCH 36/41] v2.0.3-alpha.2 --- lerna.json | 2 +- packages/react-api/package.json | 2 +- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-core/package.json | 2 +- packages/react-redux/package.json | 2 +- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 2 +- packages/react-workers/package.json | 4 ++-- 9 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lerna.json b/lerna.json index 1beacd0b9..5be7d1efa 100644 --- a/lerna.json +++ b/lerna.json @@ -4,5 +4,5 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "2.0.3-alpha.1" + "version": "2.0.3-alpha.2" } diff --git a/packages/react-api/package.json b/packages/react-api/package.json index b00acf62a..ca109db7b 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-api", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Api", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index da5d6b15f..9b94a2155 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-auth", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Auth", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index 47f838d06..7694b23d2 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-basemaps", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Basemaps", "keywords": [ "carto", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 7951a6340..7e4821e76 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-core", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Core", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index 5498e7e45..369e9024e 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-redux", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Redux", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 5800415a3..95bd180e4 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-ui", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - UI", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index 25716bc21..c2651a0af 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-widgets", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Widgets", "author": "CARTO Dev Team", "keywords": [ diff --git a/packages/react-workers/package.json b/packages/react-workers/package.json index 8b40778c1..9d3adff40 100644 --- a/packages/react-workers/package.json +++ b/packages/react-workers/package.json @@ -1,6 +1,6 @@ { "name": "@carto/react-workers", - "version": "2.0.3-alpha.1", + "version": "2.0.3-alpha.2", "description": "CARTO for React - Workers", "author": "CARTO Dev Team", "keywords": [ @@ -62,7 +62,7 @@ }, "dependencies": { "@babel/runtime": "^7.13.9", - "@carto/react-core": "^2.0.3-alpha.1", + "@carto/react-core": "^2.0.3-alpha.2", "@turf/bbox-polygon": "^6.3.0", "@turf/boolean-intersects": "^6.3.0", "@turf/boolean-within": "^6.3.0", From 6fa38d8cbf6092ecb4e1eb18839ca2fa38aa2d1f Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 18 May 2023 12:33:24 +0200 Subject: [PATCH 37/41] Aligning peer dependencies --- packages/react-api/package.json | 6 +++--- packages/react-auth/package.json | 2 +- packages/react-basemaps/package.json | 2 +- packages/react-redux/package.json | 4 ++-- packages/react-ui/package.json | 2 +- packages/react-widgets/package.json | 10 +++++----- 6 files changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/react-api/package.json b/packages/react-api/package.json index ca109db7b..aca7bb244 100644 --- a/packages/react-api/package.json +++ b/packages/react-api/package.json @@ -64,9 +64,9 @@ "@babel/runtime": "^7.13.9" }, "peerDependencies": { - "@carto/react-core": "^2.1.0-alpha.1", - "@carto/react-redux": "^2.1.0-alpha.1", - "@carto/react-workers": "^2.1.0-alpha.1", + "@carto/react-core": "^2.0.3-alpha.2", + "@carto/react-redux": "^2.0.3-alpha.2", + "@carto/react-workers": "^2.0.3-alpha.2", "@deck.gl/carto": "^8.9.6", "@deck.gl/core": "^8.9.6", "@deck.gl/extensions": "^8.9.6", diff --git a/packages/react-auth/package.json b/packages/react-auth/package.json index 9b94a2155..77586cca3 100644 --- a/packages/react-auth/package.json +++ b/packages/react-auth/package.json @@ -64,7 +64,7 @@ "@babel/runtime": "^7.13.9" }, "peerDependencies": { - "@carto/react-core": "^2.1.0-alpha.1", + "@carto/react-core": "^2.0.3-alpha.2", "react": "17.x || 18.x", "react-dom": "17.x || 18.x" } diff --git a/packages/react-basemaps/package.json b/packages/react-basemaps/package.json index 7694b23d2..036b01582 100644 --- a/packages/react-basemaps/package.json +++ b/packages/react-basemaps/package.json @@ -64,7 +64,7 @@ "@babel/runtime": "^7.13.9" }, "peerDependencies": { - "@carto/react-core": "^2.1.0-alpha.1", + "@carto/react-core": "^2.0.3-alpha.2", "@deck.gl/google-maps": "^8.9.6", "react": "17.x || 18.x", "react-dom": "17.x || 18.x" diff --git a/packages/react-redux/package.json b/packages/react-redux/package.json index 369e9024e..9e49d30f5 100644 --- a/packages/react-redux/package.json +++ b/packages/react-redux/package.json @@ -63,8 +63,8 @@ "@babel/runtime": "^7.13.9" }, "peerDependencies": { - "@carto/react-core": "^2.1.0-alpha.1", - "@carto/react-workers": "^2.1.0-alpha.1", + "@carto/react-core": "^2.0.3-alpha.2", + "@carto/react-workers": "^2.0.3-alpha.2", "@deck.gl/carto": "^8.9.6", "@deck.gl/core": "^8.9.6", "@reduxjs/toolkit": "^1.5.0" diff --git a/packages/react-ui/package.json b/packages/react-ui/package.json index 95bd180e4..a824df10f 100644 --- a/packages/react-ui/package.json +++ b/packages/react-ui/package.json @@ -78,7 +78,7 @@ "@babel/runtime": "^7.13.9" }, "peerDependencies": { - "@carto/react-core": "^2.1.0-alpha.1", + "@carto/react-core": "^2.0.3-alpha.2", "@emotion/react": "^11.10.6", "@emotion/styled": "^11.10.6", "@mui/icons-material": "^5.11.16", diff --git a/packages/react-widgets/package.json b/packages/react-widgets/package.json index c2651a0af..15dca27db 100644 --- a/packages/react-widgets/package.json +++ b/packages/react-widgets/package.json @@ -65,11 +65,11 @@ "@babel/runtime": "^7.13.9" }, "peerDependencies": { - "@carto/react-api": "^2.1.0-alpha.1", - "@carto/react-core": "^2.1.0-alpha.1", - "@carto/react-redux": "^2.1.0-alpha.1", - "@carto/react-ui": "^2.1.0-alpha.1", - "@carto/react-workers": "^2.1.0-alpha.1", + "@carto/react-api": "^2.0.3-alpha.2", + "@carto/react-core": "^2.0.3-alpha.2", + "@carto/react-redux": "^2.0.3-alpha.2", + "@carto/react-ui": "^2.0.3-alpha.2", + "@carto/react-workers": "^2.0.3-alpha.2", "@deck.gl/core": "^8.9.6", "@deck.gl/layers": "^8.9.6", "@emotion/react": "^11.10.6", From 756e46d8d938b199249cac243242a1ca80eda41d Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 18 May 2023 13:14:34 +0200 Subject: [PATCH 38/41] Switch to quadbin 0.1.9 --- package.json | 2 +- packages/react-core/package.json | 2 +- yarn.lock | 21 ++++++++++++++++++++- 3 files changed, 22 insertions(+), 3 deletions(-) diff --git a/package.json b/package.json index aaa8a6cb1..5b7b00f70 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "lint-staged": "^10.5.3", "nyc": "^15.1.0", "patch-package": "6.4.7", - "quadbin": "^0.1.5", + "quadbin": "^0.1.9", "react": "^17.0.1", "react-dom": "^17.0.1", "react-redux": "^7.2.2", diff --git a/packages/react-core/package.json b/packages/react-core/package.json index 7e4821e76..2d27e15f4 100644 --- a/packages/react-core/package.json +++ b/packages/react-core/package.json @@ -71,6 +71,6 @@ "@turf/boolean-within": "^6.3.0", "@turf/intersect": "^6.3.0", "h3-js": "^3.7.2", - "quadbin": "^0.1.5" + "quadbin": "^0.1.9" } } diff --git a/yarn.lock b/yarn.lock index e228a6afb..3789d4099 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2796,6 +2796,13 @@ resolved "https://registry.yarnpkg.com/@mapbox/point-geometry/-/point-geometry-0.1.0.tgz#8a83f9335c7860effa2eeeca254332aa0aeed8f2" integrity sha512-6j56HdLTwWGO0fJPlrZtdU/B13q8Uwmo18Ck2GnGgN9PCFyKTZ3UbXeEdRFh18i9XQ92eH2VdtpJHpBD3aripQ== +"@mapbox/tile-cover@3.0.1": + version "3.0.1" + resolved "https://registry.yarnpkg.com/@mapbox/tile-cover/-/tile-cover-3.0.1.tgz#ad0dbe69d02e4e9ff74bf228b3ee8fa533034210" + integrity sha512-R8aoFY/87HWBOL9E2eBqzOY2lpfWYXCcTNgBpIxAv67rqQeD4IfnHD0iPXg/Z1cqXrklegEYZCp/7ZR/RsWqBQ== + dependencies: + tilebelt "^1.0.1" + "@mapbox/tile-cover@^3.0.2": version "3.0.2" resolved "https://registry.yarnpkg.com/@mapbox/tile-cover/-/tile-cover-3.0.2.tgz#e10b1bbfe65ee28a7f1a0127deb699635d0f8d7a" @@ -15353,13 +15360,20 @@ qs@~6.5.2: resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad" integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA== -quadbin@^0.1.2, quadbin@^0.1.5: +quadbin@^0.1.2: version "0.1.5" resolved "https://registry.yarnpkg.com/quadbin/-/quadbin-0.1.5.tgz#aa6dba53d0558236f8070450c90d6ed9b87507c8" integrity sha512-/MQnN7V73myA+31gTxldTGN8ixqrUCXtUoDvRKSI9QZJOaq0cS9SNQkdToMxjC3ZSM2hN7mleOAn+9QVNlPZOg== dependencies: "@mapbox/tile-cover" "^3.0.2" +quadbin@^0.1.9: + version "0.1.9" + resolved "https://registry.yarnpkg.com/quadbin/-/quadbin-0.1.9.tgz#322bd5f8b63960ef0a31a8b69863b0a0ab0b2e22" + integrity sha512-5V6m6+cL/6+uBl3hYL+CWF06rRvlHkIepYKGQjTLYaHhu9InPppql0+0ROiCaOQdz8gPNlgge3glk5Qg1mWOYw== + dependencies: + "@mapbox/tile-cover" "3.0.1" + query-string@^6.13.8: version "6.14.1" resolved "https://registry.yarnpkg.com/query-string/-/query-string-6.14.1.tgz#7ac2dca46da7f309449ba0f86b1fd28255b0c86a" @@ -17500,6 +17514,11 @@ through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +tilebelt@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/tilebelt/-/tilebelt-1.0.1.tgz#3bbf7113b3fec468efb0d9148f4bb71ef126a21a" + integrity sha512-cxHzpa5JgsugY9NUVRH43gPaGJw/29LecAn4X7UGOP64+kB8pU4VQ3bIhSyfb5Mk4jDxwl3yk330L/EIhbJ5aw== + timers-browserify@^2.0.4: version "2.0.12" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" From c96c6cd4d252f04292b6a34b0450c8de8749bd00 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 18 May 2023 13:41:20 +0200 Subject: [PATCH 39/41] Refactor geo functions in their own file --- .../__tests__/filters/tileFeatures.test.js | 63 ------------------- .../react-core/__tests__/utils/geo.test.js | 63 +++++++++++++++++++ .../react-core/src/filters/geojsonFeatures.js | 2 +- .../react-core/src/filters/tileFeatures.d.ts | 5 +- .../react-core/src/filters/tileFeatures.js | 38 +---------- packages/react-core/src/index.d.ts | 3 +- packages/react-core/src/index.js | 7 +-- packages/react-core/src/utils/geo.d.ts | 6 ++ packages/react-core/src/utils/geo.js | 37 +++++++++++ 9 files changed, 113 insertions(+), 111 deletions(-) create mode 100644 packages/react-core/__tests__/utils/geo.test.js create mode 100644 packages/react-core/src/utils/geo.d.ts create mode 100644 packages/react-core/src/utils/geo.js diff --git a/packages/react-core/__tests__/filters/tileFeatures.test.js b/packages/react-core/__tests__/filters/tileFeatures.test.js index 7ba32ddfb..c286032a5 100644 --- a/packages/react-core/__tests__/filters/tileFeatures.test.js +++ b/packages/react-core/__tests__/filters/tileFeatures.test.js @@ -2,69 +2,6 @@ import { TILE_FORMATS } from '@deck.gl/carto'; import { geojsonToBinary } from '@loaders.gl/gis'; import { tileFeatures } from '../../src'; import * as transformToTileCoords from '../../src/utils/transformToTileCoords'; -import { getGeometryToIntersect, isGlobalViewport } from '../../src/filters/tileFeatures'; -import bboxPolygon from '@turf/bbox-polygon'; - -/** @type { import('../../src').Viewport } */ -const viewport = [-10, -10, 10, 10]; // west - south - east - north -const viewportGeometry = bboxPolygon(viewport).geometry; - -/** @type { import('geojson').Polygon } */ -const filterGeometry = { - type: 'Polygon', - coordinates: [ - [ - [-1, -1], - [1, -1], - [1, 1], - [-1, 1], - [-1, -1] - ] - ] -}; - -describe('isGlobalViewport', () => { - const normalViewports = [ - { v: null }, - { v: viewport }, - { - v: [-344.2596303029739, -75.05112877980663, 230.26452782294038, 75.05112877980655] - }, - { v: [-125.2596303029739, -85.05112877980663, 230.26452782294038, 85.05112877980655] } - ]; - const globalViewports = [ - { v: [-344.2596303029739, -85.05112877980663, 230.26452782294038, 85.05112877980655] } - ]; - - test.each(normalViewports)('return false for normal viewports', ({ v }) => { - expect(!isGlobalViewport(v)); - }); - - test.each(globalViewports)('return true for global viewports', ({ v }) => { - console.log(viewport); - expect(isGlobalViewport(v)); - }); -}); - -describe('getGeometryToIntersect', () => { - test('returns null in case no viewport or geometry is present', () => { - expect(getGeometryToIntersect(null, null)).toStrictEqual(null); - expect(getGeometryToIntersect([], null)).toStrictEqual(null); - expect(getGeometryToIntersect(null, {})).toStrictEqual(null); - expect(getGeometryToIntersect([], {})).toStrictEqual(null); - }); - - test('returns the viewport as geometry', () => { - expect(getGeometryToIntersect(viewport, null)).toStrictEqual(viewportGeometry); - }); - - test('returns the filter as geometry', () => { - expect(getGeometryToIntersect(null, filterGeometry)).toStrictEqual(filterGeometry); - expect(getGeometryToIntersect(viewport, filterGeometry)).toStrictEqual( - filterGeometry - ); - }); -}); describe('viewport features with binary mode', () => { const viewport = [-10, -10, 10, 10]; // west - south - east - north diff --git a/packages/react-core/__tests__/utils/geo.test.js b/packages/react-core/__tests__/utils/geo.test.js new file mode 100644 index 000000000..3cbc0d57b --- /dev/null +++ b/packages/react-core/__tests__/utils/geo.test.js @@ -0,0 +1,63 @@ +import bboxPolygon from '@turf/bbox-polygon'; +import { isGlobalViewport, getGeometryToIntersect } from '../../src/utils/geo'; + +/** @type { import('../../src').Viewport } */ +const viewport = [-10, -10, 10, 10]; // west - south - east - north +const viewportGeometry = bboxPolygon(viewport).geometry; + +/** @type { import('geojson').Polygon } */ +const filterGeometry = { + type: 'Polygon', + coordinates: [ + [ + [-1, -1], + [1, -1], + [1, 1], + [-1, 1], + [-1, -1] + ] + ] +}; + +describe('isGlobalViewport', () => { + const normalViewports = [ + { v: null }, + { v: viewport }, + { + v: [-344.2596303029739, -75.05112877980663, 230.26452782294038, 75.05112877980655] + }, + { v: [-125.2596303029739, -85.05112877980663, 230.26452782294038, 85.05112877980655] } + ]; + const globalViewports = [ + { v: [-344.2596303029739, -85.05112877980663, 230.26452782294038, 85.05112877980655] } + ]; + + test.each(normalViewports)('return false for normal viewports', ({ v }) => { + expect(!isGlobalViewport(v)); + }); + + test.each(globalViewports)('return true for global viewports', ({ v }) => { + console.log(viewport); + expect(isGlobalViewport(v)); + }); +}); + +describe('getGeometryToIntersect', () => { + test('returns null in case no or invalid viewport or geometry is present', () => { + expect(getGeometryToIntersect(null, null)).toStrictEqual(null); + expect(getGeometryToIntersect([], null)).toStrictEqual(null); + expect(getGeometryToIntersect(null, {})).toStrictEqual(null); + expect(getGeometryToIntersect([], {})).toStrictEqual(null); + }); + + test('returns the viewport as geometry', () => { + expect(getGeometryToIntersect(viewport, null)).toStrictEqual(viewportGeometry); + }); + + test('returns the filter as geometry', () => { + expect(getGeometryToIntersect(null, filterGeometry)).toStrictEqual(filterGeometry); + expect(getGeometryToIntersect(viewport, filterGeometry)).toStrictEqual( + filterGeometry + ); + }); +}); diff --git a/packages/react-core/src/filters/geojsonFeatures.js b/packages/react-core/src/filters/geojsonFeatures.js index 5c7693ddc..bd8417834 100644 --- a/packages/react-core/src/filters/geojsonFeatures.js +++ b/packages/react-core/src/filters/geojsonFeatures.js @@ -1,5 +1,5 @@ import intersects from '@turf/boolean-intersects'; -import { getGeometryToIntersect } from './tileFeatures'; +import { getGeometryToIntersect } from '../utils/geo'; export function geojsonFeatures({ geojson, viewport, geometry, uniqueIdProperty }) { let uniqueIdx = 0; diff --git a/packages/react-core/src/filters/tileFeatures.d.ts b/packages/react-core/src/filters/tileFeatures.d.ts index 0c62d7faa..c5526a41e 100644 --- a/packages/react-core/src/filters/tileFeatures.d.ts +++ b/packages/react-core/src/filters/tileFeatures.d.ts @@ -1,6 +1,3 @@ -import { TileFeatures, TileFeaturesResponse, Viewport } from '../types'; -import { Polygon, MultiPolygon } from 'geojson'; +import { TileFeatures, TileFeaturesResponse } from '../types'; -export function getGeometryToIntersect(viewport: number[] | null, geometry: Polygon | MultiPolygon | null): Polygon | MultiPolygon | null; -export function isGlobalViewport(viewport: Viewport | null): boolean; export function tileFeatures(arg: TileFeatures): TileFeaturesResponse; \ No newline at end of file diff --git a/packages/react-core/src/filters/tileFeatures.js b/packages/react-core/src/filters/tileFeatures.js index feababb70..3a1db9ece 100644 --- a/packages/react-core/src/filters/tileFeatures.js +++ b/packages/react-core/src/filters/tileFeatures.js @@ -1,43 +1,7 @@ -import bboxPolygon from '@turf/bbox-polygon'; +import { getGeometryToIntersect } from '../utils/geo'; import tileFeaturesGeometries from './tileFeaturesGeometries'; import tileFeaturesSpatialIndex from './tileFeaturesSpatialIndex'; -/** - * Select the geometry to use for widget calculation and data filtering. - * If a spatial filter (mask) is set, use the mask otherwise use the current viewport. - * Since it's possible that no mask and no viewport is set, return null in this case. - * - * @typedef { import('geojson').Polygon | import('geojson').MultiPolygon } Geometry - * @typedef { import('geojson').BBox } BBox - * - * @param { BBox? } viewport viewport [minX, minY, maxX, maxY], if any - * @param { Geometry? } geometry the active spatial filter (mask), if any - * @returns { Geometry? } the geometry to use for filtering - */ -export function getGeometryToIntersect(viewport, geometry) { - return geometry && geometry.coordinates - ? geometry - : Array.isArray(viewport) && viewport.length === 4 - ? bboxPolygon(viewport).geometry - : null; -} - -/** - * Check if a viewport is large enough to represent a global coverage. - * In this case the spatial filter parameter for widget calculation - * can be removed. This also normalizes viewports that are too large. - * - * @param { import('../types').Viewport? } viewport - * @returns { boolean } - */ -export function isGlobalViewport(viewport) { - if (viewport) { - const [minx, miny, maxx, maxy] = viewport; - return maxx - minx > 179.5 * 2 && maxy - miny > 85.05 * 2; - } - return false; -} - export function tileFeatures({ tiles, viewport, diff --git a/packages/react-core/src/index.d.ts b/packages/react-core/src/index.d.ts index 7406943af..be9db20bc 100644 --- a/packages/react-core/src/index.d.ts +++ b/packages/react-core/src/index.d.ts @@ -15,6 +15,7 @@ export { debounce } from './utils/debounce'; export { throttle } from './utils/throttle'; export { randomString } from './utils/randomString'; export { assert as _assert } from './utils/assert'; +export { getGeometryToIntersect, isGlobalViewport } from './utils/geo'; export { makeIntervalComplete } from './utils/makeIntervalComplete'; @@ -27,7 +28,7 @@ export { scatterPlot } from './operations/scatterPlot'; export { FilterTypes as _FilterTypes } from './filters/FilterTypes'; -export { tileFeatures, getGeometryToIntersect, isGlobalViewport } from './filters/tileFeatures'; +export { tileFeatures } from './filters/tileFeatures'; export { geojsonFeatures } from './filters/geojsonFeatures'; export { AggregationFunctions, GroupByFeature, HistogramFeature, Viewport, TileFeatures } from './types'; diff --git a/packages/react-core/src/index.js b/packages/react-core/src/index.js index 51119ec17..64acf71b4 100644 --- a/packages/react-core/src/index.js +++ b/packages/react-core/src/index.js @@ -13,6 +13,7 @@ export { debounce } from './utils/debounce'; export { throttle } from './utils/throttle'; export { randomString } from './utils/randomString'; export { assert as _assert } from './utils/assert'; +export { getGeometryToIntersect, isGlobalViewport } from './utils/geo'; export { makeIntervalComplete } from './utils/makeIntervalComplete'; @@ -34,11 +35,7 @@ export { applyFilters as _applyFilters } from './filters/Filter'; -export { - tileFeatures, - getGeometryToIntersect, - isGlobalViewport -} from './filters/tileFeatures'; +export { tileFeatures } from './filters/tileFeatures'; export { geojsonFeatures } from './filters/geojsonFeatures'; export { GroupDateTypes } from './operations/constants/GroupDateTypes'; diff --git a/packages/react-core/src/utils/geo.d.ts b/packages/react-core/src/utils/geo.d.ts new file mode 100644 index 000000000..fef625c1c --- /dev/null +++ b/packages/react-core/src/utils/geo.d.ts @@ -0,0 +1,6 @@ +import { Viewport } from '../types'; +import { Polygon, MultiPolygon } from 'geojson'; + +export function getGeometryToIntersect(viewport: Viewport | null, geometry: Polygon | MultiPolygon | null): Polygon | MultiPolygon | null; + +export function isGlobalViewport(viewport: Viewport | null): boolean; diff --git a/packages/react-core/src/utils/geo.js b/packages/react-core/src/utils/geo.js new file mode 100644 index 000000000..822ad4b79 --- /dev/null +++ b/packages/react-core/src/utils/geo.js @@ -0,0 +1,37 @@ +import bboxPolygon from '@turf/bbox-polygon'; + +/** + * Select the geometry to use for widget calculation and data filtering. + * If a spatial filter (mask) is set, use the mask otherwise use the current viewport. + * Since it's possible that no mask and no viewport is set, return null in this case. + * + * @typedef { import('geojson').Polygon | import('geojson').MultiPolygon } Geometry + * @typedef { import('../types').Viewport? } Viewport + * + * @param { Viewport? } viewport viewport [minX, minY, maxX, maxY], if any + * @param { Geometry? } geometry the active spatial filter (mask), if any + * @returns { Geometry? } the geometry to use for filtering + */ +export function getGeometryToIntersect(viewport, geometry) { + return geometry && geometry.coordinates + ? geometry + : Array.isArray(viewport) && viewport.length === 4 + ? bboxPolygon(viewport).geometry + : null; +} + +/** + * Check if a viewport is large enough to represent a global coverage. + * In this case the spatial filter parameter for widget calculation + * can be removed. + * + * @param { import('../types').Viewport? } viewport + * @returns { boolean } + */ +export function isGlobalViewport(viewport) { + if (viewport) { + const [minx, miny, maxx, maxy] = viewport; + return maxx - minx > 179.5 * 2 && maxy - miny > 85.05 * 2; + } + return false; +} From 6e3652c19f1890bfc748f19220592796360e4a61 Mon Sep 17 00:00:00 2001 From: Stefano Pettini Date: Thu, 18 May 2023 16:59:31 +0200 Subject: [PATCH 40/41] Fixed warnings --- .../react-api/src/hooks/useGeojsonFeatures.js | 45 ++++++++++--------- .../react-api/src/hooks/useTileFeatures.js | 45 ++++++++++--------- .../CategoryItem.js | 2 - 3 files changed, 50 insertions(+), 42 deletions(-) diff --git a/packages/react-api/src/hooks/useGeojsonFeatures.js b/packages/react-api/src/hooks/useGeojsonFeatures.js index dec45b4ce..094211bcf 100644 --- a/packages/react-api/src/hooks/useGeojsonFeatures.js +++ b/packages/react-api/src/hooks/useGeojsonFeatures.js @@ -44,26 +44,31 @@ export default function useGeojsonFeatures({ [computeFeatures] ); - useEffect(() => { - if (sourceId && isGeoJsonLoaded) { - clearDebounce(); - setSourceFeaturesReady(false); - debounceIdRef.current = debouncedComputeFeatures({ - viewport, - spatialFilter, - uniqueIdProperty - }); - } - }, [ - spatialFilter ? spatialFilter : viewport, - uniqueIdProperty, - sourceId, - isGeoJsonLoaded, - debouncedComputeFeatures, - setSourceFeaturesReady, - clearDebounce, - debounceIdRef - ]); + useEffect( + () => { + if (sourceId && isGeoJsonLoaded) { + clearDebounce(); + setSourceFeaturesReady(false); + debounceIdRef.current = debouncedComputeFeatures({ + viewport, + spatialFilter, + uniqueIdProperty + }); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [ + // eslint-disable-next-line react-hooks/exhaustive-deps + spatialFilter ? spatialFilter : viewport, + uniqueIdProperty, + sourceId, + isGeoJsonLoaded, + debouncedComputeFeatures, + setSourceFeaturesReady, + clearDebounce, + debounceIdRef + ] + ); const onDataLoad = useCallback( (geojson) => { diff --git a/packages/react-api/src/hooks/useTileFeatures.js b/packages/react-api/src/hooks/useTileFeatures.js index 09c401435..3b93f9a7f 100644 --- a/packages/react-api/src/hooks/useTileFeatures.js +++ b/packages/react-api/src/hooks/useTileFeatures.js @@ -96,26 +96,31 @@ export default function useTileFeatures({ loadTiles ]); - useEffect(() => { - if (sourceId && isTilesetLoaded) { - clearDebounce(); - setSourceFeaturesReady(false); - debounceIdRef.current = debouncedComputeFeatures({ - viewport, - spatialFilter, - uniqueIdProperty - }); - } - }, [ - spatialFilter ? spatialFilter : viewport, - uniqueIdProperty, - debouncedComputeFeatures, - sourceId, - isTilesetLoaded, - setSourceFeaturesReady, - clearDebounce, - debounceIdRef - ]); + useEffect( + () => { + if (sourceId && isTilesetLoaded) { + clearDebounce(); + setSourceFeaturesReady(false); + debounceIdRef.current = debouncedComputeFeatures({ + viewport, + spatialFilter, + uniqueIdProperty + }); + } + }, + // eslint-disable-next-line react-hooks/exhaustive-deps + [ + // eslint-disable-next-line react-hooks/exhaustive-deps + spatialFilter ? spatialFilter : viewport, + uniqueIdProperty, + debouncedComputeFeatures, + sourceId, + isTilesetLoaded, + setSourceFeaturesReady, + clearDebounce, + debounceIdRef + ] + ); const onViewportLoad = useCallback( (tiles) => { diff --git a/packages/react-ui/src/widgets/comparative/ComparativeCategoryWidgetUI/CategoryItem.js b/packages/react-ui/src/widgets/comparative/ComparativeCategoryWidgetUI/CategoryItem.js index 2ee993026..38a0557b7 100644 --- a/packages/react-ui/src/widgets/comparative/ComparativeCategoryWidgetUI/CategoryItem.js +++ b/packages/react-ui/src/widgets/comparative/ComparativeCategoryWidgetUI/CategoryItem.js @@ -94,8 +94,6 @@ function CategoryItem({ names, tooltip }) { - const theme = useTheme(); - function getProgressbarLength(value) { return `${Math.min(100, ((value || 0) / maxValue) * 100)}%`; } From 0c1869951333f792103a6325f04771262e393442 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Velarde?= Date: Thu, 18 May 2023 18:31:31 +0200 Subject: [PATCH 41/41] Prepare changelog for landing --- CHANGELOG.md | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 27eede8ad..319116282 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,13 +1,8 @@ # CHANGELOG -## 2.1 - -## 2.1.0-alpha.0 (2021-05-11) - -- Calculation of widget using maps API #658](https://github.com/CartoDB/carto-react/pull/658) - ## Not released +- Calculation of widget using maps API under FF [#658](https://github.com/CartoDB/carto-react/pull/658) - TablePagination fixes & DS application [#673](https://github.com/CartoDB/carto-react/pull/673) - Remove ReactDOMServer dependency and simplify avatar image fallback [#672](https://github.com/CartoDB/carto-react/pull/672) - Remove @mui/styles after dumping makeStyles [#670](https://github.com/CartoDB/carto-react/pull/670)