You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
343 lines
9.5 KiB
343 lines
9.5 KiB
var overlayControl = gantt.ext.overlay; |
|
var today = new Date(); |
|
var return_first; |
|
var parts = []; |
|
|
|
var sCurvePayload = { |
|
period: 'week', |
|
project_id: proyekId, |
|
gantt_id: ganttId |
|
}; |
|
|
|
function callback(response) { |
|
return_first = response; |
|
} |
|
|
|
function messageListener(event) { |
|
if (event.data && event.data.action === 'sendUrl') { |
|
const parentUrl = event.data.url; |
|
const isHierarchy = event.data.isHierarchy; |
|
|
|
// Split the remaining path by "/" |
|
parts = parentUrl.split("/"); |
|
if (parts[7] && parts[7] == "1" && isHierarchy) { |
|
$.ajax({ |
|
headers: { |
|
"Content-Type": "application/json", |
|
"Authorization": `Bearer ${token}` |
|
}, |
|
url: `${base_url}project/calculate-s-curve`, |
|
type: "POST", |
|
data: JSON.stringify(sCurvePayload), |
|
success: function (data) { |
|
callback(data) |
|
window.removeEventListener('message', messageListener); |
|
} |
|
}); |
|
$.ajax({ |
|
headers: { |
|
"Content-Type": "application/json", |
|
"Authorization": `Bearer ${token}` |
|
}, |
|
url: `${base_url}project/s-curve-command`, |
|
type: "POST", |
|
data: JSON.stringify(sCurvePayload), |
|
}); |
|
} else { |
|
$.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) |
|
window.removeEventListener('message', messageListener); |
|
} |
|
}); |
|
} |
|
} |
|
} |
|
|
|
function getSCurveData() { |
|
window.parent.postMessage({ action: 'getUrl' }, '*'); |
|
window.addEventListener('message', messageListener); |
|
}; |
|
|
|
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); |
|
// } |
|
cells.push(date); |
|
}); |
|
return cells; |
|
} |
|
|
|
function getProgressLine() { |
|
// 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; |
|
cumulativeRealDurations[cumulativeRealDurations.length - 1] = Math.ceil(cumulativeRealDurations[cumulativeRealDurations.length - 1]); |
|
var maxPlan = cumulativePlannedDurations[cumulativePlannedDurations.length - 1] |
|
var maxReal = cumulativeRealDurations[cumulativeRealDurations.length - 1] |
|
var dates = return_first.data[0].data.date; |
|
// Determine the appropriate data points based on the Gantt chart zoom level |
|
var chartScaleRange = getChartScaleRange(); |
|
var zoomLevel = gantt.ext.zoom.getCurrentLevel(); |
|
|
|
// Adjust data points based on the zoom level |
|
var plannedDurations, realDurations; |
|
|
|
if (zoomLevel === 2) { |
|
// Adjust data to monthly points |
|
plannedDurations = adjustDataToZoom(dates, cumulativePlannedDurations, chartScaleRange, 2).data; |
|
realDurations = adjustDataToZoom(dates, cumulativeRealDurations, chartScaleRange, 2).data; |
|
dates = adjustDataToZoom(dates, cumulativeRealDurations, chartScaleRange, 2).dates; |
|
} else if (zoomLevel === 1) { |
|
// Adjust data to weekly points |
|
plannedDurations = adjustDataToZoom(dates, cumulativePlannedDurations, chartScaleRange, 1).data; |
|
realDurations = adjustDataToZoom(dates, cumulativeRealDurations, chartScaleRange, 1).data; |
|
dates = adjustDataToZoom(dates, cumulativeRealDurations, chartScaleRange, 1).dates; |
|
} else { |
|
// Default: Use daily data points |
|
plannedDurations = cumulativePlannedDurations; |
|
realDurations = cumulativeRealDurations; |
|
|
|
} |
|
if (Math.floor(maxReal) > 110 || Math.floor(maxPlan) > 110) { |
|
plannedDurations = plannedDurations.map((item) => { |
|
return item / maxPlan * 100; |
|
}) |
|
realDurations = realDurations.map((item) => { |
|
if (maxPlan >= 200) { |
|
return item / maxPlan * 100; |
|
} else { |
|
return item / maxReal * 100; |
|
} |
|
}) |
|
} |
|
|
|
return { planned: plannedDurations, real: realDurations, dates: dates }; |
|
} |
|
function adjustDataToZoom(dates, data, chartScaleRange, zoomLevel) { |
|
// Implement logic to adjust data points based on the Gantt chart zoom level |
|
// For example, if zoomLevel is 'month', aggregate daily data to monthly data |
|
|
|
// Placeholder logic: This example assumes that the chartScaleRange is in days |
|
var newData = []; |
|
var newDates = []; |
|
var aggregateValue = 0; |
|
|
|
for (var i = 0; i < data.length; i++) { |
|
aggregateValue = data[i]; |
|
|
|
if (zoomLevel === 2 && i % 30 === 0) { |
|
// Aggregate data for each month (assuming 30 days in a month) |
|
newData.push(aggregateValue); |
|
newDates.push(dates[i]); |
|
aggregateValue = 0; |
|
} else if (zoomLevel === 1 && (i + 1) % 7 === 1) { |
|
// Aggregate data for each week |
|
newData.push(aggregateValue); |
|
newDates.push(dates[i]); |
|
aggregateValue = 0; |
|
} |
|
} |
|
|
|
// If there are remaining data points after the loop, add them to the result |
|
if (aggregateValue > 0) { |
|
newData.push(aggregateValue); |
|
newDates.push(dates[data.length - 1]); |
|
} |
|
|
|
return { |
|
data: newData, |
|
dates: newDates |
|
}; |
|
} |
|
|
|
function getScalePaddings(values) { |
|
let zoom = gantt.ext.zoom.getCurrentLevel(); |
|
var scale = gantt.getScale(); |
|
var dataRange = gantt.getSubtaskDates(); |
|
// let minDate = new Date(); |
|
// let maxDate = new Date(); |
|
let minValueDate = new Date(values.dates[0]); |
|
let maxValueDate = new Date(values.dates[values.dates.length - 1]); |
|
|
|
// gantt.eachTask(function(task){ |
|
// let plannedEarlier = task.planned_start < task.start_date; |
|
// let plannedLater = task.planned_end > task.end_date; |
|
|
|
// if (plannedEarlier) { |
|
// minDate = new Date(Math.min(minDate.getTime(), task.planned_start.getTime())); |
|
// } else { |
|
// minDate = new Date(Math.min(minDate.getTime(), task.start_date.getTime())); |
|
// } |
|
|
|
// if (plannedLater) { |
|
// maxDate = new Date(Math.max(maxDate.getTime(), task.planned_end.getTime())); |
|
// } else { |
|
// maxDate = new Date(Math.max(maxDate.getTime(), task.end_date.getTime())); |
|
// } |
|
// }) |
|
|
|
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(minValueDate); |
|
padding.right = scale.full_width - gantt.posFromDate(maxValueDate); |
|
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 values = getProgressLine(); |
|
var scaleLabels = []; |
|
|
|
// if(parts[2] && parts[2] == '1'){ |
|
// values.dates.forEach(function(date){ |
|
// var dateScale = new Date(date); |
|
// scaleLabels.push(dateToStr(dateScale)); |
|
// }) |
|
// } else { |
|
// var chartScale = getChartScaleRange(); |
|
|
|
// chartScale.forEach(function(date){ |
|
// scaleLabels.push(dateToStr(date)); |
|
// }); |
|
// } |
|
values.dates.forEach(function (date) { |
|
var dateScale = new Date(date); |
|
scaleLabels.push(dateToStr(dateScale)); |
|
}) |
|
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: "#0000cc", |
|
borderColor: "#0000cc", |
|
data: values.planned, |
|
fill: false, |
|
cubicInterpolationMode: 'monotone' |
|
}, |
|
{ |
|
label: "Real progress", |
|
backgroundColor: "#006600", |
|
borderColor: "#006600", |
|
data: values.real, |
|
fill: false, |
|
cubicInterpolationMode: 'monotone' |
|
} |
|
] |
|
}, |
|
options: { |
|
responsive: true, |
|
maintainAspectRatio: false, |
|
layout: { |
|
padding: getScalePaddings(values) |
|
}, |
|
onResize: function (chart, newSize) { |
|
var dataRange = gantt.getSubtaskDates(); |
|
if (dataRange.start_date) { |
|
// align chart with the scale range |
|
chart.options.layout.padding = getScalePaddings(values); |
|
} |
|
}, |
|
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, |
|
stepSize: 10, |
|
} |
|
}, |
|
] |
|
} |
|
} |
|
}); |
|
return canvas; |
|
}); |