ScoDoc/app/templates/assiduites/timeline.j2
2023-04-17 15:53:30 +02:00

212 lines
6.5 KiB
Django/Jinja

<div class="timeline-container">
<div class="period" style="left: 0%; width: 20%">
<div class="period-handle left"></div>
<div class="period-handle right"></div>
</div>
</div>
<script>
const timelineContainer = document.querySelector(".timeline-container");
const periodTimeLine = document.querySelector(".period");
function createTicks() {
for (let i = 8; i <= 18; i++) {
const hourTick = document.createElement("div");
hourTick.classList.add("tick", "hour");
hourTick.style.left = `${((i - 8) / 10) * 100}%`;
timelineContainer.appendChild(hourTick);
const tickLabel = document.createElement("div");
tickLabel.classList.add("tick-label");
tickLabel.style.left = `${((i - 8) / 10) * 100}%`;
tickLabel.textContent = i < 10 ? `0${i}:00` : `${i}:00`;
timelineContainer.appendChild(tickLabel);
if (i < 18) {
for (let j = 1; j < 4; j++) {
const quarterTick = document.createElement("div");
quarterTick.classList.add("tick", "quarter");
quarterTick.style.left = `${((i - 8 + j / 4) / 10) * 100}%`;
timelineContainer.appendChild(quarterTick);
}
}
}
}
function snapToQuarter(value) {
return Math.round(value * 4) / 4;
}
timelineContainer.addEventListener("mousedown", (event) => {
const startX = event.clientX;
if (event.target === periodTimeLine) {
const startLeft = parseFloat(periodTimeLine.style.left);
const onMouseMove = (moveEvent) => {
const deltaX = moveEvent.clientX - startX;
const containerWidth = timelineContainer.clientWidth;
const newLeft = startLeft + (deltaX / containerWidth) * 100;
adjustPeriodPosition(newLeft, parseFloat(periodTimeLine.style.width));
};
document.addEventListener("mousemove", onMouseMove);
document.addEventListener(
"mouseup",
() => {
generateAllEtudRow();
snapHandlesToQuarters()
document.removeEventListener("mousemove", onMouseMove);
},
{ once: true }
);
} else if (event.target.classList.contains("period-handle")) {
const startWidth = parseFloat(periodTimeLine.style.width);
const startLeft = parseFloat(periodTimeLine.style.left);
const isLeftHandle = event.target.classList.contains("left");
const onMouseMove = (moveEvent) => {
const deltaX = moveEvent.clientX - startX;
const containerWidth = timelineContainer.clientWidth;
const newWidth =
startWidth + ((isLeftHandle ? -deltaX : deltaX) / containerWidth) * 100;
if (isLeftHandle) {
const newLeft = startLeft + (deltaX / containerWidth) * 100;
adjustPeriodPosition(newLeft, newWidth);
} else {
adjustPeriodPosition(parseFloat(periodTimeLine.style.left), newWidth);
}
};
document.addEventListener("mousemove", onMouseMove);
document.addEventListener(
"mouseup",
() => {
snapHandlesToQuarters()
generateAllEtudRow();
document.removeEventListener("mousemove", onMouseMove);
},
{ once: true }
);
}
});
function adjustPeriodPosition(newLeft, newWidth) {
const snappedLeft = snapToQuarter(newLeft);
const snappedWidth = snapToQuarter(newWidth);
const minLeft = 0;
const maxLeft = 100 - snappedWidth;
const clampedLeft = Math.min(Math.max(snappedLeft, minLeft), maxLeft);
periodTimeLine.style.left = `${clampedLeft}%`;
periodTimeLine.style.width = `${snappedWidth}%`;
}
function getPeriodValues() {
const leftPercentage = parseFloat(periodTimeLine.style.left);
const widthPercentage = parseFloat(periodTimeLine.style.width);
const startHour = (leftPercentage / 100) * 10 + 8;
const endHour = ((leftPercentage + widthPercentage) / 100) * 10 + 8;
const startValue = Math.round(startHour * 4) / 4;
const endValue = Math.round(endHour * 4) / 4;
return [startValue, endValue]
}
function setPeriodValues(deb, fin) {
let leftPercentage = (deb - 8) / 10 * 100
let widthPercentage = (fin - deb) / 10 * 100
periodTimeLine.style.left = `${leftPercentage}%`
periodTimeLine.style.width = `${widthPercentage}%`
snapHandlesToQuarters()
generateAllEtudRow();
}
function snapHandlesToQuarters() {
const periodValues = getPeriodValues();
let lef = Math.min((periodValues[0] - 8) * 10, 97.5)
if (lef < 0) {
lef = 0;
}
const left = `${lef}%`
let wid = Math.max((periodValues[1] - periodValues[0]) * 10, 2.5)
if (wid > 100) {
wid = 100;
}
const width = `${wid}%`
periodTimeLine.style.left = left;
periodTimeLine.style.width = width;
}
createTicks();
</script>
<style>
.timeline-container {
width: 75%;
margin-left: 5%;
background-color: white;
border-radius: 15px;
position: relative;
height: 40px;
}
/* ... */
.tick {
position: absolute;
bottom: 0;
width: 1px;
background-color: rgba(0, 0, 0, 0.5);
}
.tick.hour {
height: 100%;
}
.tick.quarter {
height: 50%;
}
.tick-label {
position: absolute;
bottom: 0;
font-size: 12px;
text-align: center;
transform: translateY(100%) translateX(-50%);
user-select: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
}
.period {
position: absolute;
height: 100%;
background-color: rgba(0, 183, 255, 0.5);
border-radius: 15px;
}
.period-handle {
position: absolute;
top: 0;
bottom: 0;
width: 8px;
border-radius: 0 4px 4px 0;
cursor: col-resize;
}
.period-handle.right {
right: 0;
border-radius: 4px 0 0 4px;
}
</style>