10

基本的に、各ピクセルが午前 9 時から午後 9 時までの 1 分を表す高さ 720 ピクセルのコンテナーであり、幅が 620 ピクセル (左右から 10 ピクセルのパディング) のイベント システムに取り組んでいます。

暦体系の自然な要件は次のとおりです。

  • オブジェクトは、視覚的に重ならないように配置する必要があります。
  • 時間帯に 1 つのイベントがある場合、その幅は 600px になります。
  • すべての衝突イベントは、衝突する他のすべてのイベントと同じ幅でなければなりません。
  • イベントは、最初の制約を守りながら、可能な限り最大の幅を使用する必要があります。

ここに画像の説明を入力

入力は次のような配列になります。

[
 {id : 1, start : 30, end : 150},  // an event from 9:30am to 11:30am
 {id : 2, start : 540, end : 600}, // an event from 6pm to 7pm
 {id : 3, start : 560, end : 620}, // an event from 6:20pm to 7:20pm
 {id : 4, start : 610, end : 670} // an event from 7:10pm to 8:10pm
]

必要なレイアウトを作成しましたが、JavaScript の部分で立ち往生しています :( これは私がこれまでに持っているものです:

var Calendar = function() {

   var layOutDay = function(events) {
     var eventsLength = events.length;

     if (! eventsLength) return false;

     // sort events
     events.sort(function(a, b){return a.start - b.start;});

     for (var i = 0; i < eventsLength; i++) {
         // not sure what is next
     }         

   };

   return {
       layOutDay : layOutDay,
   }

}();

div を作成し、上記の要件に従って配置する必要があります。

JSBin のデモをご覧ください。

どんな助けでも大歓迎です。

4

6 に答える 6

7

ここに実用的なソリューションがあります: http://jsbin.com/igujil/13/edit#preview

ご覧のとおり、これは簡単に解決できる問題ではありません。私がそれをどのように行ったかを説明しましょう。

Step 0とラベル付けされた最初のステップは、イベントが ID でソートされていることを確認することです。これにより、データをいじり始めると、私たちの生活が楽になります。

ステップ 1は、タイムスロットの 2 次元配列を初期化することです。カレンダーの分ごとに、その分に発生するイベントを含む配列を作成します。私たちはそれを...

ステップ2!イベントが終了する前に開始することを確認するチェックを追加したことに気付くでしょう。少し防御的ですが、私のアルゴリズムは不良データで無限ループに陥る可能性があるため、イベントが理にかなっていることを確認したいと考えています。

このループの最後で、タイムスロット配列は次のようになります。

0: []
1: []
...
30: [1]
31: [1]
...
(いくつかの興味深い数字にスキップします)
540: [2]
560: [2,3]
610: [3,4 ]

console.log(timeslots)混乱している場合や興味がある場合は、ステップ 3 の直前に追加することをお勧めします。これはソリューションの非常に重要な部分であり、次のステップは説明するのがはるかに困難です。

ステップ 3では、スケジュールの競合を解決します。各イベントは、次の 2 つのことを知る必要があります。

  1. 競合する最大回数。
  2. その水平方向の順序 (競合が重ならないようにするため)。

(1) データの保存方法により簡単です。各タイムスロットの配列の幅はイベント数です。たとえば、タイムスロット 30 には 1 つのイベントしかありません。これは、イベント #1 がその時点で唯一のイベントであるためです。ただし、タイムスロット 560 には 2 つのイベントがあるため、各イベント (#2 と #3) のカウントは 2 になります。(そして、3 つのイベントの行があった場合、それらはすべて 3 のカウントを取得します。)

(2)はもう少し微妙です。イベント #1 は、カレンダーの幅全体に広がる可能性があるため、十分に明白です。イベント #2 は幅を縮小する必要がありますが、それでも左端に沿って開始できます。イベント#3はできません。

と呼ばれるタイムスロットごとの変数でこれを解決しますnext_hindex。デフォルトでは左端に沿って配置するため、0 から始まりますが、競合が見つかるたびに増加します。そうすれば、次のイベント (競合の次の部分) が次の水平位置から開始されます。

ステップ 4はかなり簡単です。幅の計算には、ステップ 3 の最大競合数が使用されます。たとえば、5:50 に 2 つのイベントがあることがわかっている場合、各イベントはカレンダーの幅の 1/2 でなければならないことがわかります。(3 つのイベントがある場合、それぞれが 1/3 などになります) x 位置も同様に計算されます。(競合の数) イベントの幅でオフセットしたいので、hindex を掛けています。

最後に、小さな DOM を作成し、イベント div を配置して、簡単に区別できるようにランダムな色を設定します。結果は(私が思うに)あなたが探していたものです。

ご不明な点がございましたら、お気軽にお問い合わせください。これはおそらくあなたが予想していたよりも多くのコード (および複雑さ) であることはわかっていますが、解決するのは驚くほど複雑な問題でした:)

于 2012-05-22T09:14:53.360 に答える
2

独自のロールを作成する場合は、次のコードを使用します:
DEMO: http://jsfiddle.net/CBnJY/11/

var Calendar = function() {
var layOutDay = function(events) {
    var eventsLength = events.length;

    if (!eventsLength) return false;

    // sort events
    events.sort(function(a, b) {
        return a.start - b.start;
    });

    $(".timeSlot").each(function(index, val) {
        var CurSlot = $(this);
        var SlotID = CurSlot.prop("SlotID");
        var EventHeight = CurSlot.height() - 1;
        //alert(SlotID);
        //get events and add to calendar
        var CurrEvent = [];
        for (var i = 0; i < eventsLength; i++) {
            // not sure what is next
            if ((events[i].start <= SlotID) && (SlotID < events[i].end)) {
                CurrEvent.push(events[i]);
            }
        }

        var EventTable = $('<table style="border:1px dashed purple;width:100%"><tr></tr></table');
        for (var x = 0; x < CurrEvent.length; x++) {
            var newEvt = $('<td></td>');
            newEvt.html(CurrEvent[x].start+"-"+CurrEvent[x].end);
            newEvt.addClass("timeEvent");
            newEvt.css("width", (100/CurrEvent.length)+"%");
            newEvt.css("height", EventHeight);
            newEvt.prop("id", CurrEvent[x].id);
            newEvt.appendTo(EventTable.find("tr"));
        }
        EventTable.appendTo(CurSlot);
    });

};

return {
    layOutDay: layOutDay
}
}();

var events = [
{
id: 1,
start: 30,
end: 150},
{
id: 2,
start: 180,
end: 240},
{
id: 3,
start: 180,
end: 240}];

$(document).ready(function() {
var SlotId = 0;
$(".slot").each(function(index, val) {
    var newDiv = $('<div></div>');
    newDiv.prop("SlotID", SlotId)
    //newDiv.html(SlotId);
    newDiv.height($(this).height()+2);
    newDiv.addClass("timeSlot");
    newDiv.appendTo($("#calander"));
    SlotId = SlotId + 30;
});

// call now
Calendar.layOutDay(events);
});

http://arshaw.com/fullcalendar/
デモを使用することを強くお勧めします: http://jsfiddle.net/jGG34/2/
達成しようとしているものはすべて、これで既に実装されています。デイモードを有効にして、CSS を実行するだけです。ハック..それだけです!!

于 2012-05-18T12:48:05.920 に答える
1

あなたの理解が正しければ、入力は開始時刻と終了時刻を含むイベントのリストであり、出力はイベントごとに、そのイベントの列番号とそのイベント中の列の総数です。基本的に、間隔グラフに色を付ける必要があります。ここにいくつかの擬似コードがあります。

  1. イベントごとに、 を指すe2 つの「インスタント」(start, e) と (end, ) を作成します。ee

  2. これらのインスタントを時間順に並べ替え、同時開始インスタントの前に終了インスタントを表示します。

  3. component空リスト、空リストcolumn_stack、数値num_columns = 0、および数値を初期化しますnum_active = 0component同じ数の列が割り当てられるすべてのイベントが含まれます。column_stackどの列が空いているかを覚えています。

  4. インスタントを順番にスキャンします。イベントの開始インスタントの場合は、列eを割り当てる必要がeあります。column_stack空でない場合はポップしてこの列を取得します。それ以外の場合は、新しい列 (number num_columns) を割り当ててインクリメントしますnum_columns(0 ベースではなく 1 ベースのインデックス付けの別の順序)。に追加ecomponentます。増分しnum_activeます。終了インスタントの場合、eの割り当てられた列を にプッシュしcolumn_stackます。減分しnum_activeます。num_activeが現在 0 の場合、 からすべてのイベントをポップしcomponentて列の総数を に設定しnum_columns、続いてクリアして 0column_stackにリセットすることにより、新しい接続コンポーネントを開始します。num_columns

于 2012-05-16T12:05:20.773 に答える
0

キーポイントは、予定からすべての衝突を数えることです。これを行うための非常に単純なアルゴリズムがあります。

  • appointments開始日に従って予定の配列を並べ替え、終了日との関係を解消します。
  • active最初は空であるすべてのアクティブな予定の配列を維持します
  • 各予定の値を維持しますcollision(既にオブジェクトがあるため、別のプロパティとして保存できます)[{id : 1, start : 30, end : 150, collisions : 0},...]

appointments次の手順を繰り返します。

  1. 最初の項目 ( i) をappointments
  2. i内のすべてのアイテムの開始日と終了日を比較- <のすべてのアイテムjactive削除j.enddatei.startdate
  3. 残りのすべてから衝突を更新j(それぞれ +1)
  4. i( i.collision = active.length)の衝突を更新
  5. i配列にポップactive

のすべてのアイテムに対してこれらの手順を繰り返しますappointments

例:

(疑似コードに注意):

var unsorted = [7,9],[2,8],[1,3],[2,5],[10,12]
// var appointments = sort(unsorted);
var appointments = [1,3],[2,5],[2,8],[7,9],[10,12]

// now for all items of appoitments:
for (var x = 0; x<appointments.length;x++){
    var i = appointments[x];                 // step 1
    for (var j=0; j<active.length;j++){      
     // remove j if j.enddate < j.startdate  // step 2
     // else j.collision += 1;               // step 3
    }
    i.collision = active.length;             // step 4
    active.pop(i);                           // step 5
}

アクティブから削除されたアイテムを収集すると、開始日より前の終了日でソートされた配列が得られ、これを div の表示に使用できます。

それでは、コードを取得して機能させることができるか試してみてください。さらにヘルプが必要な場合はコメントを書いてください。

于 2012-05-16T12:26:19.270 に答える
0

私は次のように問題に取り組みます。

ディバイダーは、イベントが交差しない 1 日内の任意の瞬間です。したがって、午前 9 時から午前 11 時までのイベントと午前 11 時から午後 1 時までの別のイベントがあり、他にイベントがない場合、午前 11 時、午後 1 時以降、いつでも 9 時に仕切りがあります。午前またはそれ以前。

私は毎日を、分割線を含まない最大の時間範囲である一連の「波乱に満ちた時間範囲」に分割します。イベントの多い期間ごとに、同時に重複するイベントの最大数を計算し、それをそのイベント期間の「列番号」として使用します。次に、イベントの開始時刻の順序で、すべてのイベントが可能な限り左にレイアウトされるように、計算された列数にすべてのイベントの多い期間を貪欲にレイアウトします。

たとえば、次のようなスケジュールです。

A  9 am - 11 am
B 10 am - 12 pm
C 10 am -  1 pm
D  1 pm  - 2 pm
E  2 pm  - 5 pm
F  3 pm  - 4 pm

以下のように処理されます。午前 9 時から午後 1 時、午後 1 時から午後 2 時、午後 2 時から午後 5 時は、午後 1 時と午後 2 時に仕切りがあるため、イベントが盛んな時間帯です (これらの時間を超えるイベントはありません)

最初のスパンでは最大 3 つのオーバーラップ イベントがあり、2 番目のスパンでは 1 つだけ、3 番目のスパンでは 2 つです。

列は次のように割り当てられます。

 9 am - 10 am  |   |   |   |
10 am - 11 am  |   |   |   |
11 am - 12 pm  |   |   |   |
12 pm -  1 pm  |   |   |   |___ end of first e.t.s.
 1 pm -  2 pm  |           |___ end of second e.t.s.
 2 pm -  3 pm  |     |     |
 3 pm -  4 pm  |     |     |
 4 pm -  5 pm  |     |     |

その後、イベントが時系列順に貪欲に記入されます。

 9 am - 10 am  | A |###|###|
10 am - 11 am  |_A_| B | C |
11 am - 12 pm  |###|_B_| C |
12 pm -  1 pm  |###|###|_C_|
 1 pm -  2 pm  |_____D_____|
 2 pm -  3 pm  |  E  |#####|
 3 pm -  4 pm  |  E  |__F__|
 4 pm -  5 pm  |__E__|#####|

これは非常に合理的に見えます。# は空き容量を示します

于 2012-05-12T18:54:22.057 に答える