[英]Place colliding elements next to each other
我正在創建某種日歷/日程表來顯示特定日期的事件。 每個事件在垂直小時網格中顯示為HTML元素。 可能同時存在多個(“碰撞”)事件,並且在這些情況下,元素應該彼此相鄰放置,水平放置,並且具有相等的寬度。 例如,四個碰撞事件得到列值4,這樣寬度為25%。
棘手的部分是這些碰撞事件。 我以為我解決了它,但是有些元素得到了錯誤的列數。
可能有更好的方法來計算列數和位置 - 我願意接受建議。
當前(錯誤)結果的示例圖像:
相關代碼:
<?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);
}
}
?>
嘗試這個:
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;
)
);
}
}
我實際上無法測試它,但我認為應該給你一個正確的塊數組。
編輯1:似乎沒有產生所需的結果,請參閱下面的評論。
編輯2:我認為這是完全相同的問題: 日歷事件的可視化。 布局具有最大寬度的事件的算法 。 有人用C#解決了它,但將PHP的答案移植到解決你的問題應該相對容易。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.