Archive

Archive for the ‘actionscript’ Category

Loading TIFF Images in Flex and AIR

May 30th, 2012 Adam 1 comment

Flex and Actionscript doesn’t handle TIFF images inherently. However, there is a library of TIFF decoding functions that I found buried in the interwebs (Big thanks to C.T. Yeung).

I made a few slight modifications because it wasn’t working when I downloaded it from Yeung. Speaking of which, this decoder doesn’t support TIFF compression. So you can’t load LZW or ZIP compressed TIFFs.

Here are the modified library files.

Here is how you would load a TIFF in Flex:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
import mx.controls.Alert;
import com.utils.Tiff.TIFF6Decoder;
 
private var tiffDecoder:TIFF6Decoder;
private var byteArray:ByteArray;
 
private function loadFile():void{
	var request:URLRequest = new URLRequest(
		"http://test.url.com/sample.tif"
	);
	var urlLoader:URLLoader = new URLLoader(request);
 
	urlLoader.addEventListener(Event.COMPLETE, onLoadComplete);
	urlLoader.dataFormat = URLLoaderDataFormat.BINARY;
	urlLoader.load(request);
}
 
private function onLoadComplete(e:Event):void{
	byteArray = e.target.data;
 
	tiffDecoder = new TIFF6Decoder();
	if(tiffDecoder.decode(byteArray))
		img.source = new Bitmap(tiffDecoder.bitmapData);
	else 
		Alert.show("Failed TIFF decoding");
}

Here is an AIR example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import mx.controls.Alert;
import com.Tiff.TIFF6Decoder;
 
private var tiffDecoder:TIFF6Decoder;
private var fileStream:FileStream;
 
private function loadFile():void{
	var tiffFile:File = new File("C:/tiffs/sample.tif");
	fileStream = new FileStream();
	fileStream.addEventListener(Event.COMPLETE, onLoadComplete);
	fileStream.openAsync(tiffFile, FileMode.READ);
}
 
private function onLoadComplete(e:Event):void{
	var byteArray:ByteArray = new ByteArray();
	fileStream.readBytes(byteArray);
	fileStream.close();
 
	tiffDecoder = new TIFF6Decoder();
	if(tiffDecoder.decode(byteArray))
		img.source = new Bitmap(tiffDecoder.bitmapData);
	else 
		Alert.show("Failed TIFF decoding");
}
Categories: actionscript, air, flex Tags: , , , ,

Flex Chart Zoom Window

March 18th, 2010 Adam 11 comments

This code will show you how to create zoom functionality on your flex charts, as shown here: (click and drag on the chart to create the zoom window)
(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Before I get to the code, there’s a couple of notes:

You will notice that the data tips don’t show up, even if you enable showDataTips. This is a known bug, caused by disabling filterData on the chart series. filterData forces the chart to render all data points, even if they’re not shown on the current chart view. This is important, because if those points aren’t rendered, the chart doesn’t draw the lines that extend to those points.

If you’re worried that rendering unnecessary data points will cause performance issues, you can extend your series class and override the updateFilter method. You’ll need to rewrite it so that it excludes/includes the proper data points.

If you’re not worried about the effects of filterData, and you’d like a quick work-around for showing data tips, you’ll still need to extend your series class, but its a bit more simple. You just need to override findDataPoints with some minor adjustments, and add the private function formatDataTip. Here’s a link with the edited class: FilterLineSeries.as I copied the code directly from the LineSeries source, and made some minor adjustments.

Now on to the important stuff…

main.mxml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
<?xml version="1.0"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" xmlns:local="com.*" 
	initialize="init()" width="600" height="520">
	<mx:Panel title="Line Chart">
		<mx:LineChart id="chart1" mouseDown="startDraw(event)" mouseUp="finishDraw(event)" 
			mouseMove="showDraw(event)" width="510">
 
			<!-- zoom window is drawn here -->
			<mx:annotationElements>
				<mx:CartesianDataCanvas id="chartCanvas"/>
			</mx:annotationElements>
 
			<mx:horizontalAxis>
				<mx:LinearAxis id="haxis"/>
			</mx:horizontalAxis>
 
			<mx:verticalAxis>
				<mx:LinearAxis id="vaxis"/>
			</mx:verticalAxis>
 
			<mx:series>
				<mx:LineSeries filterData="false" id="series1" xField="month" yField="profit" 
					displayName="Profit" dataProvider="{profits}"/>
			</mx:series>
 
		</mx:LineChart>
	</mx:Panel>
 
	<mx:Button label="Reset Zoom" click="resetZoom()" />
</mx:Application>

actionscript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
[Bindable]
private var profits:Array;
private var dragStart:Point;
private var dragEnd:Point;
private var zooming:Boolean;
 
// initializes the data provider with random data
private function init():void{
	profits = new Array({month: 0, profit: 15});
	for(var i:int=1; i<40; i++)
		profits.push({month: i, profit: Math.round(Math.random()*25-10)+profits[i-1].profit});
}
 
// sets the start point of the zoom window
private function startDraw(e:MouseEvent):void{
	zooming = true;
	dragStart = new Point(series1.mouseX, series1.mouseY);
}
 
// draws the zoom window as your mouse moves
private function showDraw(e:MouseEvent):void{
	if(zooming){
		dragEnd = new Point(series1.mouseX, series1.mouseY);
 
		// finds the top-left and bottom-right ponits of the zoom window
		var TL:Point = new Point();  // top-left point
		var BR:Point = new Point();  // bottom-right point
		if(dragStart.x < dragEnd.x){
			TL.x = dragStart.x;
			BR.x = dragEnd.x;
		}
		else{
			TL.x = dragEnd.x;
			BR.x = dragStart.x;
		}
		if(dragStart.y < dragEnd.y){
			TL.y = dragStart.y;
			BR.y = dragEnd.y;
		}
		else{
			TL.y = dragEnd.y;
			BR.y = dragStart.y;
		}
 
		// prevents the zoom window from going off the canvas
		if(TL.x < 0) TL.x = 0;
		if(BR.x > chartCanvas.width-1) BR.x = chartCanvas.width-1;
		if(TL.y < 0) TL.y = 0;
		if(BR.y > chartCanvas.height-1) BR.y = chartCanvas.height-1;
 
		// draw the actual zoom window
		chartCanvas.graphics.clear();
		chartCanvas.graphics.lineStyle(1, 0x000000, 0.25);
		chartCanvas.graphics.beginFill(0xd4e3f0,0.5);
		chartCanvas.graphics.drawRect(TL.x, TL.y, BR.x-TL.x, BR.y-TL.y);
		chartCanvas.graphics.endFill();
	}
}
 
// clears the drawing canvas and sets the new max/mins
private function finishDraw(e:MouseEvent):void{
	zooming = false;
	chartCanvas.clear();
 
	// converts the drag coordinates into axis data points
	var chartValStart:Array = chartCanvas.localToData(dragStart);
	var chartValEnd:Array = chartCanvas.localToData(dragEnd);
 
	// sets the new maximum and minimum for both axes
	haxis.minimum = (chartValStart[0] < chartValEnd[0]) ? chartValStart[0] : chartValEnd[0];
	haxis.maximum = (chartValStart[0] < chartValEnd[0]) ? chartValEnd[0] : chartValStart[0];
	vaxis.minimum = (chartValStart[1] < chartValEnd[1]) ? chartValStart[1] : chartValEnd[1];
	vaxis.maximum = (chartValStart[1] < chartValEnd[1]) ? chartValEnd[1] : chartValStart[1];
}
 
// resets the axis max/mins
private function resetZoom():void{
	haxis.minimum = NaN; 
	haxis.maximum = NaN; 
	vaxis.minimum = NaN; 
	vaxis.maximum = NaN;
}

I know there seems to be a lot of unnecessary code in the showDraw function, but it serves a good purpose. Your user isn’t always going to start their zoom at the top-left corner and drag down to the bottom-right. The code distinguishes where the corners are, and draws the box accordingly.

EDIT (11/2/2010): Here’s how it would be done if you’re using a DateTimeAxis for your horizontal axis:
main.mxml:

13
14
15
<mx:horizontalAxis>
	<mx:DateTimeAxis id="haxis"/>
</mx:horizontalAxis>

actionscript:

70
71
72
73
74
75
var ds:Date = new Date(chartValStart[0]);
var de:Date = new Date(chartValEnd[0]);
haxis.minimum = (ds < de ? ds:de);
haxis.maximum = (ds < de ? de:ds);
vaxis.minimum = (chartValStart[1] < chartValEnd[1]) ? chartValStart[1] : chartValEnd[1];
vaxis.maximum = (chartValStart[1] < chartValEnd[1]) ? chartValEnd[1] : chartValStart[1];
77
78
79
80
81
82
private function resetZoom():void{
	haxis.minimum = null; 
	haxis.maximum = null; 
	vaxis.minimum = NaN; 
	vaxis.maximum = NaN;
}

Drawing A Sine Wave In Actionscript

August 7th, 2009 Adam 10 comments

Just a simple way to draw a sine wave with a specific amplitude and frequency. Use the sliders to adjust the values.
(Either JavaScript is not active or you are using an old version of Adobe Flash Player. Please install the newest Flash Player.)

Here’s the main function:

function drawWave(amp:int, freq:int):void{
	newSine.graphics.clear();
	newSine.graphics.lineStyle(2, 0xff0000, 0.4);
	newSine.graphics.moveTo(0, yaxis);
	for(var i:int=0; i&lt;=stage.stageWidth; i++){
		var ang:Number = 2 * Math.PI * freq * i/stage.stageWidth;
		newSine.graphics.lineTo(i, yaxis - amp*Math.sin(ang));
	}
}

(EDIT 8/14/09: In the SWF above, the sine wave is upside down. That’s because I had a typo when I wrote it. On line 7 of the code, I had typed “…yaxis + amp…” but it should be minus. The code above is correct, but the SWF hasn’t been updated)