[kronolith] Reimplement column spanning in DayView and WeekView (commit please)

Jeroen Huinink j.huinink at wanadoo.nl
Thu Dec 12 22:30:05 PST 2002


Hello,

While working on the side-by-side DayView and WeekView I noticed some
problems with the current column spanning algorithm that causes
possible problems when there are different numbers of events in
different rows. The problem is obvious in the weekview. Because events
from one day run into the next day.

When you only use a single calendar this problem will probably not
occur, because it is very rare when you have more than one event at a
certain time. However if you view shared calendars (collapsed) it is
very probable that there is more than one event at a single time.

I reworked the column spanning algorithm and submit it for approval. I
am not sure if I understood all the intentions behind the current
algorithm. It seems to try to fill a row as much as possible by
expanding an event over multiple columns if possible or something like
that.

My implementation seems more straightforward and robust to me, but
without such finer points.

What I noted is that the current code is really lacking comments
explaining the intentions. I tried working within the current
algorithm first and fix it, but soon I was lost because there were no
comments/explanations guiding me.

Regards,
Jeroen
-------------- next part --------------
Index: DayView.php
===================================================================
RCS file: /repository/kronolith/lib/DayView.php,v
retrieving revision 1.106
diff -r1.106 DayView.php
104c104
<                 && count($this->_event_matrix[$i]) == 0) {
---
>                 && !isset($this->_event_matrix[$i])) {
113,136c113,130
< 
<             foreach ($this->_event_matrix[$i] as $key) {
<                 $event = $this->_events[$key];
<                 $start = mktime(floor($i/2), ($i % 2) * 30, 0, $this->month, $this->mday, $this->year);
<                 $span = $this->_span - $event->overlap + 1;
<                 if ($event->startTimestamp < $start + 60 * 30 && $event->endTimestamp > $start) {
<                     $hspan += $span;
<                 }
< 
<                 $categoryColor = isset($colors[$event->getCalendar()][$event->getCategory()]) ? $colors[$event->getCalendar()][$event->getCategory()] : '#ccccff';
<                 if ($event->startTimestamp >= $start && $event->startTimestamp < $start + 60 * 30 || $start == $this->getStamp()) {
<                     $row .= '<td class="day-eventbox" style="background-color: ' . $categoryColor . '; ';
<                     $row .= 'border-color: ' . Kronolith::borderColor($categoryColor) . '" ';
<                     $row .= 'onmouseover="javascript:style.backgroundColor=\'' . Horde_Image::modifyColor($categoryColor) . '\'" ';
<                     $row .= 'onmouseout="javascript:style.backgroundColor=\'' . $categoryColor . '\'" ';
<                     $row .= 'valign="top" width="' . round(100 * ($span / $this->_span)) . '%" colspan="' . $span . '" rowspan="' . $event->rowspan . '">';
<                     $row .= $event->getLink($this->getStamp());
<                     $row .= '&nbsp;</td>' . "\n";
<                 }
<             }
< 
<             $diff = $this->_span - $hspan;
<             if ($diff > 0) {
<                 for ($t = 0; $t < $diff; $t ++) {
---
>             if (isset($this->_event_matrix[$i])) {
>                 foreach ($this->_event_matrix[$i] as $id => $key) {
>                     if ($id!=='slotsize') {
>                         $event = $this->_events[$key];
>                         $start = mktime(floor($i/2), ($i % 2) * 30, 0, $this->month, $this->mday, $this->year);
>                         $categoryColor = isset($colors[$event->getCalendar()][$event->getCategory()]) ? $colors[$event->getCalendar()][$event->getCategory()] : '#ccccff';
>                         if ($event->startTimestamp >= $start && $event->startTimestamp < $start + 60 * 30 || $start == $this->getStamp()) {
>                             $row .= '<td class="day-eventbox" style="background-color: ' . $categoryColor . '; ';
>                             $row .= 'border-color: ' . Kronolith::borderColor($categoryColor) . '" ';
>                             $row .= 'onmouseover="javascript:style.backgroundColor=\'' . Horde_Image::modifyColor($categoryColor) . '\'" ';
>                             $row .= 'onmouseout="javascript:style.backgroundColor=\'' . $categoryColor . '\'" ';
>                             $row .= 'valign="top" width="' . round(100 * (1 / $this->_span)) . '%" rowspan="' . $event->rowspan . '">';
>                             $row .= $event->getLink($this->getStamp());
>                             $row .= '&nbsp;</td>' . "\n";
>                         }
>                     }
>                 } 
>                 for ($t = $this->_event_matrix[$i]['slotsize']; $t < $this->_span; $t++) {
138a133,134
>             } else {
>                 $row .= '<td colspan="' . $this->_span . '" class="' . $style . '">&nbsp;</td>' . "\n";
140d135
< 
172a168
>         $this->last = 0;
184c180,208
<                 $tmp[] = $event;
---
>                 $startslot = floor(($event->start->hour * 60 + $event->start->min)/30);
>                 $endslot = floor(($event->end->hour * 60 + $event->end->min)/30);
>                 if ($startslot == $endslot) {
>                     $slot = $startslot;
>                     $event->rowspan = 0;
>                     if(!isset($this->_event_matrix[$slot])) {
>                         $this->_event_matrix[$slot] = array();
>                     }
>                     if(!isset($this->_event_matrix[$slot]['slotsize'])) {
>                         $this->_event_matrix[$slot]['slotsize'] = 0;
>                     }
>                     $this->_event_matrix[$slot]['slotsize'] += 1;
>                     $this->_event_matrix[$slot][] = $key;
>                     $this->last = max($this->last,$slot);
>                 } else {
>                     $event->rowspan = $endslot - $startslot; 
>                     for ($slot = $startslot; $slot < $endslot; $slot++){ 
>                         if(!isset($this->_event_matrix[$slot])) {
>                             $this->_event_matrix[$slot] = array();
>                         }
>                         if(!isset($this->_event_matrix[$slot]['slotsize'])) {
>                             $this->_event_matrix[$slot]['slotsize'] = 0;
>                         }
>                         $this->_event_matrix[$slot]['slotsize'] += 1;
>                         $this->_event_matrix[$slot][] = $key;
>                         $this->last = max($this->last,$slot);
>                     }
>                 }
>                 $tmp[$key] = $event;
187,188d210
<         $this->_events = $tmp;
< 
190,191c212,216
<         $this->last = 0;
<         for ($i = 0; $i < 48; $i++) {
---
>         $this->_events = $tmp;
>         foreach ($this->_event_matrix as $sid => $slot) {
>             $maxspan = max($maxspan,$slot['slotsize']);
>         }
>         /*for ($i = 0; $i < 48; $i++) {
198,200d222
<                     if ($i > $this->last) {
<                         $this->last = $i;
<                     }
202,206d223
<                     if (!isset($event->rowspan)) {
<                         $this->_events[$key]->rowspan = 1;
<                     } else {
<                         $this->_events[$key]->rowspan++;
<                     }
213d229
<                     $maxspan = max(count($this->_event_matrix[$i]), $maxspan);
217c233
<         }
---
>         }*/
-------------- next part --------------
Index: WeekView.php
===================================================================
RCS file: /repository/kronolith/lib/WeekView.php,v
retrieving revision 1.62
diff -r1.62 WeekView.php
129c129
<                     $notstarted &= (count($this->days[$j]->_event_matrix[$i]) == 0);
---
>                     $notstarted &= (!isset($this->days[$j]->_event_matrix[$i]));
146,164c146,161
< 
<                 foreach ($this->days[$j]->_event_matrix[$i] as $key) {
<                     $event = $this->days[$j]->_events[$key];
<                     $start = mktime(floor($i/2), ($i % 2) * 30, 0, $this->days[$j]->month, $this->days[$j]->mday, $this->days[$j]->year);
<                     $span = $this->days[$j]->_span - $event->overlap + 1;
<                     if (($event->startTimestamp < $start + 60 * 30 && $event->endTimestamp > $start) ||
<                         ($event->startTimestamp == $event->startTimestamp && $event->startTimestamp = $start)) {
<                         $hspan += $span;
<                     }
< 
<                     $categoryColor = isset($colors[$event->getCalendar()][$event->getCategory()]) ? $colors[$event->getCalendar()][$event->getCategory()] : '#ccccff';
<                     if ($event->startTimestamp >= $start && $event->startTimestamp < $start + 60 * 30 || $start == $this->days[$j]->getStamp()) {
<                         $row .= '<td class="week-eventbox" style="background-color: ' . $categoryColor . '; ';
<                         $row .= 'border-color: ' . Kronolith::borderColor($categoryColor) . '" ';
<                         $row .= 'onmouseover="javascript:style.backgroundColor=\'' . Horde_Image::modifyColor($categoryColor) . '\'" ';
<                         $row .= 'onmouseout="javascript:style.backgroundColor=\'' . $categoryColor . '\'" ';
<                         $row .= 'valign="top" width="' . round(90 * ($span / $this->days[$j]->_span / count($this->days))) . '%" colspan="' . $span . '" rowspan="' . $event->rowspan . '">';
<                         $row .= $event->getLink($this->days[$j]->getStamp());
<                         $row .= '&nbsp;</td>' . "\n";
---
>                 if (isset($this->days[$j]->_event_matrix[$i])) {
>                     foreach ($this->days[$j]->_event_matrix[$i] as $id => $key) {
>                         if($id!=='slotsize') {
>                             $event = $this->days[$j]->_events[$key];
>                             $start = mktime(floor($i/2), ($i % 2) * 30, 0, $this->days[$j]->month, $this->days[$j]->mday, $this->days[$j]->year);
>                             $categoryColor = isset($colors[$event->getCalendar()][$event->getCategory()]) ? $colors[$event->getCalendar()][$event->getCategory()] : '#ccccff';
>                             if ($event->startTimestamp >= $start && $event->startTimestamp < $start + 60 * 30 || $start == $this->days[$j]->getStamp()) {
>                                 $row .= '<td class="week-eventbox" style="background-color: ' . $categoryColor . '; ';
>                                 $row .= 'border-color: ' . Kronolith::borderColor($categoryColor) . '" ';
>                                 $row .= 'onmouseover="javascript:style.backgroundColor=\'' . Horde_Image::modifyColor($categoryColor) . '\'" ';
>                                 $row .= 'onmouseout="javascript:style.backgroundColor=\'' . $categoryColor . '\'" ';
>                                 $row .= 'valign="top" width="' . round(90 * (1/ $this->days[$j]->_span / count($this->days))) . '%" rowspan="' . $event->rowspan . '">';
>                                 $row .= $event->getLink($this->days[$j]->getStamp());
>                                 $row .= '&nbsp;</td>' . "\n";
>                             }
>                         }
166,172c163,164
<                 }
< 
<                 $diff = $this->days[$j]->_span - $hspan;
< 
<                 if ($diff > 0) {
<                     for ($t = 0; $t < $diff; $t++) {
<                         $row .= '<td width="' . round(90 * (1 / $this->days[$j]->_span / count($this->days))) . '%" colspan="1" class="' . $style . '">&nbsp;</td>' . "\n";
---
>                     for ($t = $this->days[$j]->_event_matrix[$i]['slotsize']; $t < $this->days[$j]->_span; $t++) {
>                         $row .= '<td width="' . round(100 * (1 / $this->days[$j]->_span / count($this->days))) . '%" colspan="1" class="' . $style . '">&nbsp;</td>' . "\n";
173a166,167
>                 } else {
>                     $row .= '<td colspan="' . $this->days[$j]->_span . '" class="' . $style . '">&nbsp;</td>' . "\n";


More information about the kronolith mailing list