?? calendardisplay.as
字號:
}
// the last hour visible on screen based on our current scroll position.
private function get lastVisibleHour():Number
{
return _scrollHour + Math.floor(_dayAreaHeight / _hourHeight*2)/2;
}
// this function will return the scroll position the can best guarantee that the events
// passed in would be visible on screen.
private function computeScrollHourToDisplayEvents(events:Array):Number
{
if(events.length == 0)
return 8;
var hoursSortedByStartTime:Array = events.concat();
hoursSortedByStartTime.sort(function(lhs:CalendarEvent, rhs:CalendarEvent):Number
{
var ltime:Number = _tz.timeOnly(lhs.start);
var rtime:Number = _tz.timeOnly(rhs.end);
return (rhs.allDay || ltime < rtime)? -1:
(lhs.allDay || ltime > rtime)? 1:
0;
}
);
return hoursSortedByStartTime[0].allDay? 8:hoursSortedByStartTime[0].start.hours;
}
//----------------------------------------------------------------------------------------------------
// animation callbacks
//----------------------------------------------------------------------------------------------------
// initialization function for the layout of new events appearing on screen. The LayoutAnimator
// will call this for each event that gets rendered for the first time.
private function setupNewEventTarget(target:LayoutTarget):void
{
// if it's an item being dragged, we don't want any animation on it,
// just to have it initialize to its starting position, size, and scale.
if(_dragEventData != null && IDataRenderer(target.item).data == _dragEventData.event)
{
target.item.setActualSize(target.unscaledWidth,target.unscaledHeight);
target.item.x = target.x;
target.item.y = target.y;
var m:Matrix = DisplayObject(target.item).transform.matrix;
m.a = m.d = 1;
DisplayObject(target.item).transform.matrix = m;
}
else
{
// we want new items to zoom out from their center point.
target.item.setActualSize(target.unscaledWidth,target.unscaledHeight);
target.item.x = target.x + target.unscaledWidth/2;
target.item.y = target.y + target.unscaledHeight/2;
m = DisplayObject(target.item).transform.matrix;
m.a = m.d = 0;
DisplayObject(target.item).transform.matrix = m;
}
}
// an initializer function for items that we want to fade in to place
// at their full size.
private function fadeInTarget(target:LayoutTarget):void
{
target.item.setActualSize(target.unscaledWidth,target.unscaledHeight);
target.item.x = target.x;
target.item.y = target.y;
target.item.alpha = 0;
}
// a remove function for items that we want to fade out in place
// at their full size.
private function fadeOutTarget(target:LayoutTarget):void
{
target.alpha = 0;
target.unscaledHeight = target.item.height;
target.unscaledWidth = target.item.width;
target.x = target.item.x;
target.y = target.item.y;
}
//----------------------------------------------------------------------------------------------------
// managing event data
//----------------------------------------------------------------------------------------------------
// this function makes sure that our EventData objects, which store all the metadata we need to
// render a single CalendarEvent, are in sync with our data provider.
private function updateEventData():void
{
// normally, when we update the screen, any events that were previously
// on screen animate to their new position, and any new ones appear.
// Sometimes, however, we don't want existing events to animate into place...
// we just want all events on screen to just appear in place (i.e., sometimes
// it would look odd to the user to try and correlate the previous view to the new
// view).
if(false && _removeAllEventData)
{
// throw out all previous event data. Our animation keys off the identify of our
// eventData objects, so if we throw them all out, every event will be new from an
// animation perspective.
removeAllEventData();
for(var i:int = 0;i<_visibleEvents.length;i++)
{
var event:CalendarEvent = _visibleEvents[i];
buildEventData(event);
}
}
else
{
// we keep a dictionary so we can look up
// event data by event. Here we're going to
// iterate through our visible events, and build a new lookup dtable.
// for each event, we'll see if we have a matching eventData in our old
// lookup table. If we do, we transfer it to the new one and remove it from the old
// one. Otherwise, we'll create a new one and add it to the new lookup table. In the
// end, we should be left with two lookup tables...the new one, with data for each event
// now visible on screen, and the old one, which should at that point only have the data
// for items that are no longer on screen. So at that point we just cleanup the unneeded old
// event data, and call it a day.
var oldEventData:Dictionary = _eventData;
_eventData = new Dictionary();
for(i = 0;i<_visibleEvents.length;i++)
{
event = _visibleEvents[i];
// try and find data for this event in the old lookup table
var ed:EventData = oldEventData[event];
if(ed == null)
{
// none existed, so create new data.
buildEventData(event);
}
else
{
// some existed, so add it to the lookup table
_eventData[event] = ed;
// make sure it's still correct for our new state.
validateEventData(ed);
// and remove it from the old lookup table.
delete oldEventData[event];
}
}
for(var anEvent:* in oldEventData)
{
// throw out everything remaining from the old lookup table.
removeEventData(oldEventData[anEvent]);
}
}
}
// utility function that cleans up every piece of EventData in our lookup table.
private function removeAllEventData():void
{
for(var aKey:* in _eventData)
{
var data:EventData = _eventData[aKey];
for(var i:int=0;i<data.renderers.length;i++)
{
// clean up the renderers associated with this event data.
var renderer:UIComponent = data.renderers[i];
renderer.parent.removeChild(renderer);
// make sure our layout animator forgets about it.
var target:LayoutTarget = _animator.releaseTarget(renderer);
if(target != null)
target.animate = false;
}
}
// all our event data is gone, so start with a fresh lookup table.
_eventData = new Dictionary();
}
// remove a single piece of EventData from our lookup table
private function removeEventData(data:EventData):void
{
for(var i:int=0;i<data.renderers.length;i++)
{
// clean up all of its renderers
var renderer:UIComponent = data.renderers[i];
renderer.parent.removeChild(renderer);
// and remove it from the lookup table.
var target:LayoutTarget = _animator.releaseTarget(renderer);
if(target != null)
target.animate = false;
}
}
// initalize a new eventData structure for the given CalendarEvent.
private function buildEventData(event:CalendarEvent):EventData
{
var data:EventData = _eventData[event] = new EventData();
data.renderers = [];
data.event = event;
validateEventData(data);
return data;
}
// utility function that validates a single EventData structure to make
// sure it has the right information for the event given our current state.
private function validateEventData(data:EventData):void
{
var event:CalendarEvent = data.event;
// EventData.range contains the visible portion of the this event's range,
// given our current visible range. So we intersect the two.
data.range = event.range.intersect(_visibleRange);
// now, we know how long the visible portion of this event is. We want
// to create the renderers we need to display it. Usually it's
// 1-1, but sometimes we need more than one renderer for an event.
// specifically, if we're showing multiple weeks, and the event spans
// more than one week, we'll need 1 renderer for each visible week it spans.
// find out how many weeks it spans.
var weekSpan:int = _tz.rangeWeekSpan(data.range);
// figure out where we're going to place these events. Because we scroll and mask
// intra-day events in days view, we need to place it in a different parent
// than all/multi day events
var parent:UIComponent = (event.allDay)? _allDayEventLayer:_eventLayer;
var sn:String = getStyle("eventStyleName");
var rendererCount:Number = data.renderers.length;
// if we don't have enough renderers for this event
if(weekSpan > rendererCount)
{
for(var i:int = rendererCount;i<weekSpan;i++)
{
// create a renderer, listen for mouse down events
var renderer:CalendarEventRenderer = new CalendarEventRenderer();
renderer.addEventListener(MouseEvent.MOUSE_DOWN,mouseDownOnEventHandler);
data.renderers.push(renderer);
// assign it the right data and style.
renderer.data = event;
renderer.styleName = sn;
parent.addChild(renderer);
if(data == _dragEventData)
{
// if we're currently dragging this event, we need to give it a nice dropshadow.
// TODO: centralize the configuration of a dragging item, and make it customizable
renderer.filters = [
_dragFilter
]
}
}
}
else
{
// we have too many renderers, so let's throw the extra ones away.
for(i = weekSpan;i<rendererCount;i++)
{
renderer = data.renderers[i];
//Check if the renderer is null, if null, we needn't remove it.
if(renderer!=null){
renderer.parent.removeChild(renderer);
}
}
data.renderers.splice(weekSpan,rendererCount-weekSpan);
}
}
//----------------------------------------------------------------------------------------------------
// click event handlers
//----------------------------------------------------------------------------------------------------
// event handler called when the user clicks on a day header.
private function headerClickHandler(e:MouseEvent):void
{
var d:Date = IDataRenderer(e.currentTarget).data as Date;
if(d == null)
return;
// rename and redispatch the event
var newEvent:CalendarDisplayEvent = new CalendarDisplayEvent(CalendarDisplayEvent.HEADER_CLICK);
newEvent.dateTime = d;
dispatchEvent(newEvent);
}
// event handler called when the user clicks on a day
private function dayClickHandler(e:MouseEvent):void
{
var d:Date = IDataRenderer(e.currentTarget).data as Date;
if(d == null)
return;
//rename and redispatch the event
var newEvent:CalendarDisplayEvent = new CalendarDisplayEvent(CalendarDisplayEvent.DAY_CLICK);
newEvent.dateTime = d;
dispatchEvent(newEvent);
}
//----------------------------------------------------------------------------------------------------
// event dragging behavior
//----------------------------------------------------------------------------------------------------
// converts a point, in the calendar's coordinate system, into a date.
private function localToDateTime(pt:Point):Date
{
var result:Date = new Date(_visibleRange.start);
if(_displayMode == "day" || _displayMode == "days")
{
// in day(s) mode, we only have one row. So we convert our horizontal position into
// an index by dividing by the width of each day
var dayIndex:Number = (pt.x - _border.left)/_cellWidth;
dayIndex = Math.floor(Math.max(dayIndex,0));
// in day(s) mode, the vertical position corresponds to the hour. So we divide the y value
// by the height of one our, accounting for our current scroll position.
var hourCount:Number = (pt.y + _scroller.scrollPosition - _allDayAreaHeight)/_hourHeight;
// round off to half hours (this probably should be configurable)
// TODO: make the roundoff configurable
hourCount = Math.round(hourCount*2)/2;
// if the mouse is too high or too low, it will round out to the next day. So clamp it.
hourCount = Math.max(0,Math.min(24,hourCount));
// add our hour and day calculations to the start of our visible range to get the actual time represented.
result.date += dayIndex;
result.milliseconds = result.seconds = result.minutes = 0;
result.hours = Math.floor(hourCount);
result.minutes = (hourCount - result.hours)*60;
// we didn't clamp our day range...so if we go beyond our horizontal range, clamp it to the last day of the visible range.
if(result > _visibleRange.end)
{
result.fullYear = _visibleRange.end.fullYear;
result.date = _visibleRange.end.date;
result.month = _visibleRange.end.month;
}
}
else
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -