A dynamic graph based on an editable table

In this chapter, we are going to combine a few of the previous recipes and make a graph editable by showing a table to the user in which he can change the values at will.

We'll use the infrastructure that was created in the Sending data updates to the graph recipe in this chapter, to send new data to the graph.

Getting ready

This recipe starts from virtually the same class, only now we've freed up some screen space underneath the graph where we will put the editable table:

package com.graphing.dynamictable
{
    import flash.display.Sprite;
    import com.graphing.PointGraph;
    public class Recipe5 extends Sprite
    {
        private var _graph:PointGraph;
        private var _data:Array = [[0, 20], [50, 70], [100, 0], [150, 150], [200, 300], [250, 200], [300, 400], [350, 20], [400, 60], [450, 250], [500, 90], [550, 400], [600, 500], [650, 450], [700, 320]];

        public function Recipe5() 
        {
            _graph = new PointGraph();
            _graph.data = _data;
            _graph.graphWidth = 800;
            _graph.graphHeight = 480;
            _graph.graphLeft = -50;
            _graph.graphRight = 750;
            _graph.graphTop = 550;
            _graph.graphBottom = -50;
            _graph.createGraph();
            addChild(_graph);

            _graph.drawHorizontalAxis(0, 0, 700, 50, ["0", "700"]);
            _graph.drawVerticalAxis(0, 0, 500, 40, ["0", "250", "500"]);
        }
    }
}

How to do it...

To keep things tidy, we're going to put all code related to a new class called EditTable. Let's first add it to the display:

  1. Add a private property that will hold the display:
    private var _edit:EditTable;
  2. And initialize it in the constructor:
    _edit = new EditTable(_data, _graph);
    _edit.y = 500;
    _edit.x = 25;
    addChild(_edit);
  3. Now create a new class called EditTable and have it implement Sprite. We will also store the references to the data and graph in private fields so we can use them later:
    package com.graphing.dynamictable {
        import com.graphing.PointGraph;
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.text.TextField;
        import flash.text.TextFieldAutoSize;
        public class EditTable extends Sprite {
            private var _data:Array;
            private var _graph:PointGraph;
    
            public function EditTable(data:Array, graph:PointGraph) {
                _data = data;
                _graph = graph;
            }
        }
    }
  4. Now we add the display of the values in a grid underneath the graph. In the EditTable constructor add this loop:
    for (var i:int = 0; i < data.length; i++)
    {
        var tf:TextField = new TextField();
        tf.text = data[i][1];
        tf.width = 48;
        tf.height = 20;
        tf.border = true;
        tf.type = "input";
        tf.x = i * 50;
        tf.addEventListener(Event.CHANGE, onChange);
        addChild(tf);
    }
  5. You may have noticed that we added a change listener. So we need to implement it:
    private function onChange(event:Event):void {
        var field:TextField = event.target as TextField;
        var index:int       = getChildIndex(field);
        var value:Number    = Number(field.text);
    
            _data[index] = [index * 50, value];
    
            _graph.updateData(_data);
    }

    Run the program and you should see a grid that you can change at will. The changes will be reflected as you type in the graph.

How it works...

The recipe's main functionality is split into two parts: drawing the editable table and executing the updates.

The table is drawn in the constructor and uses TextField objects. To keep the code compact we use mostly standard fields, but all the customizations that we've seen can be done here too.

Setting the field's type to input will turn it into a field that can be edited. In the case of editable fields, it's usually a good idea to show the border. When the user deletes all the data in the field, the field would no longer be visible without a border.

The change listener is fired every time the text inside the field changes.

The listener finds the position of the field in the display list. This position is the same as the position of the data point in the data set. This is because we used a for loop in the constructor to go from one point to the next. If you use other techniques to draw the table or add more elements, keep that in mind.

Finally we cast the input to a number, update the data set, and send it to the graph. You may want to do some data validation here in a real program.

There's more...

We've just described the basic components of an interactive graph. There are of course many things that you'll want to customize.

Data validation

Though mentioned at the end of the previous section, data validation should not be underestimated. It is very valuable for a user to get feedback on why something isn't working.

So you may want to change the border of the field to red and add some popup text when a user enters invalid data.

Zoom/pan on entry

In the recipe, if you enter data that is outside of the current view, you won't be able to see it. You can add the zooming and panning code from the Zooming and panning around the graph recipe. You can also automatically recalculate the zoom level based on the user's input data so everything is visible at all times.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.15.27.232