Muhammad Sulaiman Yusuf
2 years ago
8 changed files with 430 additions and 1376 deletions
@ -1,209 +1,55 @@
|
||||
var hrModal = $('#modal-hr > .modal-dialog > .modal-content'); |
||||
|
||||
function resetFormAssign() { |
||||
$('#select-role-hr').val(null).trigger("change"); |
||||
$('#select-role-hr').find('option').remove(); |
||||
$('#select-role-hr').val(""); |
||||
$('#select-hr').val(null).trigger("change"); |
||||
$('#select-hr').find('option').remove(); |
||||
$('#select-hr').val(""); |
||||
$("#hr_role").val(""); |
||||
// $("#hide-form-hr").hide();
|
||||
// $("#show-form-hr").show();
|
||||
// $("#form-assign-hr").hide();
|
||||
$('#form-assign-hr').trigger("reset"); |
||||
$('#btn-assign-hr').html('Assign'); |
||||
$('#btn-assign-hr').prop("disabled", false); |
||||
$('#select-role-hr').val(null).trigger("change"); |
||||
$('#select-role-hr').find('option').remove(); |
||||
$('#select-role-hr').val(""); |
||||
$('#select-hr').val(null).trigger("change"); |
||||
$('#select-hr').find('option').remove(); |
||||
$('#select-hr').val(""); |
||||
$("#hr_role").val(""); |
||||
$('#form-assign-hr').trigger("reset"); |
||||
$('#btn-assign-hr').html('Assign'); |
||||
$('#btn-assign-hr').prop("disabled", false); |
||||
}; |
||||
|
||||
$(document).ready(function () { |
||||
var tableHr = $("#table-hr").DataTable({ |
||||
"processing": true, |
||||
"serverSide": true, |
||||
"ajax": { |
||||
"url": `${base_url}user-to-activity/datatables`, |
||||
"data": function (d) { |
||||
d.idact = activityId; |
||||
} |
||||
}, |
||||
"columns": [ |
||||
{ data: 'user_name', name: 'user_name' }, |
||||
{ data: 'role_name', name: 'role_name' }, |
||||
{ |
||||
data: 'action', |
||||
name: 'action', |
||||
orderable: true, |
||||
searchable: true |
||||
}, |
||||
] |
||||
}); |
||||
var tableHr = $("#table-hr").DataTable({ |
||||
"processing": true, |
||||
"serverSide": true, |
||||
"ajax": { |
||||
"url": `${base_url}user-to-activity/datatables`, |
||||
"data": function (d) { |
||||
d.idact = activityId; |
||||
} |
||||
}, |
||||
"columns": [ |
||||
{ data: 'user_name', name: 'user_name' }, |
||||
{ data: 'role_name', name: 'role_name' }, |
||||
] |
||||
}); |
||||
|
||||
|
||||
$("#modal-hr").on("click", "#show-form-hr", function () { |
||||
$(this).hide(); |
||||
$("#hide-form-hr").show(); |
||||
$("#form-assign-hr").show(); |
||||
}); |
||||
|
||||
$("#modal-hr").on("click", "#hide-form-hr", function () { |
||||
$(this).hide(); |
||||
resetFormAssign() |
||||
$("#show-form-hr").show(); |
||||
}); |
||||
|
||||
$('#modal-hr').on('show.bs.modal', function (event) { |
||||
tableHr.draw(); |
||||
}); |
||||
|
||||
$('#modal-hr').on('hide.bs.modal', function (event) { |
||||
$("#hide-form-hr").hide(); |
||||
$("#show-form-hr").show(); |
||||
resetFormAssign(); |
||||
}); |
||||
|
||||
function deleteHrAssign(id) { |
||||
$.ajax({ |
||||
url: `${base_url}user-to-activity/delete/${id}`, |
||||
type: "DELETE", |
||||
success: function (data) { |
||||
actionHappen = true; |
||||
gantt.alert("Delete Human Resource Assign Success!"); |
||||
tableHr.draw(); |
||||
}, |
||||
error: function (data) { |
||||
gantt.alert("Delete Human Resource Assign Failed, try again later!"); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
$("#modal-hr").on("click", "#show-form-hr", function () { |
||||
$(this).hide(); |
||||
$("#hide-form-hr").show(); |
||||
$("#form-assign-hr").show(); |
||||
}); |
||||
|
||||
$("#modal-hr").on("click", "#hide-form-hr", function () { |
||||
$(this).hide(); |
||||
resetFormAssign() |
||||
$("#show-form-hr").show(); |
||||
}); |
||||
|
||||
$('#modal-hr').on('show.bs.modal', function (event) { |
||||
tableHr.draw(); |
||||
}); |
||||
|
||||
$('#modal-hr').on('hide.bs.modal', function (event) { |
||||
$("#hide-form-hr").hide(); |
||||
$("#show-form-hr").show(); |
||||
if (actionHappen) { |
||||
console.log("there's action change"); |
||||
updateActivity(activityId); |
||||
} |
||||
resetFormAssign(); |
||||
}); |
||||
|
||||
$('#select-role-hr').select2({ |
||||
dropdownParent: hrModal, |
||||
placeholder: 'Pilih human resource role', |
||||
allowClear: true, |
||||
ajax: { |
||||
url: `${base_url}project-role/select`, |
||||
dataType: 'json', |
||||
data: function (params) { |
||||
var query = { |
||||
search: params.term, |
||||
type: 'public', |
||||
} |
||||
return query; |
||||
}, |
||||
processResults: function (result) { |
||||
return { |
||||
results: $.map(result, function (item) { |
||||
// console.log("cek item", item)
|
||||
return { |
||||
text: item.name, |
||||
id: item.id |
||||
} |
||||
}) |
||||
}; |
||||
}, |
||||
cache: false |
||||
} |
||||
}); |
||||
$('#select-hr').select2({ |
||||
dropdownParent: hrModal, |
||||
placeholder: 'Pilih human resource', |
||||
allowClear: true, |
||||
ajax: { |
||||
url: `${base_url}human-resource/select`, |
||||
dataType: 'json', |
||||
data: function (params) { |
||||
var query = { |
||||
search: params.term, |
||||
type: 'public', |
||||
idact: activityId, |
||||
idProyek: proyekId |
||||
} |
||||
return query; |
||||
}, |
||||
processResults: function (result) { |
||||
return { |
||||
results: $.map(result, function (item) { |
||||
// console.log("cek item", item)
|
||||
return { |
||||
text: item.name, |
||||
id: item.id, |
||||
proyek_role: item.proyek_role |
||||
} |
||||
}) |
||||
}; |
||||
}, |
||||
cache: false |
||||
} |
||||
}); |
||||
|
||||
$('#select-hr').on('select2:select', function (e) { |
||||
console.log('select event', e.params.data); |
||||
let param_data = e.params.data; |
||||
if (param_data && param_data.proyek_role) { |
||||
let proyek_role = param_data.proyek_role |
||||
$("#hr_role").val(proyek_role); |
||||
} |
||||
|
||||
}); |
||||
|
||||
|
||||
$("#form-assign-hr").on('submit', function (e) { |
||||
e.preventDefault(); |
||||
|
||||
$('#btn-assign-hr').html('Assign...'); |
||||
$('#btn-assign-hr').prop("disabled", true); |
||||
|
||||
// var formData = new FormData(this);
|
||||
let user_id = $("#select-hr").val(); |
||||
let user_role = $("#hr_role").val(); |
||||
if (!user_id || user_id < 0) { |
||||
gantt.alert("Please choose user to assign!"); |
||||
$('#btn-assign-hr').html('Assign'); |
||||
$('#btn-assign-hr').prop("disabled", false); |
||||
return false |
||||
} |
||||
|
||||
|
||||
let payload = { |
||||
user_id: user_id, |
||||
role_proyek_id: user_role, |
||||
version_gantt_id: ganttId, |
||||
proyek_id: proyekId, |
||||
activity_id: activityId |
||||
} |
||||
$.ajax({ |
||||
data: JSON.stringify(payload), |
||||
url: `${base_url}user-to-activity/add`, |
||||
type: "POST", |
||||
processData: false, |
||||
contentType: false, |
||||
success: function (data) { |
||||
actionHappen = true; |
||||
resetFormAssign(); |
||||
tableHr.draw(); |
||||
gantt.alert("Human Resource Assign Success!"); |
||||
}, |
||||
error: function (data) { |
||||
resetFormAssign(); |
||||
gantt.alert("Human Resource Assign Failed, try again later!"); |
||||
} |
||||
}); |
||||
}); |
||||
|
||||
$("#table-hr").on("click", ".btn-hr-delete", function () { |
||||
let id = $(this).data('id'); |
||||
var box = gantt.confirm({ |
||||
text: "Human resource will be deleted from activity, continue?", |
||||
ok: "Delete", |
||||
cancel: "Cancel", |
||||
callback: function (result) { |
||||
if (result) { |
||||
deleteHrAssign(id); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
}); |
@ -1,299 +1,66 @@
|
||||
var materialModal = $('#modal-material > .modal-dialog > .modal-content'); |
||||
|
||||
function resetFormAssignMaterial() { |
||||
$('#select-material').val(null).trigger("change"); |
||||
$('#select-material').find('option').remove(); |
||||
$('#select-material').val(""); |
||||
$('#form-assign-material').trigger("reset"); |
||||
$('#btn-assign-material').html('Assign'); |
||||
$('#btn-assign-material').prop("disabled", false); |
||||
$('#select-material').val(null).trigger("change"); |
||||
$('#select-material').find('option').remove(); |
||||
$('#select-material').val(""); |
||||
$('#form-assign-material').trigger("reset"); |
||||
$('#btn-assign-material').html('Assign'); |
||||
$('#btn-assign-material').prop("disabled", false); |
||||
}; |
||||
|
||||
|
||||
var rupiah = document.getElementById('price-req-material'); |
||||
rupiah.addEventListener('keyup', function (e) { |
||||
rupiah.value = formatRibuanInput(this.value); |
||||
}); |
||||
|
||||
var qty = document.getElementById('qty-req-material'); |
||||
qty.addEventListener('keyup', function (e) { |
||||
qty.value = formatRibuanInput(this.value); |
||||
}); |
||||
|
||||
$(document).ready(function () { |
||||
var tableMaterial = $("#table-material").DataTable({ |
||||
"processing": true, |
||||
"serverSide": true, |
||||
"ajax": { |
||||
"url": `${base_url}assign-material/datatables`, |
||||
"data": function (d) { |
||||
d.idact = activityId; |
||||
} |
||||
}, |
||||
"columns": [ |
||||
|
||||
{ data: 'material_name', name: 'material_name' }, |
||||
{ |
||||
data: 'qty_planning', render: function (data, type) { |
||||
return data ? formatRupiah(data) : '-' |
||||
} |
||||
}, |
||||
{ data: 'uom', name: 'uom' }, |
||||
{ |
||||
data: 'budget', render: function (data, type) { |
||||
return data ? "Rp. " + formatRupiah(data) : '-' |
||||
} |
||||
}, |
||||
{ |
||||
data: 'plan_date', render: function (data, type) { |
||||
return data ? formatDate(data) : '-' |
||||
} |
||||
}, |
||||
{ |
||||
data: 'action', |
||||
name: 'action', |
||||
orderable: true, |
||||
searchable: true |
||||
}, |
||||
] |
||||
}); |
||||
|
||||
function deleteMaterialAssign(id) { |
||||
$.ajax({ |
||||
url: `${base_url}assign-material/delete/${id}`, |
||||
type: "DELETE", |
||||
success: function (data) { |
||||
actionHappen = true; |
||||
gantt.alert("Delete Material Assign Success!"); |
||||
tableMaterial.draw(); |
||||
}, |
||||
error: function (data) { |
||||
gantt.alert("Delete Material Assign Failed, try again later!"); |
||||
} |
||||
}); |
||||
} |
||||
|
||||
$("#modal-material").on("click", "#show-form-material", function () { |
||||
$(this).hide(); |
||||
$("#hide-form-material").show(); |
||||
$("#form-assign-material").show(); |
||||
}); |
||||
|
||||
$("#modal-material").on("click", "#hide-form-material", function () { |
||||
$(this).hide(); |
||||
resetFormAssignMaterial() |
||||
$("#show-form-material").show(); |
||||
}); |
||||
|
||||
$('#modal-material').on('show.bs.modal', function (event) { |
||||
$('#modal-material-title').html("Material Resource " + activityName); |
||||
tableMaterial.draw(); |
||||
}); |
||||
|
||||
$('#modal-material').on('hide.bs.modal', function (event) { |
||||
// $("#hide-form-material").hide();
|
||||
$("#show-form-material").show(); |
||||
console.log("there's before action change ", actionHappen); |
||||
if (actionHappen) { |
||||
console.log("there's action change ", actionHappen); |
||||
updateActivity(activityId); |
||||
} |
||||
resetFormAssignMaterial(); |
||||
}); |
||||
|
||||
$('#select-material').select2({ |
||||
dropdownParent: materialModal, |
||||
placeholder: 'Pilih material resource', |
||||
allowClear: true, |
||||
ajax: { |
||||
url: `${base_url}material-resource/select`, |
||||
dataType: 'json', |
||||
data: function (params) { |
||||
var query = { |
||||
search: params.term, |
||||
type: 'public', |
||||
idProyek: proyekId, |
||||
idact: activityId |
||||
} |
||||
return query; |
||||
}, |
||||
processResults: function (result) { |
||||
return { |
||||
results: $.map(result, function (item) { |
||||
// console.log("cek item", item)
|
||||
return { |
||||
text: item.description, |
||||
id: item.id |
||||
} |
||||
}) |
||||
}; |
||||
}, |
||||
cache: false |
||||
} |
||||
}); |
||||
var tableMaterial = $("#table-material").DataTable({ |
||||
"processing": true, |
||||
"serverSide": true, |
||||
"ajax": { |
||||
"url": `${base_url}assign-material/datatables`, |
||||
"data": function (d) { |
||||
d.idact = activityId; |
||||
} |
||||
}, |
||||
"columns": [ |
||||
|
||||
$('#select-material-integration').select2({ |
||||
dropdownParent: materialModal, |
||||
placeholder: 'Pilih material', |
||||
allowClear: true, |
||||
ajax: { |
||||
url: `${adwIntegrationUrl}/request-material/get-material-integration`, |
||||
type: "get", |
||||
delay: 1000, |
||||
data: function (params) { |
||||
var query = { |
||||
'name': params.term, |
||||
{ data: 'material_name', name: 'material_name' }, |
||||
{ |
||||
data: 'qty_planning', render: function (data, type) { |
||||
return data ? formatRupiah(data) : '-' |
||||
} |
||||
return query; |
||||
}, |
||||
headers: { |
||||
'Authorization': `Bearer ${token}` |
||||
{ data: 'uom', name: 'uom' }, |
||||
{ |
||||
data: 'budget', render: function (data, type) { |
||||
return data ? "Rp. " + formatRupiah(data) : '-' |
||||
} |
||||
}, |
||||
processResults: function (data) { |
||||
var dataIntegrasiMaterial = []; |
||||
if (data.data) { |
||||
for(var i = 0; i < data.data.length; i++){ |
||||
var newData = { |
||||
id: data.data[i].description, |
||||
text: data.data[i].description, |
||||
} |
||||
dataIntegrasiMaterial.push(newData); |
||||
} |
||||
{ |
||||
data: 'plan_date', render: function (data, type) { |
||||
return data ? formatDate(data) : '-' |
||||
} |
||||
return { |
||||
results: dataIntegrasiMaterial |
||||
}; |
||||
} |
||||
} |
||||
}); |
||||
|
||||
$("#form-assign-material").on('submit', function (e) { |
||||
e.preventDefault(); |
||||
|
||||
$('#btn-assign-material').html('Assign...'); |
||||
$('#btn-assign-material').prop("disabled", true); |
||||
|
||||
// /request-material/add
|
||||
let desc_req_material = $("#select-material-integration").val(); |
||||
let required_date = $("#required-date-req-material").val(); |
||||
let plan_date = $("#required-date-plan-material").val(); |
||||
let uom = $("#uom-req-material").val(); |
||||
let price = $("#price-req-material").val(); |
||||
let qty_planning = $("#qty-req-material").val(); |
||||
let material_id = null; |
||||
|
||||
let payload = { |
||||
description: desc_req_material, |
||||
fom_date: required_date, |
||||
required_date: required_date, |
||||
proyek_id: proyekId, |
||||
uom: uom, |
||||
qty: formatReplaceTitikRibuan(qty_planning), |
||||
price: formatReplaceTitikRibuan(price) |
||||
} |
||||
$.ajax({ |
||||
data: JSON.stringify(payload), |
||||
url: `${base_url}request-material/add`, |
||||
type: "POST", |
||||
processData: false, |
||||
contentType: false, |
||||
success: function (data) { |
||||
if (data && data.code === 200) { |
||||
material_id = data.data.id; |
||||
// actionHappen = true;
|
||||
// gantt.alert("Material Request Success!");
|
||||
// tableMaterial.draw();
|
||||
resetFormAssignMaterial(); |
||||
|
||||
let payloadAssign = { |
||||
proyek_id: proyekId, |
||||
activity_id: activityId, |
||||
material_id: material_id, |
||||
qty_planning: qty_planning, |
||||
plan_date: plan_date |
||||
// budget: budget
|
||||
} |
||||
$.ajax({ |
||||
data: JSON.stringify(payloadAssign), |
||||
url: `${base_url}assign-material/add`, |
||||
type: "POST", |
||||
processData: false, |
||||
contentType: false, |
||||
success: function (data) { |
||||
if (data && data.code === 200) { |
||||
actionHappen = true; |
||||
gantt.alert("Material Assign Success!"); |
||||
tableMaterial.draw(); |
||||
resetFormAssignMaterial(); |
||||
} |
||||
else { |
||||
gantt.alert({ type: "error", text: data.message }); |
||||
$('#btn-assign-material').html('Assign'); |
||||
$('#btn-assign-material').prop("disabled", false); |
||||
} |
||||
}, |
||||
error: function (data) { |
||||
gantt.alert("Material Assign Failed, try again later!"); |
||||
resetFormAssignMaterial(); |
||||
} |
||||
}); |
||||
} |
||||
else { |
||||
gantt.alert({ type: "error", text: data.message }); |
||||
$('#btn-assign-material').html('Assign'); |
||||
$('#btn-assign-material').prop("disabled", false); |
||||
} |
||||
}, |
||||
error: function (data) { |
||||
gantt.alert("Material Request Failed, try again later!"); |
||||
resetFormAssignMaterial(); |
||||
} |
||||
}); |
||||
|
||||
// let material_id = $("#select-material").val();
|
||||
|
||||
// if (!material_id || material_id < 0) {
|
||||
// gantt.alert("Please choose material to assign!");
|
||||
// $('#btn-assign-material').html('Assign');
|
||||
// $('#btn-assign-material').prop("disabled", false);
|
||||
// return false
|
||||
// }
|
||||
|
||||
// if (!qty_planning || qty_planning < 0) {
|
||||
// gantt.alert("Please input qty material!");
|
||||
// $('#btn-assign-material').html('Assign');
|
||||
// $('#btn-assign-material').prop("disabled", false);
|
||||
// return false
|
||||
// }
|
||||
|
||||
// if(!budget || budget < 0){
|
||||
// gantt.alert("Please input price per-unit!");
|
||||
// $('#btn-assign-material').html('Assign');
|
||||
// $('#btn-assign-material').prop("disabled",false);
|
||||
// return false
|
||||
// }
|
||||
|
||||
// if(material_id === null){
|
||||
// gantt.alert("Material Assign Failed, try again later!");
|
||||
// resetFormAssignMaterial();
|
||||
// }else{
|
||||
|
||||
// }
|
||||
|
||||
}); |
||||
}, |
||||
] |
||||
}); |
||||
|
||||
$("#modal-material").on("click", "#show-form-material", function () { |
||||
$(this).hide(); |
||||
$("#hide-form-material").show(); |
||||
$("#form-assign-material").show(); |
||||
}); |
||||
|
||||
$("#modal-material").on("click", "#hide-form-material", function () { |
||||
$(this).hide(); |
||||
resetFormAssignMaterial() |
||||
$("#show-form-material").show(); |
||||
}); |
||||
|
||||
$('#modal-material').on('show.bs.modal', function (event) { |
||||
$('#modal-material-title').html("Material Resource " + activityName); |
||||
tableMaterial.draw(); |
||||
}); |
||||
|
||||
$('#modal-material').on('hide.bs.modal', function (event) { |
||||
$("#show-form-material").show(); |
||||
resetFormAssignMaterial(); |
||||
}); |
||||
|
||||
// delete from row
|
||||
$("#table-material").on("click", ".btn-material-delete", function () { |
||||
let id = $(this).data('id'); |
||||
var box = gantt.confirm({ |
||||
text: "Material resource will be deleted from activity, continue?", |
||||
ok: "Delete", |
||||
cancel: "Cancel", |
||||
callback: function (result) { |
||||
if (result) { |
||||
deleteMaterialAssign(id); |
||||
} |
||||
} |
||||
}); |
||||
}); |
||||
}); |
||||
|
@ -0,0 +1,284 @@
|
||||
var overlayControl = gantt.ext.overlay; |
||||
var today = new Date(); |
||||
|
||||
function toggleOverlay() { |
||||
if(overlayControl.isOverlayVisible(lineOverlay)){ |
||||
gantt.config.readonly = false; |
||||
overlayControl.hideOverlay(lineOverlay); |
||||
gantt.$root.classList.remove("overlay_visible"); |
||||
}else{ |
||||
gantt.config.readonly = true; |
||||
overlayControl.showOverlay(lineOverlay); |
||||
gantt.$root.classList.add("overlay_visible"); |
||||
} |
||||
} |
||||
|
||||
function getChartScaleRange(){ |
||||
var tasksRange = gantt.getSubtaskDates(); |
||||
var cells = []; |
||||
var scale = gantt.getScale(); |
||||
if(!tasksRange.start_date){ |
||||
return scale.trace_x; |
||||
} |
||||
|
||||
scale.trace_x.forEach(function(date){ |
||||
if(date >= tasksRange.start_date && date <= tasksRange.end_date){ |
||||
cells.push(date); |
||||
} |
||||
}); |
||||
return cells; |
||||
} |
||||
|
||||
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}; |
||||
} |
||||
|
||||
function getScalePaddings(){ |
||||
var scale = gantt.getScale(); |
||||
var dataRange = gantt.getSubtaskDates(); |
||||
|
||||
var chartScale = getChartScaleRange(); |
||||
var newWidth = scale.col_width; |
||||
var padding = { |
||||
left:0, |
||||
right:0 |
||||
}; |
||||
|
||||
if(dataRange.start_date){ |
||||
var yScaleLabelsWidth = 48; |
||||
// fine tune values in order to align chart with the scale range
|
||||
padding.left = gantt.posFromDate(dataRange.start_date) - yScaleLabelsWidth; |
||||
padding.right = scale.full_width - gantt.posFromDate(dataRange.end_date) - yScaleLabelsWidth; |
||||
padding.top = gantt.config.row_height - 12; |
||||
padding.bottom = gantt.config.row_height - 12; |
||||
} |
||||
return padding; |
||||
} |
||||
|
||||
var myChart; |
||||
var lineOverlay = overlayControl.addOverlay(function(container) { |
||||
|
||||
var scaleLabels = []; |
||||
|
||||
var chartScale = getChartScaleRange(); |
||||
|
||||
chartScale.forEach(function(date){ |
||||
scaleLabels.push(dateToStr(date)); |
||||
}); |
||||
|
||||
var values = getProgressLine(); |
||||
|
||||
var canvas = document.createElement("canvas"); |
||||
container.appendChild(canvas); |
||||
canvas.style.height = container.offsetHeight + "px"; |
||||
canvas.style.width = container.offsetWidth + "px"; |
||||
|
||||
var ctx = canvas.getContext("2d"); |
||||
if(myChart){ |
||||
myChart.destroy(); |
||||
} |
||||
myChart = new Chart(ctx, { |
||||
type: "line", |
||||
data: { |
||||
datasets: [ |
||||
{ |
||||
label: "Planned progress", |
||||
backgroundColor: "#001eff", |
||||
borderColor: "#001eff", |
||||
data: values.planned, |
||||
fill: false, |
||||
cubicInterpolationMode: 'monotone' |
||||
}, |
||||
{ |
||||
label: "Real progress", |
||||
backgroundColor: "#ff5454", |
||||
borderColor: "#ff5454", |
||||
data: values.real, |
||||
fill: false, |
||||
cubicInterpolationMode: 'monotone' |
||||
} |
||||
, |
||||
{ |
||||
label: "Real progress (predicted)", |
||||
backgroundColor: "#ff5454", |
||||
borderColor: "#ff5454", |
||||
data: values.predicted, |
||||
borderDash: [5, 10], |
||||
fill: false, |
||||
cubicInterpolationMode: 'monotone' |
||||
} |
||||
] |
||||
}, |
||||
options: { |
||||
responsive: true, |
||||
maintainAspectRatio: false, |
||||
layout: { |
||||
padding: getScalePaddings() |
||||
}, |
||||
onResize: function(chart, newSize) { |
||||
var dataRange = gantt.getSubtaskDates(); |
||||
if(dataRange.start_date){ |
||||
// align chart with the scale range
|
||||
chart.options.layout.padding = getScalePaddings(); |
||||
} |
||||
}, |
||||
legend: { |
||||
display: false |
||||
}, |
||||
tooltips: { |
||||
mode: "index", |
||||
intersect: false, |
||||
callbacks: { |
||||
label: function(tooltipItem, data) { |
||||
var dataset = data.datasets[tooltipItem.datasetIndex]; |
||||
return dataset.label + ": " + dataset.data[tooltipItem.index] + "%"; |
||||
} |
||||
} |
||||
}, |
||||
hover: { |
||||
mode: "nearest", |
||||
intersect: true |
||||
}, |
||||
scales: { |
||||
xAxes: [{ |
||||
labels: scaleLabels, |
||||
gridLines:{ |
||||
display: false |
||||
}, |
||||
ticks: { |
||||
display: false |
||||
} |
||||
}, |
||||
{ |
||||
position:"top", |
||||
labels: scaleLabels, |
||||
gridLines:{ |
||||
display: false |
||||
}, |
||||
ticks: { |
||||
display: false |
||||
} |
||||
} |
||||
], |
||||
yAxes: [{ |
||||
display: true, |
||||
gridLines: { |
||||
display:false |
||||
}, |
||||
ticks: { |
||||
display: true, |
||||
min: 0, |
||||
max: 100, |
||||
stepSize: 10, |
||||
callback: function(current) { |
||||
if (current > 100) {return "";} |
||||
return current + "%"; |
||||
} |
||||
} |
||||
}, |
||||
{ |
||||
display: true, |
||||
position: "right", |
||||
gridLines: { |
||||
display:false |
||||
}, |
||||
ticks: { |
||||
display: true, |
||||
min: 0, |
||||
max: 100, |
||||
stepSize: 10, |
||||
callback: function(current) { |
||||
if (current > 100) {return "";} |
||||
return current + "%"; |
||||
} |
||||
}} |
||||
] |
||||
} |
||||
} |
||||
}); |
||||
return canvas; |
||||
}); |
Loading…
Reference in new issue