Registrierung Kalender Mitgliederliste Teammitglieder Suche Häufig gestellte Fragen Zur Startseite

Informatiker Board » Themengebiete » Praktische Informatik » Algorithmen » Kalendertermine in der Tagesansicht richtig anordnen » Hallo Gast [Anmelden|Registrieren]
Letzter Beitrag | Erster ungelesener Beitrag Druckvorschau | An Freund senden | Thema zu Favoriten hinzufügen
Neues Thema erstellen Antwort erstellen
Zum Ende der Seite springen Kalendertermine in der Tagesansicht richtig anordnen
Autor
Beitrag « Vorheriges Thema | Nächstes Thema »
ubik
Mitglied


Dabei seit: 10.04.2015
Beiträge: 41

Kalendertermine in der Tagesansicht richtig anordnen Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Hallo,

ich habe einen Kalendar, der mir in einer Tagesansicht Termine anzeigen soll. Dabei werden die Termine als Rechtecke dargestellt.

Jetzt habe ich ein Problem:

Wenn ich mehr als einen Termin zur selben Zeit habe, dann muss ich die Termine irgendwie so anordnen, dass sie möglichst nebeneinander sind.

Das heißt, der längste Termin muss auf der linken Seite sein. Und alle Termine, die kleiner gleich diesem Termin sind, auf der rechten Seite.

Weiterhin besteht das Problem, dass wenn ich einen Termin habe, der länger ist als der auf der linken Seite, dann habe ich das Problem, dass die Breite des Rechtecks angepasst werden muss (siehe grünes und pinkes Rechteck im Bild).

Ein weiteres Problem besteht darin, dass (siehe grünes Rechteck) sich, falls die Spaltenbreite bereits größer ist, dass man dann die Rechteckbreite vergrößern muss.

Es darf sich kein Rechteck mit einem anderen überschneiden!

Kennt jemand einen Algorithmus, wie man das macht?


Meine Ideen bisher:

Ich zähle, wieviele Rechtecke ich in jeder Stundenzeile aufgelistet sind. Das heißt etwa so:

7:00 Rot
8:00 Rot
9:00 Rot, Blau, Gelb,
10:00 Rot, Blau, Gelb
11:00 Rot, Grün
12:00 Rot, Grün
13:00 Grün
14:00 Grün
15:00 Pink, Grün
16:00 Pink
17:00 Pink
18:00 Pink
19:00 -
20:00 -

Und weiter weiß ich nicht...

ubik hat dieses Bild (verkleinerte Version) angehängt:
termine.png

26.06.2017 20:32 ubik ist offline E-Mail an ubik senden Beiträge von ubik suchen Nehmen Sie ubik in Ihre Freundesliste auf
as_string as_string ist männlich
Haudegen


Dabei seit: 06.11.2013
Beiträge: 639
Herkunft: Heidelberg

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Ich würde zuerst die Liste aller Termine nach ihrer Länge nach sortieren. Dann ist der Längste schon ganz links. Für jede Stunde merkst Du Dir, wieviele Termine in dieser einen Stunde schon parallel aktiv sind (also einfach ein int-Array mit einem Element pro Stunde oder vielleicht besser gleich Viertelstunde und alle Werte mit 0 initialisieren), also musst Du für alle Stunden des längsten Balkens in diesem Array den Wert um eins erhöhen.
Dann kommt der zweite Balken. Da gehst Du über die Stunden des neuen Termins durch das Array und suchst nach dem Maximum der Werte, während Du gleich alle Werte um eins hoch zählst. Anhand des Maximums weißt Du dann, wie weit Du den zweiten Termin einrücken musst.
Dann machst Du mit dem nächsten Termin weiter genau so.

Willst Du das in einer bestimmten Programmiersprache machen? Magst Du das mal hier Posten, damit ich mal drüber schauen kann?

Gruß
Marco
27.06.2017 10:19 as_string ist offline E-Mail an as_string senden Beiträge von as_string suchen Nehmen Sie as_string in Ihre Freundesliste auf
ubik
Mitglied


Dabei seit: 10.04.2015
Beiträge: 41

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Hallo,

ja, ich will das in Java machen.

Also, hier die Klasse ReadEvent.java. Diese beinhaltet einen Termin.

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
62:
63:
64:
65:
66:
67:
68:
69:
70:
71:
72:
73:
74:
75:
76:
77:
78:
79:
80:
81:
82:
83:
84:
85:
86:
87:
88:
89:
90:
91:
92:
93:
94:
95:
96:
97:
98:
99:
100:
101:
102:
103:
104:
105:
106:
107:
108:
109:
110:
111:
112:
113:
114:
115:
116:
117:
118:
package de.ubik.kalender;

import android.support.annotation.NonNull;

/**
 * Created by ubik on 01.06.17.
 */

public class ReadEvent {
    int calendarid;
    int eventid;
    String eventname;
    String eventlocation;
    String description;
    String eventcolor;
    long dtstart;
    long dtend;
    String eventtimezone;
    String eventtimezone_end;
    String duration;
    boolean allday;
    int eventcount;
    int hindex;
    int wpixels;

    public ReadEvent(int calendarid, int eventid, String eventname, String eventlocation, String description, String eventcolor, long dtstart, long dtend, String eventtimezone, String eventtimezone_end, String duration, boolean allday) {
        this.calendarid = calendarid;
        this.eventid = eventid;
        this.eventname = eventname;
        this.eventlocation = eventlocation;
        this.description = description;
        this.eventcolor = eventcolor;
        this.dtstart = dtstart;
        this.dtend = dtend;
        this.eventtimezone = eventtimezone;
        this.eventtimezone_end = eventtimezone_end;
        this.duration = duration;
        this.allday = allday;
        this.eventcount = -1;
        this.hindex = -1000;
        this.wpixels = 0;
    }

    public int getEventid() {
        return this.eventid;
    }

    public int getCalendarid() {
        return this.calendarid;
    }

    public String getEventname() {
        return this.eventname;
    }

    public String getEventlocation() {
        return this.eventlocation;
    }

    public String getDescription() {
        return this.description;
    }

    public String getEventcolor() {
        return this.eventcolor;
    }

    public long getDtstart() {
        return this.dtstart;
    }

    public long getDtend() {
        return this.dtend;
    }

    public String getEventtimezone() {
        return this.eventtimezone;
    }

    public String getEventtimezone_end() {
        return this.eventtimezone_end;
    }

    public String getDuration() {
        return this.duration;
    }

    public boolean getAllday() {
        return this.allday;
    }

    public void setEventCount(int eventcount) {
        this.eventcount = eventcount;
    }

    public int getEventCount() {
        return this.eventcount;
    }

    public void setHIndex(int hindex) {
        this.hindex = hindex;
    }

    public int getHIndex() {
        return this.hindex;
    }


    public boolean issethindex() {
        if(this.hindex == -1000) return false;
        else return true;
    }

    public void setPixelW(int wpixels) {
        this.wpixels = wpixels;
    }
}


Nun lese ich alle Termine in eine ArrayList (alldateshourly_init) und sortiere sie mittels Collections.sort:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
  alldateshourly_init = events.getAllEventsByDay(c1_init, c2_init);

        Collections.sort(alldateshourly_init, new Comparator<ReadEvent>() {
            @Override public int compare(ReadEvent p1, ReadEvent p2) {
                return (int) ((p2.getDtend() - p2.getDtstart()) - (p1.getDtend() - p1.getDtstart()));
            }

        });

        for (ReadEvent readevent : alldateshourly_init) {

            addMultiplyDates(readevent.getEventid(), readevent.getDtstart(), readevent.getDtend());
        }       


Die Funktion addMultiplyDates fügt alle Kalendarid's in eine ArrayList, dessen Index die Stunde beinhaltet. Sie sieht so aus:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
private void addMultiplyDates(int eventid, long start, long end) {
        Calendar mCalendar = new GregorianCalendar();
        TimeZone mTimeZone = mCalendar.getTimeZone();
        int mGMTOffset = mTimeZone.getRawOffset();
        long offset = TimeZone.getDefault().getOffset(System.currentTimeMillis());

        start = start - offset;
        end = end - offset;

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(start);
        int starthour = c.get(Calendar.HOUR_OF_DAY);

        Calendar c2 = Calendar.getInstance();
        c2.setTimeInMillis(end);
        int endhour = c2.get(Calendar.HOUR_OF_DAY);
        int endminute = c2.get(Calendar.MINUTE);

        starthour = (int) (starthour - firsthour);
        endhour = (int) (endhour - firsthour);

        int checknextday = (int)lasthour - (int)firsthour +1;


        if(endminute == 0) {
            endhour = endhour - 1;
        }

        if(endhour > (int)lasthour - (int)firsthour) {
            endhour = (int)lasthour - (int)firsthour;
        }

        if(starthour >= 0 && endhour <= (int)lasthour - (int)firsthour) {
            for(int i = starthour; i <= endhour; i++) {
                multidates.get(i).add(eventid);
            }
        }
    }


Die ArrayList sieht dann beispielsweise so aus von (7:00 Uhr morgens bis 22:00 Uhr abends, 0 ist dann 7 Uhr, 1 dann 8 Uhr, usw..):

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
0: 358 
1: 358 360 
2: 358 
3: 358 347 
4: 358 347 
5: 358 356 
6: 358 356 
7: 358 356 354 349 
8: 358 356 
9: 358 356 348 357 
10: 358 356 348 
11: 
12: 
13:
14: 



Nun könnte ich die Länge jedes Feldes auslesen, richtig?

Aber jetzt habe ich ein Problem.

Wenn ich bei 0 die Länge auslese, erhalte ich 1 als Länge. Das ist aber quatsch, denn ich habe eine andere Länge bei Index 7 für 358, nämlich 4.

Wie könnte ich das Problem lösen?

Ich glaube, dass das nicht so einfach sein wird. :-) Ach ja: Jeder Termin soll als eine Box dargestellt werden mit Breite, Höhe, x- und y-Position.

Die y-Position wird nicht das Problem sein, die Höhe auch nicht. Bloß die Breite und die x-Position muss berechnet werden. Und ich weiß leider nicht wie.

Dieser Beitrag wurde 1 mal editiert, zum letzten Mal von ubik: 27.06.2017 21:02.

27.06.2017 21:01 ubik ist offline E-Mail an ubik senden Beiträge von ubik suchen Nehmen Sie ubik in Ihre Freundesliste auf
as_string as_string ist männlich
Haudegen


Dabei seit: 06.11.2013
Beiträge: 639
Herkunft: Heidelberg

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Ich hab doch geschrieben: Such das Maximum!
In der Funktion addMultiplyDates() hast Du ziemlich zum Schluss (Zeile 35) eine Schleife. Wenn Du vor dieser Schleife eine int Variable, mit Namen "max" z. B., mit null initialisierst und dann im Schleifendurchlauf immer dann die Variable auf multidates.get(i).size() setzt, wenn multidates.get(i).size() größer ist als max.
Am Ende steht dann das Maximum in der Variable, das gleich Deiner Einrückung der Box entspricht.

Gruß
Marco
27.06.2017 21:53 as_string ist offline E-Mail an as_string senden Beiträge von as_string suchen Nehmen Sie as_string in Ihre Freundesliste auf
ubik
Mitglied


Dabei seit: 10.04.2015
Beiträge: 41

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Hallo,

hmmm.

Okay, soweit so gut.

Hab den Code geändert:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:

            for(int i = starthour; i <= endhour; i++) {
                multidates.get(i).add(eventid);

                if(multidates.get(i).size() - 1 > max) { max = multidates.get(i).size() - 1; }
            }

            getEventById(eventid).setPixelW(max);


Hmm.. Allerdings scheint es nicht das gewünschte Ergebnis zu bringen. (siehe Screenshots)

Problem:
Das Datum "Llll" ist als dreispaltig markiert. Es müsste aber vierspaltig sein und in Spalte 2 angezeigt werden.

ubik hat dieses Bild (verkleinerte Version) angehängt:
Screenshot_20170628-115330.png

Dieser Beitrag wurde 3 mal editiert, zum letzten Mal von ubik: 28.06.2017 13:45.

28.06.2017 11:59 ubik ist offline E-Mail an ubik senden Beiträge von ubik suchen Nehmen Sie ubik in Ihre Freundesliste auf
as_string as_string ist männlich
Haudegen


Dabei seit: 06.11.2013
Beiträge: 639
Herkunft: Heidelberg

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Ja, ok. Wenn Du nur die Anzahl der Dates zählst, gehst Du natürlich implizit von einer Breite von 1 aus. Wenn die unterschiedlich breite sein können, dann musst Du nicht das Maximum der Termin-Anzahl nehmen (was ja size() ist), sondern Du müsstest über jedes einzelne in einem Stunden-Slot iterieren und dessen Breite aufaddieren und Dir im Anschluss das Maximum dieser Breiten merken.

Außerdem: Wenn Du die size() bestimmst bevor Du das add() machst (wie ich es Dir auch geschrieben hatte!), dann brauchst Du von size() nicht wieder eins abziehen logischerweise!

Aber mit unterschiedlichen Breiten: Brauchst Du überhaupt das multidates-Array für irgendetwas? Du befüllst das zwar, aber dann machst Du ja eigentlich nichts (bis auf das Maximum-Bestimmen jetzt).
Angenommen Du merkst Dir für jede Stunde die bisherige maximale x-Position. Für alle Termine gehst Du einmal über jede betreffende Stunde und suchst die maximale bisherige x-Position. Wenn Du die hast, kennst Du die x-Position für diesen Termin und kannst zu dieser noch die Breite des Fensters dazu rechnen. Dann musst Du aber nochmal über die Stunden laufen und alle maximale-x-Positionen der betreffenden Stunden auf den neuen Wert setzen.

Gruß
Marco
28.06.2017 16:59 as_string ist offline E-Mail an as_string senden Beiträge von as_string suchen Nehmen Sie as_string in Ihre Freundesliste auf
ubik
Mitglied


Dabei seit: 10.04.2015
Beiträge: 41

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

Zitat:
Original von as_string
Aber mit unterschiedlichen Breiten: Brauchst Du überhaupt das multidates-Array für irgendetwas?


Nun ja, ich brauche ja die Position auf der x-Achse und die Breite des Datums.

Die Breite des Datums berechnet sich aus:

int widthdate = width / getNumberOfMultipleDates(readevent.getDtstart(), readevent.getDtend());

Position x berechnet sich aus:

int position_x = start + ((readevent.getPixelW()) * widthdate);

Also wörtlich: Linker Abstand + (Anzahl Elemente * Breite des Datums)

getNumberOfMultipleDates() berechnet bereits die maximale Anzahl von Terminen zur gleichen Zeit. Hier ist der Code:

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
public int getNumberOfMultipleDates(long start, long end) {
        Calendar mCalendar = new GregorianCalendar();
        TimeZone mTimeZone = mCalendar.getTimeZone();
        int mGMTOffset = mTimeZone.getRawOffset();
        long offset = TimeZone.getDefault().getOffset(System.currentTimeMillis());

        start = start - offset;
        end = end - offset;

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(start);
        int starthour = c.get(Calendar.HOUR_OF_DAY);

        Calendar c2 = Calendar.getInstance();
        c2.setTimeInMillis(end);
        int endhour = c2.get(Calendar.HOUR_OF_DAY);
        int endminute = c2.get(Calendar.MINUTE);

        starthour = (int) (starthour - firsthour);
        endhour = (int) (endhour - firsthour);

        if(endminute == 0) {
            endhour--;
        }

        System.out.println("starthour: " + starthour);
        System.out.println("endhour: " + endhour);

        int max = 0;
        for(int i = starthour; i <= endhour; i++) {
            int num = multidates.get(i).size();

            if(num > max) { max = num; }
        }

        return max;

    }


Leider verstehe ich nicht, wie du das meinst :-(

Kannst du mir das in Pseudocode oder Java angeben?
28.06.2017 19:09 ubik ist offline E-Mail an ubik senden Beiträge von ubik suchen Nehmen Sie ubik in Ihre Freundesliste auf
ubik
Mitglied


Dabei seit: 10.04.2015
Beiträge: 41

Auf diesen Beitrag antworten Zitatantwort auf diesen Beitrag erstellen Diesen Beitrag editieren/löschen Diesen Beitrag einem Moderator melden       Zum Anfang der Seite springen

code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
45:
46:
47:
48:
49:
50:
51:
52:
53:
54:
55:
56:
57:
58:
59:
60:
61:
    private void addMultiplyDates(ReadEvent readevent, long start, long end) {
        Calendar mCalendar = new GregorianCalendar();
        TimeZone mTimeZone = mCalendar.getTimeZone();
        int mGMTOffset = mTimeZone.getRawOffset();
        long offset = TimeZone.getDefault().getOffset(System.currentTimeMillis());

        start = start - offset;
        end = end - offset;

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(start);
        int starthour = c.get(Calendar.HOUR_OF_DAY);

        Calendar c2 = Calendar.getInstance();
        c2.setTimeInMillis(end);
        int endhour = c2.get(Calendar.HOUR_OF_DAY);
        int endminute = c2.get(Calendar.MINUTE);

        starthour = (int) (starthour - firsthour);
        endhour = (int) (endhour - firsthour);

        int checknextday = (int)lasthour - (int)firsthour +1;


        if(endminute == 0) {
            endhour = endhour - 1;
        }

        if(endhour > (int)lasthour - (int)firsthour) {
            endhour = (int)lasthour - (int)firsthour;
        }

        System.out.println("Fuege " + readevent.getEventname() + " von " + starthour + " bis " + endhour + " hinzu");


        if(starthour >= 0 && endhour <= (int)lasthour - (int)firsthour) {
            int max = 0;

            for(int i = starthour; i <= endhour; i++) {
                if(multidates.get(i).size() > max) { max = multidates.get(i).size(); }

                for(int k = 0; k < multidates.get(i).size(); k++) {
                    System.out.println("if(" + multidates.get(i).get(k).getPixelW() + " > " + max);
                    if((multidates.get(i).get(k).getPixelW() + 1) > max) {
                        max = multidates.get(i).get(k).getPixelW() + 1;
                    }
                }
                multidates.get(i).add(readevent);


            }
            printAllMultidates();
            readevent.setPixelW(max);

            System.out.println("MAXIMUM: " + max + " " + readevent.getEventname() + " Starthour " + starthour + " endhour: " + endhour);
        }
    }




code:
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
44:
public int getNumberOfMultipleDates(ReadEvent readevent) {
        long start = readevent.getDtstart();
        long end = readevent.getDtend();

        Calendar mCalendar = new GregorianCalendar();
        TimeZone mTimeZone = mCalendar.getTimeZone();
        int mGMTOffset = mTimeZone.getRawOffset();
        long offset = TimeZone.getDefault().getOffset(System.currentTimeMillis());

        start = start - offset;
        end = end - offset;

        Calendar c = Calendar.getInstance();
        c.setTimeInMillis(start);
        int starthour = c.get(Calendar.HOUR_OF_DAY);

        Calendar c2 = Calendar.getInstance();
        c2.setTimeInMillis(end);
        int endhour = c2.get(Calendar.HOUR_OF_DAY);
        int endminute = c2.get(Calendar.MINUTE);

        starthour = (int) (starthour - firsthour);
        endhour = (int) (endhour - firsthour);

        if(endminute == 0) {
            endhour--;
        }

        System.out.println("starthour: " + starthour);
        System.out.println("endhour: " + endhour);

        int max = 0;
        for(int i = starthour; i <= endhour; i++) {
            for(int k = 0; k < multidates.get(i).size(); k++) {
                if((multidates.get(i).get(k).getPixelW() + 1) > max) {
                    max = multidates.get(i).get(k).getPixelW() + 1;
                }
            }
        }

        return max;

    }


Okay, ich habs jetzt fast.

Das Einzige, was ich jetzt nur noch machen muss, ist hintere Termine, die in eine vorherige Spalte passen, einfügen (Zum Beispiel siehe Bild Ddddf auf Spalte 1 und Termin 10:00-12:00 auf Spalte2, sowie "Lo" auf Spalte 2).

Aber das mach ich morgen ^^, jetzt ist der Tag schon vorbei.

ubik hat dieses Bild (verkleinerte Version) angehängt:
Screenshot_20170628-210412.png

28.06.2017 21:06 ubik ist offline E-Mail an ubik senden Beiträge von ubik suchen Nehmen Sie ubik in Ihre Freundesliste auf
Baumstruktur | Brettstruktur
Gehe zu:
Neues Thema erstellen Antwort erstellen
Informatiker Board » Themengebiete » Praktische Informatik » Algorithmen » Kalendertermine in der Tagesansicht richtig anordnen