91 lines
2.8 KiB
TypeScript
91 lines
2.8 KiB
TypeScript
import { useEffect, useRef } from 'react'
|
||
|
||
import type { SlotData } from '../../types/dashboard'
|
||
|
||
type Props = {
|
||
slots: SlotData[]
|
||
nowIndex: number
|
||
chartPaddingLeft: number
|
||
chartPaddingRight: number
|
||
/** Pixely plot oblasti z EnergyChart (chartArea), pokud známe – přesnější zarovnání. */
|
||
chartArea: { left: number; right: number } | null
|
||
}
|
||
|
||
const REGIME_STYLES: Record<
|
||
string,
|
||
{ bg: string; fg: string; bgPlan: string; fgPlan: string }
|
||
> = {
|
||
AUTO: { bg: '#1D9E7518', fg: '#0F6E56', bgPlan: '#1D9E7510', fgPlan: '#0F6E5699' },
|
||
SELF_SUSTAIN: { bg: '#E24B4A18', fg: '#993C1D', bgPlan: '#E24B4A10', fgPlan: '#993C1D99' },
|
||
CHARGE_CHEAP: { bg: '#EF9F2718', fg: '#854F0B', bgPlan: '#EF9F2710', fgPlan: '#854F0B99' },
|
||
PRESERVE: { bg: '#53B0AA18', fg: '#185FA5', bgPlan: '#53B0AA10', fgPlan: '#185FA599' },
|
||
MANUAL: { bg: '#88878018', fg: '#5F5E5A', bgPlan: '#88878010', fgPlan: '#5F5E5A99' },
|
||
}
|
||
|
||
const DEFAULT_STYLE = { bg: '#88878018', fg: '#5F5E5A', bgPlan: '#88878010', fgPlan: '#5F5E5A99' }
|
||
|
||
function normCode(code: string | null): string {
|
||
return (code ?? 'AUTO').toUpperCase().replace(/-/g, '_')
|
||
}
|
||
|
||
export function RegimeBar({ slots, nowIndex, chartPaddingLeft, chartPaddingRight, chartArea }: Props) {
|
||
const canvasRef = useRef<HTMLCanvasElement>(null)
|
||
|
||
useEffect(() => {
|
||
const canvas = canvasRef.current
|
||
if (!canvas || !slots.length) return
|
||
const ctx = canvas.getContext('2d')
|
||
if (!ctx) return
|
||
|
||
const dpr = window.devicePixelRatio || 1
|
||
const h = 28
|
||
const w = canvas.clientWidth || canvas.parentElement?.clientWidth || 300
|
||
canvas.width = Math.floor(w * dpr)
|
||
canvas.height = Math.floor(h * dpr)
|
||
canvas.style.height = `${h}px`
|
||
canvas.style.width = `${w}px`
|
||
ctx.setTransform(dpr, 0, 0, dpr, 0, 0)
|
||
|
||
const plotLeft = chartArea?.left ?? chartPaddingLeft
|
||
const plotRight = chartArea?.right ?? w - chartPaddingRight
|
||
const plotW = Math.max(1, plotRight - plotLeft)
|
||
const n = slots.length
|
||
const segW = plotW / n
|
||
|
||
ctx.clearRect(0, 0, w, h)
|
||
|
||
for (let i = 0; i < n; i++) {
|
||
const s = slots[i]!
|
||
const code = normCode(s.regime_code)
|
||
const st = REGIME_STYLES[code] ?? DEFAULT_STYLE
|
||
const planned = s.regime_is_planned
|
||
ctx.fillStyle = planned ? st.bgPlan : st.bg
|
||
const x0 = plotLeft + i * segW
|
||
ctx.fillRect(x0, 0, segW + 0.5, h)
|
||
}
|
||
|
||
if (nowIndex >= 0 && nowIndex < n) {
|
||
const x = plotLeft + nowIndex * segW
|
||
ctx.save()
|
||
ctx.strokeStyle = '#378ADD'
|
||
ctx.setLineDash([4, 3])
|
||
ctx.lineWidth = 1.5
|
||
ctx.beginPath()
|
||
ctx.moveTo(x, 0)
|
||
ctx.lineTo(x, h)
|
||
ctx.stroke()
|
||
ctx.restore()
|
||
}
|
||
}, [slots, nowIndex, chartPaddingLeft, chartPaddingRight, chartArea])
|
||
|
||
return (
|
||
<canvas
|
||
ref={canvasRef}
|
||
className="block w-full"
|
||
style={{ height: 28 }}
|
||
aria-hidden
|
||
height={28}
|
||
/>
|
||
)
|
||
}
|