Rework graphs to widget
ci/woodpecker/push/woodpecker Pipeline was successful
Details
ci/woodpecker/push/woodpecker Pipeline was successful
Details
This commit is contained in:
parent
1c570ea2a0
commit
557df68c75
|
|
@ -8,6 +8,7 @@ import { ALIGN } from '../../lib/dow/constants'
|
|||
import { DowWidget } from '../../lib/dow/constants'
|
||||
import { rectangleWithTitle } from '../../lib/dow/widgets/rectangleWithTitle'
|
||||
import { text } from '../../lib/dow/primitives/text'
|
||||
import { barGraph } from '../../lib/dow/widgets/barGraph'
|
||||
|
||||
const weekdaysInCs = [
|
||||
'Pondeli',
|
||||
|
|
@ -167,56 +168,17 @@ export const dowRoutes = router((router, ctx) => {
|
|||
|
||||
const next12Hours = Object.entries(weather.hours).slice(1, 22)
|
||||
|
||||
const minTemp =
|
||||
Math.min(...next12Hours.map(([, h]) => h.temperature as number)) - 5
|
||||
|
||||
const minTempIndex = Object.entries(weather.hours).reduce(
|
||||
(acc, [i, h]) => {
|
||||
if (typeof h.temperature !== 'number') {
|
||||
return acc
|
||||
}
|
||||
|
||||
if (!acc || h.temperature < acc.temp) {
|
||||
return { temp: h.temperature, index: i }
|
||||
}
|
||||
|
||||
return acc
|
||||
},
|
||||
{} as { temp: number; index: string } | undefined,
|
||||
)?.index
|
||||
|
||||
const maxTemp = Math.max(
|
||||
...next12Hours.map(([, h]) => h.temperature as number),
|
||||
)
|
||||
|
||||
const maxTempIndex = Object.entries(weather.hours).reduce(
|
||||
(acc, [i, h]) => {
|
||||
if (typeof h.temperature !== 'number') {
|
||||
return acc
|
||||
}
|
||||
|
||||
if (!acc || h.temperature > acc.temp) {
|
||||
return { temp: h.temperature, index: i }
|
||||
}
|
||||
|
||||
return acc
|
||||
},
|
||||
{} as { temp: number; index: string } | undefined,
|
||||
)?.index
|
||||
|
||||
const tempRange = maxTemp - minTemp
|
||||
|
||||
const tempY = 250
|
||||
const tempY = 230
|
||||
const tempX = 30
|
||||
const tempW = 280
|
||||
const tempH = 120
|
||||
const tempGraphP = 10
|
||||
const tempGraphW = tempW - tempGraphP * 2
|
||||
const tempGraphP = 5
|
||||
const tempGraphW = tempW - tempGraphP * 4
|
||||
|
||||
widgets.push(
|
||||
...rectangleWithTitle({
|
||||
x: tempX,
|
||||
y: tempY - 40,
|
||||
y: tempY - 20,
|
||||
width: tempW,
|
||||
height: tempH,
|
||||
title: 'Teplota',
|
||||
|
|
@ -225,54 +187,26 @@ export const dowRoutes = router((router, ctx) => {
|
|||
}),
|
||||
)
|
||||
|
||||
for (const [offset, hour] of next12Hours) {
|
||||
const offsetInt = +offset
|
||||
|
||||
const x = Math.floor(
|
||||
tempX +
|
||||
tempGraphP +
|
||||
(offsetInt - 1) * (tempGraphW / next12Hours.length),
|
||||
widgets.push(
|
||||
...barGraph({
|
||||
x: tempX + tempGraphP * 2,
|
||||
y: tempY + tempGraphP,
|
||||
width: tempGraphW,
|
||||
height: tempH - 20 - tempGraphP * 2,
|
||||
data: next12Hours.map(([offset, h]) => ({
|
||||
x: now.plus({ hours: +offset }).hour.toString().padStart(2, '0'),
|
||||
yFormatted: Math.floor(h.temperature as number).toString(),
|
||||
y: h.temperature as number,
|
||||
})),
|
||||
xAxisFont: 3,
|
||||
yAxisFont: 3,
|
||||
adjustMinValue: (min) => Math.min(0, min - 5),
|
||||
showMinValue: true,
|
||||
showMaxValue: true,
|
||||
}),
|
||||
)
|
||||
|
||||
const y = tempY
|
||||
const temperature = hour.temperature as number
|
||||
const ratio = (temperature - minTemp) / tempRange
|
||||
const height = Math.floor(50 * ratio)
|
||||
const t = now.plus({ hours: offsetInt }).hour
|
||||
|
||||
widgets.push({
|
||||
x: x + 7,
|
||||
y: y + 5 + 50 - height,
|
||||
x2: 6,
|
||||
y2: height,
|
||||
t: TYPES.RECT_FILL,
|
||||
})
|
||||
|
||||
if (offset === minTempIndex || offset === maxTempIndex) {
|
||||
widgets.push({
|
||||
x: x + 10,
|
||||
y: y,
|
||||
c: Math.floor(hour.temperature as number).toString(),
|
||||
t: TYPES.TEXT,
|
||||
va: ALIGN.END,
|
||||
ha: ALIGN.CENTER,
|
||||
f: 3,
|
||||
})
|
||||
}
|
||||
|
||||
if ((offsetInt - 1) % 2 === 0) {
|
||||
widgets.push({
|
||||
x: x + 10,
|
||||
y: y + 60,
|
||||
c: t.toString().padStart(2, '0'),
|
||||
t: TYPES.TEXT,
|
||||
va: ALIGN.START,
|
||||
ha: ALIGN.CENTER,
|
||||
f: 3,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
const minPre = Math.min(
|
||||
...next12Hours.map(([, h]) => h.precipitationAmount as number),
|
||||
)
|
||||
|
|
@ -298,18 +232,19 @@ export const dowRoutes = router((router, ctx) => {
|
|||
|
||||
const displayedMaxPre = Math.max(maxPre, 1)
|
||||
const preRange = displayedMaxPre - minPre
|
||||
*/
|
||||
|
||||
const preY = 250 + 120 + 20
|
||||
const preY = 250 + 120
|
||||
const preX = 30
|
||||
const preW = 280
|
||||
const preH = 120
|
||||
const preGraphP = 10
|
||||
const preGraphW = preW - preGraphP * 2
|
||||
const preGraphP = 5
|
||||
const preGraphW = preW - preGraphP * 4
|
||||
|
||||
widgets.push(
|
||||
...rectangleWithTitle({
|
||||
x: preX,
|
||||
y: preY - 40,
|
||||
y: preY - 20,
|
||||
width: preW,
|
||||
height: preH,
|
||||
title: 'Srazky',
|
||||
|
|
@ -318,52 +253,25 @@ export const dowRoutes = router((router, ctx) => {
|
|||
}),
|
||||
)
|
||||
|
||||
for (const [offset, hour] of next12Hours) {
|
||||
const offsetInt = +offset
|
||||
|
||||
const x = Math.floor(
|
||||
preX + preGraphP + (offsetInt - 1) * (preGraphW / next12Hours.length),
|
||||
widgets.push(
|
||||
...barGraph({
|
||||
x: preX + preGraphP * 2,
|
||||
y: preY + preGraphP,
|
||||
width: preGraphW,
|
||||
height: preH - 20 - preGraphP * 2,
|
||||
data: next12Hours.map(([offset, h]) => ({
|
||||
x: now.plus({ hours: +offset }).hour.toString().padStart(2, '0'),
|
||||
yFormatted: (h.precipitationAmount as number).toFixed(1) + 'mm',
|
||||
y: h.precipitationAmount as number,
|
||||
})),
|
||||
xAxisFont: 3,
|
||||
yAxisFont: 3,
|
||||
adjustMinValue: () => 0,
|
||||
adjustMaxValue: (max) => Math.max(1, max),
|
||||
showMaxValue: true,
|
||||
}),
|
||||
)
|
||||
|
||||
const y = preY
|
||||
const pre = hour.precipitationAmount as number
|
||||
const ratio = (pre - minPre) / preRange
|
||||
const height = Math.floor(50 * ratio)
|
||||
const t = now.plus({ hours: offsetInt }).hour
|
||||
|
||||
widgets.push({
|
||||
x: x + 7,
|
||||
y: y + 5 + 50 - height,
|
||||
x2: 6,
|
||||
y2: height,
|
||||
t: TYPES.RECT_FILL,
|
||||
})
|
||||
|
||||
if (offset === maxPreIndex && maxPre > 0.01) {
|
||||
widgets.push({
|
||||
x: x + 10,
|
||||
y: y,
|
||||
c: (hour.precipitationAmount as number).toFixed(1) + 'mm',
|
||||
t: TYPES.TEXT,
|
||||
va: ALIGN.END,
|
||||
ha: ALIGN.CENTER,
|
||||
f: 3,
|
||||
})
|
||||
}
|
||||
|
||||
if ((offsetInt - 1) % 2 === 0) {
|
||||
widgets.push({
|
||||
x: x + 10,
|
||||
y: y + 60,
|
||||
c: t.toString().padStart(2, '0'),
|
||||
t: TYPES.TEXT,
|
||||
va: ALIGN.START,
|
||||
ha: ALIGN.CENTER,
|
||||
f: 3,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
res.json(widgets)
|
||||
}),
|
||||
)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,129 @@
|
|||
import { ALIGN, DowWidget } from '../constants'
|
||||
import { defineWidget } from '../defineWidget'
|
||||
import { rectangle } from '../primitives/rectangle'
|
||||
import { text } from '../primitives/text'
|
||||
|
||||
type Params = {
|
||||
data: {
|
||||
x: string
|
||||
y: number
|
||||
yFormatted?: string
|
||||
}[]
|
||||
showMaxValue?: boolean
|
||||
showMinValue?: boolean
|
||||
adjustMaxValue?: (max: number) => number
|
||||
adjustMinValue?: (min: number) => number
|
||||
x: number
|
||||
y: number
|
||||
width: number
|
||||
height: number
|
||||
xAxisFont: number
|
||||
yAxisFont: number
|
||||
}
|
||||
|
||||
export const barGraph = defineWidget(
|
||||
({
|
||||
data,
|
||||
showMaxValue,
|
||||
showMinValue,
|
||||
adjustMaxValue,
|
||||
adjustMinValue,
|
||||
x,
|
||||
y,
|
||||
width,
|
||||
height,
|
||||
xAxisFont,
|
||||
yAxisFont,
|
||||
}: Params) => {
|
||||
if (data.length === 0) {
|
||||
return []
|
||||
}
|
||||
|
||||
const minValue = data.reduce(
|
||||
(acc, { y }, index) =>
|
||||
!acc || y < acc?.value ? { value: y, index } : acc,
|
||||
undefined as { value: number; index: number } | undefined,
|
||||
)
|
||||
|
||||
const maxValue = data.reduce(
|
||||
(acc, { y }, index) =>
|
||||
!acc || y > acc?.value ? { value: y, index } : acc,
|
||||
undefined as { value: number; index: number } | undefined,
|
||||
)
|
||||
|
||||
if (!minValue || !maxValue) {
|
||||
return []
|
||||
}
|
||||
|
||||
const adjustedMinValue = adjustMinValue
|
||||
? adjustMinValue(minValue.value)
|
||||
: minValue.value
|
||||
|
||||
const adjustedMaxValue = adjustMaxValue
|
||||
? adjustMaxValue(maxValue.value)
|
||||
: maxValue.value
|
||||
|
||||
const valueRange = adjustedMaxValue - adjustedMinValue
|
||||
|
||||
const widgets = [] as DowWidget[]
|
||||
|
||||
// DEBUG: widgets.push(rectangle({ x, y, width, height, filled: false }))
|
||||
|
||||
const xAxisHeight = 25
|
||||
const yAxisHeight = 20
|
||||
|
||||
const barsHeight = height - xAxisHeight - yAxisHeight
|
||||
const barSpaceWidth = width / data.length
|
||||
const barsWidth = 6
|
||||
|
||||
for (const [index, dataPoint] of data.entries()) {
|
||||
const barX = Math.floor(x + index * barSpaceWidth)
|
||||
const barY = y + yAxisHeight
|
||||
|
||||
const value = dataPoint.y
|
||||
const ratio = (value - adjustedMinValue) / valueRange
|
||||
const barHeight = Math.floor(barsHeight * ratio)
|
||||
|
||||
widgets.push(
|
||||
rectangle({
|
||||
x: Math.floor(barX + barSpaceWidth / 2 - barsWidth / 2),
|
||||
y: barY + 5 + barsHeight - barHeight,
|
||||
width: barsWidth,
|
||||
height: barHeight,
|
||||
filled: true,
|
||||
}),
|
||||
)
|
||||
|
||||
if (
|
||||
(index === minValue.index && showMinValue) ||
|
||||
(index === maxValue.index && showMaxValue)
|
||||
) {
|
||||
widgets.push(
|
||||
text({
|
||||
x: Math.floor(barX + barSpaceWidth / 2),
|
||||
y: barY,
|
||||
text: dataPoint.yFormatted ?? dataPoint.y.toString(),
|
||||
verticalAlign: ALIGN.END,
|
||||
horizontalAlign: ALIGN.CENTER,
|
||||
font: yAxisFont,
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
if (index % 2 === 0) {
|
||||
widgets.push(
|
||||
text({
|
||||
x: Math.floor(barX + barSpaceWidth / 2),
|
||||
y: barY + barsHeight + 10,
|
||||
text: dataPoint.x,
|
||||
verticalAlign: ALIGN.START,
|
||||
horizontalAlign: ALIGN.CENTER,
|
||||
font: xAxisFont,
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return widgets
|
||||
},
|
||||
)
|
||||
Loading…
Reference in New Issue