File "graphique0021.php"
Full Path: /home/analogde/www/MassageV3/eliot/import_export/graphique0021.php
File size: 35.92 KB
MIME-type: text/x-php
Charset: utf-8
<?php
if (isset($_POST['data'])) {
$jsonData = $_POST['data'];
$tableData = json_decode($jsonData, true);
$jsonData = json_encode($tableData);
}
?>
<!DOCTYPE html>
<html lang="fr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Improve courbe planning</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://code.jquery.com/ui/1.12.1/jquery-ui.min.js"></script>
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" rel="stylesheet">
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet">
<script src="https://cdn.jsdelivr.net/npm/chartjs-plugin-zoom@latest"></script>
<style>
.back-button {
position: absolute;
top: 10px;
left: 10px;
padding: 10px 20px;
font-size: 16px;
background-color: #007bff;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
}
.back-button:hover {
background-color: #0056b3;
}
.chart-title {
text-align: center;
margin-bottom: 20px;
font-size: 1.5em;
font-weight: bold;
}
#chart-container {
width: 95vw;
height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
#myChart {
width: 100% !important;
height: 100% !important;
}
#burnDownChart {
width: 100%; /* Largeur du canvas */
height: 100%; /* Hauteur du canvas */
}
</style>
<script>
/********************************************************************************************************/
function getEasterDate(year)
{
const f = Math.floor,
G = year % 19,
C = f(year / 100),
H = (C - f(C / 4) - f((8 * C + 13) / 25) + 19 * G + 15) % 30,
I = H - f(H / 28) * (1 - f(29 / (H + 1)) * f((21 - G) / 11)),
J = (year + f(year / 4) + I + 2 - C + f(C / 4)) % 7,
L = I - J;
const month = 3 + f((L + 40) / 44);
const day = L + 28 - 31 * f(month / 4);
return new Date(year, month - 1, day);
}
/********************************************************************************************************/
function generateRandomStrings(count = 10, length = 12)
{
const characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
const strings = [];
for (let i = 0; i < count; i++)
{
let randomString = '';
for (let j = 0; j < length; j++) {
const randomIndex = Math.floor(Math.random() * characters.length);
randomString += characters[randomIndex];
}
strings.push(randomString);
}
return strings;
}
/********************************************************************************************************/
function getFrenchHolidays(year)
{
const easter = getEasterDate(year);
const addDays = (date, days) => new Date(date.getFullYear(), date.getMonth(), date.getDate() + days);
return [
new Date(year, 0, 1), // Jour de l'an
new Date(year, 4, 1), // Fête du Travail
new Date(year, 4, 8), // Victoire 1945
new Date(year, 6, 14), // Fête Nationale
new Date(year, 7, 15), // Assomption
new Date(year, 10, 1), // Toussaint
new Date(year, 10, 11), // Armistice
new Date(year, 11, 25), // Noël
easter, // Pâques
addDays(easter, 1), // Lundi de Pâques
addDays(easter, 39), // Ascension
addDays(easter, 49), // Pentecôte
addDays(easter, 50), // Lundi de Pentecôte
];
}
/********************************************************************************************************/
function isWeekend(date)
{
const day = date.getDay();
return day === 0 || day === 6;
}
function isHoliday(date, holidays)
{
return holidays.some(holiday =>
date.getDate() === holiday.getDate() &&
date.getMonth() === holiday.getMonth() &&
date.getFullYear() === holiday.getFullYear()
);
}
/********************************************************************************************************/
function countWorkingDays(startDate, endDate)
{
alert("TRACE");
let count = 0;
const current = new Date(startDate);
const holidays = [];
// collect holidays for all years involved
for (let y = startDate.getFullYear(); y <= endDate.getFullYear(); y++) {
holidays.push(...getFrenchHolidays(y));
}
while (current <= endDate) {
if (!isWeekend(current) && !isHoliday(current, holidays)) {
count++;
}
current.setDate(current.getDate() + 1);
}
return count;
}
/********************************************************************************************************/
function addWorkingDays(startDate, workingDaysToAdd)
{
let addedDays = 0;
const current = new Date(startDate);
const holidays = [];
// On prépare les jours fériés pour 5 ans autour de la date de départ
const startYear = startDate.getFullYear();
for (let y = startYear - 1; y <= startYear + 5; y++) {
holidays.push(...getFrenchHolidays(y));
}
while (addedDays < workingDaysToAdd) {
current.setDate(current.getDate() + 1);
if (!isWeekend(current) && !isHoliday(current, holidays)) {
addedDays++;
}
}
return current;
}
/********************************************************************************************************/
function toto()
{
// passage du tableau
var tableData = <?php echo $jsonData; ?>;
var x_temps_passe = [];
var x_temps_estimation = [];
var taches = [];
var plages = [];
var tmp = [];
var compteur_taches = 0;
tableData.forEach(function(subArray)
{
if (subArray.id.includes("standard"))
{
compteur_taches = compteur_taches + 1;
}
});
console.log(" Nombre de points " + compteur_taches);
tableData.forEach(function(subArray)
{
if (subArray.id.includes("standard"))
{
var stockage = [];
x_temps_passe.push(subArray.count);
taches.push(subArray.name);
if (subArray.cells && typeof subArray.cells === 'object')
{
console.log(`Contenu des éléments dans 'cells' pour la tâche '${subArray.name}' :`);
// Parcourir chaque clé de "cells"
Object.keys(subArray.cells).forEach(key =>
{
const value = subArray.cells[key];
if (typeof value === 'object')
{
//console.log(` 222 Clé '${key}' (Objet):`, JSON.stringify(value, null, 2));
var flag = 0;
for (const [prop, val] of Object.entries(value))
{
if (prop === 'value' && val === "1")
{
flag = 1;
tmp.push(compteur_taches);
}
else if (prop === 'full_date' && flag === 1)
{
stockage.push(val);
flag = 0;
}
}
}
});
}
console.log(" PLAGE " + stockage);
plages.push(stockage);
compteur_taches = compteur_taches - 1;
}
else if (subArray.id.includes("estimation"))
{
x_temps_estimation.push(subArray.estimationValue);
}
});
console.log("Plages sauvegardées : ", plages);
console.log(" ZZZZZZZZ : ", tmp + " " + tmp.length);
/******* création des infos : durée ... **********/
// Créez un tableau pour stocker les premiers et derniers éléments
var premiersEtDerniers = [];
premiersEtDerniers.push(["", ""]);
for (var i = 0; i < plages.length; i++)
{
var sousTableau = plages[i];
if (sousTableau.length === 0)
{
premiersEtDerniers.push([null, null]); // Ajoute [null, null] si le sous-tableau est vide
}
else
{
premiersEtDerniers.push([sousTableau[0], sousTableau[sousTableau.length - 1]]);
}
}
console.log(premiersEtDerniers);
console.log(taches + " nombre " + taches.length);
x_temps_passe.unshift("0");
x_temps_estimation.unshift("0");
x_temps_passe = x_temps_passe.map(Number);
for (var i = 2; i < x_temps_passe.length; i++)
{
x_temps_passe[i] += x_temps_passe[i - 1];
}
x_temps_estimation = x_temps_estimation.map(Number);
for (var i = 2; i < x_temps_estimation.length; i++)
{
x_temps_estimation[i] += x_temps_estimation[i - 1];
}
var gap_array = [];
for (var i = 0; i < x_temps_estimation.length; i++)
{
let gap = (-1) * (x_temps_passe[i] - x_temps_estimation[i]);
gap_array.push(gap);
}
/*****************/
var y = [];
// generation des valeurs y
for ( i = taches.length ; i >= 0; i--)
{
y.push(i);
}
// const y = [ 7, 6, 5, 4, 3, 2, 1, 0 ];
console.log(" Passé " + x_temps_passe );
console.log(" Estimation " + x_temps_estimation );
console.log(" axe Y " + y );
console.log(" cretin .. " + gap_array);
console.log(" Nb taches .. " + taches.length);
draw_chart(x_temps_passe, x_temps_estimation, y, gap_array, taches, premiersEtDerniers);
draw_other(tmp, x_temps_passe, x_temps_estimation, 120, taches.length , taches , y);
}
/********************************************************************************************************/
function draw_other(tmp, x_temps_passe, x_temps_estimation, totalDays, totalTasks, taskLabels, y)
{
var array_repetition = [];
console.log(" Local Passé " + x_temps_passe);
console.log(" Local Estimation " + x_temps_estimation);
let dernierElement_temps_passe = x_temps_passe[x_temps_passe.length - 1];
let dernierElement_estimation = x_temps_estimation[x_temps_estimation.length - 1];
let maxValue = Math.max(dernierElement_temps_passe, dernierElement_estimation);
console.log("La plus grande valeur est : " + maxValue);
taskLabels.reverse();
taskLabels.unshift('');
y.pop(); // supprime le dernier element
console.log(" zorro " + y);
x_temps_estimation.shift();
console.log(" Bla " + x_temps_estimation);
for (let i = 0; i < x_temps_estimation.length; i++) {
if (i === 0) {
array_repetition.push(x_temps_estimation[0]);
} else {
array_repetition.push(x_temps_estimation[i] - x_temps_estimation[i - 1]);
}
}
console.log(" Tableau répetition " + array_repetition);
// 10,15,29,24,10,12,12
var ensemble = [];
for (let i = 0; i < array_repetition.length; i++) {
var loop = array_repetition[i];
for (let j = 0; j < loop; j++) {
ensemble.push(y[i]);
}
}
console.log(" ****** " + ensemble);
/****** courbe 1 *********/
let xyCouples_passe = [];
// Générer les couples (x, y)
for (let i = 0; i < tmp.length; i++) {
let x = i + 1; // Valeur de x (jours)
let y = tmp[i]; // Valeur de y (tâches restantes)
xyCouples_passe.push({ x: x, y: y });
}
// Afficher les couples (x, y) dans la console
//console.log("Couples (x, y) passé :", xyCouples);
for (let i = 1; i < xyCouples_passe.length; i++) {
if (xyCouples_passe[i].y === xyCouples_passe[i - 1].y - 1) {
const newPoint = { x: xyCouples_passe[i - 1].x, y: xyCouples_passe[i].y };
xyCouples_passe.splice(i, 0, newPoint);
i++; // Skip the newly inserted point in the next iteration
}
}
console.log("Changed (x, y) passé :", xyCouples_passe);
var temps_passe_step = [];
for (let i = 1; i < xyCouples_passe.length; i++)
{
if (xyCouples_passe[i - 1].x === xyCouples_passe[i].x)
{
console.log(" Find : " + xyCouples_passe[i].x);
temps_passe_step.push(xyCouples_passe[i].x);
}
}
temps_passe_step.push( dernierElement_temps_passe);
console.log(" X passe transition :", temps_passe_step);
var temps_passe_diff = [];
[7, 24, 50, 69, 79, 90, 112]
for (let i = 0; i < temps_passe_step.length; i++)
{
if( i === 0)
{
temps_passe_diff.push(temps_passe_step[i]);
}
else
{
var substracte = temps_passe_step[i] - temps_passe_step[i-1]
temps_passe_diff.push( temps_passe_step[i] - temps_passe_step[i-1] );
}
}
temps_passe_diff = temps_passe_diff.map(Number);
console.log(" BOOM 2 :", temps_passe_diff);
/****** courbe 2 *********/
let xyCouples_estimation = [];
// Générer les couples (x, y)
for (let i = 0; i < ensemble.length; i++) {
let x = i + 1; // Valeur de x (jours)
let y = ensemble[i]; // Valeur de y (tâches restantes)
xyCouples_estimation.push({ x: x, y: y });
}
// Afficher les couples (x, y) dans la console
//console.log("Couples (x, y) estimation :", xyCouples_estimation);
// Afficher les couples (x, y) dans la page HTML
//document.getElementById('xyCouplesDisplay').textContent = JSON.stringify(xyCouples, null, 2);
for (let i = 1; i < xyCouples_estimation.length; i++) {
if (xyCouples_estimation[i].y === xyCouples_estimation[i - 1].y - 1) {
const newPoint = { x: xyCouples_estimation[i - 1].x, y: xyCouples_estimation[i].y };
xyCouples_estimation.splice(i, 0, newPoint);
i++; // Skip the newly inserted point in the next iteration
}
}
console.log("Changed estimation(x, y) :", xyCouples_estimation);
var estimation_step = [];
for (let i = 1; i < xyCouples_estimation.length; i++)
{
if (xyCouples_estimation[i - 1].x === xyCouples_estimation[i].x)
{
console.log(" Find : " + xyCouples_estimation[i].x);
estimation_step.push(xyCouples_estimation[i].x);
}
}
estimation_step.push( dernierElement_estimation);
console.log(" X estimation transition :", estimation_step);
/**************************/
// pour chaque courbes, il faut insérer un point au debut des tableaux de couples [ 0, numero tache la plus grande]
const p1 = { x: 0, y: y[0] };
xyCouples_passe.unshift(p1);
xyCouples_estimation.unshift(p1);
/**************************/
// Créer le graphique
const ctx = document.getElementById('burnDownChart').getContext('2d');
const burnDownChart = new Chart(ctx, {
type: 'line',
data: {
//labels: Array.from({ length: totalDays }, (_, i) => i + 1), // Étiquettes pour l'axe X (jours)
//labels: Array.from({ length: totalDays + 1 }, (_, i) => i), // Étiquettes pour l'axe X (jours)
labels: Array.from({ length: maxValue + 1 }, (_, i) => i), // Étiquettes pour l'axe X (jours)
datasets: [
{
label: 'Temps estimé',
data: xyCouples_passe,
borderColor: 'rgba(153, 192, 192, 1)',
borderWidth: 1,
fill: false
//stepped: true // Ajouter cette option pour créer une courbe en escalier
},
{
label: 'Temps passé',
data: xyCouples_estimation,
borderColor: 'rgba(75, 102, 255, 1)',
borderWidth: 1,
fill: false
}
]
},
options: {
scales: {
x: {
title: {
display: true,
text: 'Nombre de jours'
},
ticks: {
stepSize: 10 // Définissez le pas de la graduation de l'axe X à 10
}
},
// max ????
y: {
beginAtZero: true,
title: {
display: true,
text: 'Tâches'
},
ticks: {
callback: function(value) {
return taskLabels[value] || '';
},
}
}
},
plugins: {
tooltip: {
callbacks: {
title: function(context) {
const xValue = context[0].parsed.x;
return 'Jour ' + xValue;
},
label: function(context)
{
const label = context.dataset.label || '';
const value = context.raw.y;
const taskName = taskLabels[value] || 'Tâche inconnue';
const index = context.dataIndex;
let lines = []; // Initialisez lines comme un tableau
let tooltipText = `${label}: ${taskName}`;
lines.push(`${label}: ${taskName}`);
// Vérifier si xValue est défini et l'ajouter à l'infobulle
if (context.raw.xValue !== undefined)
{
var duree = -1;
var position = -1;
if (context.raw.savedDatasetIndex === 0)
{
position = temps_passe_step.indexOf(context.raw.xValue);
//console.log(" POSITION 0 " + position);
//console.log(" XXXXX " + context.raw.xValue);
if( position === 0)
{
duree = temps_passe_step[position];
}
else
{
duree = temps_passe_step[position] - temps_passe_step[position-1];
}
}
else if (context.raw.savedDatasetIndex === 1)
{
position = estimation_step.indexOf(context.raw.xValue);
//console.log(" POSITION 1" + position);
//console.log(" ZZZZZ " + context.raw.xValue);
if( position === 0)
{
duree = estimation_step[position];
}
else
{
duree = estimation_step[position] - estimation_step[position-1];
}
}
console.log(" :::::::::: " + duree);
//tooltipText += ` (Durée écoulée : ${duree})`;
lines.push( ` (Durée écoulée : ${duree}) ` );
//lines.push( ` xValue: ${context.raw.xValue} ` );
// tooltipText += ` (xValue: ${context.raw.xValue})`;
}
if (context.raw.savedDatasetIndex !== undefined)
{
if (context.raw.savedDatasetIndex === 0)
{
tooltipText += `<br>(Courbe: Temps estimé)`;
lines.push("Courbe: Temps estimé");
}
else if (context.raw.savedDatasetIndex === 1)
{
tooltipText += `<br>(Courbe: Temps passé)`;
lines.push("Courbe: Temps passé");
}
}
/*if (context.raw.showBidule)
{
//var element = temps_passe_diff[index];
//const index = fruits.indexOf("banane");
//console.log(">>> " + index);
//tooltipText += `${element}`;
//tooltipText += '\nbidule';
}*/
//return tooltipText;
return lines;
//return `${label}: ${taskName}`;
}
}
}
}
}
});
// Ajouter un écouteur d'événement pour suivre les mouvements de la souris sur le graphique
ctx.canvas.addEventListener('mousemove', function(evt)
{
const activePoints = burnDownChart.getElementsAtEventForMode(evt, 'nearest', { intersect: true }, true);
if (activePoints.length > 0)
{
const xValue = activePoints[0].element.$context.raw.x;
const datasetIndex = activePoints[0].datasetIndex;
//const xValueInt = parseInt(xValue, 10); // Convertir xValue en entier
//if (isInArray(temps_passe_diff, xValueInt )) {
// console.log("BINGO");
// alert("444");
//}
//console.log(" +++ " + xValue);
if (temps_passe_step.includes(xValue))
{
console.log("BINGO temps_passe_step " + xValue + " " + temps_passe_step);
activePoints[0].element.$context.raw.xValue = xValue;
activePoints[0].element.$context.raw.savedDatasetIndex = datasetIndex;
// Ajouter une propriété personnalisée pour indiquer que "bidule" doit être affiché
activePoints[0].element.$context.raw.showBidule = true;
burnDownChart.update(); // Mettre à jour le graphique pour refléter les changements
}
if (estimation_step.includes(xValue))
{
console.log("BINGO estimation_step " + xValue + " " + estimation_step);
activePoints[0].element.$context.raw.xValue = xValue;
activePoints[0].element.$context.raw.savedDatasetIndex = datasetIndex;
// Ajouter une propriété personnalisée pour indiquer que "bidule" doit être affiché
activePoints[0].element.$context.raw.showBidule = true;
burnDownChart.update(); // Mettre à jour le graphique pour refléter les changements
}
else
{
delete activePoints[0].element.$context.raw.xValue;
// Supprimer la propriété personnalisée si elle existe
delete activePoints[0].element.$context.raw.showBidule;
// Supprimer savedDatasetIndex si elle existe
delete activePoints[0].element.$context.raw.savedDatasetIndex;
burnDownChart.update(); // Mettre à jour le graphique pour refléter les changements
}
}
});
}
/********************************************************************************************************/
function isInArray(array, value) {
for (let i = 0; i < array.length; i++) {
if (array[i] === value) {
return true;
}
}
return false;
}
function draw_chart(x1, x2, y, gap_array, taskLabels, premiersEtDerniers)
{
let x1_diff = [];
let x2_diff = [];
taskLabels.reverse();
taskLabels.unshift('');
console.log(taskLabels);
for (let i = 1; i < x1.length; i++) {
let res_X1 = x1[i] - x1[i - 1];
let res_X2 = x2[i] - x2[i - 1];
x1_diff.push(`Durée écoulé = ${res_X1}`);
x2_diff.push(`Durée écoulé = ${res_X2}`);
}
// Déterminez la valeur maximale pour l'axe X
let maxXValue = Math.max(...x1, ...x2);
const ctx = document.getElementById('myChart').getContext('2d');
const myChart = new Chart(ctx, {
type: 'line',
data: {
datasets: [
{
label: 'Temps estimé',
data: x1.map((value, index) => ({ x: value, y: y[index] })),
borderColor: 'rgba(75, 192, 192, 1)',
borderWidth: 1,
fill: false,
showLine: true
},
{
label: 'Temps passé',
data: x2.map((value, index) => ({ x: value, y: y[index] })),
borderColor: 'rgba(153, 102, 255, 1)',
borderWidth: 1,
fill: false,
showLine: true
}
]
},
options: {
scales: {
x: {
type: 'linear',
position: 'bottom',
title: {
display: true,
text: 'Nombre de jours'
},
max: maxXValue, // Définissez la valeur maximale pour l'axe X
ticks: {
stepSize: 2 // Définissez le pas de la graduation de l'axe X
}
},
y: {
beginAtZero: true,
title: {
display: true,
text: 'Tâches'
},
ticks: {
callback: function(value) {
return taskLabels[value] || '';
}
}
}
},
plugins: {
tooltip: {
callbacks: {
title: function(context) {
const xValue = context[0].parsed.x;
return 'Jour ' + xValue;
},
label: function(context) {
const label = context.dataset.label || '';
const value = context.raw.y;
const index = context.dataIndex;
let diffInfo = '';
if (context.datasetIndex === 0 && index > 0) {
diffInfo = x1_diff[index - 1];
} else if (context.datasetIndex === 1 && index > 0) {
diffInfo = x2_diff[index - 1];
}
console.log("Victoire ...");
const taskName = taskLabels[value] || 'Tâche inconnue';
let start = premiersEtDerniers[index][0];
let stop = premiersEtDerniers[index][1];
let lines = [];
if (index === 0) {
lines = [`${label}`];
} else {
if (context.datasetIndex === 0) {
lines = [`${label} : ${taskName}`];
} else if (context.datasetIndex === 1) {
let aaa = "Début : " + start;
let bbb = "Fin : " + stop;
//lines = [`${label} : ${taskName}`, `${start}`, `${stop}`];
lines = [`${label} : ${taskName}`, `${aaa}`, `${bbb}`];
}
}
if (diffInfo && index > 0) lines.push(diffInfo);
if (context.datasetIndex === 1 && gap_array[index] !== undefined && index > 0) {
const gap = gap_array[index];
if (gap > 0) {
lines.push(`perdu (retard) = ${gap} jour(s)`);
} else if (gap < 0) {
lines.push(`gagné (avance) = ${gap} jour(s)`);
}
}
return lines;
}
}
}
}
}
});
}
/********************************************************************************************************/
document.addEventListener('DOMContentLoaded', function()
{
toto();
console.log("Version 20");
document.getElementById('backButton').addEventListener('click', function() {
sessionStorage.setItem('returnValue', 'rechargement');
window.history.back();
});
});
/********************************************************************************************************/
</script>
</head>
<body>
<button id="backButton" class="back-button">Retour</button>
<div class="chart-container">
<div class="chart-title">Double : Improve graphique 2 courbes</div>
<canvas id="myChart"></canvas>
<canvas id="burnDownChart"></canvas>
<div id="xyCouplesDisplay"></div>
</div>
</body>
</html>