Takvim, ofset örtüşen olaylar

4 Cevap php

PHP bir takvim yazmaya çalışıyorum. Hafta görünümünde, benim olayları eşzamanlı olaylar yarısı boyutuna genişliğini azaltır iCal gibi listede olmak istiyorum.

Ama bu bir sergiyi son derece zor bir zaman var, bu yüzden bana yardımcı olabilir umuyoruz. Ya da bu yönde bir şey (: Ben bu en etkili çözüm olup olmadığı konusunda emin değilim oku) - Ne istediğiniz bir olayı örtüşen ise, her iki olay diziler [split] => true set gerektiğidir. Sonra olayları yazdırır foreach döngüsünde split == true için kontrol edebilirsiniz.

İşte iki eşzamanlı olayları içeren bir örnek dizidir:

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

Nasıl bu bir çözersiniz?

4 Cevap

Ben son zamanlarda bir sürü tarih çarpışma sorunları ile uğraşmak zorunda kalmıştım, ve ben ile gelmek mümkün oldum en iyisi:

date1.start < date2.end ve date1.end> date2.start = çarpışma

Bu basit formül aşağıdaki durumlardan tüm hesap verecek:

--same for all situations:
date1.start = 1/1/2009
date1.end = 1/10/2009

--Start date is in first dates range:
date2.start = 1/9/2009
date2.end = 2/10/2009

--End date is in first dates range:
date2.start = 12/10/2008
date2.end = 1/3/2009

--Start & End date is inside first dates range:
date2.start = 1/2/2009
date2.end = 1/3/2009

--First date is inside of second dates range:
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;
}

Based on your comment this is probably the solution you are looking for: Note that this solution isn't very optimized, and should only be used for figuring out a better solution. Never trust code from the 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;
}

* Kod test edilmemiştir

Ben üç olay daha iyi bir çözüm yol açan, üst üste gelirse ne soru yayınlanmıştır. Aynı yapı içinde GUI ve verilerinizi koymayın. Verilerinizi kaydedin ve sonra görüntülemek için nasıl anlamaya.

I would revert your problem. Map the events on an array representing the week you want to display:

$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 () gibi bir fonksiyonu olduğu

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

Şimdi $eventCollisions Eğer çarpışma maksimum sayı görüntülemek zorunda hafta boyunca meydana gelen her türlü olaylar için bir olay meydana sahip. Şimdi altdizilim $ olaylarda alan bölünmüş doldurmak için bu dizideki değerleri kullanabilirsiniz:

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

Ya da sadece $ eventCollisions değerleri kullanmak "ondemand"

İşte Ramiz'in cevap dayalı çalışan, modifiye kodu:

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