【问题标题】:Calendar, offset overlapping events日历,偏移重叠事件
【发布时间】:2009-05-20 22:32:37
【问题描述】:

我正在尝试用 PHP 编写日历。在周视图中,我希望我的事件像 iCal 一样列出,同时发生的事件将它们的宽度缩小到一半。

不过,我很难弄清楚这一点,所以我希望你能帮助我。我想要的是,如果一个事件与另一个事件重叠,它应该在两个事件数组上设置[split] => true - 或者在那个方向上的东西(阅读:我不确定这是否是最有效的解决方案)。然后我可以在打印出事件的 foreach 循环中检查split == true

这是一个包含两个同时发生的事件的示例数组:

$events = array(
  array(
    "id" => 21,
    "start" => 1242219600,
    "end" => 1242237600,
    "title" => "foo",
    "split" => false
  ),
  array(
    "id" => 22,
    "start" => 1242223200,
    "end" => 1242234000,
    "title" => "foo",
    "split" => false
  )
);

$events = someFunctionToOffsetEvents($events);

你会如何解决这个问题?

【问题讨论】:

  • 如果三个事件重叠怎么办?

标签: php arrays prototype calendar offset


【解决方案1】:

我最近不得不处理很多日期冲突问题,我能想到的最好的办法是:

date1.start date2.start = 碰撞

这个简单的公式将解释以下所有情况:

——所有情况都一样: date1.start = 2009 年 1 月 1 日 date1.end = 2009 年 1 月 10 日 --开始日期在第一个日期范围内: date2.start = 2009 年 1 月 9 日 date2.end = 2/10/2009 --结束日期在第一个日期范围内: date2.start = 2008 年 12 月 10 日 date2.end = 2009 年 1 月 3 日 --开始和结束日期在第一个日期范围内: date2.start = 2009 年 1 月 2 日 date2.end = 2009 年 1 月 3 日 --第一个日期在第二个日期范围内: date2.start = 12/1/2008 date2.end = 2/1/2009
$date1 = array('start' => '2009-01-05', 'end' => '2009-01-10');
$date2 = array('start' => '2009-01-01', 'end' => '2009-01-04'); // end inside one
$date3 = array('start' => '2009-01-04', 'end' => '2009-01-15'); // start inside one
$date4 = array('start' => '2009-01-01', 'end' => '2009-01-15'); // one inside me
$date5 = array('start' => '2009-01-04', 'end' => '2009-01-05'); // inside one

function datesCollide($date1, $date2)
{
    $start1TS = strtotime($date1['start']);
    $end1TS = strtotime($date1['end']);
    $start2TS = strtotime($date2['start']);
    $end2TS = strtotime($date2['end']);

    if ($start1TS <= $end2TS && $end1TS >= $start2)
    {
        return true;
    }

    return false;
}

根据您的评论,这可能是您正在寻找的解决方案: 请注意,此解决方案不是很优化,只能用于找出更好的解决方案。 永远不要相信来自网络的代码。

$events = array(
  array(
        "id" => 21,
        "start" => 1242219600,
        "end" => 1242237600,
        "title" => "foo",
        "split" => false
  ),
  array(
        "id" => 22,
        "start" => 1242223200,
        "end" => 1242234000,
        "title" => "foo",
        "split" => false
  )
);

foreach ($events as $key => $event)
{
    $events[$key]->split = dateCollisionCheck($event, $events);
}

function dateCollisionCheck(&$event, &$eventList)
{
    foreach ($eventList as $checkEvent)
    {
        if ($event->id != $checkEvent->id)
        {
            if ($event->start <= $checkEvent->end && $event->end >= $checkEvent->start)
            {
                return true; // return as soon as we know there is a collision
            }
        }
    }

    return false;
}

*代码未经测试

【讨论】:

  • 嗨,罗伯。谢谢你的建议。我的代码与您的不同之处在于,我的所有事件都有一个数组,这需要我的“datesCollide”函数遍历整个多维数组。你会怎么做?我想我在这个上花了很多时间,这让我有点盲目。
  • 所以你有 1 个带有 X 事件的数组,你必须检查它们中的任何一个是否相互碰撞?
  • 我有一个函数 getEvents($start, $end),它只提取我感兴趣的那一周的事件。因此,我实际上认为您的解决方案已尽可能优化。我看不出如何以更好的方式做到这一点。我不得不稍微修改您的代码以使其正常工作。我会把它贴在底部。但是你会得到解决方案奖。非常感谢您的帮助!
【解决方案2】:

我发布了一个问题,即如果三个事件重叠会导致更好的解决方案。不要把你的 GUI 和你的数据放在同一个结构中。保存您的数据,然后弄清楚如何显示它。

【讨论】:

  • 您可以粘贴指向该问题/解决方案的链接吗?谢谢:-)
  • 对不起。那只是指上面的评论,对你的问题。
  • 我只是说你需要担心的不仅仅是两个事件冲突,而是三个或更多。所以,你真的需要首先存储你的数据,然后有一个单独的对象来显示数据,并处理绘图过程中的任何时间冲突。分解你的问题,使数据和显示完全分开。此外,您可以将数据用于不止一个显示,并且该显示不仅仅包含该组数据。
  • 我完全同意 thrusdaysgeek。数据和显示之间的清晰分离将是您在项目推进过程中不断给予的礼物。
【解决方案3】:

我会回复你的问题。 将事件映射到表示您要显示的星期的数组上:

$weekdayEvents=array();
foreach ($events as $event) {
   $day=toThisWeek($event['start'], $firstweekday),
   $lastDay=toThisWeek($event['end'], $firstweekday); 
   while ($day<=$lastDay) {
     $weekdayEvents[$day++][]=$event['id'];
   }
}
// now you have an array of array filled with ids
$eventCollisions=array();
foreach($weekdaysEvents as $activeDay) {
  $eventsOnDay = count($activeDay);
  foreach($activeDay as $eventID) {
    if ($eventCollisions[$eventID]<$eventsOnDay) {
      $eventCollisions[$eventID]=$eventsOnDay;
    }
  }
}

}

toThisWeek() 是一个类似

的函数
function toThisWeek($dayTimestamp, $firstDayOfWeekTimestamp) {
  $dayOfWeek = unixtojd($firsDayOfWeekTimestamp) - unixtojd($dayTimestamp);
  if($dayOfWeek<0) return 0;
  if($dayOfWeek>6) return 6; 
  return $dayOfWeek;      
}

现在在 $eventCollisions 中,您可以在必须显示的一周内发生的每个事件的事件上发生最大碰撞次数。现在您可以使用此数组中的值来填充 $events 子数组中的拆分字段:

foreach ($events as $event) {
  $event['split']=$eventCollisions[$event['id']]-1;
}

或者只使用 $eventCollisions 中的值"ondemand"

【讨论】:

    【解决方案4】:

    这是根据 Rob 的回答修改后的工作代码:

    // this is in my getEvents function
    if(is_array($events)) {
      foreach ($events as $key => $event) {
        $events[$key]['collides'] = $this->dateCollisionCheck($event, $events);
      }
    }
    
    //this is another function added to calendar.class.php
    function dateCollisionCheck(&$event, &$eventList) {
      foreach ($eventList as $checkEvent) {
        if ($event['id'] != $checkEvent['id']) {
          if ($event['start'] <= $checkEvent['end'] && $event['end'] >= $checkEvent['start']) {
            return true;
          }
        }
      }
    
      return false;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-11-10
      • 2015-11-04
      • 1970-01-01
      • 2021-01-08
      • 2019-07-02
      • 2021-12-26
      相关资源
      最近更新 更多