-
-
-
- abbreviate(num)} />
-
- {tooltip.value ? : null}
-
-
+
+
+ {data.length === 0 ?
: null}
+
+
+ abbreviate(num)} />
+
+
+
+
+
+
+
+ {tooltip &&
+ tooltip.value.map((v: any, idx: number) => (
+
+ |
+ {v.title}
+ |
+
+ {v.value}
+ |
+
+ ))}
+
+
+
+
+
+
+
+
+
)
}, [width, props.data, tooltip, props.interpolation, props.range, props.color, props.theme, xDomain])
})
+function NoData() {
+ return (
+
+
+ No Data
+
+
+ )
+}
+
function domainForData(data: Array<{ x: number; y: number }>): [number, number] {
if (!data[0]) {
const defaultDomain: [number, number] = [-1, 1]
diff --git a/app/src/components/Sidebar/useCustomXDomain.tsx b/app/src/components/Sidebar/useCustomXDomain.tsx
new file mode 100644
index 0000000..e5fe3e0
--- /dev/null
+++ b/app/src/components/Sidebar/useCustomXDomain.tsx
@@ -0,0 +1,10 @@
+import { useMemo } from 'react'
+import { Props } from './PlotHistory'
+
+export function useCustomXDomain(props: Props): [number, number] | undefined {
+ return useMemo(() => {
+ const lastDataPoint = [...props.data].sort((a, b) => b.x - a.x)[0]
+ const lastDataDate = lastDataPoint ? lastDataPoint.x : Date.now()
+ return props.timeRangeStart ? [Date.now() - props.timeRangeStart, lastDataDate] : undefined
+ }, [props.data, props.timeRangeStart])
+}
diff --git a/app/src/components/TopicPlot.tsx b/app/src/components/TopicPlot.tsx
index e81c838..a401405 100644
--- a/app/src/components/TopicPlot.tsx
+++ b/app/src/components/TopicPlot.tsx
@@ -51,9 +51,13 @@ function nodeDotPathToHistory(startTime: number | undefined, history: q.MessageH
function TopicPlot(props: Props) {
const startOffset = props.timeInterval ? parseDuration(props.timeInterval) : undefined
- const data = props.dotPath
- ? nodeDotPathToHistory(startOffset, props.history, props.dotPath)
- : nodeToHistory(startOffset, props.history)
+ const data = React.useMemo(
+ () =>
+ props.dotPath
+ ? nodeDotPathToHistory(startOffset, props.history, props.dotPath)
+ : nodeToHistory(startOffset, props.history),
+ [props.history.last(), startOffset, props.dotPath]
+ )
return (
{
private localizedDate(locale: string) {
return moment(this.props.date)
.locale(locale)
- .format('L LTS')
+ .format(this.props.timeFirst ? 'LTS L' : 'L LTS')
}
private unitForInterval(milliseconds: number) {
diff --git a/app/src/components/helper/NumberFormatter.tsx b/app/src/components/helper/NumberFormatter.tsx
new file mode 100644
index 0000000..05f6cc4
--- /dev/null
+++ b/app/src/components/helper/NumberFormatter.tsx
@@ -0,0 +1,39 @@
+import React from 'react'
+import { AppState } from '../../reducers'
+import { connect } from 'react-redux'
+import { Tooltip } from '@material-ui/core'
+
+function NumberFormatter(props: { locale: string; value: number; grouping?: boolean }) {
+ let formatter: Intl.NumberFormat | undefined
+
+ const formatterOptions = { useGrouping: Boolean(props.grouping) }
+ const defaultFormatter = Intl.NumberFormat(undefined, formatterOptions)
+
+ try {
+ formatter = Intl.NumberFormat(props.locale, formatterOptions)
+ } catch {
+ // locale unknown
+ }
+
+ try {
+ const formatted = (formatter || defaultFormatter).format(props.value)
+
+ return (
+
+ {formatted}
+
+ )
+ } catch {
+ // localization fail, use fallback
+ }
+
+ return props.value
+}
+
+const mapStateToProps = (state: AppState) => {
+ return {
+ locale: state.settings.get('timeLocale'),
+ }
+}
+
+export default connect(mapStateToProps)(NumberFormatter)
diff --git a/backend/src/Model/RingBuffer.ts b/backend/src/Model/RingBuffer.ts
index 5a83ec3..94a9580 100644
--- a/backend/src/Model/RingBuffer.ts
+++ b/backend/src/Model/RingBuffer.ts
@@ -35,6 +35,7 @@ export class RingBuffer {
private compact() {
this.items = this.toArray()
+ this.start = 0
this.end = this.items.length
}