Live-editing Chart Data

Sometimes we get the questions that go along like this “How do I hook up HTML controls to live chart data?”. While technically it’s beyond what charts do, we’re feeling generous, so let’s build a nice chart data editor. Shall we?

NOTE: If you don’t feel like parsing so many letters, you can jump right to this working example which is the final product of this article.

I’m gonna start by building a vanilla HTML table out of <input> tags, also populate with some initial data along the way: (I’m not gonna clutter the code with the CSS that goes with it, you will be able to grab the CSS from the final example linked at the bottom of this article or in the paragraph above)

<div id="data-table">
    <div class="data-row">
        <input class="data-cell data-category" value="USA" />
        <input class="data-cell data-value" value="4000" type="number" step="10" />
        <input class="data-button delete-button" type="button" value="X" />
    </div>
    <div class="data-row">
        <input class="data-cell data-category" value="China" />
        <input class="data-cell data-value" value="1882" type="number" step="10" />
        <input class="data-button delete-button" type="button" value="X" />
    </div>
    <div class="data-row">
        <input class="data-cell data-category" value="Japan" />
        <input class="data-cell data-value" value="1809" type="number" step="10" />
        <input class="data-button delete-button" type="button" value="X" />
    </div>
    <div class="data-row">
        <input class="data-cell data-category" value="Germany" />
        <input class="data-cell data-value" value="1322" type="number" step="10" />
        <input class="data-button delete-button" type="button" value="X" />
    </div>
    <div class="data-row">
        <input class="data-cell data-category" value="UK" />
        <input class="data-cell data-value" value="1122" type="number" step="10" />
        <input class="data-button delete-button" type="button" value="X" />
    </div>
</div>
<br/>
<input type="button" value="Add Row" onclick="addRow()" class="data-button" id="add-row" />

We get a nice table, complete with data entry controls, row removal buttons and a button to add new rows:

Screenshot-2013-08-30_13.07.37_thumb[2]

Now let’s add some life to this nice little control:

  • Hook up events to inputs so we catch whenever category or value is changed;
  • Attach click event to [X] buttons;
  • Make the “Add Row” button, well… add new row.

Note: For the sake of simplicity, I’m using jQuery here. Feel free to adapt to your JS library of choice.

Let’s break the above code down.

First we call initRowEvents function on all of the document. jQuery(function () {}) makes sure this happens only when the document is fully loaded)

initRowEvents does these things:

  • Finds all inputs with the class "data-cell", then
  • attaches title parameter so it is displayed on mouse hover;
  • binds keypress, keyup and change events to update the chart whenever their content is updated;
  • Finds all buttons with class "delete-button" and binds the code to both remove the related line and update the chart to reflect the new data.

More on updating the chart after data change later, now let’s look at our custom function addRow(). First it creates a new element for the data row, complete with input fields and delete button. Then it appends the newly created element to our table body. And finally it calls the initRowEvents you already know so that the same events are added to controls it just added.

The actual code, that updates and reloads the chart is just these two lines:

chart.dataProvider = generateChartData();
chart.validateData();

The first one calls the function generateChartData() and set chart.dataProvider property. The second one instructs the chart to take in the new data with a chart.validateData() call.

And here we come to the final piece of the puzzle: generateChartData() function.

jQuery(function () {
    // initialize the table
    initRowEvents(jQuery(document));
});

function initRowEvents(scope) {
    scope.find('.data-cell').attr('title', 'Click to edit').on('keypress keyup change', function () {
        // re-generate chart data and reload it in chart
        chart.dataProvider = generateChartData();
        chart.validateData();
    }).end().find('.delete-button').click(function () {
        // remove the row
        $(this).parents('.data-row').remove();
        // re-generate chart data and reload it in chart
        chart.dataProvider = generateChartData();
        chart.validateData();
    });
}

function addRow() {
    jQuery('<div class="data-row"><input class="data-cell data-category"/><input class="data-cell data-value" type="number" step="10"/><input class="data-button delete-button" type="button" value="X"/></div>').appendTo('#data-table').each(function () {
        initRowEvents(jQuery(this));
    });
}

Once again, we use the all-wonderful jQuery to iterate through each "data-row", take values for both category and value fields and assemble into chartData array.

That’s it.

I’m not going to post the whole code here. Just head over to the following live example on jsFiddle to the complete JavaScript code, HTML and related CSS.

Once again, the purpose of these tutorials is to show what you can do with just a little effort. To broaden the horizons of the possibilities. We do not aim at providing run-of-the-mill ready-made solutions. We’re just showing you the path, the actual walking is up to you.