Browse Source

s-curve api implementation

pull/1/head
Muhammad Sulaiman Yusuf 2 years ago
parent
commit
727a59b167
  1. 2
      edit-mode/function/restActivityLink.js
  2. 244
      view-mode/function/ganttConfig.js
  3. 125
      view-mode/function/overlaySCurve.js
  4. 26
      view-mode/index.html

2
edit-mode/function/restActivityLink.js

@ -84,7 +84,7 @@ var dp = gantt.createDataProcessor(function(entity, action, data, id) {
}).then(function(response){
let res = response.responseText
res = JSON.parse(res)
// console.log("cek response", res)
console.log("qqqqqqcek response", res)
if(entity=="link"){
gantt.changeLinkId(id, res.tid);
}else if(entity=="task"){

244
view-mode/function/ganttConfig.js

@ -210,113 +210,113 @@ function createColumnsConfig(selectedColumns){
}
var allColumns = [
{ name: "kode_sortname", label: "Kode / Sortname",align: "center", min_width: 120, resize: true },
// { name: "kode_sortname", label: "Kode / Sortname",align: "center", min_width: 120, resize: true },
{ name: "text", label: "Activity", tree: true, min_width: 150, resize: true },
{ name: "start_date", label: "Start Date", align: "center", min_width: 80, resize: true },
{ name: "end_date", label: "Finish Date", align: "center", min_width: 80, resize: true },
{ name: "duration", label: "Duration", align: "center", min_width: 50, resize: true },
{ name: "rencana_biaya", label: "Cost Planning", align: "center", min_width: 100, resize: true, template: function (text) {
if(!text.rencana_biaya){
return
}
let rencana_biaya = text.rencana_biaya
return "Rp. "+ formatRupiah(rencana_biaya)
} },
{ name: "cost_actual", label: "Cost Actual", align: "center", min_width: 100, template: function (text) {
if(!text.biaya_actual){
return
}
let biaya_actual = text.biaya_actual
return "Rp. "+ formatRupiah(biaya_actual)
} },
{ name: "assign_hr", label: "Assign To", align: "center", min_width: 150, template: function (text) {
if(text.type=="project" || text.type=="milestone"){
return;
}
let html = ``;
var assign_hr = text.assign_hr
if(!assign_hr || !assign_hr.length){
html = `<span class="badge badge-pill badge-danger">Unassigned</span>`;
}else{
if(assign_hr.length==1){
html = `<span class="text-capitalize badge badge-pill badge-primary">${assign_hr[0]}</span>`;
}else{
assign_hr.forEach(function(val, index) {
html += `<span class="text-capitalize badge badge-primary mr-1">${val.substr(0, 1)}</span>`;
});
}
}
return `<div class="d-flex justify-content-center align-items-center" data-toggle="modal" data-target="#modal-hr" style="min-width:100%;height:100%;">
${html}
</div>`
}
},
{ name: "material", label: "Material", align: "center", min_width: 150, resize: true, template: function (text) {
if(text.type=="project" || text.type=="milestone"){
return;
}
let html = ``;
var assign_material = text.assign_material
if(!assign_material || !assign_material.length){
html = `<span class="badge badge-pill badge-danger">Unassigned</span>`;
}else{
if(assign_material.length > 0 ){
html = `<span class="text-capitalize badge badge-pill badge-primary">Assigned</span>`;
}
}
return `<div class="d-flex justify-content-center align-items-center" data-toggle="modal" data-target="#modal-material" style="min-width:100%;height:100%;">
${html}
</div>`
} },
{ name: "bobot_planning", label: "Bobot Activity (%)", align: "center", resize: true, min_width: 115, template: function (text) {
if(!text.bobot_planning){
return
}
let bobot_planning = parseFloat(text.bobot_planning);
return roundToTwo(bobot_planning);
} },
{ name: "progress", label: "Actual Progress (%)", align: "center", min_width: 125, template: function (text) {
let progress = text.progress
progress = progress*100
return progress;
}, resize: true },
{ name:"progress_actual", label: "Total Actual Progress (%)", align: "center", min_width: 150, template: function (text) {
let progress = text.progress
progress = progress*100
let bobot = text.bobot_planning
let actual = (progress*bobot) / 100
return roundToTwo(actual);
}, resize: true },
{ name: "jumlah_pekerjaan", label: "Volume Plan", align: "center", min_width: 100, resize: true},
{ name: "jobs_done", label: "Volume Actual", align: "center", min_width: 100, resize: true, template: function (text) {
if(text.type=="project" || text.type=="milestone"){
return;
}
let html = text.jobs_done ? text.jobs_done : 0;
return `<div class="d-flex justify-content-center align-items-center" data-toggle="modal" data-target="#modal_report_activity" style="min-width:100%;height:100%;">
${html}
</div>`
} },
{ name: "updated_by", label: "Last Updated By", align: "center", min_width: 100, resize: true }
// { name: "start_date", label: "Start Date", align: "center", min_width: 80, resize: true },
// { name: "end_date", label: "Finish Date", align: "center", min_width: 80, resize: true },
// { name: "duration", label: "Duration", align: "center", min_width: 50, resize: true },
// { name: "rencana_biaya", label: "Cost Planning", align: "center", min_width: 100, resize: true, template: function (text) {
// if(!text.rencana_biaya){
// return
// }
// let rencana_biaya = text.rencana_biaya
// return "Rp. "+ formatRupiah(rencana_biaya)
// } },
// { name: "cost_actual", label: "Cost Actual", align: "center", min_width: 100, template: function (text) {
// if(!text.biaya_actual){
// return
// }
// let biaya_actual = text.biaya_actual
// return "Rp. "+ formatRupiah(biaya_actual)
// } },
// { name: "assign_hr", label: "Assign To", align: "center", min_width: 150, template: function (text) {
// if(text.type=="project" || text.type=="milestone"){
// return;
// }
// let html = ``;
// var assign_hr = text.assign_hr
// if(!assign_hr || !assign_hr.length){
// html = `<span class="badge badge-pill badge-danger">Unassigned</span>`;
// }else{
// if(assign_hr.length==1){
// html = `<span class="text-capitalize badge badge-pill badge-primary">${assign_hr[0]}</span>`;
// }else{
// assign_hr.forEach(function(val, index) {
// html += `<span class="text-capitalize badge badge-primary mr-1">${val.substr(0, 1)}</span>`;
// });
// }
// }
// return `<div class="d-flex justify-content-center align-items-center" data-toggle="modal" data-target="#modal-hr" style="min-width:100%;height:100%;">
// ${html}
// </div>`
// }
// },
// { name: "material", label: "Material", align: "center", min_width: 150, resize: true, template: function (text) {
// if(text.type=="project" || text.type=="milestone"){
// return;
// }
// let html = ``;
// var assign_material = text.assign_material
// if(!assign_material || !assign_material.length){
// html = `<span class="badge badge-pill badge-danger">Unassigned</span>`;
// }else{
// if(assign_material.length > 0 ){
// html = `<span class="text-capitalize badge badge-pill badge-primary">Assigned</span>`;
// }
// }
// return `<div class="d-flex justify-content-center align-items-center" data-toggle="modal" data-target="#modal-material" style="min-width:100%;height:100%;">
// ${html}
// </div>`
// } },
// { name: "bobot_planning", label: "Bobot Activity (%)", align: "center", resize: true, min_width: 115, template: function (text) {
// if(!text.bobot_planning){
// return
// }
// let bobot_planning = parseFloat(text.bobot_planning);
// return roundToTwo(bobot_planning);
// } },
// { name: "progress", label: "Actual Progress (%)", align: "center", min_width: 125, template: function (text) {
// let progress = text.progress
// progress = progress*100
// return progress;
// }, resize: true },
// { name:"progress_actual", label: "Total Actual Progress (%)", align: "center", min_width: 150, template: function (text) {
// let progress = text.progress
// progress = progress*100
// let bobot = text.bobot_planning
// let actual = (progress*bobot) / 100
// return roundToTwo(actual);
// }, resize: true },
// { name: "jumlah_pekerjaan", label: "Volume Plan", align: "center", min_width: 100, resize: true},
// { name: "jobs_done", label: "Volume Actual", align: "center", min_width: 100, resize: true, template: function (text) {
// if(text.type=="project" || text.type=="milestone"){
// return;
// }
// let html = text.jobs_done ? text.jobs_done : 0;
// return `<div class="d-flex justify-content-center align-items-center" data-toggle="modal" data-target="#modal_report_activity" style="min-width:100%;height:100%;">
// ${html}
// </div>`
// } },
// { name: "updated_by", label: "Last Updated By", align: "center", min_width: 100, resize: true }
];
gantt.config.columns = createColumnsConfig({
kode_sortname: true,
kode_sortname: false,
text: true,
start_date: true,
end_date: true,
duration: true,
rencana_biaya: true,
cost_actual: true,
assign_hr: true,
material: true,
bobot_planning: true,
progress: true,
progress_actual: true,
jumlah_pekerjaan: true,
jobs_done:true,
updated_by: true
start_date: false,
end_date: false,
duration: false,
rencana_biaya: false,
cost_actual: false,
assign_hr: false,
material: false,
bobot_planning: false,
progress: false,
progress_actual: false,
jumlah_pekerjaan: false,
jobs_done: false,
updated_by: false
})
gantt.config.reorder_grid_columns = true;
@ -450,19 +450,11 @@ var zoomConfig = {
scale_height: 50,
min_column_width:50,
scales:[
// {unit: "week", step: 1, format: function (date) {
// var dateToStr = gantt.date.date_to_str("%d %M");
// var endDate = gantt.date.add(date, -6, "day");
// var weekNum = gantt.date.date_to_str("%W")(date);
// var year = gantt.date.date_to_str("%Y")(date);
// return "#" + weekNum + ", " + dateToStr(date) + " - " + dateToStr(endDate) + " " + year;
// }},
{unit: "week", step: 1, format: function (date) {
var weekNum = gantt.date.date_to_str("%W")(date);
return "W#" + weekNum;
}},
{unit: "month", format: "%F, %Y"},
// {unit: "day", step: 1, format: "%j %D"}
]
},
{
@ -471,42 +463,12 @@ var zoomConfig = {
min_column_width:120,
scales:[
{unit: "month", format: "%F, %Y"},
// {unit: "week", format: "Week #%W"},
// {unit: "day", step: 1, format: "%j %D"}
]
},
// {
// name:"quarter",
// height: 50,
// min_column_width:90,
// scales:[
// {unit: "month", step: 1, format: "%M"},
// {
// unit: "quarter", step: 1, format: function (date) {
// var dateToStr = gantt.date.date_to_str("%M");
// var endDate = gantt.date.add(gantt.date.add(date, 3, "month"), -1, "day");
// return dateToStr(date) + " - " + dateToStr(endDate);
// }
// }
// ]
// },
// {
// name:"year",
// scale_height: 50,
// min_column_width: 30,
// scales:[
// {unit: "year", step: 1, format: "%Y"}
// ]
// }
]
};
gantt.ext.zoom.init(zoomConfig);
gantt.ext.zoom.setLevel("month");
// trigger when zoomIn and zoomOut clicked
gantt.ext.zoom.attachEvent("onAfterZoom", function(level, config){
document.querySelector(".gantt_radio[value='" +config.name+ "']").checked = true;
})
gantt.ext.zoom.setLevel("week");
function zoomIn(){
gantt.ext.zoom.zoomIn();

125
view-mode/function/overlaySCurve.js

@ -1,5 +1,30 @@
var overlayControl = gantt.ext.overlay;
var today = new Date();
var return_first;
var sCurvePayload = {
period: 'week',
project_id: proyekId
};
function callback(response) {
return_first = response;
}
function getSCurveData(){
$.ajax({
headers: {
"Content-Type": "application/json",
"Authorization": `Bearer ${token}`
},
url: `${base_url}project/get-s-curve`,
type: "POST",
data:JSON.stringify(sCurvePayload),
success: function (data) {
callback(data)
}
});
};
function toggleOverlay() {
if(overlayControl.isOverlayVisible(lineOverlay)){
@ -30,91 +55,11 @@ function getChartScaleRange(){
}
function getProgressLine(){
var tasks = gantt.getTaskByTime();
var scale = gantt.getScale();
var step = scale.unit;
var timegrid = {};
var totalDuration = 0;
gantt.eachTask(function(task){
if(gantt.isSummaryTask(task)){
return;
}
if(!task.duration){
return;
}
var currDate = gantt.date[scale.unit + "_start"](new Date(task.start_date));
while (currDate < task.end_date) {
var date = currDate;
currDate = gantt.date.add(currDate, 1, step);
if (!gantt.isWorkTime({date: date, task: task, unit: step})) {
continue;
}
var timestamp = currDate.valueOf();
if (!timegrid[timestamp]){
timegrid[timestamp] = {
planned: 0,
real: 0
};
}
timegrid[timestamp].planned += 1;
if (date <= today){
timegrid[timestamp].real += 1 * (task.progress || 0);
}
totalDuration += 1;
}
});
var cumulativePlannedDurations = [];
var cumulativeRealDurations = [];
var cumulativePredictedDurations = []
var totalPlanned = 0;
var totalReal = 0;
var chartScale = getChartScaleRange();
var dailyRealProgress = -1;
var totalPredictedProgress = 0;
for(var i = 0; i < chartScale.length; i++){
start = new Date(chartScale[i]);
end = gantt.date.add(start, 1, step);
var cell = timegrid[start.valueOf()] || {planned:0, real:0};
totalPlanned = cell.planned + totalPlanned;
cumulativePlannedDurations.push(totalPlanned);
if(start <= today) {
totalReal = (cell.real||0) + totalReal;
cumulativeRealDurations.push(totalReal);
cumulativePredictedDurations.push(null);
} else {
if(dailyRealProgress < 0){
dailyRealProgress = totalReal / cumulativeRealDurations.length;
totalPredictedProgress = totalReal;
cumulativePredictedDurations.pop();
cumulativePredictedDurations.push(totalPredictedProgress);
}
totalPredictedProgress += dailyRealProgress;
cumulativePredictedDurations.push(totalPredictedProgress);
}
}
for(var i = 0; i < cumulativePlannedDurations.length; i++){
cumulativePlannedDurations[i] = Math.round(cumulativePlannedDurations[i] / totalPlanned * 100);
if(cumulativeRealDurations[i] !== undefined){
cumulativeRealDurations[i] = Math.round(cumulativeRealDurations[i] / totalPlanned * 100);
}
if(cumulativePredictedDurations[i] !== null){
cumulativePredictedDurations[i] = Math.round(cumulativePredictedDurations[i] / totalPlanned * 100);
}
}
return {planned: cumulativePlannedDurations, real: cumulativeRealDurations, predicted: cumulativePredictedDurations};
// As long as the progress data length is same with chart scale range (period) then it's fine.
getSCurveData();
var cumulativePlannedDurations = return_first.data[0].data.percentagePlan;
var cumulativeRealDurations = return_first.data[0].data.percentageReal;
return {planned: cumulativePlannedDurations, real: cumulativeRealDurations};
}
function getScalePaddings(){
@ -181,16 +126,6 @@ var lineOverlay = overlayControl.addOverlay(function(container) {
fill: false,
cubicInterpolationMode: 'monotone'
}
,
{
label: "Real progress (predicted)",
backgroundColor: "#ff5454",
borderColor: "#ff5454",
data: values.predicted,
borderDash: [5, 10],
fill: false,
cubicInterpolationMode: 'monotone'
}
]
},
options: {

26
view-mode/index.html

@ -69,32 +69,6 @@
<h6 id="project-name-header"></h6>
</div>
<div class="container-action">
<div class="btn-icon-toolbar btn-sm"><span class="icon-toolbar-separator">Zoom: </span></div>
<div class="btn-icon-toolbar text-nowrap">
<input type="radio" id="scale1" class="gantt_radio" name="scale" value="day">
<label for="scale1" class="icon-toolbar btn-icon-toolbar-label">Days</label>
</div>
<div class="btn-icon-toolbar text-nowrap">
<input type="radio" id="scale2" class="gantt_radio" name="scale" value="week">
<label for="scale2" class="icon-toolbar btn-icon-toolbar-label">Weeks</label>
</div>
<div class="btn-icon-toolbar text-nowrap">
<input type="radio" id="scale3" class="gantt_radio" name="scale" value="month">
<label for="scale3" class="icon-toolbar btn-icon-toolbar-label">Months</label>
</div>
<span class="icon-toolbar-separator">|</span>
<button title="Synchronize to Report Activity" class="btn btn-sm btn-icon-toolbar" id="gantt-synchronize"><i
class="fa fa-sync icon-toolbar"></i></button>
<span class="icon-toolbar-separator">|</span>
<button title="Set Baseline" class="btn btn-sm btn-icon-toolbar" id="gantt-baseline"><i
class="fa fa-grip-lines icon-toolbar"></i></button>
<span class="icon-toolbar-separator">|</span>
<button title="Show / Hide Columns" class="btn btn-sm btn-icon-toolbar" id="gantt_toggle_columns_btn"
onclick="gantt.$showDropdown(this)"><i class="fa fa-columns icon-toolbar"></i></button>
<span class="icon-toolbar-separator">|</span>
<button title="Gantt Settings" class="btn btn-sm btn-icon-toolbar" id="gantt_setting_btn"><i
class="fa fa-cog icon-toolbar"></i></button>
<span class="icon-toolbar-separator">|</span>
<button title="Expand Activities" class="btn btn-sm btn-icon-toolbar" id="gantt_toggle_task_btn"><i
class="fa fa-expand-alt icon-toolbar"></i></button>
<span class="icon-toolbar-separator">|</span>

Loading…
Cancel
Save