Skip to content

Commit

Permalink
Freeze widgets during time-series animation (#804)
Browse files Browse the repository at this point in the history
  • Loading branch information
padawannn authored Dec 21, 2023
1 parent df123bd commit f72d2bd
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 16 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

### 2.3.3 (2023-12-15)

- Freeze widgets during time-series animation [#804](https://github.com/CartoDB/carto-react/pull/804)
- Show widget skeleton only once [#811](https://github.com/CartoDB/carto-react/pull/811)
- Added filterable prop to TimeSeriesWidget [#808](https://github.com/CartoDB/carto-react/pull/808)
- Fix dataSources store type [#807](https://github.com/CartoDB/carto-react/pull/807)
Expand Down
2 changes: 1 addition & 1 deletion packages/react-core/src/filters/FilterQueryBuilder.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export const getApplicableFilters = (filters = {}, owner) => {
Object.entries(filters).forEach(([column, filter]) => {
const filterCopy = {};
Object.keys(filter)
.filter((operator) => filter[operator].owner !== owner)
.filter((operator) => filter[operator].owner !== owner && !filter[operator].ignore)
.forEach((operator) => (filterCopy[operator] = { ...filter[operator] }));

if (Object.keys(filterCopy).length) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-redux/src/slices/cartoSlice.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type FilterBasic = {
values: FilterValues;
owner?: string;
params?: Record<string, unknown>;
ignore?: boolean;
};

type FilterCommonProps = {
Expand Down
9 changes: 5 additions & 4 deletions packages/react-redux/src/slices/cartoSlice.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ export const createCartoSlice = (initialState) => {
}
},
addFilter: (state, action) => {
const { id, column, type, values, owner, params } = action.payload;
const { id, column, type, values, owner, params, ignore } = action.payload;
const source = state.dataSources[id];

if (source) {
Expand All @@ -148,7 +148,7 @@ export const createCartoSlice = (initialState) => {
source.filters[column] = {};
}

source.filters[column][type] = { values, owner, params };
source.filters[column][type] = { values, owner, params, ignore };
}
},
removeFilter: (state, action) => {
Expand Down Expand Up @@ -326,10 +326,11 @@ export const removeSpatialFilter = (sourceId) => ({
* @param {array} data.values - values for the filter (eg: ['a', 'b'] for IN or [10, 20] for BETWEEN).
* @param {string} data.owner - (optional) id of the widget triggering the filter (to be excluded).
* @param {object=} data.params - (optional) additional filter parameters.
* * @param {string} data.ignore - (optional) boolean indicating that it should be ignored by other widgets.
*/
export const addFilter = ({ id, column, type, values, owner, params }) => ({
export const addFilter = ({ id, column, type, values, owner, params, ignore }) => ({
type: 'carto/addFilter',
payload: { id, column, type, values, owner, params }
payload: { id, column, type, values, owner, params, ignore }
});

/**
Expand Down
65 changes: 54 additions & 11 deletions packages/react-widgets/src/widgets/TimeSeriesWidget.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import {
AggregationTypes,
_FilterTypes as FilterTypes,
_hasFeatureFlag,
_FeatureFlags
_FeatureFlags,
debounce
} from '@carto/react-core';
import { capitalize, Menu, MenuItem, SvgIcon } from '@mui/material';
import { PropTypes } from 'prop-types';
Expand Down Expand Up @@ -48,6 +49,8 @@ function calculateNextStep(time, stepType, stepMultiplier = 1) {

const EMPTY_ARRAY = [];

const debounceTimeout = 250;

/**
* Renders a <TimeSeriesWidget /> component
* @param {object} props
Expand Down Expand Up @@ -145,6 +148,7 @@ function TimeSeriesWidget({
const dispatch = useDispatch();

const [selectedStepSize, setSelectedStepSize] = useState(stepSize);
const [isRunningAnimation, setIsRunningAnimation] = useState(false);

const selectedCategories =
useWidgetFilterValues({
Expand Down Expand Up @@ -249,7 +253,8 @@ function TimeSeriesWidget({
type: FilterTypes.TIME,
values: [timeWindow.map((date) => date.getTime?.() || date)],
params: { offsetBy: minTime },
owner: id
owner: id,
...(isRunningAnimation && { ignore: true })
})
);
} else {
Expand All @@ -264,7 +269,21 @@ function TimeSeriesWidget({

if (onTimeWindowUpdate) onTimeWindowUpdate(timeWindow);
},
[isLoading, dispatch, dataSource, column, minTime, id, onTimeWindowUpdate]
[
isLoading,
onTimeWindowUpdate,
dispatch,
dataSource,
column,
minTime,
id,
isRunningAnimation
]
);

const handleTimeWindowUpdateDebounced = useMemo(
() => debounce(handleTimeWindowUpdate, debounceTimeout),
[handleTimeWindowUpdate]
);

const handleTimelineUpdate = useCallback(
Expand All @@ -284,7 +303,8 @@ function TimeSeriesWidget({
[moment, calculateNextStep(moment, selectedStepSize, stepMultiplier) - 1]
],
params: { offsetBy: minTime },
owner: id
owner: id,
...(isRunningAnimation && { ignore: true })
})
);
} else {
Expand All @@ -302,17 +322,23 @@ function TimeSeriesWidget({
[
isLoading,
data,
onTimelineUpdate,
dispatch,
dataSource,
column,
selectedStepSize,
stepMultiplier,
minTime,
id,
onTimelineUpdate
isRunningAnimation
]
);

const handleTimelineUpdateDebounced = useMemo(
() => debounce(handleTimelineUpdate, debounceTimeout),
[handleTimelineUpdate]
);

const handleSelectedCategoriesChange = useCallback(
(newSelectedCategories) => {
if (!splitByCategory || !newSelectedCategories) return;
Expand Down Expand Up @@ -341,17 +367,28 @@ function TimeSeriesWidget({
);

const handleStop = useCallback(() => {
setIsRunningAnimation(false);
// The onStop must be executed before the removeFilter to avoid repeated Maps API calls in Builder
if (onStop) onStop();
dispatch(
removeFilter({
id: dataSource,
column,
owner: id
})
);

if (onStop) onStop();
}, [column, dataSource, id, dispatch, onStop]);

const handlePlay = () => {
setIsRunningAnimation(true);
if (onPlay) onPlay();
};

const handlePause = () => {
setIsRunningAnimation(false);
if (onPause) onPause();
};

const [anchorEl, setAnchorEl] = useState(null);

const handleOpenStepSizeMenu = (e) => {
Expand Down Expand Up @@ -415,13 +452,19 @@ function TimeSeriesWidget({
animation={animation}
filterable={filterable}
isPlaying={isPlaying}
onPlay={onPlay}
onPlay={handlePlay}
isPaused={isPaused}
onPause={onPause}
onPause={handlePause}
onStop={handleStop}
onTimelineUpdate={handleTimelineUpdate}
onTimelineUpdate={
isRunningAnimation ? handleTimelineUpdate : handleTimelineUpdateDebounced
}
timeWindow={timeWindow}
onTimeWindowUpdate={handleTimeWindowUpdate}
onTimeWindowUpdate={
isRunningAnimation
? handleTimeWindowUpdate
: handleTimeWindowUpdateDebounced
}
selectedCategories={selectedCategories}
onSelectedCategoriesChange={
splitByCategory ? handleSelectedCategoriesChange : undefined
Expand Down

0 comments on commit f72d2bd

Please sign in to comment.