[Ovirt-devel] [PATCH server] Add time range and data type selection to flexchart.

Steve Linabery slinabery at redhat.com
Thu Nov 20 15:52:20 UTC 2008


Also:
-change color scheme to match tallen prototype pallette
-change SingleBar elements to dynamically resized Canvas objects instead of
  HBox objects
-add new route to accept second-resolution timestamps for time range selection
---
 src/app/controllers/graph_controller.rb        |   59 ++++-
 src/app/util/stats/StatsTypes.rb               |    8 +-
 src/app/views/graph/history_graphs.rhtml       |    2 +-
 src/config/routes.rb                           |    1 +
 src/flexchart/flexchart.mxml                   |   12 +-
 src/flexchart/org/ovirt/ApplicationBus.as      |   39 ++++
 src/flexchart/org/ovirt/Constants.as           |    2 +-
 src/flexchart/org/ovirt/DataSource.as          |    7 +-
 src/flexchart/org/ovirt/charts/BarChart.as     |  287 ++++++++++++++++++------
 src/flexchart/org/ovirt/charts/Chart.as        |   38 +++-
 src/flexchart/org/ovirt/data/DataPoint.as      |    7 +-
 src/flexchart/org/ovirt/data/DataSeries.as     |   12 +-
 src/flexchart/org/ovirt/elements/SingleBar.as  |   51 ++++-
 src/flexchart/org/ovirt/elements/XAxisLabel.as |   66 ++++++
 src/flexchart/org/ovirt/elements/YAxisLabel.as |   17 +--
 15 files changed, 476 insertions(+), 132 deletions(-)
 create mode 100644 src/flexchart/org/ovirt/ApplicationBus.as
 create mode 100644 src/flexchart/org/ovirt/elements/XAxisLabel.as

diff --git a/src/app/controllers/graph_controller.rb b/src/app/controllers/graph_controller.rb
index 0105ea6..d636544 100644
--- a/src/app/controllers/graph_controller.rb
+++ b/src/app/controllers/graph_controller.rb
@@ -4,20 +4,53 @@ class GraphController < ApplicationController
   layout nil
 
   def flexchart_data
-
-    #FIXME: use the stats package aggregation (when it's available)
-    #instead of the old method
-    graph_obj = history_graph_data_object
-
-    #FIXME: for this release, the flexchart shows only peak values,
-    #       and only shows a default of the last 40 data points in rrd.
-    graph_data = { :labels => graph_obj[:timepoints].last(40),
-                   :values => graph_obj[:dataset][2][:values].last(40) }
-    my_data = graph_data[:labels].zip(graph_data[:values])
-    graph = { :vectors => my_data,
-              :max_value => graph_obj[:total_peak],
-              :description => params[:target]
-            }
+    @id = params[:id]
+    target = params[:target]
+    startTime = params[:startTime].to_i
+    endTime = params[:endTime].to_i
+    duration = endTime - startTime
+
+    #the maximum number of data points we want in any chart
+    maxPoints = 100
+    resolution =
+      case
+      when duration / RRDResolution::Minimum < maxPoints
+        RRDResolution::Minimum
+      when duration / RRDResolution::Short < maxPoints
+        RRDResolution::Short
+      when duration / RRDResolution::Medium < maxPoints
+        RRDResolution::Medium
+      when duration / RRDResolution::Long < maxPoints
+        RRDResolution::Long
+      else
+        RRDResolution::Maximum
+      end
+    devclass = DEV_KEY_CLASSES[target]
+    counter = DEV_KEY_COUNTERS[target]
+
+    #FIXME: until stats aggregation is pushed, we just get stats data for
+    # the first host in the pool. If no host in pool, the chart will be
+    # empty.
+    pool = Pool.find(@id)
+    hosts = pool.hosts
+    host = pool.hosts[0]
+    requestList = [ ]
+    requestList.push StatsRequest.new(host.hostname, devclass, 0, counter, startTime, duration, resolution, DataFunction::Peak)
+    statsList = getStatsData?(requestList)
+
+    #The aggregated (summed) stats will come back as a single stats list
+    stat = statsList[0]
+    vectors = [ ]
+    data = stat.get_data?
+    data.each{ |datum|
+      val = datum.get_value?
+      val = 0 if val.nan?
+      vectors.push [datum.get_timestamp?.to_i, val]
+    }
+    graph = { :vectors => vectors,
+      :max_value => stat.get_max_value?,
+      :description => target
+    }
     render :json => graph
   end
 
diff --git a/src/app/util/stats/StatsTypes.rb b/src/app/util/stats/StatsTypes.rb
index 41c2977..4896bb3 100644
--- a/src/app/util/stats/StatsTypes.rb
+++ b/src/app/util/stats/StatsTypes.rb
@@ -324,10 +324,12 @@ class RRDResolution
    end
 
    # Set up the resolutions for our rrd
+   RRDResolution.add_item :Minimum, 10    # Ten secs
+   RRDResolution.add_item :Short,   70    # Seventy secs
+   RRDResolution.add_item :Medium,  500   # 500 secs ( 8minute, 20 sec)
+   RRDResolution.add_item :Long,    2230
+   RRDResolution.add_item :Maximum, 26350
    RRDResolution.add_item :Default, 10    # Ten secs
-   RRDResolution.add_item :Short, 500     # 500 secs ( 8minute, 20 sec)
-   RRDResolution.add_item :Medium, 2230
-   RRDResolution.add_item :Long, 26350
 end
 
        
diff --git a/src/app/views/graph/history_graphs.rhtml b/src/app/views/graph/history_graphs.rhtml
index bebe5d9..97ed67f 100644
--- a/src/app/views/graph/history_graphs.rhtml
+++ b/src/app/views/graph/history_graphs.rhtml
@@ -10,7 +10,7 @@ $('#flex_history_chart').flash(
           height: 300,
           wmode: 'transparent',
           menu: false,
-          flashvars: { flexchart_data: "<%= url_for :controller =>'/graph', :action => 'flexchart_data' %>/<%= @id %>/memory/1" }
+          flashvars: { flexchart_data: "<%= url_for :controller =>'/graph', :action => 'flexchart_data' %>/<%= @id %>/memory/<%= Time.now.to_i - 60 * 60 * 24 %>/<%= Time.now.to_i %>" }
         },
         { version: 9 }
     );
diff --git a/src/config/routes.rb b/src/config/routes.rb
index 8d538cb..0dbe0d6 100644
--- a/src/config/routes.rb
+++ b/src/config/routes.rb
@@ -41,6 +41,7 @@ ActionController::Routing::Routes.draw do |map|
   map.connect ':controller/service.wsdl', :action => 'wsdl'
 
   # Install the default route as the lowest priority.
+  map.connect 'graph/flexchart_data/:id/:target/:startTime/:endTime', :controller => 'graph', :action => 'flexchart_data'
   map.connect 'graph/flexchart_data/:id/:target/:days', :controller => 'graph', :action => 'flexchart_data'
   map.connect ':controller/:action/:id.:format'
   map.connect ':controller/:action/:id'
diff --git a/src/flexchart/flexchart.mxml b/src/flexchart/flexchart.mxml
index 35fa9a6..c4a089f 100644
--- a/src/flexchart/flexchart.mxml
+++ b/src/flexchart/flexchart.mxml
@@ -6,6 +6,7 @@
     import mx.containers.VBox;
     import mx.effects.Resize;
     import org.ovirt.Constants;
+    import org.ovirt.ApplicationBus;
     import org.ovirt.charts.Chart;
     import org.ovirt.charts.BarChart;
 
@@ -21,6 +22,7 @@
     private var contractResources:Resize = new Resize();
 
     private function myInit():void {
+
       mainChart.height = Constants.height;
       mainChart.width = Constants.width;
       hostsChart.width = Constants.width;
@@ -42,6 +44,9 @@
       contractResources.heightTo = 0;
       contractResources.target = hostsChart;
       contractResources.duration = 500;
+
+      ApplicationBus.instance().barClickAction = zoomIntoSeries;
+
     }
 
     private function zoomOutSeries(e:Event):void {
@@ -61,7 +66,8 @@
 
   </mx:Script>
 
-  <mx:VBox id="mainChart"  click="zoomIntoSeries(event)" />
-  <mx:VBox id="hostsChart" visible="false" opaqueBackground="0x00ff00" click="zoomOutSeries(event)"/>
-
+  <mx:VBox id="mainChart" />
+  <mx:VBox id="hostsChart" visible="false" opaqueBackground="0x00ff00" click="zoomOutSeries(event)">
+    <mx:Text text="This Space Reserved for Drill-down Hosts Chart" />
+  </mx:VBox>
 </mx:Application>
diff --git a/src/flexchart/org/ovirt/ApplicationBus.as b/src/flexchart/org/ovirt/ApplicationBus.as
new file mode 100644
index 0000000..7d6d431
--- /dev/null
+++ b/src/flexchart/org/ovirt/ApplicationBus.as
@@ -0,0 +1,39 @@
+/*
+ Copyright (C) 2008 Red Hat, Inc.
+ Written by Steve Linabery <slinabery at redhat.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA  02110-1301, USA.  A copy of the GNU General Public License is
+ also available at http://www.gnu.org/copyleft/gpl.html.
+*/
+
+//A way to expose some functions that are defined in flexchart.mxml to
+//our ActionScript classes without needing to access Application directly
+
+package org.ovirt {
+  public class ApplicationBus {
+
+    private static var _instance:ApplicationBus;
+
+    public static function instance():ApplicationBus {
+      if (_instance == null) {
+        _instance = new ApplicationBus();
+      }
+      return _instance;
+    }
+
+    public var barClickAction:Function;
+
+  }
+}
diff --git a/src/flexchart/org/ovirt/Constants.as b/src/flexchart/org/ovirt/Constants.as
index 996a31e..14f6465 100644
--- a/src/flexchart/org/ovirt/Constants.as
+++ b/src/flexchart/org/ovirt/Constants.as
@@ -23,6 +23,6 @@ package org.ovirt {
     public static var width:int = 722;
     public static var height:int = 297;
     public static var barSpacing:int = 2;
-    public static var labelHeight:int = 40;
+    public static var labelHeight:int = 20;
   }
 }
diff --git a/src/flexchart/org/ovirt/DataSource.as b/src/flexchart/org/ovirt/DataSource.as
index 44e482d..4438900 100644
--- a/src/flexchart/org/ovirt/DataSource.as
+++ b/src/flexchart/org/ovirt/DataSource.as
@@ -20,13 +20,13 @@
 
 package org.ovirt {
 
-  import flash.net.URLLoader;
-  import flash.net.URLRequest;
   import com.adobe.serialization.json.JSON;
   import flash.events.Event;
   import flash.events.IOErrorEvent;
-  import org.ovirt.data.DataSeries;
+  import flash.net.URLLoader;
+  import flash.net.URLRequest;
   import org.ovirt.charts.Chart;
+  import org.ovirt.data.DataSeries;
 
   public class DataSource {
 
@@ -52,6 +52,7 @@ package org.ovirt {
     }
 
     private function ioError( e:IOErrorEvent ):void {
+      trace("ioError");
       //FIXME:
       //do something useful with this error
     }
diff --git a/src/flexchart/org/ovirt/charts/BarChart.as b/src/flexchart/org/ovirt/charts/BarChart.as
index 83cf0bb..88a75ca 100644
--- a/src/flexchart/org/ovirt/charts/BarChart.as
+++ b/src/flexchart/org/ovirt/charts/BarChart.as
@@ -19,40 +19,127 @@
 */
 
 package org.ovirt.charts {
-
+  import flash.events.Event;
+  import flash.events.MouseEvent;
+  import mx.collections.ArrayCollection;
   import mx.containers.Box;
   import mx.containers.HBox;
   import mx.containers.VBox;
-  import mx.controls.Text;
   import mx.containers.Canvas;
+  import mx.controls.TextInput;
+  import mx.controls.DateField;
+  import mx.controls.Button;
+  import mx.controls.PopUpMenuButton;
+  import mx.controls.Text;
+  import mx.events.MenuEvent;
+  import mx.formatters.DateFormatter;
   import org.ovirt.data.*;
   import org.ovirt.elements.*;
   import org.ovirt.Constants;
+  import org.ovirt.ApplicationBus;
 
   public class BarChart extends Chart {
 
-    private var chartArea:HBox;
-    private var labelArea:Canvas;
+    private var chartArea:Canvas;
+    private var XAxisLabelArea:Canvas;
+    private var startDateField:DateField;
+    private var endDateField:DateField;
+    private var startTimeField:TextInput;
+    private var endTimeField:TextInput;
+    private var button:Button;
+    private var menu:PopUpMenuButton;
+    private var dateBar:Box;
+    private var datePattern:RegExp;
+
 
     public function BarChart(container:Box,
                              datasourceUrl:String) {
       super(container,datasourceUrl);
-      chartArea = new HBox();
-      chartArea.setStyle("horizontalGap",Constants.barSpacing);
-      chartArea.setStyle("verticalAlign","bottom");
+      container.setStyle("verticalGap","2");
+      datePattern = /^(\d+):(\d+)$/;
+    }
+
+
+    private function timeRangeAdjusted(event:Event):void {
+      var t1:Number = startDateField.selectedDate.getTime()
+                      + (parseHour(startTimeField.text) * 3600 * 1000)
+                      + (parseMinute(startTimeField.text) * 60 * 1000);
+      setStartTime(Math.floor(t1 / 1000));
+      var t2:Number = endDateField.selectedDate.getTime()
+                      + (parseHour(endTimeField.text) * 3600 * 1000)
+                      + (parseMinute(endTimeField.text) * 60 * 1000);
+      setEndTime(Math.floor(t2 / 1000));
+      load();
+    }
+
+    private function typeSelected(event:MenuEvent):void {
+      target = event.label;
+      load();
+    }
+
+
+    private function pad(input:int):String {
+      if (input < 10) {
+        return "0" + input;
+      } else {
+        return "" + input;
+      }
+    }
+
+    private function parseHour(input:String):int {
+      var answer:int = 0;
+      try {
+        var obj:Object = datePattern.exec(input);
+        if (obj != null) {
+          answer = int(obj[1].toString());
+        }
+      } catch (e:Error) {}
+      return answer;
+    }
+
+    private function parseMinute(input:String):int {
+      var answer:int = 0;
+      try {
+        var obj:Object = datePattern.exec(input);
+        if (obj != null) {
+          answer = int(obj[2].toString());
+        }
+      } catch (e:Error) {}
+      return answer;
+    }
+
+    override public function addData(dataSeries:DataSeries):void {
+      container.removeAllChildren();
+
+      var dateFormat:DateFormatter = new DateFormatter();
+
+      //since we're reusing objects, we need to get rid of stale
+      //EventListener references
+      if (chartArea != null) {
+        var kids:Array = chartArea.getChildren();
+        var i:int;
+        for (i = 0; i < kids.length; i++) {
+          (kids[i] as SingleBar).destroy();
+        }
+      }
+
+      chartArea = new Canvas();
       chartArea.percentHeight = 80;
       chartArea.percentWidth = 100;
+      chartArea.setStyle("backgroundColor","0xbbccdd");
       this.container.addChild(chartArea);
 
-      labelArea = new Canvas();
-      labelArea.height = Constants.labelHeight;
-      labelArea.minHeight = Constants.labelHeight;
-      labelArea.percentWidth = 100;
-      this.container.addChild(labelArea);
-    }
+      XAxisLabelArea = new Canvas();
+      XAxisLabelArea.height = Constants.labelHeight;
+      XAxisLabelArea.minHeight = Constants.labelHeight;
+      XAxisLabelArea.percentWidth = 100;
+      this.container.addChild(XAxisLabelArea);
 
-    override public function addData(dataSeries:DataSeries):void {
       try {
+
+        dateBar = new HBox();
+        dateBar.setVisible(true);
+        this.container.addChild(dateBar);
         var dataPoints:Array = dataSeries.getDataPoints();
         var maxValue:Number = dataSeries.getMaxValue();
         var scale:Number = maxValue;
@@ -65,74 +152,72 @@ package org.ovirt.charts {
           throw new Error("No data points in range");
         }
 
-        //have to iterate through datapoint.timestamp strings,
-        //create a TextLiberation object with them, and add them to
-        //a parent container before we can tell how wide they are in pixels.
-        var labelWidth:Number = 0;
-        for (var i:int = 0; i < size; i++) {
-          var dataPoint:DataPoint = dataPoints[i] as DataPoint;
-          var textTemp:TextLiberation =
-            new TextLiberation(dataPoint.getTimestamp());
-          textTemp.setVisible(false);
-          chartArea.addChild(textTemp);
-          var tempLabelWidth:Number = textTemp.getTextWidth();
-          if (! isNaN(tempLabelWidth)) {
-            labelWidth = Math.max(labelWidth, tempLabelWidth);
-          }
-        }
-        //now we have to remove all the children we just added, since we don't
-        //really want them to be part of the chart.
-        chartArea.removeAllChildren();
-
-        //we always want an odd number of y-axis labels, and we'll
-        //determine this by using the labelWidth we just determined
-        var labelCount:int = Math.floor(Constants.width / labelWidth);
-        if (labelCount > 3 && labelCount % 2 == 1) {
-          labelCount--;
-        }
-
         //the distance between left edges of adjacent bars
-        var gridWidth:Number = Constants.width / size;
+        var gridWidth:Number = Math.floor(Constants.width / size);
 
         //the width of each SingleBar (does not including padding between bars)
         var barWidth:Number = gridWidth - Constants.barSpacing;
 
-        //use this to center y-axis labels on the bars
-        var labelOffset:Number = barWidth / 2;
+        //due to the discrete number of pixels, there may be space at the
+        //right side of the graph that needs to be made up by padding
+        //bars here and there
+	var shortfall:Number = Constants.width - (gridWidth * size);
+	var makeup:Number = Math.round(size / shortfall);
+	var madeup:Number = 0;
+
+        //variable to hold the numbered day of the month of the last
+        //XAxisLabel added to the label area
+        var lastDate:Number;
 
-        //distance between first and last label
-        var labelSpace:Number = Constants.width - gridWidth;
-        var labelSpacing:Number = labelSpace / labelCount;
+        //variable to hold the x-coordinate of the next bar to be added to
+        //the chart
+	var currentBarPosition:int = 0;
 
         //add the bars & labels to the chart
         var labelCounter:int = 0;
         for (i = 0; i < size; i++) {
-          dataPoint = dataPoints[i] as DataPoint;
+
+          var dataPoint:DataPoint = dataPoints[i] as DataPoint;
+	  if (i == 0) {
+            lastDate = dataPoint.getTimestamp().date;
+          }
+
+          //show long date format for first & last XAxisLabels,
+          //as well as whenever the date changes
+          if (i == 0 || i == size - 1
+              || dataPoint.getTimestamp().date != lastDate) {
+            dateFormat.formatString = "DD-MMM-YYYY JJ:NN";
+          } else {
+            dateFormat.formatString = "JJ:NN";
+          }
+
           var value:Number = dataPoint.getValue();
-          var bar:SingleBar = new SingleBar(dataPoint);
-          bar.percentHeight = ((value / scale) * 80);
-          bar.width = barWidth;
-          bar.setVisible(true);
+          var bar:SingleBar = new SingleBar(dataPoint,scale);
           chartArea.addChild(bar);
-          var currentLabelPosition:int = labelCounter * labelSpacing +
-                                           labelOffset;
-
-          if (currentLabelPosition >= i * gridWidth &&
-                currentLabelPosition < (i + 1) * gridWidth) {
-            var label:YAxisLabel = new YAxisLabel(dataPoint.getTimestamp());
-            label.setVisible(false);
-            label.y = ((labelCounter + 1) % 2) * 13 + 4;
-            labelArea.addChild(label);
-            //make sure the label is fully within the chart width
-            label.x = Math.max(0,
-                               Math.min((i) * gridWidth -
-                                 (label.labelText.getTextWidth() / 2) +
-                                 labelOffset,
-                               Constants.width -
-                                 label.labelText.getTextWidth() - 6)
-                              );
+          bar.width = barWidth;
+          bar.addEventListener(MouseEvent.CLICK,
+                               ApplicationBus.instance().barClickAction);
+	  bar.x = currentBarPosition;
+          if (makeup > 0 && i % makeup == 0 && madeup < shortfall) {
+            bar.width = bar.width + 1;
+            madeup++;
+          }
+
+          //add XAxisLabels at the endpoints of the time range,
+          //as well as the center if there are more than 6 points
+          //and two more if there are more than 14 points
+          if ((size > 6 && i == Math.floor(size / 2))
+              || (size > 14
+                  && (i == Math.floor(size / 4)
+                      || i == Math.floor(size * 3 / 4)))
+              || i == 0
+              || i == size - 1) {
+            var label:XAxisLabel =
+              new XAxisLabel(dateFormat.format(dataPoint.getTimestamp()));
+	    label.setCenter(currentBarPosition + bar.width / 2);
             label.setVisible(true);
-            labelCounter++;
+            label.y = 6;
+            XAxisLabelArea.addChild(label);
 
             //add a 'tick' in the center of the bar to which this label
             //corresponds
@@ -140,13 +225,73 @@ package org.ovirt.charts {
             ind.opaqueBackground = 0x000000;
             ind.width=1;
             ind.height=3;
-            ind.x =  (i) * gridWidth + labelOffset;
+            ind.x = label.getCenter();
             ind.y = 0;
             ind.setVisible(true);
             ind.setStyle("backgroundColor","0x000000");
-            labelArea.addChild(ind);
+            XAxisLabelArea.addChild(ind);
+            lastDate = dataPoint.getTimestamp().date;
           }
+          currentBarPosition += (bar.width + Constants.barSpacing);
+        }
+
+        //fill in the time range selection bar
+        var t:Date;
+        var f1:Text = new Text();
+        f1.text = "View data between";
+        dateBar.addChild(f1);
+        t = new Date(dataPoints[0].getTimestamp().getTime());
+        startDateField = new DateField();
+        startDateField.selectedDate = t;
+        startDateField.editable = true;
+        startTimeField = new TextInput();
+        startTimeField.minWidth = 50;
+        startTimeField.maxWidth = 50;
+        startTimeField.text = pad(t.hours) + ":" + pad(t.minutes);
+        dateBar.addChild(startTimeField);
+        dateBar.addChild(startDateField);
+        var f2:Text = new Text();
+        f2.text = "and";
+        dateBar.addChild(f2);
+
+        t = new Date(dataPoints[size - 1].getTimestamp().getTime());
+        endDateField = new DateField();
+        endDateField.selectedDate = t;
+        endDateField.editable = true;
+        endTimeField = new TextInput();
+        endTimeField.minWidth = 50;
+        endTimeField.maxWidth = 50;
+        endTimeField.text = pad(t.hours) + ":" + pad(t.minutes);
+        dateBar.addChild(endTimeField);
+        dateBar.addChild(endDateField);
+
+	button = new Button();
+	button.label = "go";
+	button.addEventListener(MouseEvent.CLICK,timeRangeAdjusted);
+	dateBar.addChild(button);
+
+        //FIXME: these should be fetched from the graph controller so
+        //that different types can be added (or restricted) dynamically
+        var menuItems:ArrayCollection =
+          new ArrayCollection( [{label: "memory"},
+                                {label: "cpu"},
+                                {label: "load"},
+                                {label: "netin"},
+                                {label: "netout"},
+                                {label: "disk"}
+                               ]);
+
+
+        if (menu != null) {
+          menu.removeEventListener(MenuEvent.ITEM_CLICK,typeSelected);
         }
+
+        menu = new PopUpMenuButton();
+        menu.label = "Select Data Type";
+        menu.dataProvider = menuItems;
+        menu.addEventListener(MenuEvent.ITEM_CLICK,typeSelected);
+        dateBar.addChild(menu);
+
       } catch (e:Error) {
         var err:Text = new Text();
         err.text = e.message;
diff --git a/src/flexchart/org/ovirt/charts/Chart.as b/src/flexchart/org/ovirt/charts/Chart.as
index 26c8d02..f2faf33 100644
--- a/src/flexchart/org/ovirt/charts/Chart.as
+++ b/src/flexchart/org/ovirt/charts/Chart.as
@@ -19,19 +19,32 @@
 */
 
 package org.ovirt.charts {
-
-  public class Chart {
-
     import org.ovirt.DataSource;
     import mx.containers.Box;
     import org.ovirt.data.DataSeries;
 
+  public class Chart {
+
     protected var container:Box;
     protected var datasourceUrl:String;
 
+    protected var startTime:Number;
+    protected var endTime:Number;
+    protected var target:String;
+    protected var id:int;
+
     public function Chart(container:Box, datasourceUrl:String) {
       this.container = container;
       this.datasourceUrl = datasourceUrl;
+      if (datasourceUrl != null) {
+        var results:Array = datasourceUrl.split("/");
+        if (results != null && results.length > 7) {
+          setId(new int(results[4]));
+          setTarget(results[5] as String);
+          setStartTime(new int(results[6]));
+          setEndTime(new int(results[7]));
+        }
+      }
     }
 
     public function addData(dataSeries:DataSeries):void {
@@ -40,7 +53,24 @@ package org.ovirt.charts {
 
     public function load():void {
       var dataSource:DataSource = new DataSource(this);
-      dataSource.retrieveData(datasourceUrl);
+      var myString:String = "/ovirt/graph/flexchart_data/" + id + "/" + target +  "/" + startTime  + "/" + endTime;
+      dataSource.retrieveData(myString);
+    }
+
+    public function setStartTime(startTime:Number):void {
+      this.startTime = startTime;
+    }
+
+    public function setEndTime(endTime:Number):void {
+      this.endTime = endTime;
+    }
+
+    public function setTarget(target:String):void {
+      this.target = target;
+    }
+
+    public function setId(id:int):void {
+      this.id = id;
     }
   }
 }
diff --git a/src/flexchart/org/ovirt/data/DataPoint.as b/src/flexchart/org/ovirt/data/DataPoint.as
index 00cd0a4..5d59de9 100644
--- a/src/flexchart/org/ovirt/data/DataPoint.as
+++ b/src/flexchart/org/ovirt/data/DataPoint.as
@@ -22,17 +22,18 @@ package org.ovirt.data {
 
   public class DataPoint {
 
-    private var timestamp:String;
+    private var timestamp:Date;
     private var value:Number;
     private var description:String;
 
-    public function DataPoint (timestamp:String, value:Number, description:String) {
+    public function DataPoint (timestamp:Date, value:Number,
+                               description:String) {
       this.timestamp = timestamp;
       this.value = value;
       this.description = description;
     }
 
-    public function getTimestamp():String {
+    public function getTimestamp():Date {
       return timestamp;
     }
 
diff --git a/src/flexchart/org/ovirt/data/DataSeries.as b/src/flexchart/org/ovirt/data/DataSeries.as
index 764fd34..709ceea 100644
--- a/src/flexchart/org/ovirt/data/DataSeries.as
+++ b/src/flexchart/org/ovirt/data/DataSeries.as
@@ -36,9 +36,15 @@ package org.ovirt.data {
       dataPoints = new Array();
       var inDataPoints:Array = object["vectors"] as Array;
       for (var i:int = 0; i < inDataPoints.length; i++) {
-        dataPoints.push(new DataPoint((inDataPoints[i] as Array)[0] as String,
-                                  (inDataPoints[i] as Array)[1] as Number,
-                                  description));
+        var value:Number = 0;
+        var valuea:Number = (inDataPoints[i] as Array)[1] as Number;
+        if (!isNaN(valuea)) {
+          value = (inDataPoints[i] as Array)[1] as Number;
+        }
+        var seconds:Number = new Number((inDataPoints[i] as Array)[0]) * 1000;
+        dataPoints.push(new DataPoint(new Date(seconds),
+                                      value,
+                                      description));
       }
       maxValue = object["max_value"] as Number;
     }
diff --git a/src/flexchart/org/ovirt/elements/SingleBar.as b/src/flexchart/org/ovirt/elements/SingleBar.as
index 6e09bff..e7caf93 100644
--- a/src/flexchart/org/ovirt/elements/SingleBar.as
+++ b/src/flexchart/org/ovirt/elements/SingleBar.as
@@ -20,39 +20,66 @@
 
 package org.ovirt.elements {
 
-  import mx.containers.Box;
-  import mx.controls.ToolTip;
-  import mx.managers.ToolTipManager;
+  import flash.display.DisplayObject;
   import flash.events.Event;
   import flash.events.MouseEvent;
   import flash.geom.Rectangle;
-  import flash.display.DisplayObject;
+  import mx.containers.Canvas;
+  import mx.controls.ToolTip;
+  import mx.events.FlexEvent;
+  import mx.events.ResizeEvent;
+  import mx.formatters.DateFormatter;
+  import mx.managers.ToolTipManager;
   import org.ovirt.data.DataPoint;
 
-  public class SingleBar extends Box {
+  public class SingleBar extends Canvas {
 
     private var tip:ToolTip;
     private var dataPoint:DataPoint;
+    private var scale:Number;
+    private var dateFormat:DateFormatter = new DateFormatter();
 
-    public function SingleBar(dataPoint:DataPoint) {
+    public function SingleBar(dataPoint:DataPoint,scale:Number) {
       super();
       this.dataPoint = dataPoint;
+      this.scale = scale;
       addEventListener(MouseEvent.MOUSE_OVER,showTip);
       addEventListener(MouseEvent.MOUSE_OUT,destroyTip);
-      this.setStyle("backgroundColor","0x0000FF");
-      this.setStyle("left","1");
-      this.setStyle("right","1");
+      addEventListener(ResizeEvent.RESIZE,myResize);
+      addEventListener(FlexEvent.CREATION_COMPLETE,myResize);
+      addEventListener(Event.RENDER,myResize);
+      this.setStyle("backgroundColor","0x2875c1");
+      dateFormat.formatString = "DD-MMM-YYYY JJ:NN";
+    }
+
+    public function destroy():void {
+      removeEventListener(MouseEvent.MOUSE_OVER,showTip);
+      removeEventListener(MouseEvent.MOUSE_OUT,destroyTip);
+      removeEventListener(ResizeEvent.RESIZE,myResize);
+      removeEventListener(FlexEvent.CREATION_COMPLETE,myResize);
+      removeEventListener(FlexEvent.UPDATE_COMPLETE,myResize);
+      removeEventListener(Event.RENDER,myResize);
+    }
+
+
+    private function myResize(event:Event):void {
+       trace(event.type);
+       this.height = (dataPoint.getValue() / scale) * parent.height * .9 * -1;
+       this.y = parent.height;
     }
 
     private function showTip(event:Event):void {
+
       var w:Number = this.stage.width;
       var target:DisplayObject = event.currentTarget as DisplayObject;
       var pt:Rectangle = this.stage.getBounds(target);
       var yPos:Number = pt.y * -1;
       var xPos:Number = pt.x * -1;
-      tip = ToolTipManager.createToolTip(dataPoint.getDescription() + "\n" +
-                                           dataPoint.getTimestamp() + "\n" +
-                                           dataPoint.getValue(),
+      tip = ToolTipManager.createToolTip(dataPoint.getDescription() +
+                                         "\n" +
+                                         dateFormat.format(dataPoint.getTimestamp()) +
+                                         "\n" +
+                                         dataPoint.getValue(),
                                          xPos,yPos) as ToolTip;
       tip.x = Math.min(tip.x,
                        w - tip.width);
diff --git a/src/flexchart/org/ovirt/elements/XAxisLabel.as b/src/flexchart/org/ovirt/elements/XAxisLabel.as
new file mode 100644
index 0000000..9bf4c26
--- /dev/null
+++ b/src/flexchart/org/ovirt/elements/XAxisLabel.as
@@ -0,0 +1,66 @@
+/*
+ Copyright (C) 2008 Red Hat, Inc.
+ Written by Steve Linabery <slinabery at redhat.com>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ MA  02110-1301, USA.  A copy of the GNU General Public License is
+ also available at http://www.gnu.org/copyleft/gpl.html.
+*/
+
+package org.ovirt.elements {
+
+  import mx.containers.Box;
+  import mx.core.ScrollPolicy;
+  import flash.events.*;
+  import flash.events.MouseEvent;
+  import mx.events.*;
+  import mx.events.FlexEvent;
+
+  public class XAxisLabel extends Box {
+
+    public var labelText:TextLiberation;
+    private var center:int;
+
+    public function XAxisLabel(text:String) {
+      super();
+      labelText = new TextLiberation(text);
+      labelText.setVisible(true);
+      this.addChild(labelText);
+      this.horizontalScrollPolicy = ScrollPolicy.OFF;
+      this.verticalScrollPolicy = ScrollPolicy.OFF;
+      this.setStyle("paddingLeft","0");
+      this.setStyle("paddingRight","0");
+      addEventListener(FlexEvent.CREATION_COMPLETE,centerLabel);
+    }
+
+    public function setCenter(center:int):void {
+      this.center = center;
+    }
+
+    public function getCenter():int {
+      return center;
+    }
+
+    private function centerLabel(event:Event):void {
+      this.x = center - labelText.getTextWidth() / 2;
+      if (parent != null) {
+        if (this.x < 0) {
+          this.x = 0;
+        } else if (this.x > parent.width - labelText.getTextWidth() - 5) {
+          this.x = parent.width - labelText.getTextWidth() - 5;
+        }
+      }
+    }
+  }
+}
diff --git a/src/flexchart/org/ovirt/elements/YAxisLabel.as b/src/flexchart/org/ovirt/elements/YAxisLabel.as
index 0e93b97..73e1239 100644
--- a/src/flexchart/org/ovirt/elements/YAxisLabel.as
+++ b/src/flexchart/org/ovirt/elements/YAxisLabel.as
@@ -18,24 +18,11 @@
  also available at http://www.gnu.org/copyleft/gpl.html.
 */
 
-package org.ovirt.elements {
+//class for labeling the scale of the y-axis of a chart
 
-  import mx.containers.Box;
-  import mx.core.ScrollPolicy;
+package org.ovirt.elements {
 
   public class YAxisLabel extends Box {
 
-    public var labelText:TextLiberation;
-
-    public function YAxisLabel(text:String) {
-      super();
-      labelText = new TextLiberation(text);
-      labelText.setVisible(true);
-      this.addChild(labelText);
-      this.horizontalScrollPolicy = ScrollPolicy.OFF;
-      this.verticalScrollPolicy = ScrollPolicy.OFF;
-      this.setStyle("paddingLeft","0");
-      this.setStyle("paddingRight","0");
-    }
   }
 }
-- 
1.5.6.5




More information about the ovirt-devel mailing list