2014-10-07 60 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