Custom calendar with event divs

前端 未结 6 1042
心在旅途
心在旅途 2020-12-29 13:04

I am working on an event system which is basically a container with 720px height with each pixel representing one minute from 9AM to 9PM and has width of 620px (10px padding

6条回答
  •  南笙
    南笙 (楼主)
    2020-12-29 13:47

    Here is a working solution: http://jsbin.com/igujil/13/edit#preview

    As you can see, it's not an easy problem to solve. Let me walk you through how I did it.

    The first step, labelled Step 0, is to make sure the events are sorted by id. This will make our lives easier when we start playing with the data.

    Step 1 is to initialize a 2-dimensional array of timeslots. For each minute in the calendar, we're going to make an array which will contain the events that take place during that minute. We do that in...

    Step 2! You'll note I added a check to make sure the event starts before it ends. A little defensive, but my algorithm would hit an infinite loop on bad data, so I want to make sure the events make sense.

    At the end of this loop, our timeslot array will look like this:

    0: []
    1: []
    ...
    30: [1]
    31: [1]
    ...
    (skipping ahead to some interesting numbers)
    540: [2]
    560: [2,3]
    610: [3,4]

    I encourage you to add console.log(timeslots) just before Step 3 if you're confused/curious. This is a very important piece of the solution, and the next step is a lot more difficult to explain.

    Step 3 is where we resolve scheduling conflicts. Each event needs to know two things:

    1. The maximum number of times it conflicts.
    2. Its horizontal ordering (so that conflicts don't overlap).

    (1) is easy because of how our data is stored; the width of each timeslot's array is the number of events. Timeslot 30, for example, has only 1 event, because Event #1 is the only one at that time. At Timeslot 560, however, we have two events, so each event (#2 and #3) gets a count of two. (And if there was a row with three events, they would all get a count of three, etc.)

    (2) is a little more subtle. Event #1 is obvious enough, because it can span the entire width of the calendar. Event #2 will have to shrink its width, but it can still start along the left edge. Event #3 can't.

    We solve this with a per-timeslot variable I called next_hindex. It starts at 0, because by default we want to position along the left edge, but it will increase each time we find a conflict. That way, the next event (the next piece of our conflict) will start at the next horizontal position.

    Step 4 is quite a bit more straightforward. The width calculation uses our max-conflict count from Step 3. If we know we have 2 events at 5:50, for example, we know each event has to be 1/2 the width of the calendar. (If we had 3 events, each would be 1/3, etc.) The x-position is calculated similarly; we're multiplying by the hindex because we want to offset by the width of (number of conflict) events.

    Finally, we just create a little DOM, position our event divs, and set a random colour so they're easy to tell apart. The result is (I think) what you were looking for.

    If you have any questions, I'd be happy to answer. I know this is probably more code (and more complexity) than you were expecting, but it was a surprisingly complicated problem to solve :)

提交回复
热议问题