More graph options
This commit is contained in:
parent
f50b8f1d2e
commit
da7f4aa5b2
|
|
@ -53,7 +53,7 @@ export const BoxDialContent = ({ box, data, refreshRef }: Props) => {
|
|||
{value.data && (
|
||||
<>
|
||||
{displayValue}
|
||||
{` ${data.unit}`}
|
||||
{data.unit && ` ${data.unit}`}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,6 @@
|
|||
import { getSensorValues } from '@/api/sensorValues'
|
||||
import { max } from '@/utils/max'
|
||||
import { min } from '@/utils/min'
|
||||
import { DashboardGraphData } from '@/utils/parseDashboard'
|
||||
import { RefObject } from 'preact'
|
||||
import { useEffect, useRef } from 'preact/hooks'
|
||||
|
|
@ -33,42 +35,58 @@ export const BoxGraphContent = ({ box, data, refreshRef }: Props) => {
|
|||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (bodyRef.current && values.data) {
|
||||
// TODO: These should be probably returned by server, could be outdated
|
||||
const from = filter.customFrom
|
||||
const to = filter.customTo
|
||||
const minValue = parseFloat(data.min ?? '')
|
||||
const maxValue = parseFloat(data.max ?? '')
|
||||
const customRange = !isNaN(minValue) && !isNaN(maxValue)
|
||||
const customRange = !isNaN(minValue) || !isNaN(maxValue)
|
||||
const graphType = data.graphType ?? 'line'
|
||||
const fill = data.fill ?? undefined
|
||||
const colorMode = data.colorMode
|
||||
const staticColor = data.staticColor
|
||||
|
||||
const x = values.data.map((v) => new Date(v.timestamp * 1000))
|
||||
const y = values.data.map((v) => v.value)
|
||||
|
||||
if (bodyRef.current && values.data) {
|
||||
window.Plotly.newPlot(
|
||||
bodyRef.current,
|
||||
[
|
||||
{
|
||||
...(data.graphType === 'line' && {
|
||||
...(graphType === 'line' && {
|
||||
type: 'scatter',
|
||||
mode: 'lines',
|
||||
fill,
|
||||
}),
|
||||
...(data.graphType === 'points' && {
|
||||
...(graphType === 'points' && {
|
||||
type: 'scatter',
|
||||
mode: 'markers',
|
||||
fill,
|
||||
}),
|
||||
...(data.graphType === 'lineAndPoints' && {
|
||||
...(graphType === 'lineAndPoints' && {
|
||||
type: 'scatter',
|
||||
mode: 'lines+markers',
|
||||
fill,
|
||||
}),
|
||||
...(data.graphType === 'bar' && { type: 'bar' }),
|
||||
x: values.data.map((v) => new Date(v.timestamp * 1000)),
|
||||
y: values.data.map((v) => v.value),
|
||||
...(graphType === 'bar' && { type: 'bar' }),
|
||||
x,
|
||||
y,
|
||||
line: {
|
||||
width: 1,
|
||||
...(colorMode === 'static' && { color: staticColor }),
|
||||
},
|
||||
},
|
||||
],
|
||||
{
|
||||
xaxis: { range: [from, to], type: 'date' },
|
||||
yaxis: {
|
||||
...(customRange && { range: [minValue, maxValue] }),
|
||||
...(customRange && {
|
||||
range: [
|
||||
isNaN(minValue) ? min(y) : minValue,
|
||||
isNaN(maxValue) ? max(y) : maxValue,
|
||||
],
|
||||
}),
|
||||
...(data.unit && { ticksuffix: ` ${data.unit}` }),
|
||||
},
|
||||
margin: {
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { omit } from '@/utils/omit'
|
||||
import { DashboardGraphData } from '@/utils/parseDashboard'
|
||||
import { useEffect, useState } from 'preact/hooks'
|
||||
|
||||
|
|
@ -8,10 +9,7 @@ type Props = {
|
|||
|
||||
export const GraphSettings = ({ value, onChange }: Props) => {
|
||||
const [formState, setFormState] = useState(() => ({
|
||||
min: value?.min,
|
||||
max: value?.max,
|
||||
graphType: value?.graphType,
|
||||
unit: value?.unit,
|
||||
...(value && omit(value, ['type'])),
|
||||
}))
|
||||
|
||||
const handleChange = (e: Event) => {
|
||||
|
|
@ -43,18 +41,67 @@ export const GraphSettings = ({ value, onChange }: Props) => {
|
|||
</select>
|
||||
</div>
|
||||
|
||||
<div className="input">
|
||||
<label>Fill area</label>
|
||||
<select
|
||||
name="fill"
|
||||
value={formState.fill || ''}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<option value="">None</option>
|
||||
<option value="tozeroy">To zero</option>
|
||||
<option value="tonexty">To next value</option>
|
||||
<option value="toself">To self</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div className="input">
|
||||
<label>Unit</label>
|
||||
<input name="unit" value={formState.unit} onChange={handleChange} />
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>Min value</label>
|
||||
<input name="min" value={formState.min} onChange={handleChange} />
|
||||
<input
|
||||
type="number"
|
||||
step="any"
|
||||
name="min"
|
||||
value={formState.min}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>Max value</label>
|
||||
<input name="max" value={formState.max} onChange={handleChange} />
|
||||
<input
|
||||
type="number"
|
||||
step="any"
|
||||
name="max"
|
||||
value={formState.max}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
<div className="input">
|
||||
<label>Color mode</label>
|
||||
<select
|
||||
name="colorMode"
|
||||
value={formState.colorMode ?? ''}
|
||||
onChange={handleChange}
|
||||
>
|
||||
<option value="">None</option>
|
||||
<option value="static">Static</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
{formState.colorMode === 'static' && (
|
||||
<div className="input">
|
||||
<label>Max value</label>
|
||||
<input
|
||||
type="color"
|
||||
name="staticColor"
|
||||
value={formState.staticColor}
|
||||
onChange={handleChange}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
export const max = (v: number[]) =>
|
||||
v.reduce((acc, item) => (item > acc ? item : acc), 0)
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
export const min = (v: number[]) =>
|
||||
v.reduce((acc, item) => (item > acc ? item : acc), 0)
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
export const omit = <T, TOmitKeys extends keyof T>(v: T, keys: TOmitKeys[]) => {
|
||||
const keysSet = new Set<string>(keys as string[])
|
||||
|
||||
return Object.fromEntries(
|
||||
Object.entries(v).filter(([key]) => !keysSet.has(key))
|
||||
) as Omit<T, TOmitKeys>
|
||||
}
|
||||
|
|
@ -20,6 +20,16 @@ export type DashboardGraphData = {
|
|||
max?: string
|
||||
unit?: string
|
||||
graphType?: string
|
||||
fill?:
|
||||
| 'none'
|
||||
| 'tozeroy'
|
||||
| 'tozerox'
|
||||
| 'tonexty'
|
||||
| 'tonextx'
|
||||
| 'toself'
|
||||
| 'tonext'
|
||||
colorMode?: 'static'
|
||||
staticColor?: string
|
||||
}
|
||||
|
||||
export type DashboardDialData = {
|
||||
|
|
|
|||
Loading…
Reference in New Issue