CARTO for React

CARTO for React

Widgets

Package Version Downloads
@carto/react-widgets version downloads

A set of advanced widgets, which allow not only a visual representation but a rich interaction with data & map layers, such as filtering or an automatic data refresh on viewport change, thanks to the connection with the CARTO slice on redux.

This package, @carto/react-widgets contains the widgets business logic and the @carto/react-ui package contains the user interface components. The UI is decoupled from the business logic so you can provide your own user interface or modify the business logic. To review interactively the UI for the widgets, check the Storybook catalogue.

Components

CategoryWidget

Renders a <CategoryWidget /> component, binded to a source at redux. The widget displays the calculations considering just the viewport features.

  • Input:
Param Type Default Description
props Object
props.id string ID for the widget instance.
props.title string Title to show in the widget header.
props.dataSource string ID of the data source to get the data from.
props.column string Name of the data source’s column to get the data from.
props.operation string Operation to apply to the operationColumn. Must be one of those defined in AggregationTypes object.
[props.operationColumn] string (optional) Name of the data source’s column to operate with. If not defined, same as column.
[props.formatter] function (optional) formatterCallback: Function to format each value returned.
[props.labels] Object {} (optional) Overwrite category labels.
[props.onError] function (optional) errorCallback: Function to handle error messages from the widget.
[props.wrapperProps] Object (optional) Extra props to pass to WrapperWidgetUI
  • Example:

    In this example, the widget would display the SUM of population for all the countries, grouped by continent

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    
    import { CategoryWidget } from "@carto/react-widgets";
    
    const customFormatter = (value) => `${value} people`;
    
    return (
      <CategoryWidget
        id="populationByContinent"
        title="Population by continent"
        dataSource="countriesSourceId"
        column="continent"
        operationColumn="population"
        operation={AggregationTypes.SUM}
        formatter={customFormatter}
        onError={console.error}
      />
    );
    
    // The operationColumn wouldn't be required if using AggregationTypes.COUNT, to count the number of countries per continent
    

FormulaWidget

Renders a <FormulaWidget /> component, binded to a source at redux. The widget displays the calculations considering just the viewport features.

  • Input:
Param Type Default Description
props Object
props.id string ID for the widget instance.
props.title string Title to show in the widget header.
props.dataSource string ID of the data source to get the data from.
props.column string Name of the data source’s column to get the data from.
props.operation string Operation to apply to the operationColumn. Must be one of those defined in AggregationTypes object.
[props.formatter] function (optional) formatterCallback: Function to format each value returned.
[props.onError] errorCallback (optional) errorCallback: Function to handle error messages from the widget.
[props.wrapperProps] Object (optional) Extra props to pass to WrapperWidgetUI
  • Example:

    In this example, the widget would display the AVG sales for all the stores on screen

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    
    import { FormulaWidget } from "@carto/react-widgets";
    
    const customFormatter = (value) => `${value} $`;
    
    return (
      <FormulaWidget
        id="averageRevenue"
        title="Average revenue"
        dataSource="storesSourceId"
        column="revenue"
        operation={AggregationTypes.AVG}
        formatter={customFormatter}
        onError={console.error}
      />
    );
    

HistogramWidget

Renders a <HistogramWidget /> component, binded to a source at redux. The widget displays the calculations considering just the viewport features.

  • Input:
Param Type Default Description
props Object
props.id string ID for the widget instance.
props.title string Title to show in the widget header.
props.dataSource string ID of the data source to get the data from.
props.column string Name of the data source’s column to get the data from.
props.operation string Operation to apply to the operationColumn. Must be one of those defined in AggregationTypes object.
props.ticks Array.<number> Array of numbers to build intervals (eg 1, 5, 10 will define 4 intervals: <1, 1 to 5, 5 to 10 and >10)
[props.xAxisFormatter] function (optional) formatterCallback: Function to format X axis values.
[props.formatter] function (optional) formatterCallback: Function to format tooltip and Y axis values.
[props.onError] function (optional) errorCallback: Function to handle error messages from the widget.
[props.wrapperProps] Object Extra props to pass to WrapperWidgetUI
  • Example:

    In this example, the widget would display the number of stores in different ranks, based on their number of sales.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    
    import { HistogramWidget } from "@carto/react-widgets";
    
    const customFormatter = (value) => `${value} $`;
    
    return (
      <HistogramWidget
        id="storesByNumberOfSales"
        title="Stores by number of sales"
        dataSource="storesSourceId"
        operation={AggregationTypes.COUNT}
        column="salesNumber"
        ticks={[10, 100, 500, 1000]}
        onError={console.error}
      />
    );
    // bins for the histogram would be <10, 10 to 100, 100 to 500, 500 to 1000 and > 1000
    

LegendWidget

Renders a <LegendWidget /> component. The widget can display a switch to show or hide a layer and a legend for the layer. The legend representation depends on the legend type. You can check the available LEGEND_TYPES here. The widget accesses the layer information from the store and add the legend for those layers where it has been specified.

  • Input:
Param Type Default Description
props Object
[props.className] string (optional) Material-UI withStyle class for styling

You can control the legend options through the following properties that must be added to the layerAttributes property for the layer in the store:

Param Type Default Description
title string Layer title
switchable boolean true Whether the layer can be hide/shown
legend Object Legend properties
legend.type string Legend type. Must be one of the types defined in the LEGEND_TYPES enum
legend.attr string Attribute used for styling the layer
legend.colors Array or string Array of colors (RGB arrays) or CARTO colors palette (string). Used for LEGEND_TYPES.CATEGORY, LEGEND_TYPES.BINS and LEGEND_TYPES.CONTINUOUS_RAMP
legend.labels Array - Array of strings for labels when using LEGEND_TYPES.CATEGORY and LEGEND_TYPES.ICON.
- Array of numbers for LEGEND_TYPES.BINS and LEGEND_TYPES.CONTINUOUS_RAMP. The first and last elements will be used for the labels and the intermediate elements will be used for defining the bins/intervals (for bins ramps) or the colors that we are interpolating (for continuous ramps).
- Array of [min, max] numbers for LEGEND_TYPES.PROPORTION.
legend.icons Array Array of string with icons URLs. Used for LEGEND_TYPES.ICON.
legend.note string Note to show below th legend to add additional explanations.
legend.collapsible boolean true Whether the legend is collapsible or not.
  • Example:

    If you want to show a legend for a layer, you need to define some layer attributes before you instantiate the layer. Here we are going to create a BINS type legend where we are assigning colors and labels to the different legend elements. We use the same colors in the CARTO for deck.gl colorBins helper when creating the layer. When data is loaded for the layer, we add the legend information from the layerConfig object to the layer attributes in the Redux store by dispatching the updateLayer action. We also manage the layer visibility through the visible attribute in the store:

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    
    import { LEGEND_TYPES } from "@carto/react-ui";
    import { updateLayer } from "@carto/react-redux";
    import { CartoLayer, colorBins } from "@deck.gl/carto";
    
    export const COLORS = [
      [247, 254, 174],
      [183, 230, 165],
      [124, 203, 162],
      [70, 174, 160],
      [4, 82, 117],
    ];
    
    export const LABELS = [
      '$100M',
      '$500M',
      '$1B',
      '$1.5B',
    ];
    
    const DATA = LABELS.map((elem, index) => {
      return { color: rgbToHex(COLORS[index]), label: elem };
    });
    
    const layerConfig = {
      title: 'Layer Name',
      visible: true,
      legend: {
        attr: 'revenue',
        type: LEGEND_TYPES.BINS,
        labels: DATA.map((data) => data.label),
        colors: DATA.map((data) => data.color),
      },
    };
    
    const { myLayer } = useSelector((state) => state.carto.layers);
    const source = useSelector((state) => selectSourceById(state, myLayer?.source));
    const cartoLayerProps = useCartoLayerProps({ source });
    
    if (myLayer && source) {
      return new CartoLayer({
        ...cartoLayerProps,
        id: MY_LAYER_ID,
        visible: myLayer.visible,
        getFillColor: colorBins({
          attr: layerConfig.legend.attr,
          domain: [100e6, 500e6, 1e9, 1.5e9],
          colors: COLORS,
        }),
        onDataLoad: () => {
          dispatch(
            updateLayer({
              id: MY_LAYER_ID,
              layerAttributes: { ...layerConfig },
            })
          );
        }
      });
    }
    

    Now you can add the LegendWidget component. In this example, the widget uses a custom CSS class.

    1
    2
    3
    4
    5
    
    import { LegendWidget } from "@carto/react-widgets";
    
    return (
      <LegendWidget className={myCSSClassName} />
    );
    

PieWidget

Renders a <PieWidget /> component, binded to a source at redux. The widget displays the calculations considering just the viewport features. From a data perspective, PieWidget would present a behaviour equivalent to CategoryWidget (groups or ‘categories’ from a column, with an aggregated calculation), but with a different UI.

  • Input:
Param Type Default Description
props Object
props.id string ID for the widget instance.
props.title string Title to show in the widget header.
props.dataSource string ID of the data source to get the data from.
props.column string Name of the data source’s column to get the data from.
props.operation string Operation to apply to the operationColumn. Must be one of those defined in AggregationTypes object.
props.height string 300px Height of the chart in CSS format.
[props.operationColumn] string Name of the data source’s column to operate with. If not defined it will default to the one defined in column.
[props.formatter] function (optional) formatterCallback: Function to format each value returned.
[props.tooltipFormatter] formatterCallback (optional) formatterCallback: Function to format the tooltip values.
[props.onError] errorCallback (optional) errorCallback: Function to handle error messages from the widget.
[props.wrapperProps] Object (optional) Extra props to pass to WrapperWidgetUI
  • Example:

    In this example, the widget would display a pie chart by continent with the SUM of population for all the countries in that continent

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    
    import { PieWidget } from "@carto/react-widgets";
    
    return (
      <PieWidget
        id="populationByContinent"
        title="Population by continent"
        dataSource="countriesSourceId"
        column="continent"
        operationColumn="population"
        operation={AggregationTypes.SUM}
      />
    );
    
    // The operationColumn wouldn't be required if using AggregationTypes.COUNT, to count the number of countries per continent
    

ScatterPlotWidget

Renders a <ScatterPlotWidget /> component, binded to a source at redux. The widget displays the calculations considering just the viewport features. From a data perspective, the ScatterPlotWidget represents two properties/columns in a cartesian chart from a data source to help understand if there is correlation between them.

  • Input:
Param Type Default Description
props Object
props.id string ID for the widget instance.
props.title string Title to show in the widget header.
props.dataSource string ID of the data source to get the data from.
props.xAxisColumn string Name of the data source’s column to get the data for the X axis from.
props.yAxisColumn string Name of the data source’s column to get the data for the Y axis from.
[props.xAxisFormatter] function (optional) formatterCallback: Function to format X axis values.
[props.yAxisFormatter] function (optional) formatterCallback: Function to format X axis values.
[props.tooltipFormatter] formatterCallback (optional) formatterCallback: Function to format the tooltip values.
[props.onError] errorCallback (optional) errorCallback: Function to handle error messages from the widget.
[props.wrapperProps] Object (optional) Extra props to pass to WrapperWidgetUI
  • Example:

    In this example, the widget would display the values from the size and revenue columns.

     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    
    import { ScatterPlotWidget } from "@carto/react-widgets";
    
    return (
      <ScatterPlotWidget
        id="sizeRevenueCorrelation"
        title="Size / Revenue"
        dataSource="storesSourceId"
        xAxisColumn="size"
        yAxisColumn="revenue"
      />
    );