second version
This commit is contained in:
90
frontend/src/components/charts/RegimeBar.tsx
Normal file
90
frontend/src/components/charts/RegimeBar.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
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}
|
||||
/>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user