Show
Ignore:
Timestamp:
08/14/10 12:54:49 (21 months ago)
Author:
mszopinski
Message:

calendar, one-week display
fixes

Files:
1 modified

Legend:

Unmodified
Added
Removed
  • ssme/trunk/flex/Calendar/src/com/kh/ssme/components/DayCanvas.as

    r4040 r4042  
    2424 
    2525    import com.kh.ssme.entity.TimeFrameEntity; 
    26 import com.kh.ssme.util.DateUtil; 
    27 import com.kh.ssme.util.HashArray; 
    28  
    29 import flash.display.DisplayObject; 
    30  
    31 import mx.containers.Canvas; 
    32 import mx.controls.Label; 
    33 import mx.controls.TextArea; 
    34  
    35 public class DayCanvas extends GridCanvas { 
     26    import com.kh.ssme.util.DateUtil; 
     27    import com.kh.ssme.util.HashArray; 
     28 
     29import com.kh.ssme.util.Logger; 
     30import com.kh.ssme.util.Logger; 
     31 
     32    public class DayCanvas extends GridCanvas { 
    3633 
    3734        public function DayCanvas() { 
     
    4138        public var currentDay:Date; 
    4239 
     40        private var oldWidth:Number, oldHeight:Number; 
    4341        override protected function updateDisplayList(unscaledWidth:Number, unscaledHeight:Number):void{ 
    4442 
    45             if(visible){    // repaint only if visible 
     43            if(visible){    // necessary only if visible 
     44 
    4645                // call first in order to get grid drawn correctly 
    47                 super.updateDisplayList(unscaledWidth, unscaledHeight); 
     46                super.updateDisplayList(unscaledWidth, unscaledHeight);                 
     47 
     48                // call repaint only if dimensions were changed 
     49                if((unscaledWidth+unscaledHeight) - (oldWidth+oldHeight)){ 
     50                    oldWidth = unscaledWidth; 
     51                    oldHeight = unscaledHeight; 
     52                    repaint();     
     53                } 
    4854            } 
    4955        } 
     
    5157        [ArrayElementType("com.kh.ssme.entity.TimeFrameEntity")] 
    5258        private var dataProvider_:HashArray; 
     59        private var eventsMap:HashArray = new HashArray(); 
     60 
    5361        public function set dataProvider(value:HashArray):void{ 
     62            dataProviderAvailable = false; 
     63            eventFieldsUpToDate = false; 
     64            recreateEvents = true; 
    5465            dataProvider_ = value; 
    5566             
     
    5768                if( eventsMap.getValueAt(i) ){ 
    5869                    this.removeChild( eventsMap.getValueAt(i) );                     
    59                     trace( "REMOVE : "+eventsMap.getValueAt(i).data+" - ["+eventsMap.getValueAt(i).data.UUID+"] " ); 
    6070                } 
    6171            } 
    6272            eventsMap.clear(); 
    63              
    64             createEvents(); 
     73            dataProviderAvailable = true;             
     74 
     75            repaint(); 
    6576            validateNow(); 
    6677        } 
     
    6980        }     
    7081 
    71         private var eventsMap:HashArray = new HashArray(); 
    72         public function createEvents():void{ 
    73  
    74             // prepare additional data about events 
    75              
    76  
    77             // create events 
     82        private var dataProviderAvailable:Boolean = false; 
     83        private var recreateEvents:Boolean = false;         
     84        private var eventFieldsUpToDate:Boolean = false; 
     85        public function repaint():void{ 
     86            if(dataProviderAvailable){ 
     87                createEvents(); 
     88                repaintEvents(); 
     89            } 
     90        } 
     91 
     92        /** 
     93         * Create display object for each TimeFrameEntity in dataProvider 
     94         */ 
     95        protected function createEvents():void{ 
     96 
     97            // in order to save time we recreate EventFields 
     98            // only if it is necessary 
     99            if(recreateEvents){ 
     100 
     101                // create events 
     102                var ev:EventField; 
     103                var i:int = 0, timeBegin:int, timeEnd:int; 
     104                var from:DateUtil, to:DateUtil, current:DateUtil = (new DateUtil(currentDay)).dayBegin(); 
     105                for each(var json:TimeFrameEntity in dataProvider_){ 
     106                    ev = new EventField(); 
     107                    eventsMap.put(json.UUID, ev); 
     108 
     109                    ev.eventInfo = new SimpleEventDisplay(); 
     110                    ev.data = json; 
     111                    ev.name = json.UUID; 
     112 
     113                    // event boundaries, index 
     114                    timeBegin = (json.from.getHours() * 4) + ((json.from.getMinutes() as int)/15); 
     115                    timeEnd = (json.to.getHours() * 4) + ((json.to.getMinutes() as int)/15); 
     116                    // check if event exceed current day 
     117                    from = (new DateUtil(json.from)).dayBegin(); 
     118                    to = (new DateUtil(json.to)).dayBegin(); 
     119                    if( current.compare(from) > 0 )    timeBegin = 0; 
     120                    if( current.compare(to) < 0 )       timeEnd = rowsPosition[1].length - 1; 
     121                    // store for future use 
     122                    ev.beginIndex = timeBegin; 
     123                    ev.endIndex = timeEnd; 
     124 
     125                    ev.setStyle("borderThickness", 5); 
     126                    ev.setStyle("cornerRadius", 20); 
     127 
     128                    addChild( ev ); 
     129                } 
     130 
     131                recreateEvents = false; 
     132            } 
     133        } 
     134 
     135        // used by repaint 
     136        private var clusterOfEventsMap:HashArray = new HashArray();         
     137        /** 
     138         * Calculates rank and coordinates for each TimeFrame display object   
     139         */ 
     140        protected function repaintEvents():void{ 
    78141            var ev:EventField; 
    79             var i:int = 0; 
    80             for each(var json:TimeFrameEntity in dataProvider_){                 
    81                 ev = new EventField(); 
    82                 eventsMap.put(json.UUID, ev); 
     142            var countArray:Array; 
     143            var i:int, j:int = 0; 
     144 
     145            // in order to save time we recalculate ranks, clusters etc. 
     146            // only if it is necessary 
     147            if(!eventFieldsUpToDate){ 
     148                //------------------------------------------------ 
     149                // "rank" events 
     150                // count number of events for each quarter 
     151                countArray = new Array(96); 
     152                for each(ev in eventsMap){ 
     153                    for(i=ev.beginIndex; i<ev.endIndex; i++){ 
     154                        if(countArray[i]<0 || isNaN(countArray[i]))     countArray[i]=0; 
     155                        countArray[i]++; 
     156                    } 
     157                } 
     158 
     159                // calculate rank and number of neighbours for each event 
     160                var neighbours:int; 
     161                for each(ev in eventsMap){ 
     162                    neighbours = 0; 
     163                    for(i=ev.beginIndex; i<ev.endIndex; i++)   neighbours = Math.max( neighbours, countArray[i] ); 
     164                    ev.neighbours = neighbours - 1; 
     165                    ev.rank = neighbours*10000 + (ev.endIndex - ev.beginIndex)*100 + ev.beginIndex; 
     166                } 
     167                //------------------------------------------------ 
     168 
     169 
     170                //------------------------------------------------ 
     171                //clustering events into separated groups which don't intersect each other 
     172                var clusterIndex:Array = new Array(96); 
     173                var helpMap:HashArray, lastCreatedClusterID:int = 1; 
     174                var trace:String = ""; 
     175 
     176                // clear old clusters 
     177                clusterOfEventsMap.clear(); 
    83178                 
    84                 ev.eventInfo = new SimpleEventDisplay(); 
    85                 ev.data = json; 
    86                 ev.name = json.UUID; 
    87                 ev.setStyle("borderThickness", 5); 
    88                 ev.setStyle("cornerRadius", 20); 
    89                 trace( "ADD : "+ev.data+" - ["+ev.data.UUID+"] " );                      
    90  
    91                 addChild( ev ); 
    92                 sizeEvent( ev, i ); 
    93                 i += 100; 
    94  
    95             } 
    96  
    97         } 
    98  
    99         private function sizeEvent(ev:EventField, i:int):void{ 
     179                // for each of the events 
     180                for each(ev in eventsMap){ 
     181                    helpMap = new HashArray(); 
     182 
     183                    // check the time span of current event 
     184                    // if there were already clusters defined for this span then collect their ids 
     185                    for(i=ev.beginIndex; i<ev.endIndex; i++){ 
     186                        if(clusterIndex[i]<0 || isNaN(clusterIndex[i]))     clusterIndex[i]=0; 
     187                        if(!helpMap.containsKey(clusterIndex[i]) && clusterIndex[i]>0){ 
     188                            helpMap.put(clusterIndex[i], clusterIndex[i]); 
     189                        } 
     190                    } 
     191 
     192                    if(helpMap.size == 0){  //  helpMap.size == #clusters 
     193                        // there were no clusters so far for this span, 
     194                        // so we 'book' the span and create new cluster on the base of current event 
     195                        for(i=ev.beginIndex; i<ev.endIndex; i++)    clusterIndex[i] = lastCreatedClusterID; 
     196                        clusterOfEventsMap.put(lastCreatedClusterID, [ ev ]); 
     197                        lastCreatedClusterID++; 
     198                    } 
     199                    if(helpMap.size == 1){ 
     200                        // there was one cluster for this span 
     201                        // so we just join current event to cluster we found 
     202                        var currentCluster:int = helpMap.getKeyAt(0); 
     203                        for(i=ev.beginIndex; i<ev.endIndex; i++)    clusterIndex[i] = currentCluster; 
     204                        clusterOfEventsMap[currentCluster].push( ev ); 
     205                    } 
     206                    if(helpMap.size > 1){ 
     207                        // there was more than one cluster for this span 
     208                        // we join cluster we found into new single one 
     209                        // so we just join current event to cluster we found 
     210                        var temp:Array = [ ev ]; 
     211                        var minIndex:int = ev.beginIndex, maxIndex:int = ev.endIndex; 
     212                        for each(var value:* in helpMap){ 
     213                            for each(var clusterElement:EventField in clusterOfEventsMap[value]){ 
     214                                temp.push( clusterElement ); // add to new cluster 
     215                                minIndex = Math.min(minIndex, clusterElement.beginIndex ); 
     216                                maxIndex = Math.max(maxIndex, clusterElement.beginIndex ); 
     217                            } 
     218                            clusterOfEventsMap.deleteWithKey(value); 
     219                        } 
     220                        for(i=minIndex; i<maxIndex; i++)    clusterIndex[i] = lastCreatedClusterID; 
     221                        clusterOfEventsMap.put(lastCreatedClusterID, temp); 
     222                        lastCreatedClusterID++; 
     223                    } 
     224 
     225                } 
     226 
     227                for (var key:String in clusterOfEventsMap){ 
     228                    trace = ""; 
     229                    var el:EventField; 
     230                    for each(el in clusterOfEventsMap[key])  trace+= (el.data as TimeFrameEntity).UUID.substr(0, 3)+"|"; 
     231                    Logger.debug( "~("+key+") -> ["+trace+"]" ); 
     232                } 
     233                //------------------------------------------------ 
     234 
     235                eventFieldsUpToDate = true; 
     236            } 
     237 
     238 
     239            //------------------------------------------------ 
     240            // for each cluster size it's events 
     241            j = 0; 
     242            var placeArray:Array = new Array(96); 
     243            var minPosition:int = 0, numberOfPositions:int = 0; 
     244            for each(var eventsArray:Array in clusterOfEventsMap){ 
     245                // sort events by rank 
     246                eventsArray.sort( sortEventsByRank ); 
     247 
     248                // calculate sub-optimal position within cluster 
     249                // surely there's a better algorithm :) 
     250                numberOfPositions = 0;                 
     251                for each(ev in eventsArray){ 
     252                    minPosition = 0; 
     253                    // find minimal possible position (maximum of available position in span) 
     254                    for(i=ev.beginIndex; i<ev.endIndex; i++){ 
     255                        if(placeArray[i]<0 || isNaN(placeArray[i]))     placeArray[i]=0; 
     256                        minPosition = Math.max( minPosition, placeArray[i] ); 
     257                    } 
     258                    // store information in event 
     259                    ev.leftPosition = minPosition; 
     260                    //update position availability array for current span 
     261                    for(i=ev.beginIndex; i<ev.endIndex; i++){ 
     262                        placeArray[i] = minPosition + 1; 
     263                    } 
     264                    numberOfPositions = Math.max( numberOfPositions, minPosition ); 
     265                }                 
     266 
     267                // size events 
     268                for each(ev in eventsArray){ 
     269                    sizeEvent( ev, eventsArray.length, numberOfPositions, j ); 
     270                    j += 100; 
     271                } 
     272            } 
     273            //------------------------------------------------         
     274        } 
     275        private function sortEventsByRank(a:EventField, b:EventField):int { 
     276            return ( a.rank < b.rank ) ? -1 : (( a.rank > b.rank ) ? 1 : 0 ); 
     277        }     
     278 
     279        private function sizeEvent(ev:EventField, clusterSize:int, numberOfPositions:int, i:int):void{ 
    100280            var data:TimeFrameEntity = ev.eventInfo.eventData; 
    101281            if(data){ 
    102                 var timeBegin:int = (data.from.getHours() * 4) + ((data.from.getMinutes() as int)/15); 
    103                 var timeEnd:int = (data.to.getHours() * 4) + ((data.to.getMinutes() as int)/15); 
    104  
    105                 // if event exceed current day 
    106                 var from:DateUtil = (new DateUtil(data.from)).dayBegin(); 
    107                 var current:DateUtil = (new DateUtil(currentDay)).dayBegin(); 
    108                 var to:DateUtil = (new DateUtil(data.to)).dayBegin(); 
    109             
    110                 if( current.compare(from) > 0 ){ 
    111                     timeBegin = 0; 
    112                 } 
    113                 if( current.compare(to) < 0 ){ 
    114                     timeEnd = rowsPosition[1].length - 1; 
    115                 } 
    116         
    117                 ev.width = 200;//XXX 
    118                 ev.height = rowsPosition[1][timeEnd] - rowsPosition[1][timeBegin];                 
    119                 ev.x = 50+i;//XXX 
    120                 ev.y = rowsPosition[1][timeBegin]; 
     282                var availableWidth:Number = this.width - this.leftHorizontalMargin_ - this.rightHorizontalMargin_; 
     283                ev.width = availableWidth * (2 / (numberOfPositions+2)); 
     284                ev.height = rowsPosition[1][ev.endIndex] - rowsPosition[1][ev.beginIndex]; 
     285                ev.x = this.leftHorizontalMargin_ + ((availableWidth / (numberOfPositions+2)) * ev.leftPosition); 
     286                ev.y = rowsPosition[1][ev.beginIndex]; 
     287                this.setChildIndex( ev, 0 ); 
    121288                ev.invalidateSize(); 
    122289                ev.invalidateDisplayList();