Skip to content

Instantly share code, notes, and snippets.

@johnyanarella
Created May 26, 2010 15:55
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnyanarella/414671 to your computer and use it in GitHub Desktop.
Save johnyanarella/414671 to your computer and use it in GitHub Desktop.
package com.codecatalyst.charting.component
{
import flash.geom.Point;
import flash.geom.Rectangle;
import mx.charts.DateTimeAxis;
import mx.charts.chartClasses.CartesianChart;
import mx.charts.chartClasses.CartesianDataCanvas;
import mx.charts.chartClasses.ChartState;
import mx.styles.CSSStyleDeclaration;
import mx.styles.StyleManager;
/**
* Day(s) to highlight.
*
* @see Date#days
*/
[Style(name="days", type="Array", format="Number", inherit="no")]
/**
* Color(s) used when highlighting the specified day(s).
*
* NOTE: If fewer colors are specfied than days, the first specified color is used for when highlighting all days.
*/
[Style(name="highlightColors", type="Array", format="Color", inherit="no")]
/**
* Alphas(s) used when highlighting the specified day(s).
*
* NOTE: If fewer alphas are specfied than days, the first specified alpha is used for when highlighting all days.
*/
[Style(name="highlightAlphas", type="Array", format="Number", inherit="no")]
/**
* Custom chart background element that highlights the specified days on charts that use a DateTimeAxis.
*/
public class DayHighlighter extends CartesianDataCanvas
{
// ========================================
// Default style initialization
// ========================================
/**
* @private
*/
protected static var stylesInitialized:Boolean = initializeStyles();
/**
* @private
*/
protected static function initializeStyles():Boolean
{
if ( !StyleManager.getStyleDeclaration( "DayHighlighter" ) )
{
var defaultStyles:CSSStyleDeclaration = new CSSStyleDeclaration();
defaultStyles.defaultFactory =
function():void
{
this.days = [ 0, 6 ];
this.highlightColors = [ 0xCCCCCC ];
this.highlightAlphas = [ 0.5 ];
};
StyleManager.setStyleDeclaration( "DayHighlighter", defaultStyles, true );
}
return true;
}
// ========================================
// Protected constants
// ========================================
/**
* Day defined in milliseconds.
*/
protected static const DAY_IN_MS:Number = 24 * 60 * 60 * 1000;
/**
* Vertical direction.
*/
protected static const VERTICAL:String = "vertical";
/**
* Horizontal direction.
*/
protected static const HORIZONTAL:String = "horizontal";
// ========================================
// Protected properties
// ========================================
/**
* DateTimeAxis associated with the <code>chart</code>, if applicable.
*/
protected var dateTimeAxis:DateTimeAxis;
/**
* Direction of the DateTimeAxis (<code>HORIZONTAL</code> or <code>VERTICAL</code>).
*/
protected var dateTimeAxisDirection:String;
// ========================================
// Constructor
// ========================================
/**
* Constructor.
*/
public function DayHighlighter()
{
super();
}
// ========================================
// Protected methods
// ========================================
/**
* @inheritDoc
*/
override protected function commitProperties():void
{
super.commitProperties();
dateTimeAxis = getDateTimeAxis();
dateTimeAxisDirection = getDateTimeAxisDirection();
}
/**
* @inheritDoc
*/
override protected function updateDisplayList( unscaledWidth:Number, unscaledHeight:Number ):void
{
super.updateDisplayList( unscaledWidth, unscaledHeight );
if ( ( chart == null ) || ( chart.chartState == ChartState.PREPARING_TO_HIDE_DATA ) || ( chart.chartState == ChartState.HIDING_DATA ) )
return;
graphics.clear();
if ( dateTimeAxis != null )
{
// get the days to highlight from the associated style
var days:Array = getStyle( "days" ) as Array;
if ( days != null )
{
// get the highlight colors and alphas from the associated styles
var colors:Array = getStyle( "highlightColors" ) as Array;
var alphas:Array = getStyle( "highlightAlphas" ) as Array;
// calculate the 'floored' starting and ending date (i.e. round down to the nearest day )
var startDate:Date = new Date( dateTimeAxis.minimum.fullYear, dateTimeAxis.minimum.month, dateTimeAxis.minimum.date );
var endDate:Date = new Date( dateTimeAxis.maximum.fullYear, dateTimeAxis.maximum.month, dateTimeAxis.maximum.date );
// iterate through all the days between the starting and ending date
var date:Date = new Date( startDate.getTime() );
while ( date.getTime() <= endDate.getTime() )
{
// determine if this date is one of the specified days
var index:int = days.indexOf( date.day );
if ( index != -1 )
{
// determine the color and alpha to use
var color:Number = ( colors.length == days.length ) ? colors[ index ] : colors[ 0 ];
var alpha:Number = ( alphas.length == days.length ) ? alphas[ index ] : alphas[ 0 ];
// draw the day
drawDay( date, color, alpha );
}
date.setTime( date.getTime() + DAY_IN_MS );
}
}
}
}
/**
* Draws the rectangular bounds of the specified day with the specified color and alpha.
*/
protected function drawDay( day:Date, color:Number, alpha:Number ):void
{
var rectangle:Rectangle = calculateDayRectangle( day );
if ( rectangle != null )
{
graphics.beginFill( color, alpha );
graphics.drawRect( rectangle.x, rectangle.y, rectangle.width, rectangle.height );
graphics.endFill();
}
}
/**
* Calculate the rectangular bounds of the day within the chart, in component coordinates.
*/
protected function calculateDayRectangle( day:Date ):Rectangle
{
var rectangle:Rectangle = null;
var nextDay:Date = new Date( day.getTime() + DAY_IN_MS );
var dayBegin:Point;
var dayEnd:Point;
if ( dateTimeAxisDirection == HORIZONTAL )
{
// convert from data coordinates to component coordinates
dayBegin = dataToLocal( day );
dayEnd = dataToLocal( nextDay );
// construct a rectangle that describes the bounds of the day, in component coordinates
rectangle = new Rectangle();
rectangle.top = 0;
rectangle.left = dayBegin.x;
rectangle.bottom = height;
rectangle.right = dayEnd.x;
}
else if ( dateTimeAxisDirection == VERTICAL )
{
// convert from data coordinates to component coordinates
dayBegin = dataToLocal( null, day );
dayEnd = dataToLocal( null, nextDay );
// construct a rectangle that describes the bounds of the day, in component coordinates
rectangle = new Rectangle();
rectangle.top = dayBegin.y;
rectangle.left = 0;
rectangle.bottom = dayEnd.y;
rectangle.right = width;
}
return rectangle;
}
/**
* Returns the DateTimeAxis, or <code>null</code> if the associated chart does not have a DateTimeAxis.
*/
protected function getDateTimeAxis():DateTimeAxis
{
if ( horizontalAxis is DateTimeAxis )
return horizontalAxis as DateTimeAxis;
if ( verticalAxis is DateTimeAxis )
return verticalAxis as DateTimeAxis;
if ( chart is CartesianChart )
{
var cartesianChart:CartesianChart = chart as CartesianChart;
if ( cartesianChart.horizontalAxis is DateTimeAxis )
return cartesianChart.horizontalAxis as DateTimeAxis;
if ( cartesianChart.verticalAxis is DateTimeAxis )
return cartesianChart.verticalAxis as DateTimeAxis;
}
return null;
}
/**
* Returns the DateTimeAxis direction (<code>HORIZONTAL</code> or <code>VERTICAL</code>), or <code>null</code> if the associated chart does not have a DateTimeAxis.
*/
protected function getDateTimeAxisDirection():String
{
if ( horizontalAxis is DateTimeAxis )
return HORIZONTAL;
if ( verticalAxis is DateTimeAxis )
return VERTICAL;
if ( chart is CartesianChart )
{
var cartesianChart:CartesianChart = chart as CartesianChart;
if ( cartesianChart.horizontalAxis is DateTimeAxis )
return HORIZONTAL;
if ( cartesianChart.verticalAxis is DateTimeAxis )
return VERTICAL;
}
return null;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment