Files
mqtt-explorer/app/src/components/Tree/Tree.tsx
2019-01-20 22:34:15 +01:00

119 lines
2.9 KiB
TypeScript

import * as React from 'react'
import * as q from '../../../../backend/src/Model'
import { makeConnectionMessageEvent, rendererEvents, MqttMessage } from '../../../../events'
import { AppState } from '../../reducers'
import TreeNode from './TreeNode'
import { connect } from 'react-redux'
const MovingAverage = require('moving-average')
const timeInterval = 10 * 1000
const average = MovingAverage(timeInterval)
declare var window: any
interface Props {
autoExpandLimit: number
didSelectNode?: (node: q.TreeNode) => void
connectionId?: string
tree?: q.Tree
}
class Tree extends React.Component<Props, {}> {
private updateTimer?: any
private lastUpdate: number = 0
private perf: number = 0
constructor(props: any) {
super(props)
this.state = { }
}
public time(): number {
const time = performance.now() - this.perf
this.perf = performance.now()
return time
}
public componentWillReceiveProps(nextProps: Props) {
if (this.props.tree !== nextProps.tree) {
if (this.props.tree) {
this.props.tree.onMerge.unsubscribe(this.throttledTreeUpdate)
}
if (nextProps.tree) {
nextProps.tree.onMerge.subscribe(this.throttledTreeUpdate)
}
}
}
public throttledTreeUpdate = () => {
if (this.updateTimer) {
return
}
const expectedRenderTime = average.forecast()
const updateInterval = Math.max(expectedRenderTime * 7, 300)
const timeUntilNextUpdate = updateInterval - (performance.now() - this.lastUpdate)
this.updateTimer = setTimeout(() => {
window.requestIdleCallback(() => {
this.lastUpdate = performance.now()
this.updateTimer && clearTimeout(this.updateTimer)
this.updateTimer = undefined
this.setState(this.state)
}, { timeout: 500 })
}, Math.max(0, timeUntilNextUpdate))
}
public componentWillUnmount() {
if (this.props.connectionId) {
const event = makeConnectionMessageEvent(this.props.connectionId)
rendererEvents.unsubscribeAll(event)
}
}
public render() {
if (!this.props.tree) {
return null
}
const style: React.CSSProperties = {
lineHeight: '1.1',
cursor: 'default',
}
return (
<div style={style}>
<TreeNode
animateChages={true}
autoExpandLimit={this.props.autoExpandLimit}
isRoot={true}
didSelectNode={this.props.didSelectNode}
treeNode={this.props.tree}
name="/"
collapsed={false}
key="rootNode"
lastUpdate={this.props.tree.lastUpdate}
performanceCallback={this.performanceCallback}
/>
</div>
)
}
private performanceCallback = (ms: number) => {
average.push(Date.now(), ms)
}
}
const mapStateToProps = (state: AppState) => {
return {
autoExpandLimit: state.tooBigReducer.settings.autoExpandLimit,
tree: state.connection.tree,
}
}
export default connect(mapStateToProps)(Tree)