feat: item color map, fix regex matching, fix sort order, fix resize handle
This commit is contained in:
@@ -2,8 +2,11 @@
|
||||
|
||||
import 'uplot/dist/uPlot.min.css';
|
||||
import uPlot from 'uplot';
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useApp } from '@/lib/context';
|
||||
import { resolveName } from '@/lib/localization';
|
||||
import { getColorMap } from '@/lib/colors';
|
||||
import type { ColorMap } from '@/lib/colors';
|
||||
import { CardShell } from './CardShell';
|
||||
import { makeYScale, makeAnnotationHooks, makeSignalsSeries, makeSignalsAxes, CURSOR_NO_DRAG } from './plotHelpers';
|
||||
import { buildSeriesData } from './seriesData';
|
||||
@@ -24,6 +27,8 @@ interface Props {
|
||||
export default function SignalsChart({ config, rows, sessions, alerts, timeMode, onEdit, onDelete }: Props) {
|
||||
const { localeMap } = useApp();
|
||||
const locale = typeof navigator !== 'undefined' ? navigator.language : 'de-DE';
|
||||
const [colorMap, setColorMap] = useState<ColorMap>(new Map());
|
||||
useEffect(() => { getColorMap().then(setColorMap); }, []);
|
||||
|
||||
const { containerRef, legendRef } = usePlot(
|
||||
(el, w, h, lRef) => {
|
||||
@@ -45,7 +50,7 @@ export default function SignalsChart({ config, rows, sessions, alerts, timeMode,
|
||||
if (lRef.current) lRef.current.appendChild(legendEl);
|
||||
},
|
||||
},
|
||||
series: makeSignalsSeries(keys, timeMode, key => resolveName(key, localeMap)),
|
||||
series: makeSignalsSeries(keys, timeMode, key => resolveName(key, localeMap), colorMap),
|
||||
axes: makeSignalsAxes(timeMode, locale),
|
||||
scales: {
|
||||
x: { time: false },
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
import { useState, useEffect } from 'react';
|
||||
import { useApp } from '@/lib/context';
|
||||
import { resolveName } from '@/lib/localization';
|
||||
import { formatSI } from '@/lib/formatNumber';
|
||||
import { getColorMap, getItemColor } from '@/lib/colors';
|
||||
import type { ColorMap } from '@/lib/colors';
|
||||
import { CardShell } from './CardShell';
|
||||
import type { ChartConfig, SignalRow } from '@/lib/types';
|
||||
|
||||
@@ -13,6 +16,8 @@ interface Props {
|
||||
|
||||
export default function TableViz({ config, rows, onEdit, onDelete }: Props) {
|
||||
const { localeMap } = useApp();
|
||||
const [colorMap, setColorMap] = useState<ColorMap>(new Map());
|
||||
useEffect(() => { getColorMap().then(setColorMap); }, []);
|
||||
|
||||
const latest = new Map<string, { green?: number; red?: number }>();
|
||||
for (const row of rows) {
|
||||
@@ -37,7 +42,11 @@ export default function TableViz({ config, rows, onEdit, onDelete }: Props) {
|
||||
const [combinator, item_key] = key.split('::');
|
||||
return (
|
||||
<tr key={key} className="border-t border-gray-800 hover:bg-gray-800/50">
|
||||
<td className="px-2 py-0.5">{resolveName(item_key, localeMap)}</td>
|
||||
<td className="px-2 py-0.5 flex items-center gap-1.5">
|
||||
<span className="inline-block w-2 h-2 rounded-full shrink-0"
|
||||
style={{ backgroundColor: getItemColor(item_key, colorMap) }} />
|
||||
{resolveName(item_key, localeMap)}
|
||||
</td>
|
||||
<td className="px-2 py-0.5 text-gray-500">{combinator}</td>
|
||||
{config.signal_type !== 'red' && (
|
||||
<td className={`px-2 py-0.5 text-right font-mono ${(vals.green ?? 0) < 0 ? 'text-red-400' : 'text-green-400'}`}>
|
||||
|
||||
@@ -1,19 +1,8 @@
|
||||
import uPlot from 'uplot';
|
||||
import type { ChartConfig } from '@/lib/types';
|
||||
import { formatSI } from '@/lib/formatNumber';
|
||||
|
||||
// --- Color helpers ---
|
||||
|
||||
function djb2(s: string): number {
|
||||
let h = 5381;
|
||||
for (let i = 0; i < s.length; i++) h = (h * 33) ^ s.charCodeAt(i);
|
||||
return h >>> 0;
|
||||
}
|
||||
|
||||
function hslColor(key: string): string {
|
||||
const hue = djb2(key) % 360;
|
||||
return `hsl(${hue},70%,60%)`;
|
||||
}
|
||||
import type { ColorMap } from '@/lib/colors';
|
||||
import { getItemColor } from '@/lib/colors';
|
||||
|
||||
const SEMANTIC_GREEN = '#4ade80';
|
||||
const SEMANTIC_RED = '#f87171';
|
||||
@@ -24,10 +13,11 @@ export interface SeriesStyle {
|
||||
}
|
||||
|
||||
export function getSeriesStyle(
|
||||
key: string,
|
||||
uCombs: number,
|
||||
uItems: number,
|
||||
uSigs: number,
|
||||
key: string,
|
||||
uCombs: number,
|
||||
uItems: number,
|
||||
uSigs: number,
|
||||
colorMap: ColorMap = new Map(),
|
||||
): SeriesStyle {
|
||||
const [combinator, item_key, sig] = key.split('::');
|
||||
|
||||
@@ -35,9 +25,9 @@ export function getSeriesStyle(
|
||||
return { color: sig === 'green' ? SEMANTIC_GREEN : SEMANTIC_RED, dash: undefined };
|
||||
}
|
||||
if (uItems > 1) {
|
||||
return { color: hslColor(item_key), dash: uSigs > 1 && sig === 'red' ? [4, 2] : undefined };
|
||||
return { color: getItemColor(item_key, colorMap), dash: uSigs > 1 && sig === 'red' ? [4, 2] : undefined };
|
||||
}
|
||||
return { color: hslColor(combinator), dash: uSigs > 1 && sig === 'red' ? [4, 2] : undefined };
|
||||
return { color: getItemColor(combinator, colorMap), dash: uSigs > 1 && sig === 'red' ? [4, 2] : undefined };
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -137,6 +127,7 @@ export function makeSignalsSeries(
|
||||
keys: string[],
|
||||
timeMode: 'real' | 'tick',
|
||||
resolveName: (key: string) => string,
|
||||
colorMap: ColorMap = new Map(),
|
||||
): uPlot.Series[] {
|
||||
const uCombs = new Set(keys.map(k => k.split('::')[0])).size;
|
||||
const uItems = new Set(keys.map(k => k.split('::')[1])).size;
|
||||
@@ -154,7 +145,7 @@ export function makeSignalsSeries(
|
||||
xSeries,
|
||||
...keys.map(k => {
|
||||
const [, item_key] = k.split('::');
|
||||
const { color, dash } = getSeriesStyle(k, uCombs, uItems, uSigs);
|
||||
const { color, dash } = getSeriesStyle(k, uCombs, uItems, uSigs, colorMap);
|
||||
return {
|
||||
label: getSeriesLabel(k, uCombs, uItems, uSigs, resolveName(item_key)),
|
||||
stroke: color,
|
||||
|
||||
Reference in New Issue
Block a user