changeset 5:f828c7c408d4

Add source code
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Mon, 26 Apr 2021 19:02:46 +0200
parents fd3fb56afc53
children 9802bdd5c7f3
files InteractiveCharts.xcodeproj/project.pbxproj InteractiveCharts.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate InteractiveCharts/LineChart/ChartView.swift InteractiveCharts/LineChart/Helpers/ChartLabel.swift InteractiveCharts/LineChart/Helpers/IndicatorPoint.swift InteractiveCharts/LineChart/Helpers/LinePath.swift InteractiveCharts/LineChart/Helpers/LineView.swift
diffstat 7 files changed, 254 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- a/InteractiveCharts.xcodeproj/project.pbxproj	Mon Apr 26 11:14:50 2021 +0200
+++ b/InteractiveCharts.xcodeproj/project.pbxproj	Mon Apr 26 19:02:46 2021 +0200
@@ -7,6 +7,11 @@
 	objects = {
 
 /* Begin PBXBuildFile section */
+		95075B3F26370E81005E0066 /* LineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95075B3E26370E81005E0066 /* LineView.swift */; };
+		95075B4326370EAA005E0066 /* LinePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95075B4226370EAA005E0066 /* LinePath.swift */; };
+		95075B472637153E005E0066 /* ChartView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95075B462637153E005E0066 /* ChartView.swift */; };
+		95075B4B263718C7005E0066 /* IndicatorPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95075B4A263718C7005E0066 /* IndicatorPoint.swift */; };
+		95075B4F2637227D005E0066 /* ChartLabel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95075B4E2637227D005E0066 /* ChartLabel.swift */; };
 		955788432636B8D800D1192D /* InteractiveCharts.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 955788392636B8D800D1192D /* InteractiveCharts.framework */; };
 		955788482636B8D800D1192D /* InteractiveChartsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 955788472636B8D800D1192D /* InteractiveChartsTests.swift */; };
 		9557884A2636B8D800D1192D /* InteractiveCharts.h in Headers */ = {isa = PBXBuildFile; fileRef = 9557883C2636B8D800D1192D /* InteractiveCharts.h */; settings = {ATTRIBUTES = (Public, ); }; };
@@ -23,6 +28,11 @@
 /* End PBXContainerItemProxy section */
 
 /* Begin PBXFileReference section */
+		95075B3E26370E81005E0066 /* LineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineView.swift; sourceTree = "<group>"; };
+		95075B4226370EAA005E0066 /* LinePath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinePath.swift; sourceTree = "<group>"; };
+		95075B462637153E005E0066 /* ChartView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartView.swift; sourceTree = "<group>"; };
+		95075B4A263718C7005E0066 /* IndicatorPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndicatorPoint.swift; sourceTree = "<group>"; };
+		95075B4E2637227D005E0066 /* ChartLabel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChartLabel.swift; sourceTree = "<group>"; };
 		955788392636B8D800D1192D /* InteractiveCharts.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = InteractiveCharts.framework; sourceTree = BUILT_PRODUCTS_DIR; };
 		9557883C2636B8D800D1192D /* InteractiveCharts.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InteractiveCharts.h; sourceTree = "<group>"; };
 		9557883D2636B8D800D1192D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -50,6 +60,26 @@
 /* End PBXFrameworksBuildPhase section */
 
 /* Begin PBXGroup section */
+		95075B5426372506005E0066 /* LineChart */ = {
+			isa = PBXGroup;
+			children = (
+				95075B462637153E005E0066 /* ChartView.swift */,
+				95075B552637251A005E0066 /* Helpers */,
+			);
+			path = LineChart;
+			sourceTree = "<group>";
+		};
+		95075B552637251A005E0066 /* Helpers */ = {
+			isa = PBXGroup;
+			children = (
+				95075B3E26370E81005E0066 /* LineView.swift */,
+				95075B4226370EAA005E0066 /* LinePath.swift */,
+				95075B4A263718C7005E0066 /* IndicatorPoint.swift */,
+				95075B4E2637227D005E0066 /* ChartLabel.swift */,
+			);
+			path = Helpers;
+			sourceTree = "<group>";
+		};
 		9557882F2636B8D700D1192D = {
 			isa = PBXGroup;
 			children = (
@@ -73,6 +103,7 @@
 			children = (
 				9557883C2636B8D800D1192D /* InteractiveCharts.h */,
 				9557883D2636B8D800D1192D /* Info.plist */,
+				95075B5426372506005E0066 /* LineChart */,
 			);
 			path = InteractiveCharts;
 			sourceTree = "<group>";
@@ -147,6 +178,7 @@
 				TargetAttributes = {
 					955788382636B8D800D1192D = {
 						CreatedOnToolsVersion = 12.4;
+						LastSwiftMigration = 1240;
 					};
 					955788412636B8D800D1192D = {
 						CreatedOnToolsVersion = 12.4;
@@ -194,6 +226,11 @@
 			isa = PBXSourcesBuildPhase;
 			buildActionMask = 2147483647;
 			files = (
+				95075B4326370EAA005E0066 /* LinePath.swift in Sources */,
+				95075B3F26370E81005E0066 /* LineView.swift in Sources */,
+				95075B4B263718C7005E0066 /* IndicatorPoint.swift in Sources */,
+				95075B4F2637227D005E0066 /* ChartLabel.swift in Sources */,
+				95075B472637153E005E0066 /* ChartView.swift in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -341,6 +378,7 @@
 		9557884E2636B8D800D1192D /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
 				DEFINES_MODULE = YES;
 				DEVELOPMENT_TEAM = MTX83R5H8X;
@@ -358,6 +396,7 @@
 				PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
 				SKIP_INSTALL = YES;
 				SUPPORTS_MACCATALYST = NO;
+				SWIFT_OPTIMIZATION_LEVEL = "-Onone";
 				SWIFT_VERSION = 5.0;
 				TARGETED_DEVICE_FAMILY = "1,2";
 			};
@@ -366,6 +405,7 @@
 		9557884F2636B8D800D1192D /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				CLANG_ENABLE_MODULES = YES;
 				CODE_SIGN_STYLE = Automatic;
 				DEFINES_MODULE = YES;
 				DEVELOPMENT_TEAM = MTX83R5H8X;
@@ -391,6 +431,7 @@
 		955788512636B8D800D1192D /* Debug */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				CODE_SIGN_STYLE = Automatic;
 				DEVELOPMENT_TEAM = MTX83R5H8X;
 				INFOPLIST_FILE = InteractiveChartsTests/Info.plist;
@@ -409,6 +450,7 @@
 		955788522636B8D800D1192D /* Release */ = {
 			isa = XCBuildConfiguration;
 			buildSettings = {
+				ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
 				CODE_SIGN_STYLE = Automatic;
 				DEVELOPMENT_TEAM = MTX83R5H8X;
 				INFOPLIST_FILE = InteractiveChartsTests/Info.plist;
Binary file InteractiveCharts.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteractiveCharts/LineChart/ChartView.swift	Mon Apr 26 19:02:46 2021 +0200
@@ -0,0 +1,42 @@
+//
+//  ChartView.swift
+//  InteractiveCharts
+//
+//  Created by Dennis Concepción Martín on 26/4/21.
+//
+
+import SwiftUI
+import GameplayKit
+
+struct ChartView: View {
+    var data: [Double]
+    var dates: [String]?
+    var hours: [String]?
+    
+    @State private var showingLabel = false
+    @State private var IndicatorPointPosition: CGPoint = .zero
+    @State private var indexPosition = Int()
+    
+    var body: some View {
+        ZStack {
+            if showingLabel {
+                ChartLabel(data: data, dates: dates, hours: hours, indexPosition: $indexPosition)
+            }
+            
+            LineView(data: data)
+        }
+    }
+}
+
+struct ChartView_Previews: PreviewProvider {
+    static var previews: some View {
+        ChartView(data: [10.0, 11.1, 10.5, 11.0, 11.9, 11.7, 10.4, 10.9])
+    }
+    
+    /*
+     Generate sample data
+     */
+    static func generateSampleData(_ n: Int) -> [Double] {
+        return (0..<n).map { _ in .random(in: 1...20) }
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteractiveCharts/LineChart/Helpers/ChartLabel.swift	Mon Apr 26 19:02:46 2021 +0200
@@ -0,0 +1,56 @@
+//
+//  ChartLabel.swift
+//  InteractiveCharts
+//
+//  Created by Dennis Concepción Martín on 26/4/21.
+//
+
+import SwiftUI
+
+struct ChartLabel: View {
+    var data: [Double]
+    var dates: [String]?
+    var hours: [String]?
+    
+    @Binding var indexPosition: Int  // Data point position
+    
+    var body: some View {
+        HStack {
+            Group {
+                if let dates = self.dates {
+                    let date = formatStringDate(dates[indexPosition])
+                    Text(date)
+                }
+                if let hours = self.hours {
+                    let hour = hours[indexPosition]
+                    Text(hour)
+                }
+                Text("\(data[indexPosition], specifier: "%.2f")")
+//                    .foregroundColor(colour)
+            }
+            .font(.subheadline)
+        }
+    }
+    
+    /*
+     Take string in format yy-MM-dd (2021-01-01) and transform it
+     to long default string format
+     */
+    private func formatStringDate(_ stringDate: String) -> String {
+        let dateFormatter = DateFormatter()
+        dateFormatter.dateFormat = "yy-MM-dd"
+        let date = dateFormatter.date(from: stringDate)
+        
+        // Format date to the final format
+        dateFormatter.dateStyle = .long
+        let finalDate = dateFormatter.string(from: date!)
+        
+        return finalDate
+    }
+}
+
+struct Label_Previews: PreviewProvider {
+    static var previews: some View {
+        ChartLabel(data: [10.0, 11.1, 10.5, 10.0, 11.9, 11.7, 10.4, 10.9], indexPosition: .constant(0))
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteractiveCharts/LineChart/Helpers/IndicatorPoint.swift	Mon Apr 26 19:02:46 2021 +0200
@@ -0,0 +1,23 @@
+//
+//  IndicatorPoint.swift
+//  InteractiveCharts
+//
+//  Created by Dennis Concepción Martín on 26/4/21.
+//
+
+import SwiftUI
+
+struct IndicatorPoint: View {
+    var body: some View {
+        Circle()
+            .frame(width: 20, height: 20)
+            .foregroundColor(Color(.systemBlue))
+            
+    }
+}
+
+struct IndicatorPoint_Previews: PreviewProvider {
+    static var previews: some View {
+        IndicatorPoint()
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteractiveCharts/LineChart/Helpers/LinePath.swift	Mon Apr 26 19:02:46 2021 +0200
@@ -0,0 +1,55 @@
+//
+//  LinePath.swift
+//  InteractiveCharts
+//
+//  Created by Dennis Concepción Martín on 26/4/21.
+//
+
+import SwiftUI
+
+struct LinePath: Shape {
+    var data: [Double]
+    var (width, height): (CGFloat, CGFloat)
+    
+    func path(in rect: CGRect) -> Path {
+        var path = Path()
+        
+        let normalizedData = normalize(data)
+        let widthBetweenDataPoints = Double(width) / Double(normalizedData.count - 1)  // Remove first point
+        let initialPoint = normalizedData[0] * Double(height)
+        var x: Double = 0
+        
+        var pathPoints = [CGPoint]()
+        
+        path.move(to: CGPoint(x: x, y: initialPoint))
+        for y in normalizedData {
+            if normalizedData.firstIndex(of: y) != 0 {  // Skip first point
+                x += widthBetweenDataPoints
+                let y = y * Double(height)
+                path.addLine(to: CGPoint(x: x, y: y))
+            }
+
+            // Append current point to an array. Later will be used for Drag Gesture
+            pathPoints.append(path.currentPoint!)
+        }
+        
+        return path
+    }
+    
+    /*
+     Get data -> normalize it -> 0 <= output <= 1
+     */
+    func normalize(_ data: [Double]) -> [Double] {
+        var normalData = [Double]()
+        let min = data.min()!
+        let max = data.max()!
+
+        for value in data {
+            let normal = (value - min) / (max - min)
+            normalData.append(normal)
+        }
+        
+        return normalData
+    }
+}
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/InteractiveCharts/LineChart/Helpers/LineView.swift	Mon Apr 26 19:02:46 2021 +0200
@@ -0,0 +1,36 @@
+//
+//  LineView.swift
+//  InteractiveCharts
+//
+//  Created by Dennis Concepción Martín on 26/4/21.
+//
+
+import SwiftUI
+
+struct LineView: View {
+    var data: [Double]
+    
+    var body: some View {
+        GeometryReader { proxy in
+            LinePath(data: data, width: proxy.size.width, height: proxy.size.height)
+                .stroke(colorLine(), lineWidth: 2)
+                .rotationEffect(.degrees(180), anchor: .center)
+                .rotation3DEffect(.degrees(180), axis: (x: 0.0, y: 1.0, z: 0.0))
+        }
+    }
+    
+    /*
+     Color path depending on data.
+     */
+    private func colorLine() -> Color {
+        var color = Color(.systemGreen)
+        
+        if data.first! > data.last! {
+            color = Color(.systemRed)
+        } else if data.first! == data.last! {
+            color = Color(.systemTeal)
+        }
+        
+        return color
+    }
+}