changeset 273:39428219f832

Implementing LineChart drag animation
author Dennis Concepción Martín <66180929+denniscm190@users.noreply.github.com>
date Wed, 17 Mar 2021 17:01:13 +0100
parents 9e23e9b0ab36
children 61208d7aa715
files LazyBear.xcodeproj/project.pbxproj LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate LazyBear/UI/ChartView.swift LazyBear/UI/IndicatorPoint.swift LazyBear/UI/LineChart.swift LazyBear/UI/LinePath.swift LazyBear/UI/LineView.swift
diffstat 7 files changed, 115 insertions(+), 102 deletions(-) [+]
line wrap: on
line diff
--- a/LazyBear.xcodeproj/project.pbxproj	Mon Mar 15 20:06:24 2021 +0100
+++ b/LazyBear.xcodeproj/project.pbxproj	Wed Mar 17 17:01:13 2021 +0100
@@ -49,7 +49,7 @@
 		95ACB5A925E0397B00A3CCC8 /* CompanyView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ACB5A825E0397B00A3CCC8 /* CompanyView.swift */; };
 		95ACB5AC25E03A7D00A3CCC8 /* themes.json in Resources */ = {isa = PBXBuildFile; fileRef = 95ACB5AB25E03A7D00A3CCC8 /* themes.json */; };
 		95ACB5AF25E03AA100A3CCC8 /* ThemeModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95ACB5AE25E03AA100A3CCC8 /* ThemeModel.swift */; };
-		95AEF3AC25FFBB4D001B77BB /* LinePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AEF3AB25FFBB4D001B77BB /* LinePath.swift */; };
+		95AEF3AC25FFBB4D001B77BB /* LineView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AEF3AB25FFBB4D001B77BB /* LineView.swift */; };
 		95AEF3B025FFD8CF001B77BB /* LineChart.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AEF3AF25FFD8CF001B77BB /* LineChart.swift */; };
 		95AEF3B325FFDC04001B77BB /* DeviceSize.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95AEF3B225FFDC04001B77BB /* DeviceSize.swift */; };
 		95B3E09F25E127D7007EFDE3 /* Request.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95B3E09E25E127D7007EFDE3 /* Request.swift */; };
@@ -72,6 +72,7 @@
 		95F0460B25E970DB006A5A17 /* LanguagePicker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F0460A25E970DB006A5A17 /* LanguagePicker.swift */; };
 		95F0461025E976B5006A5A17 /* SettingRow.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F0460F25E976B5006A5A17 /* SettingRow.swift */; };
 		95F0462825E98376006A5A17 /* default.png in Resources */ = {isa = PBXBuildFile; fileRef = 95F0462625E98376006A5A17 /* default.png */; };
+		95F8433E2602455E00770F8A /* IndicatorPoint.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F8433D2602455E00770F8A /* IndicatorPoint.swift */; };
 		95F90AB825F280190023A4B0 /* InsiderTransactions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 95F90AB725F280190023A4B0 /* InsiderTransactions.swift */; };
 /* End PBXBuildFile section */
 
@@ -122,7 +123,7 @@
 		95ACB5A825E0397B00A3CCC8 /* CompanyView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CompanyView.swift; sourceTree = "<group>"; };
 		95ACB5AB25E03A7D00A3CCC8 /* themes.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = themes.json; sourceTree = "<group>"; };
 		95ACB5AE25E03AA100A3CCC8 /* ThemeModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ThemeModel.swift; sourceTree = "<group>"; };
-		95AEF3AB25FFBB4D001B77BB /* LinePath.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LinePath.swift; sourceTree = "<group>"; };
+		95AEF3AB25FFBB4D001B77BB /* LineView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineView.swift; sourceTree = "<group>"; };
 		95AEF3AF25FFD8CF001B77BB /* LineChart.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LineChart.swift; sourceTree = "<group>"; };
 		95AEF3B225FFDC04001B77BB /* DeviceSize.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DeviceSize.swift; sourceTree = "<group>"; };
 		95B3E09E25E127D7007EFDE3 /* Request.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Request.swift; sourceTree = "<group>"; };
@@ -143,6 +144,7 @@
 		95F0460A25E970DB006A5A17 /* LanguagePicker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LanguagePicker.swift; sourceTree = "<group>"; };
 		95F0460F25E976B5006A5A17 /* SettingRow.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SettingRow.swift; sourceTree = "<group>"; };
 		95F0462625E98376006A5A17 /* default.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = default.png; sourceTree = "<group>"; };
+		95F8433D2602455E00770F8A /* IndicatorPoint.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IndicatorPoint.swift; sourceTree = "<group>"; };
 		95F90AB725F280190023A4B0 /* InsiderTransactions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = InsiderTransactions.swift; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
@@ -282,8 +284,9 @@
 				9520C26E25F4D43D0070DD71 /* TransactionDetail.swift */,
 				95DED9DA25F2B268000DFCBA /* InsiderSummary.swift */,
 				95E9D09625F6AA0400A947A1 /* ActionView.swift */,
-				95AEF3AB25FFBB4D001B77BB /* LinePath.swift */,
 				95AEF3AF25FFD8CF001B77BB /* LineChart.swift */,
+				95AEF3AB25FFBB4D001B77BB /* LineView.swift */,
+				95F8433D2602455E00770F8A /* IndicatorPoint.swift */,
 			);
 			path = UI;
 			sourceTree = "<group>";
@@ -406,7 +409,7 @@
 				95F0461025E976B5006A5A17 /* SettingRow.swift in Sources */,
 				95F0460825E9704F006A5A17 /* ThemePicker.swift in Sources */,
 				95A5D95A25FCEDDB0090C1EA /* CompanyOption.swift in Sources */,
-				95AEF3AC25FFBB4D001B77BB /* LinePath.swift in Sources */,
+				95AEF3AC25FFBB4D001B77BB /* LineView.swift in Sources */,
 				95672B9825DDA54700DCBE4A /* Persistence.swift in Sources */,
 				958A735B25E0264E00FD7ECA /* CompanyModel.swift in Sources */,
 				95B3E09F25E127D7007EFDE3 /* Request.swift in Sources */,
@@ -421,6 +424,7 @@
 				95A5D95D25FCEEBC0090C1EA /* GetUrl.swift in Sources */,
 				9517626325EEBD3800733235 /* IexAttribution.swift in Sources */,
 				95F90AB825F280190023A4B0 /* InsiderTransactions.swift in Sources */,
+				95F8433E2602455E00770F8A /* IndicatorPoint.swift in Sources */,
 				95ACB5AF25E03AA100A3CCC8 /* ThemeModel.swift in Sources */,
 				95672B8F25DDA54700DCBE4A /* LazyBearApp.swift in Sources */,
 				9517626025EEB37E00733235 /* PriceModel.swift in Sources */,
Binary file LazyBear.xcodeproj/project.xcworkspace/xcuserdata/dennis.xcuserdatad/UserInterfaceState.xcuserstate has changed
--- a/LazyBear/UI/ChartView.swift	Mon Mar 15 20:06:24 2021 +0100
+++ b/LazyBear/UI/ChartView.swift	Wed Mar 17 17:01:13 2021 +0100
@@ -26,6 +26,7 @@
             
             let prices = historicalPrices.map { $0.close }
             LineChart(data: prices)
+                .padding(.vertical)
         }
         .onAppear {
             let url = getUrl(endpoint: .historicalPrices, symbol: symbol, range: "3m")
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/UI/IndicatorPoint.swift	Wed Mar 17 17:01:13 2021 +0100
@@ -0,0 +1,21 @@
+//
+//  IndicatorPoint.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 17/3/21.
+//
+
+import SwiftUI
+
+struct IndicatorPoint: View {
+    var body: some View {
+        Circle()
+            .frame(width: 10, height: 10)
+    }
+}
+
+struct IndicatorPoint_Previews: PreviewProvider {
+    static var previews: some View {
+        IndicatorPoint()
+    }
+}
--- a/LazyBear/UI/LineChart.swift	Mon Mar 15 20:06:24 2021 +0100
+++ b/LazyBear/UI/LineChart.swift	Wed Mar 17 17:01:13 2021 +0100
@@ -12,17 +12,27 @@
     @EnvironmentObject var deviceSize: DeviceSize
     
     var body: some View {
+        if !data.isEmpty {
+            let normalizedData = normalize(data)
+            
             VStack {
-                ZStack {
-                    Grid(height: deviceSize.width, width: deviceSize.width)
-                        .clipped()
-                        .background(LinePath(width: deviceSize.width, data: data))
-                    
-                        
-                }
+                LineView(width: deviceSize.width, height: deviceSize.width / 3, normalizedData: normalizedData)
             }
-            .frame(width: deviceSize.width, height: deviceSize.width / 2)
-        
+            .frame(width: deviceSize.width, height: deviceSize.width / 3)
+        }
+    }
+    
+    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
     }
 }
 
@@ -32,25 +42,3 @@
             .environmentObject(DeviceSize())
     }
 }
-
-struct Grid: View {
-    var height: CGFloat
-    var width: CGFloat
-    
-    var body: some View {
-        VStack {
-            Rectangle()
-                .stroke(Color.gray.opacity(0.2), lineWidth: 0.5)
-            
-            Group {
-                Rectangle()
-                    .stroke(Color.gray.opacity(0.2), lineWidth: 0.5)
-                
-                Rectangle()
-                    .stroke(Color.gray.opacity(0.2), lineWidth: 0.5)
-            }
-            .offset(y: -8)
-            .padding(.bottom, -8)
-        }
-    }
-}
--- a/LazyBear/UI/LinePath.swift	Mon Mar 15 20:06:24 2021 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,67 +0,0 @@
-//
-//  LinePath.swift
-//  LazyBear
-//
-//  Created by Dennis Concepción Martín on 15/3/21.
-//
-
-import SwiftUI
-
-struct LinePath: View {
-    var width: CGFloat
-    var data: [Double]
-
-    var body: some View {
-        let height = width/2
-        if !data.isEmpty {
-            let normalizedData = normalize(data)
-                
-            // Substract 2 to skip the first and the last item
-            let widthBetweenPoints = Double(width) / Double(normalizedData.count - 2)
-            
-            Path { path in
-                let initialPoint = normalizedData[0] * Double(height)
-                var x: Double = 0
-                path.move(to: CGPoint(x: x, y: initialPoint))
-                
-                for y in normalizedData {
-                    // Skip first item
-                    if normalizedData.firstIndex(of: y) != 0 {
-                        x += widthBetweenPoints
-                        let y = y * Double(height)
-                        path.addLine(to: CGPoint(x: x, y: y))
-                    }
-                }
-            }
-            .stroke(Color.green, lineWidth: 2)
-            .rotationEffect(.degrees(180), anchor: .center)  // The path must be rotated
-            .rotation3DEffect(.degrees(180), axis: (x: 0.0, y: 1.0, z: 0.0))
-            
-        }
-    }
-    
-    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
-    }
-    
-}
-
-struct LinePath_Previews: PreviewProvider {
-    static var previews: some View {
-        GeometryReader { geo in
-            VStack {
-                let data: [Double] = [50.0, 50.5, 51.0, 50.4, 50.8, 51.3, 51.5, 52, 51.9, 52.4]
-                LinePath(width: geo.size.width, data: data)
-            }
-        }
-    }
-}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LazyBear/UI/LineView.swift	Wed Mar 17 17:01:13 2021 +0100
@@ -0,0 +1,66 @@
+//
+//  LineView.swift
+//  LazyBear
+//
+//  Created by Dennis Concepción Martín on 15/3/21.
+//
+
+import SwiftUI
+
+struct LineView: View {
+    var width: CGFloat
+    var height: CGFloat
+    var normalizedData: [Double]
+    
+    // Drag gesture
+    @State private var touchLocation: CGPoint = .zero
+
+    var body: some View {
+        Line(width: width, height: height, normalizedData: normalizedData)
+            .stroke(Color.green, lineWidth: 2)
+            .rotationEffect(.degrees(180), anchor: .center)  // The path must be rotated
+            .rotation3DEffect(.degrees(180), axis: (x: 0.0, y: 1.0, z: 0.0))
+            .gesture(DragGesture()  // Add gesture
+            .onChanged({ value in  // Take value of the gesture
+                print("Location - > \(value.location)")
+            })
+        )
+    }
+}
+
+struct Line: Shape {
+    var width: CGFloat
+    var height: CGFloat
+    var normalizedData: [Double]
+    
+    func path(in rect: CGRect) -> Path {
+        var path = Path()
+        
+        // Substract 2 to skip the first and the last item
+        let widthBetweenPoints = Double(width) / Double(normalizedData.count - 2)
+        let initialPoint = normalizedData[0] * Double(height)
+        var x: Double = 0
+        
+        path.move(to: CGPoint(x: x, y: initialPoint))
+        for y in normalizedData {
+            // Skip first item
+            if normalizedData.firstIndex(of: y) != 0 {
+                x += widthBetweenPoints
+                let y = y * Double(height)
+                path.addLine(to: CGPoint(x: x, y: y))
+            }
+        }
+        return path
+    }
+}
+
+struct LineView_Previews: PreviewProvider {
+    static var previews: some View {
+        GeometryReader { geo in
+            VStack {
+                let normalizedData: [Double] = [0, 0.1, 0.15, 0.2, 0.3, 0.4, 0.35, 0.38, 0.5, 0.55, 0.6, 0.57, 0.8, 1]
+                LineView(width: geo.size.width, height: geo.size.width / 2, normalizedData: normalizedData)
+            }
+        }
+    }
+}