Die Standard Charting-Features von Oracle Apex bieten einen schnellen unkomplizierten Weg, um eine Vielzahl einfacher Charts zu erstellen. Sobald weitere Anforderungen dazukommen, stößt man allerdings schnell an die Grenzen der Apex-Wizards. Da der Oracle Apex – Umgebung aber die volle Funktionalität der AnyChart – Library zur Verfügung steht, lassen sich wesentlich anspruchsvollere Charts erstellen. Vereinfachend kommt hinzu, dass die AnyChart – Library über eine gute Online Dokumentation und XML-Referenz verfügt.
Im letzten Beitrag stellte ich den Rahmen für die händische Einbettung von AnyGantt in Apex vor, und in einem späteren Beitrag erläutere ich ein generisches Datenmodell für die Ressourcenplanung.
In diesem Beitrag, erweitere ich das Gantt-Beispiel, um die weiteren Punkte der Anforderungsliste:
- A1 Der Resource-Gantt-Chart soll über Suchfelder gesteuert werden
- A2 Wenn ein Suchfeld geändert wird, soll der Gantt-Chart „The-Ajax-Way“ aktualisiert werden
- A3 Der Gantt-Chart soll auf deutsch sein
- A4 Feiertage sollen markiert werden
- A5 Es sollen mehrere Balkenfarben zur Verfügung stehen, die mit einem schönen Verlauf dargestellt werden sollen
- A6 Im Balken soll eine Beschriftung erscheinen
- A7 Per Maus-Hover soll bei Bedarf eine Info zum Balken ein- und ausgeblendet werden
- A8 Per Mausklick auf den Balken, soll ein Zusatzdialog zum Gantt-Chart geöffnet werden.
Hier ist meine Demo-Seite zu dem Beispiel:
https://apex.oracle.com/pls/apex/f?p=DEMO_JENS_MARRE:ANY_GANTT
(Login über: demo/demo)
Die Anforderungen A1 und A2 habe ich bereits im letzten Beitrag implementiert. Alle anderen Anforderungen werden im On-Demand-Prozess „generate_gantt_xml“ umgesetzt. Letztendlich muss hierfür der AnyGantt-Syntax bedient werden. Ich erkläre die Umsetzung der Anforderungen als XML-Kommentar direkt in dem Beispiel-XML-Code weiter unten.
In meiner Demoapplication und dem Beispiel-XML-Code verwendet ich feste Datumswerte und nicht den per Ajax geposteten Datumswert P4_DAY.
Workarounds:
Generell werden im Header-Teil der XML-Datei die allgemeinen Chart-Einstellungen und die verschiedenen Balkenstyles definiert. Für jeden Balken können im Body-Teil der XML-Datei AnyChart-Attribute einzeln und dynamisch gesetzt werden (z.B. Balkentext, Hovertext, …).
Dabei stößt man allerdings auf folgendes Problem: Farbwerte können in den Styles nicht dynamisch gesetzt werden, was die Umsetzung von Anforderung A5 vor ein Problem stellt. Ich verwende dafür folgenden Workaround:
Ich ermittle dynamisch die möglichen Farbstile in dem angefordertem Zeitraum und kopiere für jeden Farbstil einen eigenes Tag „period_style“ in die XML-Datei. Jeder Stil erhält als Namen den Hex-Wert der Grundfarbe des Balkens und kann so im Body-Teil der XML-Datei für die Balken referenziert werden.
Für die Umsetzung der Anforderungen A6 und A8 gibt es ein weiteres Problem: In der aktuellen AnyGantt-Version legt sich der Balkentext über den Mausklick-Trigger.
Hierfür habe ich folgenden Workaround gefunden: Während des Maus-Hovers, also im Hover-Style, lösche ich den Balkentext und geben dadurch den Trigger für den Mausklick wieder frei. Bewegt sich die Maus wieder vom Balken weg, erscheint auch der Balkentext wieder.
Beispiel XML-Datei
<anygantt> <settings> <navigation enabled="True" position="Top" size="30"> <buttons collapse_expand_button="false" align="Near" /> <text>Dienstplan</text> <font face="Verdana" size="10" bold="true" color="White" /> <background> <fill type="Gradient"> <gradient> <key color="#B0B0B0" position="0" /> <key color="#A0A0A0" position="0.3" /> <key color="#999999" position="0.5" /> <key color="#A0A0A0" position="0.7" /> <key color="#B0B0B0" position="1" /> </gradient> </fill> <border type="Solid" color="#494949" /> </background> </navigation> <locale> <!-- A3: Defining months Using a german locale --> <date_time_format week_starts_from_monday="True"> <months> <names>Januar,Februar,März,April,Mai,Juni,Juli,August,September, Oktober,November,Dezember</names> <short_names>Jan,Feb,Mar,Apr,Mai,Jun,Jul,Aug,Sep,Okt,Nov,Dez</short_names> </months> <!-- <time am_string="AM" short_am_string="A" pm_string="PM" short_pm_string="P" /> --> <!-- A4: Defining general weekdays Holidays are defined in timeline > calendar > execptions A3: Using a german date format --> <week_days> <names>Sonntag,Montag,Dienstag,Mittwoch,Donnerstag,Freitag,Samstag</names> <short_names>So,Mo,Di,Mi,Do,Fr,Sa</short_names> </week_days> <format> <full>%dd.%MM.%yyyy %HH24:%mi</full> <date>%dd.%MM.%yyyy</date> <time>%HH.%mm.</time> </format> </date_time_format> </locale> </settings> <datagrid width="180"> <columns> <column attribute_name="RowNum" width="30"> <header> <text>#</text> </header> </column> <column attribute_name="Name" cell_align="LEFTLEVELPADDING" padding="0" width="150"> <header> <text>Mitarbeiter</text> </header> </column> </columns> </datagrid> <timeline> <!-- A1: The beginning and the end of the time frame This is set dynamically based on the day entered by the user --> <scale start="18.08.2014" end="22.09.2014" show_start="01.09.2014" show_end="08.09.2014" /> <plot line_height="30" item_height="20" item_padding="5" > <!-- A4: Render weekends properly note the opacity value --> <non_working_days show="true"> <fill enabled="true" type="Solid" color="#aa2222" opacity="0.1" /> </non_working_days> <grid> <vertical> <line enabled="true" color="DarkSeaGreen" thickness="1" opacity="0.2"/> <!-- Do not fill even and odd columns this is just a hint for the feature --> <!-- <even> <fill enabled="true" color="DarkSeaGreen" opacity="0.5" /> </even> <odd> <fill enabled="true" color="White" opacity="1" /> </odd> --> </vertical> </grid> </plot> <!-- A4: Defining holidays general weekdays are defined in settings > locale > date_time_format > week_days The actual holidays are rendered dynamically based on time frame that the user has entered e.g. check: http://ora-sql-plsql.blogspot.de/2012/04/ermittlung-von-feiertagen-per-table.html --> <calendar> <exceptions> <exception is_working="false" start_date="01.01.2014" end_date="01.01.2014" /> <exception is_working="false" start_date="06.01.2014" end_date="06.01.2014" /> <exception is_working="false" start_date="27.02.2014" end_date="27.02.2014" /> <exception is_working="false" start_date="03.03.2014" end_date="03.03.2014" /> <exception is_working="false" start_date="17.04.2014" end_date="17.04.2014" /> <exception is_working="false" start_date="18.04.2014" end_date="18.04.2014" /> <exception is_working="false" start_date="21.04.2014" end_date="21.04.2014" /> <exception is_working="false" start_date="01.05.2014" end_date="01.05.2014" /> <exception is_working="false" start_date="29.05.2014" end_date="29.05.2014" /> <exception is_working="false" start_date="09.06.2014" end_date="09.06.2014" /> <exception is_working="false" start_date="19.06.2014" end_date="19.06.2014" /> <exception is_working="false" start_date="15.08.2014" end_date="15.08.2014" /> <exception is_working="false" start_date="03.10.2014" end_date="03.10.2014" /> <exception is_working="false" start_date="31.10.2014" end_date="31.10.2014" /> <exception is_working="false" start_date="01.11.2014" end_date="01.11.2014" /> <exception is_working="false" start_date="25.12.2014" end_date="25.12.2014" /> <exception is_working="false" start_date="26.12.2014" end_date="26.12.2014" /> </exceptions> </calendar> </timeline> <styles> <period_styles> <!-- A5: I have found no way to set the color-values dynamically My workaround: Check dynamically which colors need to be rendered in the entered time frame and dynamically create an own period style for each color. Each period style is an exact copy of this style only distinguished by its color-values. The gradients are computed via plsql using my object type UI_COLOR https://jmarre.wordpress.com/2014/08/16/blending-colors-in-oracle-plsql --> <period_style name="#FF3300_TIMES0"> <bar_style> <middle shape="Full"> <border enabled="true" type="Solid" thickness="1" color="#400D00" /> <fill enabled="true" type="Gradient"> <gradient angle="-90"> <key color="#FF9980" position="0" /> <key color="#FF3300" position="1" /> </gradient> </fill> </middle> <labels> <!-- A6: Each bar defines its own title using AnyChart attributes --> <label anchor="Center" valign="Center" halign="Center"> <font face="Verdana" size="10" bold="true" color="Black" /> <text><![CDATA[{%Title}]]></text> </label> </labels> <states> <!-- A7: The specific bar style for hover events --> <hover> <middle> <border enabled="true" type="Solid" thickness="2" color="#661400" /> <fill enabled="true" type="Gradient"> <!-- A5: On hover the gradient is turned upside down Again, the gradients are computed via plsql using my object type UI_COLOR https://jmarre.wordpress.com/2014/08/16/blending-colors-in-oracle-plsql --> <gradient angle="90"> <key color="#FF9980" position="0" /> <key color="#FF3300" position="1" /> </gradient> </fill> </middle> <!-- A7, A8: This is a workaround: I could not find any way to render both for each bar: link and label Somehow the label overwrites the link for the bar The workaround here is to remove the label on hover This makes the link somehow visible again --> <labels> <label anchor="Center" valign="Center" halign="Center"> <text></text> </label> </labels> </hover> </states> </bar_style> <!-- A7: The actual tooltip on mouse hover Each bar defines its own title using AnyChart attributes --> <tooltip enabled="true" name="periodTooltip"> <text><![CDATA[{%Longtitle} {%Name} {%Week} {%StartDay} {%Time} {%Comment}]]> </text> <font color="Black"/> <fill enabled="true" type="Solid" color="White" opacity="0.9" /> <border enabled="true" type="Solid" color="DarkRed" thickness="1" /> <margin left="10" top="2" right="10" bottom="2" /> </tooltip> </period_style> <!-- .... more period styles for other colors ---- --> </period_styles> </styles> <resource_chart> <resources> <resource id="100063" name="BLAKE" /> <resource id="100061" name="CLARK" /> <resource id="100068" name="JONES" /> <resource id="100060" name="SCOTT" /> <resource id="100073" name="FORD" /> <resource id="100064" name="TURNER" /> <resource id="100062" name="HARPER" /> </resources> <periods> <period resource_id="100073" start="15.09.2014 09:00" end="15.09.2014 17:00" name="test" style="#7D7DBE_TIMES0"> <actions> <action type="navigateToURL" url="https://apextipps.wordpress.com/?x=110184," target="_self"/></actions> <attributes> <attribute name="Title">U</attribute> <attribute name="Longtitle">Urlaub</attribute> <attribute name="StartDay">15.09.2014</attribute> <attribute name="Week">KW38</attribute> <attribute name="Time"></attribute> <attribute name="Comment"></attribute> </attributes> </period> <period resource_id="100073" start="16.09.2014 09:00" end="16.09.2014 17:00" name="test" style="#7D7DBE_TIMES0"> <actions> <action type="navigateToURL" url="https://apextipps.wordpress.com/?x=110185," target="_self"/> </actions> <attributes> <attribute name="Title">U</attribute> <attribute name="Longtitle">Urlaub</attribute> <attribute name="StartDay">16.09.2014</attribute> <attribute name="Week">KW38</attribute> <attribute name="Time"></attribute> <attribute name="Comment"></attribute> </attributes> </period> <!-- more periods --> </periods> </resource_chart> </anygantt>
Pingback: Flexible Resource-Gantt-Chart with Oracle Apex and AnyChart / AnyGantt (2) | Notes by jmarre