Skip to main content

Usage

This section describes an example implementation of United Code Gantt Pro in an example Oracle APEX application.

The usage guide shows the basic implementation of the plug-in.

Example for basic implementation.

The initial state of page 2 in page designer is presented below:

Implementation Steps

  1. Add new region of type »Static Content«

  2. Add two date picker items (for example: P2_START_DATE, P2_END_DATE). The gantt chart plug-in requires two date picker items in order to work. We also recommend specifying a default value for these two items. In this case even on the first load of the page the gantt chart will be nicely displayed.

  3. Add a new Region of type: United Codes Gantt [Plug-In]

  4. The following region properties are mandatory in order the plug-in to work:

    1. Source (in below example we use SQL query)

    2. Page Items to Submit: P2_START_DATE, P2_END_DATE

  5. Under Attributes the following must be set:

    • Task ID
    • Task name
    • Task start date
    • Task end date
    • Viewpoint start date (P2_START_DATE)
    • Viewpoint end date  (P2_END_DATE)

6. Below is an example of the page after successfully setting up the plugin:

Advanced Settings (Attributes)

  • Display events / tasks on timeline

  • Event/Task Progress

    • SQL QUERY

      select T.ID,
             P.ID PROJECT_ID,
             P.PROJECT,
             T.TASK_NAME ||
               case when T.STATUS is not null
                 then '['||T.STATUS||']'
               else null
             end TASK_NAME,
             T.START_DATE,
             T.END_DATE,
             T.STATUS,
             T.ASSIGNED_TO,
             T.COST,
             T.BUDGET,
        -- Range to have correct calculations is from 0 - 1. (0.50 is 50%)
             round(DBMS_RANDOM.VALUE(0,1),2) PROGRESS,
        case T.STATUS
          when 'On-Hold'
      then '#ed6647'
          when 'Closed'
      then '#68c182'
          else null
        end COLOR
        from EBA_DEMO_CHART_TASKS T
             inner join EBA_DEMO_CHART_PROJECTS P
      on ( P.ID = T.PROJECT )
    • ATTRIBUTES

  • Show difference of planning / actual time value (Baseline)

    • SQL Query

      select ID,
             PROJECT,
             PARENT_TASK,
             TASK_NAME,
             ROW_VERSION_NUMBER,
             START_DATE,
             END_DATE,
             STATUS,
             -- Start date of a planning the task
             START_DATE - ROWNUM/ID BASE_START,
             -- End date of a planning the task
             END_DATE + ROWNUM/ID BASE_END,                
        ASSIGNED_TO,
             COST,
             BUDGET,
             CREATED,
             CREATED_BY,
             UPDATED,
             UPDATED_BY
        from EBA_DEMO_CHART_TASKS
    • Attributes

  • Drag and drop event/task option & Resize event/task option

  • Dependency SQL specification

select ID,  
PREDECESSOR,
SUCCESSOR,
RELATION,
STATUS,
SHORTDESC
from EBA_DEMO_CHART_TASKS_DEPEND_V;

JSON options

{
"id": "5",
"predecessor": "3",
"successor": "2",
"relation": "finishStart", // "finishStart" | "finishFinish" | "startStart" | "startFinish"
"status": "critical", //used for customization
"shortDesc": "My Description finishStart|critical"
}
  • Additional event/task information (tooltip)

  • Hierarchical event/tasks view

    •  SQL Query

      select T.ID,
      T.PARENT_TASK PARENT_TASK_ID,
      P.ID PROJECT_ID,
      P.PROJECT,
      T.TASK_NAME,
      T.START_DATE,
      T.END_DATE,
      T.STATUS,
      T.ASSIGNED_TO,
      T.COST,
      T.BUDGET,
      '{"assigned":"'||T.ASSIGNED_TO||'",
      "borderRadius":"10px",
      "labelPosition":"start",
      "type":"'|| case when T.PARENT_TASK is null
      then 'summary' else 'normal' end ||'"
      }' CUSTOM_SETTINS
      from EBA_DEMO_CHART_TASKS T
      inner join EBA_DEMO_CHART_PROJECTS P
      on P.ID = T.PROJECT
    •  Attributes

Automatic Time Zone

Since Oracle APEX automatically parse date and timestamp into JavScript format (example: "2023-10-28T22:06:00Z") browsers will automatically calculate offset and display it for you.

The ISO format support short notations where the string must only include the date and not time, as in the following formats: YYYY, YYYY-MM, YYYY-MM-DD.

The ISO format does not support time zone names. You can use the Z position to specify an offset from UTC time. If you do not include a value in the Z position, UTC time is used. The correct format for UTC should always include character 'Z' if the offset time value is omitted. The date-parsing algorithms are browser-implementation-dependent and, for example, the date string '2013-02-27T17:00:00' will be parsed differently in Chrome vs Firefox vs IE.

More details can be found in the OJ GANTT documentation.

In order to avoid auto calculation you can disable that option in "Javascript Initialization Code".

function (pOptions) {

//Use browser TimeZone true/false
pOptions.automaticTimezone = false;

return pOptions;
}

Themes

By default, this plug-in select "Redwood notag". In order to be more open for developers to select one of the following theme we introduced new parameter "themeCSS".

Options are :

  • '/alta/oj-alta-min.css'
  • '/alta/oj-alta-notag-min.css'
  • '/alta-android/oj-alta-min.css'
  • '/alta-ios/oj-alta-min.css'
  • '/alta-windows/oj-alta-min.css'
  • '/redwood/oj-redwood-min.css'
  • '/redwood/oj-redwood-notag-min.css'
  • '/stable/oj-stable-min.css'

To change default theme please set themeCSS in "Javascript Initialization Code".

function (pOptions) {

//Change theme
pOptions.themeCSS = '/stable/oj-stable-min.css';

return pOptions;
}

Timeline, Weekends and Time Buckets

By default, timeline and weekends are enabled and displayed out of the box. But sometimes there is a use case to disable coloring or remove timeline. That is possible with custom options via "Javascript Initialization Code".

function (pOptions) {

//disable timeline
pOptions.display.timeLine = false;

//disable weekend coloring
pOptions.display.weekend = false;

return pOptions;
}

To be even more flexible with coloring timeline you can set current time, multiple times, and add a class on it.

function (pOptions) {

//disable timeline
pOptions.display.timeLineData = [{
value: new Date().toISOString(),
shortDesc: "Current Date",
svgClassName:'demo-current-time-indicator'
}];

return pOptions;
}

Sometimes there is a need to ave different Time Buckets, to display phase of project. That can be achieved with setting up Time Bucket JSON in "Javascript Initialization Code".

function (pOptions) {

let firstStart = new Date();
let firstEnd = new Date();
let secondStart = new Date();
let secondEnd = new Date();

firstStart.setMonth(firstStart.getMonth() - 1);
firstEnd.setDate(firstEnd.getDate() - 10);
secondStart.setDate(secondStart.getDate() + 10);
secondEnd.setMonth(secondEnd.getMonth() + 1);

pOptions.display.timeBucketsData = [
{
type: "area",
start: firstStart.toISOString(),
end: firstEnd.toISOString(),
svgStyle: { fill: "#32925e", opacity: "0.18" },
shortDesc: "Time Bucket 1",
},
{
type: "area",
start: secondStart.toISOString(),
end: secondEnd.toISOString(),
svgStyle: { fill: "#eb9632", opacity: "0.18" },
shortDesc: "Time Bucket 2",
},
];

return pOptions;
}

Result:

Javascript Initialization Code

Sometimes you can hit charters imit. In that case declare variable in page "Function and Global Variable Declaration" and reference on it within plug-in "Javascript Initialization Code".

function (pOptions) {
pOptions.gantt = {
"gridlines.horizontal":"visible",
"gridlines.vertical":"visible",
"major-axis.scale":"weeks",
"major-axis.zoom-order":'["quarters", "months", "weeks", "days"]',
"major-axis.converter.weeks":"[[dateConverter]]",
"minor-axis.scale":"days",
"minor-axis.zoom-order":'["quarters", "months", "weeks", "days"]',
"minor-axis.converter.days":"[[diffDaysConverter]]"
"selection-mode":"multiple",
"dnd.move.tasks":"enabled",
"task-defaults.resizable":"enabled",
"style":"width:100%;height:70vh",
"translations.component-name":"Component Name !",
"translations.label-invalid-data":"Something wrong with date fields!",
"task-defaults.height":40,
"task-defaults.border-radius":5,
"task-defaults.label-position":"innerStart",
"task-defaults.type":"summary",
"task-defaults.svg-style":{"fill":"#b366ff"},
"task-defaults.overlap.behavior":"stack"
};

//Use browser TimeZone true/false
pOptions.automaticTimezone = false;

//load additional modules
pOptions.loadModules = ["ojs/ojmenu", "ojs/ojdvttimecomponentscale", "ojs/ojavatar"];

pOptions.methods = {
//Invert resource sort
sortData :
function (data) {
return data.sort(function (a, b) {
return a.resource < b.resource ? 1 : -1;
})
},
// Custom validation, for more details check "Custom validations section"
validateClick : function(task) {
console.log("Validate CLICK on", task);
return false;
},
validateMove : function(task, moveData) {
console.log("Validate MOVE on", task, moveData);
return true;
},
validateResize : function(task, resizeData) {
console.log("Validate RESIZE on", task, resizeData);
return true;
}
/*
sortData : function (data) {
//No sort
return data;
},*/

};

//add elements in region before oj-gantt element
pOptions.elements = [
`<svg height="0" width="0"><defs><marker
id="demoCircleMarker"
viewBox="0 0 12 12" refX="6" refY="6" markerWidth="12" markerHeight="12"
orient="auto"
markerUnits="userSpaceOnUse">
<circle class="demo-circle-marker" cx="6" cy="6" r="5" />
</marker>
<marker
id="demoArrowMarker"
viewBox="0 0 10 10" refX="10" refY="5" markerWidth="12" markerHeight="12"
orient="auto-start-reverse"
markerUnits="userSpaceOnUse">
<path class="demo-arrow-marker" d="M 0 0 L 10 5 L 0 10 z" />
</marker>
<marker
id="demoArrowMarkerCritical"
viewBox="0 0 10 10" refX="10" refY="5" markerWidth="12" markerHeight="12"
orient="auto-start-reverse"
markerUnits="userSpaceOnUse">
<path class="demo-arrow-critical-marker" d="M 0 0 L 10 5 L 0 10 z" />
</marker>
</defs></svg>`
];

//add templates and elements inside oj-gantt element
pOptions.templates = [
`<template slot="rowAxisLabelTemplate" data-oj-as="rowAxisLabel">
<svg class="demo-gantt-row-label">
<g>
<foreignobject :x="0" y="0" width="32" height="32">
<oj-avatar
src="[[rowAxisLabel.data.resourceData.profile]]"
size="xxs"></oj-avatar>
</foreignobject>
<text :x="25" y="19">
<oj-bind-text value="[[rowAxisLabel.data.resource]]"></oj-bind-text>
</text>
</g>
</svg>
</template>`,
`<oj-menu
id="ctxMenu"
slot="contextMenu"
aria-label="Match Edit"
on-oj-menu-action="[[menuItemAction]]"
on-oj-before-open="[[beforeOpenFunction]]">
<oj-option value="Action 1">Action 1</oj-option>
<oj-option value="Action 2">Action 2</oj-option>
<oj-option value="Action 3">Action 3</oj-option>
</oj-menu>
</oj-gantt>`
];

pOptions.callback = function(ViewModel, rowData, viewPoint, ko, ojconverter, TimeUtils) {
// add additional logic and handlers after data is assigned to te ViewModel
ViewModel.dateConverter = ko.observable(new ojconverter.IntlDateTimeConverter({
formatType: "date",
dateFormat: "long",
}));
ViewModel.diffDaysConverter = {
format: (dateString) => {
const day = 24 * 60 * 60 * 1000;
const startDate = new Date(viewPoint.start);
const startTime = startDate.getTime();
const date = new Date(dateString);
return Math.round(Math.abs(date.getTime() - startTime) / day + 1);
}
};

};

return pOptions;
}