2014-10-07 63 views
3

我正在创建某种显示特定日期事件的日历/议程。每个事件在垂直小时网格中显示为HTML元素。可能同时存在多个(“碰撞”)事件,在这些情况下,这些元素应该水平放置并排放置,并且具有相同的宽度。例如。四个碰撞事件的列值为4,这样的宽度为25%。放置彼此相邻的碰撞元素

棘手的部分是这些碰撞事件。我以为我解决了它,但一些元素得到错误的列数。

可能有更好的方法来计算列数和位置 - 我愿意接受建议。当前(错误的)结果

样品图片: enter image description here

相关代码:

<?php 
    class Calendar { 
     const ROW_HEIGHT = 24; 

     public $events = array(); 
     public $blocks = array(); 


     public function calculate_blocks() { 
      foreach($this->events as $event) { 

       // Calculate the correct height and vertical placement 
       $top = $this->time_to_pixels($event->_event_start_time); 
       $bottom = $this->time_to_pixels($event->_event_end_time); 
       $height = $bottom - $top; 

       // Abort if there's no height 
       if(!$height) continue; 

       $this->blocks[] = array(
        'id' => $event->ID, 
        'columns' => 1, 
        'placement' => 0, // Column order, 0 = first 
        'css' => array(
         'top' => $top, 
         'bottom' => $bottom, // bottom = top + height 
         'height' => $height 
        ) 
       ); 
      } 

      $done = array(); 

      // Compare all the blocks with each other 
      foreach($this->blocks as &$block) { 
       foreach($this->blocks as &$sub) { 

        // Only compare two blocks once, and never compare a block with itself 
        if($block['id'] == $sub['id'] || (isset($done[$block['id']]) && in_array($sub['id'], $done[$block['id']])) || (isset($done[$sub['id']]) && in_array($block['id'], $done[$sub['id']]))) continue; 
        $done[$block['id']][] = $sub['id']; 

        // If the blocks are colliding 
        if(($sub['css']['top'] >= $block['css']['top'] && $sub['css']['top'] < $block['css']['bottom']) 
        || ($sub['css']['bottom'] >= $block['css']['top'] && $sub['css']['bottom'] < $block['css']['bottom']) 
        || ($sub['css']['top'] <= $block['css']['top'] && $sub['css']['bottom'] >= $block['css']['bottom'])) { 

         // Increase both blocks' columns and sub-block's placement 
         $sub['columns'] = ++$block['columns']; 
         $sub['placement']++; 
        } 
       } 
      } 
     } 


     private function time_to_int($time) { 

      // H:i:s (24-hour format) 
      $hms = explode(':', $time); 
      return ($hms[0] + ($hms[1]/60) + ($hms[2]/3600)); 
     } 


     private function time_to_pixels($time) { 
      $block = $this->time_to_int($time); 

      return (int)round($block * self::ROW_HEIGHT * 2); 
     } 
    } 
?> 
+0

我不认为这是要在PHP中解决的问题。这是[一个不错的JavaScript小部件](http://dhtmlx.com/docs/products/dhtmlxScheduler/)。 – Alternatex 2014-10-07 12:40:52

+0

在这种特殊情况下,应该在服务器级完成。不管怎样,谢谢你。 – Ivar 2014-10-07 13:05:48

+0

当您使用$ this-> blocks制作这些嵌套的foreach时,不会将游标设置为不同的位置吗?也许你应该检查一下。 – SenseException 2014-10-07 13:44:37

回答

1

试试这个:

public function calculate_blocks() 
{ 
    $n   = count($events); 
    $collumns = array(); 
    $placements = array(); 

    // Set initial values. 
    for ($i = 0; $i < $n; $i++) 
    { 
     $collumns[$i] = 1; 
     $placements[$i] = 0; 
    } 
    // Loop over all events. 
    for ($i = 0; $i < $n; $i++) 
    { 
     $top1   = $this->time_to_pixels($events[$i]->_event_start_time); 
     $bottom1  = $this->time_to_pixels($events[$i]->_event_end_time); 

     // Check for collisions with events with higher indices. 
     for ($j = $i + 1; $j < $n; $j++) 
     { 
      $top2  = $this->time_to_pixels($events[$k]->_event_start_time); 
      $bottom2 = $this->time_to_pixels($events[$k]->_event_end_time); 
      $collides = $top1 < $bottom2 && $top2 < $bottom1; 

      // If there is a collision, increase the collumn count for both events and move the j'th event one place to the right. 
      if ($collides) 
      { 
       $collumns[$i]++; 
       $collumns[$j]++; 
       $placements[$j]++; 
      } 
     } 

     $this->blocks[] = array(
      'id'  => $events[$i]->ID, 
      'columns' => $collumns[$i], 
      'placement' => $placements[$i], 
      'css'  => array(
       'top' => $top1, 
       'bottom' => $bottom1, 
       'height' => $bottom1 - $top1; 
      ) 
     ); 
    } 
} 

我无法实际测试,但我认为它应该给你一个正确的阵营ks数组。

编辑1:似乎没有产生所需的结果,请参阅下面的注释。

编辑2:我认为这是完全一样的问题:Visualization of calendar events. Algorithm to layout events with maximum width。有人用C#解决了这个问题,但将相应的答案移植到PHP来解决问题应该相对容易。

+0

非常感谢您的努力,我明天会对此进行测试并返回结果。 – Ivar 2014-10-07 18:59:57

+0

结果不幸的是大约相同:http://i.imgur.com/jcQf5bq.png – Ivar 2014-10-08 09:51:59

+0

我想我明白发生了什么。我只是不知道如何解决它目前。如果仔细观察这些街区,确实得到预期的数字,但不是正确的。例如,事件#68与#426和#385重叠,因此获得1/3的大小。然而,#385与#68,#383,#381和#63重叠,并且获得1/5的大小。所以块根据它们重叠的事件数量确实得到正确的大小/位置,但是这最终看起来很奇怪。需要注意的是,A + B和B + C之间的重叠并不一定意味着A + C之间的重叠。也许这可以帮助你想出一些东西。 – 2014-10-08 11:30:22