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

Steve Linabery slinabery at redhat.com
Thu Nov 20 05:10:21 UTC 2008


Gaah! Just noticed that I broke the date display somehow while editing out whitespace, etc. Revision 1st thing in AM.

Thanks,
Steve

On Wed, Nov 19, 2008 at 10:12:04PM -0600, Steve Linabery wrote:
> 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..eb653e9 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:int = int((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