• Jump To … +
    butterfly_example.ts flamechart_sunburst_example.ts legend_example.ts pie_example.ts plot_area_example.ts plot_zoom_example.ts sankey_example.ts scatterplot_example.ts stack_example.ts swimlanes_example.ts sync_example.ts table_searchable_example.ts table_selectable_example.ts table_sortable_example.ts timeline_example.ts worldbank_example.ts
  • ¶

    C3 Searchable Table

    A table of country data that is sortable, paginated, and searchable.

  • ¶

    Remember the column to specify sorting by it.

    var gdp_column: c3.Table.Column<CountryData>;
  • ¶

    Keep track of the country we searched for

    var match_country: CountryData;
  • ¶

    Create the Data Table

  • ¶

    Create a c3.Table object and set its options. Bind to an anchor DOM element using a string selector.

    var country_table: c3.Table<CountryData> = new c3.Table<CountryData>({
        anchor: '#country_table_example',
  • ¶

    Enable the user to sort this table.

        sortable: true,
  • ¶

    Limit the table to only show pages of 4 at a time, and enable pagination to change pages.

        limit_rows: 10,
        pagination: true,
  • ¶

    Make the table searchable

        searchable: true,
  • ¶

    Create an array of column objects to describe the table columns.

        columns: [
            {
                header: { text: "Country" },
                cells: { html: (country) => '<b>' + country.name + '</b>' },
            }, {
  • ¶

    These columns use custom formatters to set the html content of the cell adding commas, units, rounding, etc. You can add raw HTML if you like. These column also use the vis visualization support to render a bar graph based on the cell value.

                header: { text: "Population" },
                cells: { text: (country) => d3.format(',')(country.population) },
                sort: (country) => country.population,
                vis: 'bar',
            }, {
                header: { text: "Urbanization" },
                cells: { text: (country) => country.urban_population.toFixed(1)+'%' },
                sort: (country) => country.urban_population,
                vis: 'bar',
                total_value: 100,
            }, {
                header: { text: "Land Area" },
                cells: { html: (country) => (d3.format(',')(Math.round(country.land_area))) + "km<sup>2</sup>" },
                sort: (country) => Math.round(country.land_area),
                vis: 'bar',
            },
  • ¶

    Assign this column to a variable gdp_column so we can refer to it below for setting the default sort.

            gdp_column = {
                header: { text: "GDP" },
                cells: { text: (country) => "$" + (d3.format(',')(Math.round(country.gdp))) + "m" },
                sort: (country) => Math.round(country.gdp),
                vis: 'bar',
            }, {
  • ¶

    By default, the bar visualization will base the bar width as a percentage of the total value of all cells. This isn’t always appropriate, though, such as in the case of GDP per capita. So, here we manually set the total_value to be the maximum per capita value. Look out for Monaco!

                header: { text: "GDP per capita" },
                cells: { html: (country) => "$" + (d3.format(',')(Math.round(country.gdp_per_capita))) },
                sort: (country) => Math.round(country.gdp_per_capita),
                vis: 'bar',
                total_value: function () { return d3.max(country_table.data, (country) => country.gdp_per_capita); },
            },
        ],
  • ¶

    Configure the initial column to sort the data on based on the column varible x_column we created above.

        sort_column: gdp_column,
  • ¶

    Style the row with class match if the country matches the one found in the search. match_country is set in the match handler below.

        row_options: {
            classes: {
                'match': (country)=> country === match_country,
            },
        },
  • ¶

    Add an event handler to highlight which row was found in a search

        handlers: {
            match: function(search, found_country, i) {
                match_country = found_country;
                this.redraw();
            },
        },
    });
  • ¶

    Modify Table Options

  • ¶

    Limit the number of rows

    document.querySelector('#limit_rows').addEventListener('change', function () {
        country_table.limit_rows = this.checked ?
            +(<HTMLInputElement>document.querySelector('#number_of_rows')).value : undefined;
        country_table.redraw();
    });
    document.querySelector('#number_of_rows').addEventListener('change', function () {
        country_table.limit_rows = (<HTMLInputElement>document.querySelector('#limit_rows')).checked ? 
            +this.value : undefined;
        country_table.redraw();
    });
  • ¶

    Enable pagination to select a different page

    document.querySelector('#pagination').addEventListener('change', function () {
        country_table.pagination = this.checked;
        country_table.redraw();
    });
  • ¶

    Set how many pages are shown in the paginator

    document.querySelector('#number_of_pages').addEventListener('change', function () {
        country_table.max_pages_in_paginator = +this.value;
        country_table.redraw();
    });
  • ¶

    Allow table to be searchable if table isn’t paginated

    document.querySelector('#searchable_if_not_paginated').addEventListener('change', function () {
        country_table.searchable_if_not_paginated = this.checked;
        country_table.redraw();
    });
  • ¶

    Load the Country Data

  • ¶

    The interface is just a type definition for TypeScript. Ignore this for JavaScript.

    interface CountryData {
        name: string;
        code: string;
        population: number;
        urban_population: number;
        gdp: number;
        gdp_per_capita: number;
        land_area: number;
    }
  • ¶

    Load the country CSV data using D3. This loads and merges the data from multiple tables. The data is loaded this way to work with the file format as provided by the World Bank data source.

    d3.csv('data/countries.csv')
        .row((row) => ({
            name: row['name'],
            code: row['world_bank_code'],
        })).get((error, countries:CountryData[]) => {
            var country_lookup = {};
            countries.filter((row) => !!row.code).forEach((row) => {
                country_lookup[row.code] = row;
            });
  • ¶

    Load the country data statistics for the year 2000 from the World Bank data format.

            d3.csv('data/gdp.csv')
                .row((row) => ({
                    country_name: row['Country Name'],
                    country_code: row['Country Code'],
                    indicator: row['Indicator Code'],
                    value: +row['Value'],
                    year: +row['Year'],
                })).get((error, rows) => {
                    var indicator_mapping = {
                        'SP.POP.TOTL': 'population',
                        'EN.URB.MCTY.TL.ZS': 'urban_population',
                        'AG.LND.TOTL.K2': 'land_area',
                        'NY.GDP.MKTP.CD': 'gdp',
                        'NY.GDP.PCAP.CD': 'gdp_per_capita',
                    };
                    for (let row of rows) {
                        if (!row.country_code) continue;
                        if (row.year !== 2000) continue;
                        if (!(row.indicator in indicator_mapping)) continue;
  • ¶

    Convert GDP to millions of dollars

                        if (indicator_mapping[row.indicator] === 'gdp') row.value /= 1000000;
                        country_lookup[row.country_code][indicator_mapping[row.indicator]] = row.value;
                    }
  • ¶

    Setup the table the data and render!

                    d3.selectAll('#loading').remove();
                    country_table.data = countries.filter((country) => country.gdp > 0.000000001);
                    country_table.render();
                });
        });