Saturday, September 1, 2012

Flex: Locating a point

Probably there' a requirement that requires you to place an icon for both the highest and lowest y value of a chart, but how do you do it?

And here's my answer to the above question. :P Time for some coding... Here's my main application file - "SimpleChartPositionOfAPoint.mxml"
<?xml version="1.0" encoding="utf-8"?>
<s:Application xmlns:fx="http://ns.adobe.com/mxml/2009" 
      xmlns:s="library://ns.adobe.com/flex/spark" 
      xmlns:mx="library://ns.adobe.com/flex/mx"
      backgroundColor="#CDCDCD"
      creationComplete="creationCompleteEvent(event)">
 <fx:Script>
  <![CDATA[
   import flashx.textLayout.conversion.TextConverter;
   
   import mx.charts.HitData;
   import mx.charts.chartClasses.IChartElement2;
   import mx.charts.series.LineSeries;
   import mx.collections.ArrayCollection;
   import mx.collections.Sort;
   import mx.collections.SortField;
   import mx.events.FlexEvent;
   import mx.formatters.DateFormatter;
   
   import spark.events.IndexChangeEvent;
   
   //Records used in the chart
   [Bindable]
   private var myData:XML = 
    <records>
     <record>
      <date>16/11/2012</date>
      <people>74</people>
     </record>
     <record>
      <date>24/07/2013</date>
      <people>99</people>
     </record>
     <record>
      <date>05/04/2013</date>
      <people>79</people>
     </record>
     <record>
      <date>08/07/2012</date>
      <people>54</people>
     </record>
     <record>
      <date>22/11/2012</date>
      <people>42</people>
     </record>
     <record>
      <date>10/04/2012</date>
      <people>42</people>
     </record>
     <record>
      <date>17/03/2012</date>
      <people>57</people>
     </record>
     <record>
      <date>16/10/2011</date>
      <people>63</people>
     </record>
     <record>
      <date>06/02/2012</date>
      <people>80</people>
     </record>
     <record>
      <date>09/01/2012</date>
      <people>2</people>
     </record>
     <record>
      <date>18/11/2011</date>
      <people>100</people>
     </record>
     <record>
      <date>25/11/2011</date>
      <people>88</people>
     </record>
     <record>
      <date>29/05/2012</date>
      <people>94</people>
     </record>
     <record>
      <date>30/03/2013</date>
      <people>99</people>
     </record>
     <record>
      <date>08/09/2012</date>
      <people>33</people>
     </record>
     <record>
      <date>26/01/2012</date>
      <people>33</people>
     </record>
     <record>
      <date>12/11/2012</date>
      <people>48</people>
     </record>
     <record>
      <date>17/05/2013</date>
      <people>57</people>
     </record>
     <record>
      <date>13/04/2012</date>
      <people>57</people>
     </record>
     <record>
      <date>18/07/2013</date>
      <people>81</people>
     </record>
     <record>
      <date>09/08/2012</date>
      <people>60</people>
     </record>
     <record>
      <date>04/09/2012</date>
      <people>49</people>
     </record>
     <record>
      <date>29/12/2012</date>
      <people>15</people>
     </record>
     <record>
      <date>17/08/2011</date>
      <people>1</people>
     </record>
     <record>
      <date>09/10/2012</date>
      <people>76</people>
     </record>
     <record>
      <date>20/02/2012</date>
      <people>62</people>
     </record>
     <record>
      <date>24/06/2013</date>
      <people>70</people>
     </record>
     <record>
      <date>17/07/2013</date>
      <people>17</people>
     </record>
     <record>
      <date>21/04/2012</date>
      <people>32</people>
     </record>
     <record>
      <date>11/04/2013</date>
      <people>92</people>
     </record>
     <record>
      <date>02/08/2013</date>
      <people>97</people>
     </record>
     <record>
      <date>27/12/2011</date>
      <people>5</people>
     </record>
     <record>
      <date>01/05/2012</date>
      <people>90</people>
     </record>
     <record>
      <date>20/04/2013</date>
      <people>75</people>
     </record>
     <record>
      <date>26/10/2012</date>
      <people>60</people>
     </record>
     <record>
      <date>02/01/2012</date>
      <people>31</people>
     </record>
     <record>
      <date>04/02/2013</date>
      <people>17</people>
     </record>
     <record>
      <date>17/04/2013</date>
      <people>16</people>
     </record>
     <record>
      <date>22/03/2013</date>
      <people>94</people>
     </record>
     <record>
      <date>10/09/2011</date>
      <people>97</people>
     </record>
     <record>
      <date>27/11/2012</date>
      <people>18</people>
     </record>
     <record>
      <date>15/03/2013</date>
      <people>94</people>
     </record>
     <record>
      <date>17/10/2011</date>
      <people>85</people>
     </record>
     <record>
      <date>18/03/2012</date>
      <people>12</people>
     </record>
     <record>
      <date>09/10/2011</date>
      <people>92</people>
     </record>
     <record>
      <date>08/09/2012</date>
      <people>17</people>
     </record>
     <record>
      <date>22/10/2012</date>
      <people>45</people>
     </record>
     <record>
      <date>09/11/2012</date>
      <people>40</people>
     </record>
     <record>
      <date>06/09/2012</date>
      <people>75</people>
     </record>
     <record>
      <date>13/08/2012</date>
      <people>2</people>
     </record>
     <record>
      <date>04/03/2012</date>
      <people>20</people>
     </record>
     <record>
      <date>17/11/2012</date>
      <people>34</people>
     </record>
     <record>
      <date>01/02/2012</date>
      <people>51</people>
     </record>
     <record>
      <date>29/08/2011</date>
      <people>35</people>
     </record>
     <record>
      <date>11/02/2012</date>
      <people>35</people>
     </record>
     <record>
      <date>02/06/2012</date>
      <people>26</people>
     </record>
     <record>
      <date>20/01/2013</date>
      <people>98</people>
     </record>
     <record>
      <date>07/02/2013</date>
      <people>4</people>
     </record>
     <record>
      <date>27/08/2012</date>
      <people>44</people>
     </record>
     <record>
      <date>12/12/2012</date>
      <people>29</people>
     </record>
     <record>
      <date>18/03/2012</date>
      <people>96</people>
     </record>
     <record>
      <date>01/09/2012</date>
      <people>40</people>
     </record>
     <record>
      <date>09/02/2013</date>
      <people>34</people>
     </record>
     <record>
      <date>22/09/2012</date>
      <people>86</people>
     </record>
     <record>
      <date>28/02/2012</date>
      <people>14</people>
     </record>
     <record>
      <date>02/02/2012</date>
      <people>94</people>
     </record>
     <record>
      <date>08/06/2013</date>
      <people>16</people>
     </record>
     <record>
      <date>23/03/2012</date>
      <people>32</people>
     </record>
     <record>
      <date>21/03/2013</date>
      <people>10</people>
     </record>
     <record>
      <date>07/04/2013</date>
      <people>10</people>
     </record>
     <record>
      <date>11/03/2013</date>
      <people>28</people>
     </record>
     <record>
      <date>02/11/2012</date>
      <people>28</people>
     </record>
     <record>
      <date>14/11/2011</date>
      <people>3</people>
     </record>
     <record>
      <date>05/02/2013</date>
      <people>12</people>
     </record>
     <record>
      <date>21/03/2013</date>
      <people>41</people>
     </record>
     <record>
      <date>30/09/2012</date>
      <people>96</people>
     </record>
     <record>
      <date>19/02/2013</date>
      <people>29</people>
     </record>
     <record>
      <date>09/07/2013</date>
      <people>86</people>
     </record>
     <record>
      <date>30/04/2013</date>
      <people>35</people>
     </record>
     <record>
      <date>21/01/2012</date>
      <people>4</people>
     </record>
     <record>
      <date>26/06/2013</date>
      <people>88</people>
     </record>
     <record>
      <date>17/04/2013</date>
      <people>55</people>
     </record>
     <record>
      <date>04/10/2011</date>
      <people>38</people>
     </record>
     <record>
      <date>20/03/2013</date>
      <people>38</people>
     </record>
     <record>
      <date>19/05/2013</date>
      <people>91</people>
     </record>
     <record>
      <date>28/08/2011</date>
      <people>73</people>
     </record>
     <record>
      <date>31/08/2011</date>
      <people>65</people>
     </record>
     <record>
      <date>11/03/2013</date>
      <people>88</people>
     </record>
     <record>
      <date>10/06/2013</date>
      <people>78</people>
     </record>
     <record>
      <date>03/07/2013</date>
      <people>8</people>
     </record>
     <record>
      <date>08/10/2012</date>
      <people>16</people>
     </record>
     <record>
      <date>19/03/2012</date>
      <people>74</people>
     </record>
     <record>
      <date>28/09/2012</date>
      <people>49</people>
     </record>
     <record>
      <date>29/07/2013</date>
      <people>51</people>
     </record>
     <record>
      <date>05/10/2012</date>
      <people>60</people>
     </record>
     <record>
      <date>18/02/2012</date>
      <people>63</people>
     </record>
     <record>
      <date>03/09/2011</date>
      <people>45</people>
     </record>
     <record>
      <date>30/12/2011</date>
      <people>76</people>
     </record>
     <record>
      <date>11/04/2013</date>
      <people>96</people>
     </record>
     <record>
      <date>15/06/2012</date>
      <people>55</people>
     </record>
    </records>;
   
   private var localSeries:LineSeries = new LineSeries();
   
   //This function will show a text box which is positioned
   //above the selected point
   protected function cb1ChangeEvent(event:IndexChangeEvent):void
   {
    //We will need the date, the date in numerical format
    //and the number of people during that date
    var tempDate:Date = event.currentTarget.selectedItem.date;
    var xPos:Number = tempDate.time;
    var yPos:Number = event.currentTarget.selectedItem.people;
    
    //Next, create a point withe the date in numerical format
    //and the number of people, which is used to create the
    //x and y axis of the chart
    var myPoint:Point = new Point(xPos,yPos);
    
    //Next, check it against the line series to find the 
    //and y postion of the point on the chart
    //Note: dataToLocal didn't calculate the gutters around
    //the chart, you need to calculate yrself.
    myPoint = localSeries.dataToLocal(xPos, yPos);
    
    //Next, offset the gutters on the left and top of the point
    myPoint.x += lineChart.getStyle("gutterLeft");
    myPoint.y += lineChart.getStyle("gutterTop");
    
    //find the global position of the point
    myPoint = lineChart.localToGlobal(myPoint);
    
    //followed by the step of mapping the point into the
    //layer abouve the chart 
    myPoint = canvas.globalToLocal(myPoint);
    
    //We will position the textfield above the selected point
    txtResult.visible = true;
    txtResult.x = myPoint.x - txtResult.width / 2;
    txtResult.y = myPoint.y - txtResult.height - 5;
    
    //Let's populate the textfield with some data.
    var tempStr:String = "";
    tempStr += "Date: " + dateFormatter(tempDate) + "<br>";
    tempStr += "No. of People: " + yPos;
    txtResult.textFlow = TextConverter.importToFlow(tempStr,
     TextConverter.TEXT_FIELD_HTML_FORMAT);
   }
   
   protected function creationCompleteEvent(event:FlexEvent):void
   {
    // Parsing the xml data into ArrayCollection
    var objArray:ArrayCollection = new ArrayCollection();
    var tempObj:Object;
    var dateArray:Array;
    var tempDate:Date;
    for(var i:int = 0; i < myData.record.length(); i ++)
    {
     tempObj = new Object();
     dateArray = String(myData.record[i].date).split("/");
     //Convert the date data into a Date Object
     tempDate = new Date(dateArray[2], 
      Number(dateArray[1]) - 1, 
      dateArray[0]);
     tempObj.date = tempDate;
     tempObj.time = tempDate.time;
     tempObj.people = myData.record[i].people;
     tempObj.label = dateFormatter(tempDate);
     objArray.addItem(tempObj);
    }
    
    //Create the SortField object for the "time" field 
    //in the ArrayCollection object, and make sure we
    //do a numeric sort.
    var dataSortField:SortField = new SortField();
    dataSortField.name = "time";
    dataSortField.numeric = true;
    
    //Create the Sort object and add the SortField 
    //object created earlier to the array of fields
    //to sort on.
    var numericDataSort:Sort = new Sort();
    numericDataSort.fields = [dataSortField];
    
    objArray.sort = numericDataSort;
    objArray.refresh();
    
    //Create the new series and set its properties.
    localSeries.dataProvider = objArray;
    localSeries.yField = "people";
    localSeries.xField = "date";
    
    //Back up the current series on the chart.
    var currentSeries:Array = lineChart.series;
    //Add the new series to the current Array of 
    //series.
    currentSeries.push(localSeries);
    //Add the new Array of series to the chart.
    lineChart.series = currentSeries;
    
    cb1.dataProvider = objArray;
   }
   
   //This function will return a string based on the
   //Date format DD/MM/YYYY.
   private function dateFormatter(tempDate:Date):String
   {
    var fmt:DateFormatter = new DateFormatter();
    fmt.formatString = "DD/MM/YYYY";
    return fmt.format(tempDate);
   }
   
   //We are customizing the datatip / tool tip of the
   //chart data.
   public function myDataTipFunction(e:HitData):String {
    var s:String = "";
    var tempDate:Date = e.item.date as Date;
    s += "Date: " + dateFormatter(tempDate) + "<br>";
    s += "No. of People: " + e.item.people;
    return s;
   }
   
  ]]>
 </fx:Script>
 <s:VGroup width="100%" 
     height="100%"
     verticalAlign="middle"
     horizontalAlign="center">
  <s:BorderContainer width="100%"
         height="100%"
         backgroundAlpha="0"
         borderVisible="false">
   <s:HGroup verticalAlign="middle" horizontalAlign="center"
       width="100%"
       height="100%">
    <!-- Need to set the gutterLeft and 
     gutterTop of the chart -->
    <mx:LineChart id="lineChart"
         gutterTop="0"
         gutterLeft="50"
         showDataTips="true" 
         width="80%"
         height="80%"
         dataTipFunction="myDataTipFunction">
     <mx:horizontalAxis>
      <mx:DateTimeAxis dataUnits="days" id="dateAxis" 
           alignLabelsToUnits="true"/> 
     </mx:horizontalAxis>
    </mx:LineChart>
   </s:HGroup>
   <s:BorderContainer width="100%" 
          height="100%"
          id="canvas"
          mouseEnabled="false"
          backgroundAlpha="0"
          borderVisible="false"
          mouseChildren="false">
    <s:TextArea width="150"
       height="50" 
        visible="false"
       id="txtResult"/>
   </s:BorderContainer>
  </s:BorderContainer>
  <s:HGroup width="100%" 
      verticalAlign="middle"
      horizontalAlign="center">
   <s:Label text="Select a Date:"/>
   <s:ComboBox id="cb1" 
       change="cb1ChangeEvent(event)"/>
  </s:HGroup>
 </s:VGroup>
</s:Application>
* Click here for the demo shown in this post.
^ Click here for the source files for the demo.

No comments:

Post a Comment