Skip to content

Commit 42ce51e

Browse files
author
iexitdev
committed
docs: add realtime bar chart docs
1 parent b863461 commit 42ce51e

12 files changed

Lines changed: 350 additions & 8 deletions

File tree

apps/site/astro.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,7 @@ export default defineConfig({
126126
{ slug: docsSlug("charts/pricing") },
127127
{ slug: docsSlug("charts/candlebar") },
128128
{ slug: docsSlug("charts/radar") },
129+
{ slug: docsSlug("charts/realtime") },
129130
{ slug: docsSlug("charts/combo") }
130131
]
131132
},

apps/site/src/components/ChartKitFeatures.astro

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const features = [
1212
{
1313
icon: Gauge,
1414
title: "Advanced chart types",
15-
description: "Candlebar, combo, and radar charts for Pro product screens."
15+
description:
16+
"Candlebar, combo, radar, and realtime charts for Pro product screens."
1617
},
1718
{
1819
icon: Crosshair,

apps/site/src/components/Head.astro

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,28 @@ const reactRefreshPreamble = `
3838
color: #d8e6ff;
3939
}
4040

41+
.sidebar-content
42+
a:is(
43+
[href$="/charts/candlebar/"],
44+
[href$="/charts/radar/"],
45+
[href$="/charts/realtime/"],
46+
[href$="/charts/combo/"]
47+
)::after {
48+
flex: 0 0 auto;
49+
margin-inline-start: auto;
50+
border: 1px solid rgba(0, 85, 218, 0.38);
51+
border-radius: 999px;
52+
background: rgba(0, 85, 218, 0.16);
53+
color: #8ab6ff;
54+
content: "Pro";
55+
font-size: 0.62rem;
56+
font-weight: 800;
57+
letter-spacing: 0;
58+
line-height: 1;
59+
padding: 0.18rem 0.38rem;
60+
text-transform: uppercase;
61+
}
62+
4163
html[data-theme="light"] {
4264
background: #f6f9fd;
4365
color-scheme: light;
@@ -57,6 +79,19 @@ const reactRefreshPreamble = `
5779
color: #0f3a78;
5880
}
5981

82+
html[data-theme="light"]
83+
.sidebar-content
84+
a:is(
85+
[href$="/charts/candlebar/"],
86+
[href$="/charts/radar/"],
87+
[href$="/charts/realtime/"],
88+
[href$="/charts/combo/"]
89+
)::after {
90+
border-color: rgba(0, 85, 218, 0.22);
91+
background: rgba(0, 85, 218, 0.1);
92+
color: #0055da;
93+
}
94+
6095
html[data-theme="dark"] {
6196
background: #0b0c11;
6297
color-scheme: dark;

apps/site/src/lib/remark-strip-duplicate-title.mjs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,11 +119,12 @@ const playgroundDocs = new Set([
119119
"charts/line.md",
120120
"charts/pie.md",
121121
"charts/progress.md",
122-
"charts/radar.md"
122+
"charts/radar.md",
123+
"charts/realtime.md"
123124
]);
124125

125126
const chartComponentPattern =
126-
/<\s*(AreaChart|BarChart|CandlebarChart|CandlestickChart|ComboChart|ContributionGraph|DonutChart|LineChart|PieChart|ProgressChart|ProgressRing|RadarChart|StackedBarChart)\b/;
127+
/<\s*(AreaChart|BarChart|CandlebarChart|CandlestickChart|ComboChart|ContributionGraph|DonutChart|LineChart|PieChart|ProgressChart|ProgressRing|RadarChart|Realtime\.BarChart|StackedBarChart)\b/;
127128

128129
const slugify = (value) =>
129130
String(value)

apps/site/src/previews/ChartPlayground.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,8 @@ import {
3535
CandlebarChart,
3636
CandlestickChart,
3737
ComboChart,
38-
RadarChart
38+
RadarChart,
39+
Realtime
3940
} from "@chart-kit/pro";
4041
import { G, Line as SvgLine, Rect, Text as SvgText } from "react-native-svg";
4142
import {
@@ -544,6 +545,7 @@ export const ChartPlayground = ({ code, id }: { code: string; id: string }) => {
544545
ProgressRing,
545546
RadarChart,
546547
React,
548+
Realtime,
547549
Rect,
548550
resolveCartesianChartThemeConfig,
549551
StackedBarChart: isLegacyPreview

apps/site/src/previews/proPreviewComponents.tsx

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { Pressable, Text, View } from "react-native";
33

4-
import { CandlebarChart, ComboChart } from "@chart-kit/pro";
4+
import { CandlebarChart, ComboChart, Realtime } from "@chart-kit/pro";
55
import {
66
resolveCartesianChartThemeConfig,
77
useChartKitTheme
@@ -37,6 +37,33 @@ const crosshairCandlebarPrices = Array.from({ length: 40 }, (_, index) => {
3737
};
3838
});
3939

40+
const realtimeUpdateMs = 2000;
41+
42+
const getRealtimeUsersAt = (pointIndex: number) => {
43+
const value =
44+
44 +
45+
Math.sin(pointIndex * 0.7) * 16 +
46+
Math.cos(pointIndex * 0.25) * 10 +
47+
(pointIndex % 5) * 3;
48+
49+
return Math.max(8, Math.min(92, Math.round(value)));
50+
};
51+
52+
const createRealtimeRows = (tick: number, count = 30) =>
53+
Array.from({ length: count }, (_, index) => {
54+
const pointIndex = tick + index;
55+
56+
return {
57+
pointIndex,
58+
users: getRealtimeUsersAt(pointIndex)
59+
};
60+
});
61+
62+
const formatRealtimeAgeLabel = (minutesAgo: number) =>
63+
minutesAgo === 0 ? "Now" : `${minutesAgo} min ago`;
64+
65+
type RealtimeChartXValue = Date | number | string;
66+
4067
export const CandlebarCrosshairPreview = ({
4168
isMostMobile,
4269
mode,
@@ -435,6 +462,141 @@ export const CandlebarRealtimePreview = ({
435462
);
436463
};
437464

465+
export const RealtimeBarChartPreview = ({
466+
isMostMobile,
467+
width
468+
}: {
469+
isMostMobile: boolean;
470+
width: number;
471+
}) => {
472+
const chartKitTheme = useChartKitTheme();
473+
const chartWidth = clampChartWidth(width);
474+
const [tick, setTick] = React.useState(0);
475+
const rows = React.useMemo(() => createRealtimeRows(tick), [tick]);
476+
const total = rows.reduce((sum, row) => sum + row.users, 0);
477+
const resolvedTheme = resolveCartesianChartThemeConfig({
478+
mode: chartKitTheme.mode,
479+
preset: chartKitTheme.preset,
480+
presets: chartKitTheme.presets,
481+
theme: chartKitTheme.theme
482+
});
483+
const primaryColor = resolvedTheme.series[0] ?? "#2563eb";
484+
485+
React.useEffect(() => {
486+
const intervalId = window.setInterval(() => {
487+
setTick((currentTick) => currentTick + 1);
488+
}, realtimeUpdateMs);
489+
490+
return () => window.clearInterval(intervalId);
491+
}, []);
492+
493+
const formatXLabel = React.useCallback(
494+
(value: RealtimeChartXValue) => {
495+
const pointIndex =
496+
typeof value === "number"
497+
? value
498+
: value instanceof Date
499+
? Number.NaN
500+
: Number.parseInt(value, 10);
501+
const minutesAgo = Number.isFinite(pointIndex)
502+
? Math.max(0, tick + 29 - pointIndex)
503+
: 0;
504+
505+
return formatRealtimeAgeLabel(minutesAgo);
506+
},
507+
[tick]
508+
);
509+
510+
return (
511+
<View
512+
style={{
513+
width: chartWidth,
514+
overflow: "hidden",
515+
borderColor: resolvedTheme.axis,
516+
borderRadius: 8,
517+
borderWidth: 1,
518+
backgroundColor: resolvedTheme.background,
519+
paddingBottom: isMostMobile ? 8 : 10
520+
}}
521+
>
522+
<View
523+
style={{
524+
width: chartWidth,
525+
borderBottomColor: resolvedTheme.grid,
526+
borderBottomWidth: 1,
527+
backgroundColor: resolvedTheme.plotBackground,
528+
paddingHorizontal: isMostMobile ? 10 : 12,
529+
paddingVertical: isMostMobile ? 8 : 10,
530+
flexDirection: "row",
531+
alignItems: "center",
532+
justifyContent: "space-between",
533+
gap: 12
534+
}}
535+
>
536+
<View style={{ minWidth: 0 }}>
537+
<Text
538+
style={{
539+
color: resolvedTheme.text,
540+
fontSize: isMostMobile ? 13 : 14,
541+
fontWeight: "800"
542+
}}
543+
>
544+
Active users
545+
</Text>
546+
<Text
547+
style={{
548+
color: resolvedTheme.mutedText,
549+
fontSize: 10,
550+
fontWeight: "700",
551+
marginTop: 2
552+
}}
553+
>
554+
Last 30 minutes
555+
</Text>
556+
</View>
557+
<Text
558+
style={{
559+
color: primaryColor,
560+
fontSize: isMostMobile ? 13 : 14,
561+
fontVariant: ["tabular-nums"],
562+
fontWeight: "800"
563+
}}
564+
>
565+
{total.toLocaleString("en-US")}
566+
</Text>
567+
</View>
568+
<Realtime.BarChart
569+
accessibilityLabel="Active users per minute over a rolling thirty minute window"
570+
animation={{ duration: realtimeUpdateMs, mode: "slide" }}
571+
barRadius={3}
572+
barWidthRatio={0.82}
573+
data={rows}
574+
defaultSelectedBar={{ dataIndex: rows.length - 1, seriesKey: "users" }}
575+
formatXLabel={formatXLabel}
576+
formatYLabel={(value: number) => String(Math.round(value))}
577+
height={150}
578+
interaction="tap"
579+
labelStrategy="hide"
580+
liveKey="pointIndex"
581+
series={[{ yKey: "users", label: "Users", color: primaryColor }]}
582+
showHorizontalGridLines
583+
showXAxisLabels={false}
584+
showYAxisLabels={false}
585+
tooltip={{
586+
anchor: "bar",
587+
placement: "top",
588+
width: 108
589+
}}
590+
width={chartWidth}
591+
windowSize={30}
592+
xKey="pointIndex"
593+
yDomain={[0, 100]}
594+
yKey="users"
595+
/>
596+
</View>
597+
);
598+
};
599+
438600
const getComboToggleItems = (mode: "dark" | "light") => {
439601
const series =
440602
mode === "dark"

apps/site/src/previews/registry.tsx

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,8 @@ import {
4343
import {
4444
CandlebarCrosshairPreview,
4545
CandlebarRealtimePreview,
46-
ComboTogglePreview
46+
ComboTogglePreview,
47+
RealtimeBarChartPreview
4748
} from "./proPreviewComponents";
4849

4950
const legacyLabels = ["Jan", "Feb", "Mar", "Apr", "May", "Jun"];
@@ -590,6 +591,18 @@ export const chartPreviewExamples: Record<string, ChartPreviewExample> = {
590591
/>
591592
)
592593
},
594+
"pro-realtime-bar": {
595+
ctaHref: "/#pricing",
596+
description:
597+
"Keep a rolling analytics window moving smoothly with stable selection and renderer-backed bars.",
598+
eyebrow: "Realtime",
599+
id: "pro-realtime-bar",
600+
tier: "pro",
601+
title: "Active users stream",
602+
render: ({ isMostMobile, width }) => (
603+
<RealtimeBarChartPreview isMostMobile={isMostMobile} width={width} />
604+
)
605+
},
593606
"pro-combo": {
594607
ctaHref: "/#pricing",
595608
description:

apps/site/src/styles/starlight.css

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -711,6 +711,7 @@ chart-kit-preview .chart-kit-preview-fallback,
711711
a:is(
712712
[href$="/charts/candlebar/"],
713713
[href$="/charts/radar/"],
714+
[href$="/charts/realtime/"],
714715
[href$="/charts/combo/"]
715716
)::after {
716717
flex: 0 0 auto;
@@ -733,6 +734,7 @@ chart-kit-preview .chart-kit-preview-fallback,
733734
a:is(
734735
[href$="/charts/candlebar/"],
735736
[href$="/charts/radar/"],
737+
[href$="/charts/realtime/"],
736738
[href$="/charts/combo/"]
737739
)::after {
738740
border-color: rgba(0, 85, 218, 0.22);

docs/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ React Native Chart Kit is a library of modern and polished charts for React Nati
2828
- [Installation](charts/pro-installation.md)
2929
- [Candlebar](charts/candlebar.md)
3030
- [Radar](charts/radar.md)
31+
- [Realtime Bar](charts/realtime.md)
3132
- [Combo](charts/combo.md)
3233

3334
## Guides

docs/charts/pricing.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,10 @@ OEM terms.
3030
| Viewport tools | Line/area scroll, pan/zoom, range selector, decimation; bar scrollable windows; Pro financial chart viewport controls. | Included | Included |
3131
| Themes and custom presets | ChartKitProvider, light/dark/system modes, custom preset registry, renderer injection. | Included | Included |
3232
| Accessibility helpers | Public helpers for line, bar, pie, progress, contribution; Pro helpers for candlestick and combo. | Included | Included |
33-
| Pro chart families | CandlestickChart, CandlebarChart, CombinedChart, ComboChart, and RadarChart. | Not included | Included |
33+
| Pro chart families | CandlestickChart, CandlebarChart, CombinedChart, ComboChart, RadarChart, and Realtime.BarChart. | Not included | Included |
3434
| Financial chart workflow | OHLCV readouts, crosshair inspector, price scale, session gaps, closures, range selector. | Not included | Included |
3535
| Combo chart workflow | Mixed bar and line series, shared tooltip, visible series keys, negative domains. | Not included | Included |
36+
| Realtime chart workflow | Rolling data windows, append animations, stable selection, and renderer-backed streaming dashboard charts. | Not included | Included |
3637
| Optional Skia renderer | Injected Skia renderer adapter for CombinedChart and CandlestickChart. | Not included | Preview |
3738
| PNG/SVG export APIs | Snapshot, share sheet, and headless image generation workflows. | Not included | Planned |
3839
| Premium theme templates | Extra named palettes and design templates beyond current custom presets. | Not included | Planned |

0 commit comments

Comments
 (0)