In this recipe we focus on enriching the data display itself. When the user puts the mouse cursor over one of the points, we want to emphasize that point and show a small popup that displays more information about that point.
For example, we display the exact coordinates, but in a real-life application, you may want to show many other types of information. For instance, in a map display, you can show more information on the location that's beneath the cursor. In a results display, you might only show the average results, but when hovering over a point, you can also show the highest and lowest values.
We will start from the class that we have seen many times before:
package com.graphing.hover { import flash.display.Sprite; import com.graphing.PointGraph; public class Recipe3 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 Recipe3() { _graph = new PointGraph(); _graph.data = _data; _graph.graphWidth = 800; _graph.graphHeight = 600; _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, 50, ["0", "250", "500"]); } } }
First we will restructure the PointGraph
code a bit, so that it's a little more modular and we can add some of the functionality more easily.
Let's extract the actual
point shape into a new class, called PointGraphPoint
(our first idea was to call this class simply point
but that would have caused a lot of confusion with ActionScript's built-in point
class):
PointGraphPoint
class:package com.graphing { import flash.display.Sprite; import flash.events.Event; import flash.events.MouseEvent; import flash.geom.Point; public class PointGraphPoint extends Sprite { public function PointGraphPoint(point:Point, color:uint) { graphics.beginFill( color , 1 ); graphics.drawCircle( 0 , 0 , 5 ); x = point.x; y = point.y; } } }
drawPoint
method of the PointGraph
class:public function drawPoint(x:Number, y:Number, color:uint = 0xff9933):PointGraphPoint { var transformedLocation:Point = _matrix.transformPoint(new Point(x, y)); var point:PointGraphPoint = new PointGraphPoint(transformedLocation, color); addChild(point); return point; }
Now let's add a little zoom animation. When the user hovers the mouse over the point, it should become slightly bigger to emphasize it. This effect can be obtained fairly easily.
PointGraphPoint
class's constructor start listening for the mouse over and out events:addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
private function onMouseOver(event:MouseEvent):void { scaleX = 1.5; scaleY = 1.5; } private function onMouseOut(event:MouseEvent):void { scaleX = 1; scaleY = 1; }
Now let's show a message when the mouse is over a point in the graph. For this recipe, we want to show the coordinates of the point, so the user doesn't have to use the axes to find out.
To display the information, we create a separate class.
HoverInfo
with the following code:package com.graphing.hover { import flash.display.Sprite; import flash.text.TextField; public class HoverInfo extends Sprite { private var _text:TextField; public function HoverInfo() { _text = new TextField(); _text.text = "info"; _text.x = 5; _text.y = -20; addChild(_text); } public function set text(value:String):void { _text.text = value; } } }
Recipe3
class:private var _hoverInfo:HoverInfo = new HoverInfo();
Recipe3
constructor:_graph.addEventListener(MouseEvent.MOUSE_OVER, onMouseOver); _graph.addEventListener(MouseEvent.MOUSE_OUT, onMouseOut);
private function onMouseOver(event:MouseEvent):void { if (event.target is PointGraphPoint) { addChild(_hoverInfo); _hoverInfo.text = event.target.message; _hoverInfo.x = event.target.x; _hoverInfo.y = event.target.y; } } private function onMouseOut(event:MouseEvent):void { if (_hoverInfo.parent != null) { removeChild(_hoverInfo); } }
You may have noticed that the actual text we display is taken from event.target.message
. The event.target
event is the PointGraphPoint
class in this case, so we still need to add this field to it:
public var message:String;
Now it's a matter of filling up the point's message field with the message you'd like to show. In this case, we do this in the drawPoint
method of the PointGraph
class:
point.message = "(" + x + "," + y + ")";
In this recipe, we've attached the event listeners in two ways. It's a good idea to know the two options and apply them as you see fit:
PointGraphPoint
class.DisplayList
hierarchy. In this case, only two listeners are needed, which can service the entire graph.The second approach results in a more complicated and potentially a more confusing code. So in general, the first way is preferable, but it's good to know the options.
We also showed a slight performance optimization in how the HoverInfo
class is used. We only instantiate it once and re-use it when information is displayed. Since the user's mouse pointer can only be over one point, this technique works. If you want to create something similar, where multiple information boxes will be displayed (for instance on a multi-touch display), you will need to adapt the approach.
This recipe can be extended in many ways.
In the case of this recipe, we decided to attach the message directly to the data point. In many cases, this may not be possible, but you will need at least a way to identify the individual point, otherwise there's no way to know what message to show (unless it's always the same).
In general, you will probably replace the message field by an object that can hold any kind of data. For instance, if you are showing a time based graph, you could put the time in there and show a message based on that. Or you could put a database ID in the field and use it to look up information from the database when the user hovers over the point.
18.222.109.141