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.
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"]); } } }
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:
private var _edit:EditTable;
_edit = new EditTable(_data, _graph); _edit.y = 500; _edit.x = 25; addChild(_edit);
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; } } }
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); }
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.
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.
We've just described the basic components of an interactive graph. There are of course many things that you'll want to customize.
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.
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.
3.15.27.232