import React, { useState, useCallback, memo, useRef } from 'react' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { Paper } from '@mui/material' import * as q from '../../../../backend/src/Model' import ChartTitle from './ChartTitle' import TopicPlot from '../TopicPlot' import { ChartActions } from './ChartActions' import { chartActions } from '../../actions' import { ChartParameters } from '../../reducers/Charts' const throttle = require('lodash.throttle') class ClearableMessageBuffer extends q.RingBuffer { public clear() { this.items = [] this.start = 0 this.end = 0 } public static fromMessageBuffer(buffer: q.RingBuffer): ClearableMessageBuffer { return new ClearableMessageBuffer(buffer.capacity, buffer.maxItems, buffer.compactionFactor, buffer) } public clone(): ClearableMessageBuffer { return ClearableMessageBuffer.fromMessageBuffer(this) } } interface Props { parameters: ChartParameters treeNode?: q.TreeNode actions: { chart: typeof chartActions } } /** * Subscribes to onMessages, stores more data points then the default */ function useMessageSubscriptionToUpdate(treeNode?: q.TreeNode) { const [lastUpdated, setLastUpdate] = useState(0) const [messageHistory, setMessageHistory] = useState() let amendMessageCallback: any function subscribeToMessageUpdates() { const throttledUpdate = throttle(() => setLastUpdate(treeNode ? treeNode.lastUpdate : 0), 300) if (treeNode) { const newMessageHistory = ClearableMessageBuffer.fromMessageBuffer(treeNode.messageHistory) newMessageHistory.setCapacity(500, 2 * 500 * 10000) amendMessageCallback = (message: q.Message) => { newMessageHistory.add(message) throttledUpdate() } treeNode.onMessage.subscribe(amendMessageCallback) setMessageHistory(newMessageHistory) } return function cleanup() { treeNode && treeNode.onMessage.unsubscribe(amendMessageCallback) setMessageHistory(undefined) } } React.useEffect(subscribeToMessageUpdates, [treeNode]) return messageHistory } function useResetDataCallback(messageHistory: ClearableMessageBuffer | undefined) { const [lastUpdated, setLastUpdate] = useState(0) return React.useCallback(() => { messageHistory && messageHistory.clear() setLastUpdate(Date.now()) }, [messageHistory]) } function TopicChart(props: Props) { const { parameters, treeNode } = props const [frozenHistory, setFrozenHistory] = useState() const messageHistory = useMessageSubscriptionToUpdate(treeNode) const togglePause = useCallback(() => { if (!treeNode) { return } setFrozenHistory(frozenHistory ? undefined : messageHistory && messageHistory.clone()) }, [props.treeNode, frozenHistory, messageHistory]) const onRemove = React.useCallback(() => { props.actions.chart.removeChart(props.parameters) }, [props.parameters]) const resetData = useResetDataCallback(messageHistory) return (
) } const mapDispatchToProps = (dispatch: any) => ({ actions: { chart: bindActionCreators(chartActions, dispatch), }, }) export default connect(undefined, mapDispatchToProps)(memo(TopicChart))