u
This commit is contained in:
73
uiserver/src/components/Chart.js
vendored
73
uiserver/src/components/Chart.js
vendored
@@ -9,7 +9,8 @@ export default class Chart extends Component {
|
|||||||
super(props);
|
super(props);
|
||||||
this.state = {
|
this.state = {
|
||||||
data: [],
|
data: [],
|
||||||
loading: true
|
loading: true,
|
||||||
|
hiddenSeries: {} // { seriesId: true/false }
|
||||||
};
|
};
|
||||||
this.interval = null;
|
this.interval = null;
|
||||||
}
|
}
|
||||||
@@ -219,15 +220,41 @@ export default class Chart extends Component {
|
|||||||
return { min: axisMin, max: axisMax };
|
return { min: axisMin, max: axisMax };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
toggleSeries = (seriesId) => {
|
||||||
|
this.setState(prev => ({
|
||||||
|
hiddenSeries: {
|
||||||
|
...prev.hiddenSeries,
|
||||||
|
[seriesId]: !prev.hiddenSeries[seriesId]
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { loading, data } = this.state;
|
const { loading, data, hiddenSeries } = this.state;
|
||||||
const { channelConfig, windowEnd, range } = this.props;
|
const { channelConfig, windowEnd, range } = this.props;
|
||||||
const effectiveChannels = this.getEffectiveChannels(this.props);
|
const effectiveChannels = this.getEffectiveChannels(this.props);
|
||||||
|
|
||||||
if (loading) return <Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}><CircularProgress /></Box>;
|
if (loading) return <Box sx={{ display: 'flex', justifyContent: 'center', p: 4 }}><CircularProgress /></Box>;
|
||||||
if (effectiveChannels.length === 0) return <Box sx={{ p: 4 }}><Typography>No channels selected.</Typography></Box>;
|
if (effectiveChannels.length === 0) return <Box sx={{ p: 4 }}><Typography>No channels selected.</Typography></Box>;
|
||||||
|
|
||||||
const series = effectiveChannels.map(id => {
|
// Build legend config (all channels, for rendering custom legend)
|
||||||
|
const legendItems = effectiveChannels.map(id => {
|
||||||
|
let label = id;
|
||||||
|
let color = '#888';
|
||||||
|
if (channelConfig) {
|
||||||
|
const item = channelConfig.find(c => c.id === id);
|
||||||
|
if (item) {
|
||||||
|
if (item.alias) label = item.alias;
|
||||||
|
if (item.color) color = item.color;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return { id, label, color, hidden: !!hiddenSeries[id] };
|
||||||
|
});
|
||||||
|
|
||||||
|
// Filter out hidden series
|
||||||
|
const visibleChannels = effectiveChannels.filter(id => !hiddenSeries[id]);
|
||||||
|
|
||||||
|
const series = visibleChannels.map(id => {
|
||||||
// Find alias and axis if config exists
|
// Find alias and axis if config exists
|
||||||
let label = id;
|
let label = id;
|
||||||
let yAxisKey = 'left';
|
let yAxisKey = 'left';
|
||||||
@@ -281,6 +308,40 @@ export default class Chart extends Component {
|
|||||||
return (
|
return (
|
||||||
<Box sx={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', p: 2, boxSizing: 'border-box' }}>
|
<Box sx={{ width: '100%', height: '100%', display: 'flex', flexDirection: 'column', p: 2, boxSizing: 'border-box' }}>
|
||||||
<Paper sx={{ p: 2, flexGrow: 1, display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}>
|
<Paper sx={{ p: 2, flexGrow: 1, display: 'flex', flexDirection: 'column', minHeight: 0, overflow: 'hidden' }}>
|
||||||
|
{/* Custom Interactive Legend */}
|
||||||
|
<Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 1.5, justifyContent: 'center', mb: 1, py: 0.5 }}>
|
||||||
|
{legendItems.map(item => (
|
||||||
|
<Box
|
||||||
|
key={item.id}
|
||||||
|
onClick={() => this.toggleSeries(item.id)}
|
||||||
|
sx={{
|
||||||
|
display: 'flex',
|
||||||
|
alignItems: 'center',
|
||||||
|
gap: 0.5,
|
||||||
|
cursor: 'pointer',
|
||||||
|
opacity: item.hidden ? 0.4 : 1,
|
||||||
|
textDecoration: item.hidden ? 'line-through' : 'none',
|
||||||
|
transition: 'opacity 0.2s',
|
||||||
|
userSelect: 'none',
|
||||||
|
'&:hover': { opacity: item.hidden ? 0.6 : 0.8 },
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<Box
|
||||||
|
sx={{
|
||||||
|
width: 14,
|
||||||
|
height: 14,
|
||||||
|
borderRadius: '50%',
|
||||||
|
bgcolor: item.color,
|
||||||
|
border: '2px solid',
|
||||||
|
borderColor: item.hidden ? 'grey.500' : item.color,
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
<Typography variant="body2" component="span">
|
||||||
|
{item.label}
|
||||||
|
</Typography>
|
||||||
|
</Box>
|
||||||
|
))}
|
||||||
|
</Box>
|
||||||
<Box sx={{ flexGrow: 1, width: '100%', height: '100%' }}>
|
<Box sx={{ flexGrow: 1, width: '100%', height: '100%' }}>
|
||||||
<LineChart
|
<LineChart
|
||||||
dataset={data}
|
dataset={data}
|
||||||
@@ -295,11 +356,7 @@ export default class Chart extends Component {
|
|||||||
yAxis={yAxes}
|
yAxis={yAxes}
|
||||||
rightAxis={hasRightAxis ? 'right' : null}
|
rightAxis={hasRightAxis ? 'right' : null}
|
||||||
slotProps={{
|
slotProps={{
|
||||||
legend: {
|
legend: { hidden: true },
|
||||||
direction: 'row',
|
|
||||||
position: { vertical: 'top', horizontal: 'middle' },
|
|
||||||
padding: 0,
|
|
||||||
},
|
|
||||||
lineHighlight: { strokeWidth: 3 },
|
lineHighlight: { strokeWidth: 3 },
|
||||||
}}
|
}}
|
||||||
sx={{
|
sx={{
|
||||||
|
|||||||
Reference in New Issue
Block a user