Thursday, December 11, 2008

Add and remove lineseries - Flex LineChart

This took me some time to figure out so I thought I would post about it.

Main objective is to toggle on and off lineseries based on user input. Usually this would mean editing the dataprovider, tricky thing here is that I need the color of each line to always be the same based on data, so instead I leave the dataprovider alone and actually add and remove LineSeries to/from the LineChart. This probably isn't the best way to do this, but hey, it works, and it may help someone else out.

Here we go...

First lets start with the MXML:
Here I have a Panel with a LineChart and a Legend inside it, as well as 3 Toggle Buttons. You will notice that there are no series inside the LineChart.

<mx:Panel title="LineChart Example" height="500" width="100%" layout="vertical">

<mx:HBox id="choices" horizontalGap="0">
<mx:Button id="Profit" label="Profit" toggle="true" click="updateChart(event)"/>
<mx:Button id="Expenses" label="Expenses" toggle="true" click="updateChart(event)"/>
<mx:Button id="Amount" label="Amount" toggle="true" click="updateChart(event)"/>
</mx:HBox>

<mx:LineChart id="linechart" height="80%" width="100%" showDataTips="true" dataProvider="{expensesAC}" creationComplete="init()">

<mx:horizontalAxis>
<mx:CategoryAxis categoryField="Month"/>
</mx:horizontalAxis>

</mx:LineChart>

<mx:Legend dataProvider="{linechart}" labelPlacement="right" verticalGap="2" direction="vertical"/>

</mx:Panel>


And here is the DataProvider:

[Bindable]
private var expensesAC:ArrayCollection = new ArrayCollection( [
{ Month: "Jan", Profit: 2000, Expenses: 1500, Amount: 450 },
{ Month: "Feb", Profit: 1000, Expenses: 200, Amount: 600 },
{ Month: "Mar", Profit: 1500, Expenses: 500, Amount: 300 },
{ Month: "Apr", Profit: 1800, Expenses: 1200, Amount: 900 },
{ Month: "May", Profit: 2400, Expenses: 575, Amount: 500 } ]);


For ActionScript, lets start with the UpdateChart method:

This method looks to see if the button you just pressed is selected (toggle on) or not. If the toggle is on that means the user is adding the line, if the toggle is off that means the user is removing the line, and this method calls the appropriate method.

private function updateChart(evt:Event):void
{
if ( evt.currentTarget.selected == true )
{
addToChart(evt.currentTarget.label);
} else {
removeFromChart(evt.currentTarget.label);
}
}


Here is the addToChart method. This method creates a new LineSeries and adds it to the chart. Note that the LineSeries DataProvider is the same of the LineChart and the data you're referring to (yField) should already be present in the DataProvider.

private function addToChart(item:String):void
{
var newLS:LineSeries = new LineSeries();
var newStroke:Stroke = new Stroke();
newStroke.color = strokeColor(item);

newLS.yField = item;
newLS.displayName = item;
newLS.setStyle('form','curve');
newLS.dataProvider = expensesAC;
newLS.setStyle('lineStroke',newStroke);
var tmp:Array = linechart.series;
tmp.push(newLS);
linechart.series = tmp;
linechart.invalidateSeriesStyles();
}

You may have noticed the line newLS.setStyle('lineStroke',newStroke);. This refers to the following method, all it does is assigns a color based on the button selected.

private function strokeColor(item:String):uint
{
switch (item)
{
case 'Amount':
return 0x0000FF;
break;
case 'Profit':
return 0xFF0000;
break;
case 'Expenses':
return 0x00FF00;
break;
default:
return 0x000000;
break;
}
}


And finally here is the remove method.

private function removeFromChart(item:String):void
{
var objToRemoveIndex:int;
for ( var i:int = 0; i < linechart.series.length; i++ )
{
if ( linechart.series[i].yField == item )
{
objToRemoveIndex = i;
}
}

var tmp:Array = linechart.series;
tmp.splice(objToRemoveIndex,1);
linechart.series = tmp;
linechart.invalidateSeriesStyles();
}


The default series gets added with the CreationComplete method:

private function init():void
{
addToChart('Amount');
Amount.selected = true;
}


Anyway, I hope that wasn't too confusing. I should really start hosting these little examples somewhere with the ViewSorce available. If you need more clarification just gimmie a comment here.

Publishing source code in Blogger

Wow it worked! Sucks I still have to escape all my > and < s but way better than what I was doing before (manual formatting).

So this took me a while to figure out... maybe I can do a step-by-step to help someone else out there out... there are a lot of pages on how to do this, I needed to combine them to make it work.

K... so... inside your blogger Dashboard go Layout - Edit HTML.

Paste this just before the </head> tag:


<link href='http://syntaxhighlighter.googlecode.com/svn/trunk/Styles/SyntaxHighlighter.css' rel='stylesheet' type='text/css'/>


Then paste this just before the </body> tag


<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shCore.js'/>

<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushCSharp.js'/>

<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushXml.js'/>

<script language='javascript' src='http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/shBrushPython.js'/>

<script class='javascript'>
//<![CDATA[
function FindTagsByName(container, name, Tag)
{
var elements = document.getElementsByTagName(Tag);
for (var i = 0; i < elements.length; i++)
{
if (elements[i].getAttribute("name") == name)
{
container.push(elements[i]);
}
}
}

var elements = [];
FindTagsByName(elements, "code", "pre");
FindTagsByName(elements, "code", "textarea");

for(var i=0; i < elements.length; i++) {
if(elements[i].nodeName.toUpperCase() == "TEXTAREA") {
var childNode = elements[i].childNodes[0];
var newNode = document.createTextNode(childNode.nodeValue.replace(/<br\s*\/?>/gi,'\n'));
elements[i].replaceChild(newNode, childNode);
}
else if(elements[i].nodeName.toUpperCase() == "PRE") {
brs = elements[i].getElementsByTagName("br");
for(var j = 0, brLength = brs.length; j < brLength; j++) {
var newNode = document.createTextNode("\n");
elements[i].replaceChild(newNode, brs[0]);
}
}
}

//clipboard does not work well, no line breaks
//dp.SyntaxHighlighter.ClipboardSwf = "http://syntaxhighlighter.googlecode.com/svn/trunk/Scripts/clipboard.swf";
dp.SyntaxHighlighter.HighlightAll("code");
//]]>
</script>


Save your template.

Then to test it out create a new post and put some sample code between two PRE tags, like this:

<pre name="code" class="html">
<!-- code here -->
</pre>

BUT you have to use escape characters for html
Here's a link to a site to help you do that quickly:
http://www.accessify.com/tools-and-wizards/developer-tools/quick-escape/default.php


And here are the links to the posts that helped me figure this out:
http://www.accessify.com/tools-and-wizards/developer-tools/quick-escape/
http://azowebsphere.blogspot.com/2008/08/how-to-post-code-snippets-in-blogger.html

Publish Source code in Blogger??

testing testing one two three...



<html>
</html>

Friday, December 5, 2008