From 6aedc0194daf1b6dfaae44a683bcd28e62afb46d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ver=C3=B3nica=20Mil=C3=A1n?= Date: Fri, 26 May 2023 18:17:17 +0200 Subject: [PATCH] Scatter Plot Widget: Add a skeleton for loading state (#690) --- CHANGELOG.md | 1 + .../widgets/ScatterPlotWidget.test.js | 2 +- packages/react-ui/src/index.d.ts | 2 +- packages/react-ui/src/index.js | 2 +- packages/react-ui/src/types.d.ts | 1 + .../ScatterPlotSkeleton.js | 58 +++++++++++++++++++ .../ScatterPlotWidgetUI.js | 14 +++-- .../react-ui/src/widgets/SkeletonWidgets.js | 2 - .../widgetsUI/ScatterPlotWidgetUI.stories.js | 29 +++++++++- .../src/widgets/ScatterPlotWidget.js | 1 + 10 files changed, 100 insertions(+), 12 deletions(-) create mode 100644 packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotSkeleton.js rename packages/react-ui/src/widgets/{ => ScatterPlotWidgetUI}/ScatterPlotWidgetUI.js (89%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e45605b9..27bb875d9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Not released +- ScatterPlot Widget: Add a skeleton for loading state [#690](https://github.com/CartoDB/carto-react/pull/690) - Table Widget: Add a skeleton for loading state [#689](https://github.com/CartoDB/carto-react/pull/689) - TimeSeries Widget: Add a skeleton for loading state [#686](https://github.com/CartoDB/carto-react/pull/686) - Pie & ComparativePie Widgets: Add a skeleton for loading state [#682](https://github.com/CartoDB/carto-react/pull/682) diff --git a/packages/react-ui/__tests__/widgets/ScatterPlotWidget.test.js b/packages/react-ui/__tests__/widgets/ScatterPlotWidget.test.js index 63242579c..f60a134a2 100644 --- a/packages/react-ui/__tests__/widgets/ScatterPlotWidget.test.js +++ b/packages/react-ui/__tests__/widgets/ScatterPlotWidget.test.js @@ -1,6 +1,6 @@ import React from 'react'; import { render } from '../widgets/utils/testUtils'; -import ScatterPlotWidgetUI from '../../src/widgets/ScatterPlotWidgetUI'; +import ScatterPlotWidgetUI from '../../src/widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI'; import { mockEcharts } from './testUtils'; describe('ScatterPlotWidgetUI', () => { diff --git a/packages/react-ui/src/index.d.ts b/packages/react-ui/src/index.d.ts index 3e850c104..662e553db 100644 --- a/packages/react-ui/src/index.d.ts +++ b/packages/react-ui/src/index.d.ts @@ -10,7 +10,7 @@ import LegendCategories from './widgets/legend/LegendCategories'; import LegendIcon from './widgets/legend/LegendIcon'; import LegendProportion from './widgets/legend/LegendProportion'; import LegendRamp from './widgets/legend/LegendRamp'; -import ScatterPlotWidgetUI from './widgets/ScatterPlotWidgetUI'; +import ScatterPlotWidgetUI from './widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI'; import TimeSeriesWidgetUI from './widgets/TimeSeriesWidgetUI/TimeSeriesWidgetUI'; import { useTimeSeriesContext, diff --git a/packages/react-ui/src/index.js b/packages/react-ui/src/index.js index 19825b2e7..4a12e6267 100644 --- a/packages/react-ui/src/index.js +++ b/packages/react-ui/src/index.js @@ -10,7 +10,7 @@ import LegendCategories from './widgets/legend/LegendCategories'; import LegendIcon from './widgets/legend/LegendIcon'; import LegendProportion from './widgets/legend/LegendProportion'; import LegendRamp from './widgets/legend/LegendRamp'; -import ScatterPlotWidgetUI from './widgets/ScatterPlotWidgetUI'; +import ScatterPlotWidgetUI from './widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI'; import TimeSeriesWidgetUI from './widgets/TimeSeriesWidgetUI/TimeSeriesWidgetUI'; import FeatureSelectionWidgetUI from './widgets/FeatureSelectionWidgetUI'; import RangeWidgetUI from './widgets/RangeWidgetUI/RangeWidgetUI'; diff --git a/packages/react-ui/src/types.d.ts b/packages/react-ui/src/types.d.ts index 7a9829645..a98f3e708 100644 --- a/packages/react-ui/src/types.d.ts +++ b/packages/react-ui/src/types.d.ts @@ -125,6 +125,7 @@ export type ScatterPlotWidgetUI = { xAxisFormatter?: Function; yAxisFormatter?: Function; tooltipFormatter?: Function; + isLoading?: boolean; }; export type TimeSeriesWidgetUIData = { name: number; value: number }[]; diff --git a/packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotSkeleton.js b/packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotSkeleton.js new file mode 100644 index 000000000..dd630cf6c --- /dev/null +++ b/packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotSkeleton.js @@ -0,0 +1,58 @@ +import React from 'react'; +import { Box, styled } from '@mui/material'; +import { Skeleton } from '@mui/material'; +import { SKELETON_HEIGHT, SkeletonGraphGrid } from '../SkeletonWidgets'; +import { BREAKPOINTS } from '../../theme/themeConstants'; + +const GraphGrid = styled(SkeletonGraphGrid)(({ theme }) => ({ + flexDirection: 'column', + alignItems: 'center', + justifyContent: 'center', + marginLeft: theme.spacing(4), + containerType: 'inline-size', + + [`@container (max-width: ${BREAKPOINTS.XS}px)`]: { + ' > div': { + maxWidth: '75%' + } + } +})); + +const DotsBox = styled(Box)(({ theme }) => ({ + position: 'relative', + display: 'flex', + justifyContent: 'space-between', + width: '80%', + maxWidth: '50%' +})); + +const ScatterPlotSkeleton = ({ height }) => { + function getRandomValue() { + // get a random integer value between 0 and 5 + return Math.floor(Math.random() * 5); + } + + return ( + + + + + + + {[...Array(3)].map((_, i) => ( + // Every row is placed with an incremental margin left to reinforce the effect of a scatter plot + + {[...Array(4)].map((_, i) => ( + // Random margins are used to create the effect of a scatter plot + + + + ))} + + ))} + + + ); +}; + +export default ScatterPlotSkeleton; diff --git a/packages/react-ui/src/widgets/ScatterPlotWidgetUI.js b/packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI.js similarity index 89% rename from packages/react-ui/src/widgets/ScatterPlotWidgetUI.js rename to packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI.js index 1594782b5..a4b16cd71 100644 --- a/packages/react-ui/src/widgets/ScatterPlotWidgetUI.js +++ b/packages/react-ui/src/widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI.js @@ -1,8 +1,9 @@ import { useTheme } from '@mui/material'; import PropTypes from 'prop-types'; import React, { useRef, useState, useEffect } from 'react'; -import { areChartPropsEqual } from './utils/chartUtils'; -import ReactEcharts from '../custom-components/echarts-for-react'; +import { areChartPropsEqual } from '../utils/chartUtils'; +import ReactEcharts from '../../custom-components/echarts-for-react'; +import ScatterPlotSkeleton from './ScatterPlotSkeleton'; function __generateDefaultConfig( { tooltipFormatter, xAxisFormatter = (v) => v, yAxisFormatter = (v) => v }, @@ -76,7 +77,8 @@ function ScatterPlotWidgetUI({ animation, xAxisFormatter, yAxisFormatter, - tooltipFormatter + tooltipFormatter, + isLoading }) { const theme = useTheme(); const chartInstance = useRef(); @@ -100,12 +102,16 @@ function ScatterPlotWidgetUI({ }); }, [data, name, animation, theme, xAxisFormatter, yAxisFormatter, tooltipFormatter]); + const HEIGHT = 225; + + if (isLoading) return ; + return ( ); } diff --git a/packages/react-ui/src/widgets/SkeletonWidgets.js b/packages/react-ui/src/widgets/SkeletonWidgets.js index c73d380d1..37118c00c 100644 --- a/packages/react-ui/src/widgets/SkeletonWidgets.js +++ b/packages/react-ui/src/widgets/SkeletonWidgets.js @@ -6,7 +6,6 @@ export const SkeletonBarsGrid = styled(Box)(({ theme }) => ({ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', - width: '100%', position: 'relative', padding: theme.spacing(0, 2), @@ -28,7 +27,6 @@ export const SkeletonGraphGrid = styled(Box)(({ theme }) => ({ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', - width: '100%', // Square grid effect backgroundImage: `linear-gradient(${theme.palette.grey[50]} 0.5px, transparent 0.5px, transparent calc(100% - 0.5px), ${theme.palette.grey[50]} calc(100% - 0.5px)), linear-gradient(90deg, ${theme.palette.grey[50]} 0.5px, transparent 0.5px, transparent calc(100% - 0.5px), ${theme.palette.grey[50]} calc(100% - 0.5px))`, diff --git a/packages/react-ui/storybook/stories/widgetsUI/ScatterPlotWidgetUI.stories.js b/packages/react-ui/storybook/stories/widgetsUI/ScatterPlotWidgetUI.stories.js index 581d54588..a2e8f7054 100644 --- a/packages/react-ui/storybook/stories/widgetsUI/ScatterPlotWidgetUI.stories.js +++ b/packages/react-ui/storybook/stories/widgetsUI/ScatterPlotWidgetUI.stories.js @@ -1,5 +1,6 @@ import React from 'react'; -import ScatterPlotWidgetUI from '../../../src/widgets/ScatterPlotWidgetUI'; +import ScatterPlotWidgetUI from '../../../src/widgets/ScatterPlotWidgetUI/ScatterPlotWidgetUI'; +import { Label, ThinContainer } from '../../utils/storyStyles'; const options = { title: 'Organisms/Widgets/ScatterPlotWidgetUI', @@ -22,9 +23,28 @@ const dataDefault = [ const Template = (args) => ; +const LoadingTemplate = (args) => { + return ( + <> + + + + + + + + + ); +}; + +const defaultProps = { data: dataDefault, name: 'name' }; + export const Default = Template.bind({}); -const DefaultProps = { data: dataDefault, name: 'name' }; -Default.args = DefaultProps; +Default.args = defaultProps; export const xAxisFormatter = Template.bind({}); const xAxisFormatterProps = { @@ -50,3 +70,6 @@ const tooltipFormatterProps = { }; tooltipFormatter.args = tooltipFormatterProps; + +export const Loading = LoadingTemplate.bind({}); +Loading.args = { ...defaultProps, isLoading: true }; diff --git a/packages/react-widgets/src/widgets/ScatterPlotWidget.js b/packages/react-widgets/src/widgets/ScatterPlotWidget.js index 39726815f..c22396768 100644 --- a/packages/react-widgets/src/widgets/ScatterPlotWidget.js +++ b/packages/react-widgets/src/widgets/ScatterPlotWidget.js @@ -76,6 +76,7 @@ function ScatterPlotWidget({ xAxisFormatter={xAxisFormatter} yAxisFormatter={yAxisFormatter} animation={animation} + isLoading={isLoading} /> )}