あなたのアプローチで私が目にする問題の1つは、データの保存に構造がないことです。以前にJavascriptでカレンダーを作成しましたが、簡単な作業ではありません。まず、カレンダーイベントに何らかの抽象化があることを確認してください。何かのようなもの:
function CalendarEvent(startDateTime, endDateTime) {
this.startDateTime = startDateTime;
this.endDateTime = endDateTime;
}
CalendarEvent.prototype.start = function() {
return this.startDateTime.getTime();
};
CalendarEvent.prototype.end = function() {
return this.endDateTime.getTime();
};
CalendarEvent.new = function(startDateTime, endDateTime) {
// This is a little factory method. It prevents calendar events
// from having end times that fall before the start time.
// USE THIS TO INSTANTIATE A NEW CALENDAR EVENT
if(endDateTime.getTime() < startDateTime.getTime()) {
throw new Error("End time falls before start time");
}
return new CalendarEvent(startDateTime, endDateTime);
};
CalendarEvent.compare = function(eventOne, eventTwo) {
// this is a class method to compare two events
// If used with sort it will sort by startDateTime
return eventOne.start() - eventTwo.start();
};
// ... add any other methods you need
次に、カレンダーの予定を並べ替えます。開始時間で並べ替えます。次に、並べ替えると、変更が加えられたときに実際にすべてを再レンダリングできます。正しく並べ替える限り、カレンダーイベントが衝突するかどうかを判断するのは次のように簡単です。
CalendarEvent.prototype.intersects = function(otherEvent) {
// If the other event starts after this one ends
// then they don't intersect
if(otherEvent.start() > this.end()) {
return false;
}
// If the other event ends before this one starts
// then they don't intersect
if(otherEvent.end() < this.start()) {
return false;
}
// Everything else is true
return true;
};
データは並べ替えられているため、2つ以上のカレンダーイベントが交差する場合は、スペースを共有する必要があることがわかります。確かに、スペースを分割するときは、いくつかのことを考える必要があります。スペースを左から右に均等に共有する(開始時間が最も早い左)という単純な実装が必要ですか。その場合、スペースを共有する4つのイベントがある場合(各ブロックはイベントです)、視覚的表現は次のようになります。

ただし、イベントの形がおかしい場合は、カレンダーがおかしくなる可能性があります。次のことを考慮してください。

この場合、イベント2は多くの垂直方向のスペースを占有し、イベント1の下のスペースはすべて未使用です。たぶん、より良いUXのために、そのようなことが起こらないようにする必要があります。その場合は、それに応じてレンダリングアルゴリズムを設計する必要があります。発生したすべての変更で再レンダリングするのがおそらく最も簡単であることを覚えておいてください。ただし、それはデータの保存方法がすべてです。簡単に移動できるような構造でデータを保存しないと、このようなことはできません。
しかし、あなたの質問への答えを完成させるために、ここにかなり素朴な例があります。私はそれをテストしていないので、これはそれが機能しているというかなり大きな仮定です。完全ではありませんが、自分でレンダリングを編集する必要があります。これは、それを機能させる方法のアイデアを提供するためだけのものです。それは間違いなくきれいに見えるかもしれません:
function renderCalendarEvents(calendarEvents) {
// Sort the calendar events (assuming calendarEvents is an array)
var sortedEvents = calendarEvents.sort(CalendarEvent.compare);
var index = 0;
// renderEvents is an anonymous function that will be called every time
// you need to render an event
// it returns it's columnDivisor.
var renderEvent = function(position) {
var currentEvent = sortedEvents[index];
var nextEvent = sortedEvents[index + 1];
// The default column divisor is determined by
// the current x-position + 1
var columnDivisor = position + 1;
// Increment before any recursion
index += 1;
// Check if nextEvent even exists
if(nextEvent) {
// If the nextEvent intersects with the current event
// then recurse
if(currentEvent.intersects(nextEvent)) {
// We need to tell the next event that it starts at the
// column position that is immediately +1 to the current event
columnDivisor = renderEvent(position + 1);
}
}
// placeEvent() is some function you can call to actually place
// the calendar event element on the page
// The position is the x-position of the current event
// The columnDivisor is a count of the amount of events sharing this column
placeEvent(currentEvent, position, columnDivisor);
return columnDivisor;
};
while(true) {
// render events until we're done
renderEvent(0);
if(index >= sortedEvents.length) {
break;
}
}
}
基本的に、この特定のアルゴリズムの考え方は、リスト上のnextEventが存在し、そのイベントがcurrentEventと交差する場合、currentEventの幅を分割する必要があるということです。交差点がなくなるまで再帰を続け、その後、再帰呼び出しのチェーンを遡ります。実際のDOM操作ロジックはスキップしました。これは、これらのイベントを適合させるために実際の列を分割する必要がある量を決定することが非常に難しいためです。うまくいけば、これはすべて少し意味があります。
編集:
より明確にするために、これを既存のコードに追加するために、insertEvent
関数を次のようなものに置き換えます。私はあなたのためにすべてのロジックを書くわけではないので、あなたはあなた自身の書き込みのいくつかをしなければならないでしょう。しかし、それは半分の楽しみです:-)。
function insertEvent(start, end) {
var newEvent = Calendar.new(start, end);
// you'll have to store the array somewhere.
// i'm just assuming some kind of global right now
eventsArray.push(newEvent);
// You'll want to destroy any event elements
destroyCurrentEventElements();
// Now run the rendering function
renderCalendarEvents(eventsArray);
}