Skip to content

Chart Type Selection and Query Configuration

This interactive example allows users to explore several chart types and also experiment with different groups, limits, sort directions, and metrics.

The initial chart below represents data from a Ticket Sales table residing in our Elasticsearch server. It shows the top 15 venue cities by total venue seats. Hover on chart elements to see tooltips with the appropriate metrics. Use the configuration panel to explore different charts and configurations.

If you'd like to see the demo in full screen click here

Review the complete source code and copy/paste it to create your own.
<!DOCTYPE html>
<html>
<head lang="en">
  <meta charset="UTF-8">
  <title>Chart Selection Demo</title>
  <link rel="stylesheet" href="style.css">
</head>
<body>
  <div id="chart" class="chart">
    <div id="chart"></div>
    <div class="loader"></div>
  </div>
  <div class="options-wrapper">
  <div class="options">
    <div class="card">
      <h4 class="card-header">Chart type</h4>
      <div class="card-body">
      <div class="property-container">
        <select id="chart-select" class="input-control">
          <option value="Bars" selected>Bars</option>
          <option value="Pie">Pie</option>
          <option value="Donut">Donut</option>
          <option value="Trend">Line Trend</option>
          <option value="Scatter Plot">Scatter Plot</option>
          <option value="Tree Map">Tree Map</option>
          <option value="Bars and Line">Bars and Line</option>
          <option value="Area Line">Area Line</option>
        </select>
      </div>
      </div>
    </div>
    <div class="card">
      <h4 class="card-header">Group by</h4>
      <div class="card-body">
        <div class="property-container">
          <label for="attribute-select">Attribute</label>
          <select id="attribute-select" class="input-control">
            <option value="venuecity.keyword" selected>Venue city</option>
            <option value="venuestate">Venue state</option>
            <option value="venuename.keyword">Venue name</option>
          </select>
        </div>
        <div class="property-container">
          <label for="attribute-limit">Limit</label>
          <input id="attribute-limit" class="input-control grid-input" type="number" step="1" value="10" min="1">
        </div>
        <div class="property-container">
          <label for="attribute-sort-dir">Sort</label>
          <select id="attribute-sort-dir" class="input-control">
            <option value="desc" selected>Desc</option>
            <option value="asc">Asc</option>
          </select>
        </div>
      </div>
    </div>
    <div id="time-card-ct" class="card"  style="display:none">
      <h4 class="card-header">Time group by</h4>
      <div id="time-card" class="card-body collapse">
        <div class="property-container">
          <label for="time-attribute-select">Field</label>
          <select id="time-attribute-select" class="input-control">
            <option value="saletime" selected>Sale time</option>
            <option value="starttime">Start time</option>
          </select>
        </div>
        <div class="property-container">
          <label for="time-attribute-limit">Limit</label>
          <input id="time-attribute-limit" class="input-control grid-input" type="number" step="1" value="1000" min="1">
        </div>
        <div class="property-container">
          <label for="time-attribute-func">Granularity</label>
          <select id="time-attribute-func" class="input-control">
            <option value="SECOND">Second</option>
            <option value="HOUR">Hour</option>
            <option value="DAY">Day</option>
            <option value="MONTH" selected>Month</option>
            <option value="YEAR">Year</option>
          </select>
        </div>
      </div>
    </div>
    <div class="card">
      <h4 class="card-header">Metric</h4>
      <div class="card-body">
        <div class="property-container">
        <label for="metric-select">Field</label>
        <select id="metric-select" class="input-control">
          <option value="commission" selected>Commission</option>
          <option value="pricepaid">Price paid</option>
          <option value="venueseats">Venue seats</option>
        </select>
        </div>
      <div class="property-container">
        <label for="metric-func-select">Function</label>
        <select id="metric-func-select" class="input-control">
          <option value="sum" selected>Sum</option>
          <option value="avg">Average</option>
          <option value="min">Min</option>
          <option value="max">Max</option>
        </select>
      </div>
      </div>
    </div>
    <div id="metric2-card-ct" class="card" style="display:none">
      <h4 class="card-header">2nd Metric</h4>
      <div id="metric2-card" class="card-body collapse">
        <div class="property-container">
          <label for="metric2-select">Field</label>
          <select id="metric2-select" class="input-control">
            <option value="venueseats">Venue seats</option>
            <option value="pricepaid" selected>Price paid</option>
            <option value="commission">Commission</option>
          </select>
        </div>
        <div class="property-container">
          <label for="metric2-func-select">Function</label>
          <select id="metric2-func-select" class="input-control">
            <option value="sum" selected>Sum</option>
            <option value="avg">Average</option>
            <option value="min">Min</option>
            <option value="max">Max</option>
          </select>
        </div>
      </div>
    </div>
    <div id="metric3-card-ct" class="card" style="display:none">
      <h4 class="card-header">3rd Metric</h4>
      <div id="metric3-card" class="card-body collapse">
        <div class="property-container">
          <label for="metric3-select">Field</label>
          <select id="metric3-select" class="input-control">
            <option value="venueseats">Venue seats</option>
            <option value="pricepaid">Price paid</option>
            <option value="commission" selected>Commission</option>
          </select>
      </div>
      <div class="property-container">
        <label for="metric3-func-select">Function</label>
        <select id="metric3-func-select" class="input-control">
          <option value="sum" selected>Sum</option>
          <option value="avg">Avg</option>
          <option value="min">Min</option>
          <option value="max">Max</option>
        </select>
      </div>
      </div>
    </div>
    </div>
  </div>
  </div>
  <script src="../assets/jquery.min.js"></script>
  <script src="../../lib/cftoolkit.min.js"></script>
  <script src="../assets/cft-elasticsearch-provider.min.js"></script>
  <script src="../assets/cft-standard-charts.min.js"></script>
  <script src="./index.js"></script>
</body>
</html>
var $ = window.$;
var cf = window.cf;

var hideLoader = function () {
    $('.loading').hide();
};

var updateChart = function (event) {
    var selectedChart = $('#chart-select').val();
    var hasTime = false;
    var selectedAttribute = $('#attribute-select').val();
    var limit = $('#attribute-limit').val();
    var sortDir = $('#attribute-sort-dir').val();
    var selectedTimeAttr = $('#time-attribute-select').val();
    var timeLimit = $('#time-attribute-limit').val();
    var timeFunc = $('#time-attribute-func').val();

    var selectedMetric = $('#metric-select').val();
    var selectedMetricFunc = $('#metric-func-select').val();

    var selectedMetric2 = $('#metric2-select').val();
    var selectedMetricFunc2 = $('#metric2-func-select').val();

    var selectedMetric3 = $('#metric3-select').val();
    var selectedMetricFunc3 = $('#metric3-func-select').val();

    // Define Attribute to group by
    var groups = [];

    // Define metric
    var metrics = [];

    if (['Trend', 'Area Line'].indexOf(selectedChart) > -1) {
        $('#time-card-ct').show();
        hasTime = true;
    } else {
        $('#time-card-ct').hide();
    }
    $('.loading').show();

    const countMetric = cf.Metric('count');

    metrics.push(cf.Metric(selectedMetric, selectedMetricFunc));
    if (['Scatter Plot'].indexOf(selectedChart) > -1) {
        metrics.push(cf.Metric(selectedMetric2, selectedMetricFunc2));
        metrics.push(cf.Metric(selectedMetric3, selectedMetricFunc3));
        $('#metric2-card-ct').show();
        $('#metric3-card-ct').show();
    } else if (['Bars and Line'].indexOf(selectedChart) > -1) {
        metrics.push(cf.Metric(selectedMetric2, selectedMetricFunc2));
        $('#metric2-card-ct').show();
    } else {
        $('#metric2-card-ct').hide();
        $('#metric3-card-ct').hide();
    }

    metrics.push(countMetric);

    groups.push(
        cf
        .Attribute(selectedAttribute)
        .limit(limit)
        .sort(sortDir, metrics[0])
    );
    if (hasTime) {
        if (['Trend', 'Area Line'].indexOf(selectedChart) > -1) {
            groups.unshift(
                cf
                    .Attribute(selectedTimeAttr)
                    .limit(parseInt(timeLimit, 10))
                    .func(timeFunc)
                    .sort('asc', selectedTimeAttr)
            );
        } else {
            groups.push(
                cf
                    .Attribute(selectedTimeAttr)
                    .limit(parseInt(timeLimit, 10))
                    .func(timeFunc)
                    .sort('asc', selectedTimeAttr)
            );
        }
    }

  // Obtain it by the element id and visualize

    cf
    .getVisualization('chart')
    .groupby(...groups)
    .metrics(...metrics)
    .graph(selectedChart)
    .set('legend', 'right')
    .execute()
    .then(function () {
        hideLoader();
    })
    .catch(function (e) { console.error(e); });
};

$(document).ready(function () {

    var providers = [{
        name: 'Elasticsearch',
        provider: 'elasticsearch',
        url: 'https://chartfactor.com/elastic'
    }];

    cf.setProviders(providers);

  // Here the chart is created, there's no need to assign
  // it to a variable if is not gonna be used in the moment
  // since it can be obtained from cf.getVisualization(elementId)
    cf
    .provider('Elasticsearch')
    .source('ticket_sales')
    .element('chart');

    updateChart();

    $('.options select,.options input').on('change', updateChart);
});
html {
  font-size: 12px;
}

@media only screen and (max-width: 760px) {
  .options {
    justify-content: left !important;
  }
}

.options {
  position: relative;
  display: flex;
  justify-content: center;
  min-width: 530px;
  margin-top: 5px;
  margin-bottom: 2px;
}

.card {
  margin: 0 2px;
}

.options-wrapper {
  width: 100vw;
  overflow-x: auto;
}

.card-body {
  padding: 6px;
  border-bottom: solid 1px;
  border-right: solid 1px;
  border-left: solid 1px;
  height: 35px;
}

.card-header {
  text-align: center;
  padding: 4px;
  color: white;
  background: #24282D;
  margin: 0;
}

.card-body {
  display: inline-flex;
}

.property-container {
  margin: 2px;
}

#attribute-limit, #time-attribute-limit {
  width: 50px;
}

#chart {
  height: calc(100% - 80px);
  width: 100%;
}

html, body {
  height: 100%;
  margin: 0;
  font-family: 'Lucida Sans', 'Lucida Sans Regular', 'Lucida Grande', 'Lucida Sans Unicode', Geneva, Verdana, sans-serif;
  -webkit-font-smoothing: antialiased;
}

.loader {
  position: absolute;
  top: calc(50% - 160px);
  left: calc(50% - 60px);
  border: 16px solid #f3f3f3;
  /* Light grey */
  border-top: 16px solid #24282D;
  /* Blue */
  border-radius: 50%;
  width: 120px;
  height: 120px;
  animation: spin 2s linear infinite;
}

@keyframes spin {
  0% {
      transform: rotate(0deg);
  }
  100% {
      transform: rotate(360deg);
  }
}

div::-webkit-scrollbar {
  width: 5px;
  height: 5px;
  border-radius: 5px;
}
div::-webkit-scrollbar-track-piece {
  background: #E9ECEF;
  border-radius: 5px;
}
div::-webkit-scrollbar-thumb {
  background: #888;
  border-radius: 5px;
}

The source code illustrates the steps to render a chart:

  1. Define the data provider
  2. Define attribute(s) to group by
  3. Define metrics to aggregate
  4. Define visualization type
  5. Define the DIV element where the chart will be rendered
  6. Finally, execute your chart definition

The Ticket Sales table is derived from the Amazon’s Sample Database for Redshift. The data represents ticket sales activity for the fictional TICKIT web site, where users buy and sell tickets online for different types of events.