Skip to content

Commit 55d3a6c

Browse files
committed
feat: add tab-based showcase app with dynamic data lab
1 parent ca55ba0 commit 55d3a6c

4 files changed

Lines changed: 161 additions & 1 deletion

File tree

Examples/SwiftUIChartsShowcase/SwiftUIChartsShowcase.xcodeproj/project.pbxproj

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,20 @@
88

99
/* Begin PBXBuildFile section */
1010
0A17A65BC7246EF894FB4C46 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = F8FEFD8F7975122CADED38BF /* AppDelegate.swift */; };
11+
1D4CE1A2A00E43B69F8E917B /* ShowcaseDynamicLabView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 89D307985C5742659FBD2048 /* ShowcaseDynamicLabView.swift */; };
1112
282BC43F66ABF75981A2CA5E /* ShowcaseHomeView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 472650295568456DC645EC4F /* ShowcaseHomeView.swift */; };
1213
5C46F84CBBE811CF1BACDC53 /* SwiftUICharts in Frameworks */ = {isa = PBXBuildFile; productRef = C3965A0A2A9FEBF45BC880B8 /* SwiftUICharts */; };
1314
78F8536EADC5FE60A9B6D6B6 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = CA4C0A162EAAD03257FCC320 /* SceneDelegate.swift */; };
15+
8BC2B530A7D14FACB535629E /* ShowcaseTabContainerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 812FA90A31E14920A08CC991 /* ShowcaseTabContainerView.swift */; };
1416
/* End PBXBuildFile section */
1517

1618
/* Begin PBXFileReference section */
1719
07C74870F224E2F5213D5F81 /* ChartView */ = {isa = PBXFileReference; lastKnownFileType = folder; name = ChartView; path = ../..; sourceTree = SOURCE_ROOT; };
1820
09A022B6E881286CD3B96CB5 /* SwiftUIChartsShowcase.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = SwiftUIChartsShowcase.app; sourceTree = BUILT_PRODUCTS_DIR; };
1921
472650295568456DC645EC4F /* ShowcaseHomeView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowcaseHomeView.swift; sourceTree = "<group>"; };
2022
4EC45D31E6FCC4FF27B4F3B7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
23+
812FA90A31E14920A08CC991 /* ShowcaseTabContainerView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowcaseTabContainerView.swift; sourceTree = "<group>"; };
24+
89D307985C5742659FBD2048 /* ShowcaseDynamicLabView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShowcaseDynamicLabView.swift; sourceTree = "<group>"; };
2125
CA4C0A162EAAD03257FCC320 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
2226
F8FEFD8F7975122CADED38BF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
2327
/* End PBXFileReference section */
@@ -66,6 +70,8 @@
6670
4EC45D31E6FCC4FF27B4F3B7 /* Info.plist */,
6771
CA4C0A162EAAD03257FCC320 /* SceneDelegate.swift */,
6872
472650295568456DC645EC4F /* ShowcaseHomeView.swift */,
73+
812FA90A31E14920A08CC991 /* ShowcaseTabContainerView.swift */,
74+
89D307985C5742659FBD2048 /* ShowcaseDynamicLabView.swift */,
6975
);
7076
path = SwiftUIChartsShowcaseApp;
7177
sourceTree = "<group>";
@@ -131,6 +137,8 @@
131137
0A17A65BC7246EF894FB4C46 /* AppDelegate.swift in Sources */,
132138
78F8536EADC5FE60A9B6D6B6 /* SceneDelegate.swift in Sources */,
133139
282BC43F66ABF75981A2CA5E /* ShowcaseHomeView.swift in Sources */,
140+
8BC2B530A7D14FACB535629E /* ShowcaseTabContainerView.swift in Sources */,
141+
1D4CE1A2A00E43B69F8E917B /* ShowcaseDynamicLabView.swift in Sources */,
134142
);
135143
runOnlyForDeploymentPostprocessing = 0;
136144
};

Examples/SwiftUIChartsShowcase/SwiftUIChartsShowcaseApp/SceneDelegate.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ final class SceneDelegate: UIResponder, UIWindowSceneDelegate {
1212
}
1313

1414
let window = UIWindow(windowScene: windowScene)
15-
window.rootViewController = UIHostingController(rootView: ShowcaseHomeView())
15+
window.rootViewController = UIHostingController(rootView: ShowcaseTabContainerView())
1616
self.window = window
1717
window.makeKeyAndVisible()
1818
}
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
import SwiftUI
2+
import SwiftUICharts
3+
import UIKit
4+
5+
struct ShowcaseDynamicLabView: View {
6+
@ObservedObject private var stream = ChartStreamingDataSource(initialValues: [28, 31, 30, 35, 33, 36, 34, 37],
7+
windowSize: 8,
8+
autoScroll: true)
9+
@State private var timer: Timer?
10+
@State private var callbackText = "Touch bars to receive callback events."
11+
12+
private var pageBackgroundColor: Color { Color(UIColor.systemGroupedBackground) }
13+
private var cardBackgroundColor: Color { Color(UIColor.secondarySystemGroupedBackground) }
14+
private var chartSurfaceColor: Color { Color(UIColor.secondarySystemBackground) }
15+
16+
var body: some View {
17+
NavigationView {
18+
ScrollView {
19+
VStack(alignment: .leading, spacing: 16) {
20+
liveStreamSection
21+
callbackSection
22+
}
23+
.padding(16)
24+
.frame(maxWidth: .infinity, alignment: .leading)
25+
}
26+
.navigationBarTitle("Dynamic Data Lab", displayMode: .inline)
27+
.background(pageBackgroundColor)
28+
}
29+
.onAppear(perform: startFeed)
30+
.onDisappear(perform: stopFeed)
31+
}
32+
33+
private var liveStreamSection: some View {
34+
VStack(alignment: .leading, spacing: 8) {
35+
Text("Streaming Feed (Mock Dynamic)")
36+
.font(.headline)
37+
Text("A timer appends points continuously to emulate live network updates.")
38+
.font(.caption)
39+
.foregroundColor(.secondary)
40+
41+
AxisLabels {
42+
ChartGrid {
43+
LineChart()
44+
.chartData(stream)
45+
.chartYRange(stream.suggestedYRange)
46+
.chartStyle(ChartStyle(backgroundColor: chartSurfaceColor,
47+
foregroundColor: ColorGradient(.green, .blue)))
48+
.chartLineMarks(true, color: ColorGradient(.green, .blue))
49+
}
50+
.chartGridLines(horizontal: 5, vertical: max(2, stream.values.count))
51+
}
52+
.chartXAxisLabels(stream.xLabels)
53+
.chartYAxisAutoTicks(5, format: .number)
54+
.chartAxisFont(.caption)
55+
.chartAxisColor(.secondary)
56+
.frame(height: 240)
57+
.padding(12)
58+
.background(RoundedRectangle(cornerRadius: 14).fill(cardBackgroundColor))
59+
}
60+
}
61+
62+
private var callbackSection: some View {
63+
VStack(alignment: .leading, spacing: 8) {
64+
Text("Selection Callback Output")
65+
.font(.headline)
66+
Text(callbackText)
67+
.font(.caption.monospacedDigit())
68+
.foregroundColor(.secondary)
69+
70+
AxisLabels {
71+
ChartGrid {
72+
BarChart()
73+
.chartData(stream.values)
74+
.chartStyle(ChartStyle(backgroundColor: chartSurfaceColor,
75+
foregroundColor: [
76+
ColorGradient(.orange, .red),
77+
ColorGradient(.blue, .purple),
78+
ColorGradient(.green, .yellow)
79+
]))
80+
}
81+
.chartGridLines(horizontal: 4, vertical: 0)
82+
}
83+
.chartXAxisLabels(stream.xLabels)
84+
.chartYAxisAutoTicks(4, format: .number)
85+
.chartAxisFont(.caption)
86+
.chartAxisColor(.secondary)
87+
.chartSelectionHandler { event in
88+
guard event.isActive,
89+
let value = event.value,
90+
let index = event.index else {
91+
callbackText = "No active selection"
92+
return
93+
}
94+
95+
callbackText = "Slot \(index + 1): \(String(format: "%.2f", value))"
96+
}
97+
.frame(height: 230)
98+
.padding(12)
99+
.background(RoundedRectangle(cornerRadius: 14).fill(cardBackgroundColor))
100+
}
101+
}
102+
103+
private func startFeed() {
104+
guard timer == nil else { return }
105+
106+
let next = Timer.scheduledTimer(withTimeInterval: 1.5, repeats: true) { _ in
107+
let drift = Double.random(in: -2.0...2.0)
108+
let value = min(45, max(20, stream.latestValue + drift))
109+
stream.append(value)
110+
}
111+
next.tolerance = 0.25
112+
timer = next
113+
}
114+
115+
private func stopFeed() {
116+
timer?.invalidate()
117+
timer = nil
118+
}
119+
}
120+
121+
struct ShowcaseDynamicLabView_Previews: PreviewProvider {
122+
static var previews: some View {
123+
ShowcaseDynamicLabView()
124+
}
125+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import SwiftUI
2+
3+
struct ShowcaseTabContainerView: View {
4+
var body: some View {
5+
TabView {
6+
ShowcaseHomeView()
7+
.tabItem {
8+
Image(systemName: "chart.xyaxis.line")
9+
Text("Showcase")
10+
}
11+
.tag(0)
12+
13+
ShowcaseDynamicLabView()
14+
.tabItem {
15+
Image(systemName: "waveform.path.ecg")
16+
Text("Dynamic")
17+
}
18+
.tag(1)
19+
}
20+
}
21+
}
22+
23+
struct ShowcaseTabContainerView_Previews: PreviewProvider {
24+
static var previews: some View {
25+
ShowcaseTabContainerView()
26+
}
27+
}

0 commit comments

Comments
 (0)