149 lines
4.1 KiB
JavaScript
149 lines
4.1 KiB
JavaScript
// Timeline controller for handling timezone conversion and animations
|
|
import { Controller } from "@hotwired/stimulus"
|
|
|
|
export default class extends Controller {
|
|
static targets = ["row", "time", "bar", "timestamp", "date"]
|
|
static values = {
|
|
mode: { type: String, default: "timeline" } // "timeline", "events", or "individual"
|
|
}
|
|
|
|
connect() {
|
|
if (this.modeValue === "timeline") {
|
|
this.maxTotal = this.calculateMaxTotal()
|
|
this.updateTimeline()
|
|
} else if (this.modeValue === "events") {
|
|
this.updateEventsTimes()
|
|
} else {
|
|
this.updateIndividualTimes()
|
|
}
|
|
}
|
|
|
|
calculateMaxTotal() {
|
|
const totals = this.rowTargets.map(row => parseInt(row.dataset.total))
|
|
return Math.max(...totals, 1)
|
|
}
|
|
|
|
updateTimeline() {
|
|
this.rowTargets.forEach((row, index) => {
|
|
this.updateRow(row, index)
|
|
})
|
|
}
|
|
|
|
updateRow(row, index) {
|
|
const timeIso = row.dataset.timeIso
|
|
const total = parseInt(row.dataset.total)
|
|
const timeElement = this.timeTargets.find(target => target.closest('[data-timeline-target="row"]') === row)
|
|
const barElement = this.barTargets.find(target => target.closest('[data-timeline-target="row"]') === row)
|
|
|
|
// Convert ISO time to local time
|
|
const date = new Date(timeIso)
|
|
const localTime = date.toLocaleTimeString(undefined, {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
hour12: false
|
|
})
|
|
|
|
timeElement.textContent = localTime
|
|
timeElement.title = date.toLocaleString(undefined, {
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
timeZoneName: 'short'
|
|
})
|
|
|
|
// Animate the bar width with a slight delay for each row
|
|
const barWidth = Math.max((total / this.maxTotal) * 100, 5)
|
|
setTimeout(() => {
|
|
barElement.style.width = `${barWidth}%`
|
|
}, 100 + (index * 50))
|
|
}
|
|
|
|
updateEventsTimes() {
|
|
this.timestampTargets.forEach(element => {
|
|
const iso = element.dataset.iso
|
|
if (iso) {
|
|
this.convertToLocalTime(element, iso, "time")
|
|
}
|
|
})
|
|
|
|
this.dateTargets.forEach(element => {
|
|
const iso = element.dataset.iso
|
|
if (iso) {
|
|
this.convertToLocalTime(element, iso, "date")
|
|
}
|
|
})
|
|
}
|
|
|
|
updateIndividualTimes() {
|
|
const iso = this.element.dataset.iso
|
|
if (iso) {
|
|
this.convertToLocalTime(this.element, iso, this.element.dataset.format || "both")
|
|
}
|
|
}
|
|
|
|
convertToLocalTime(element, isoString, format) {
|
|
const date = new Date(isoString)
|
|
|
|
switch (format) {
|
|
case "time":
|
|
element.textContent = date.toLocaleTimeString(undefined, {
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
hour12: false
|
|
})
|
|
element.title = date.toLocaleString(undefined, {
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
timeZoneName: 'short'
|
|
})
|
|
break
|
|
case "date":
|
|
element.textContent = date.toLocaleDateString(undefined, {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit'
|
|
})
|
|
element.title = date.toLocaleString(undefined, {
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
timeZoneName: 'short'
|
|
})
|
|
break
|
|
case "both":
|
|
element.textContent = date.toLocaleString(undefined, {
|
|
year: 'numeric',
|
|
month: '2-digit',
|
|
day: '2-digit',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
hour12: false
|
|
})
|
|
element.title = date.toLocaleString(undefined, {
|
|
weekday: 'short',
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit',
|
|
second: '2-digit',
|
|
timeZoneName: 'short'
|
|
})
|
|
break
|
|
}
|
|
}
|
|
} |