2

PHPでカレンダーを書こうとしています。週のビューでは、イベントをiCalのようにリストして、同時イベントの幅を半分に減らしたいと思います。

私はこれを理解するのに非常に苦労しているので、あなたが私を助けてくれることを願っています。私が欲しいのは、あるイベントが別のイベントとオーバーラップしている場合、それは[split] => true両方のイベント配列に設定する必要があるということです-またはその方向の何か(読んでください:これが最も効率的な解決策であるかどうかはわかりません)。split == true次に、イベントを出力するforeachループをチェックできます。

次に、2つの同時イベントを含む配列の例を示します。

$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);

これをどのように解決しますか?

4

4 に答える 4

1

私は最近、日付の衝突の問題にたくさん対処しなければなりませんでした、そして私が思いついた最高のものは次のとおりです:

date1.start<date2.endおよびdate1.end>date2.start=衝突

この単純な式は、次のすべての状況を説明します。

-すべての状況で同じ:
date1.start=2009年1月1日
date1.end=2009年1月10日

-開始日は最初の日付範囲にあります:
date2.start=2009年1月9日
date2.end=2009年2月10日

-終了日は最初の日付範囲にあります:
date2.start=2008年12月10日
date2.end=2009年1月3日

-開始日と終了日が最初の日付範囲内にあります:
date2.start=2009年1月2日
date2.end=2009年1月3日

--最初の日付が2番目の日付の範囲内にあります:
date2.start=2008年12月1日
date2.end=2009年2月1日
$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;
}

あなたのコメントに基づいて、これはおそらくあなたが探している解決策です:この解決策はあまり最適化されておらず、より良い解決策を見つけるためにのみ使用されるべきであることに注意してください。 Webからのコードを絶対に信用しないでください。

$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;
}

*コードはテストされていません

于 2009-05-20T22:59:58.723 に答える
1

3 つのイベントが重なるとどうなるかという質問を投稿しました。これにより、より良い解決策が得られます。GUI とデータを同じ構造にしないでください。データを保存してから、それを表示する方法を見つけます。

于 2009-05-20T22:44:17.413 に答える
0

私はあなたの問題を元に戻します。表示する週を表す配列にイベントをマップします。

$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 「オンデマンド」の値を使用するだけです

于 2009-05-21T00:29:24.893 に答える