Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import SwiftUI
- import WidgetKit
- struct LineGraph: Shape {
- var pricePoints: [CGFloat]
- func path(in rect: CGRect) -> Path {
- var normalizedPrices = pricePoints.normalized
- if normalizedPrices.isEmpty {
- normalizedPrices = [0,1]
- }
- func point(at index: Int) -> CGPoint {
- let point = normalizedPrices[index]
- let x = rect.width * CGFloat(index) / CGFloat(normalizedPrices.count - 1)
- let y = (1 - point) * rect.height
- return CGPoint(x: x, y: y)
- }
- return Path { path in
- path.move(to: .zero)
- guard normalizedPrices.count > 1 else { return }
- let start = normalizedPrices[0]
- path.move(to: CGPoint(x: 0, y: (1 - start) * rect.height))
- for index in normalizedPrices.indices {
- path.addLine(to: point(at: index))
- }
- path.addLine(to: CGPoint(x: 1.1 * rect.width, y: rect.height * 1.5))
- path.addLine(to: CGPoint(x: -1.1 * rect.width , y: rect.height * 1.5))
- path.move(to: CGPoint(x: -1.1, y: (1 - start) * rect.height))
- path.closeSubpath()
- }
- }
- }
- struct OpeningPrice: Shape {
- var pricePoints: [CGFloat]
- var openingPrice: CGFloat
- func path(in rect: CGRect) -> Path {
- var prices = pricePoints
- prices.append(openingPrice)
- let normalized = prices.normalized
- return Path { path in
- path.move(to: .zero)
- guard normalized.count > 1 else { return }
- let start = normalized[normalized.count - 1]
- path.move(to: CGPoint(x: 0, y: (1 - start) * rect.height))
- path.addLine(to: CGPoint(x: 1 * rect.width, y: (1 - start) * rect.height))
- }
- }
- }
- struct ChartView: View {
- let dailyChange: Double
- var pricePoints: [CGFloat]
- let openingPrice: CGFloat
- let fillOpacity: Double
- @State var tempPoints: [CGFloat] = []
- @State var showShimmering = false
- var body: some View {
- ZStack {
- ZStack {
- LineGraph(pricePoints: pricePoints.isEmpty ? tempPoints : pricePoints)
- .fill(LinearGradient(gradient: Gradient(colors: [dailyChange.getPriceChangeColor().opacity(pricePoints.isEmpty ? 0.4 : fillOpacity), Color.clear]), startPoint: .top, endPoint: .bottom))
- .clipped()
- if pricePoints.isEmpty {
- LineGraph(pricePoints: pricePoints.isEmpty ? tempPoints : pricePoints)
- .fill(LinearGradient(gradient: Gradient(colors: [dailyChange.getPriceChangeColor().opacity(fillOpacity), Color.clear]), startPoint: .top, endPoint: .bottom))
- .clipped()
- .mask(
- Capsule()
- .fill(LinearGradient(gradient: .init(colors: [.clear, .newsColor, .clear]), startPoint: .top, endPoint: .bottom))
- .rotationEffect(.init(degrees: 30))
- .offset(x: showShimmering ? 360 : -360)
- )
- .onAppear {
- withAnimation(Animation.default.speed(0.15).delay(0).repeatForever(autoreverses: false)) {
- showShimmering.toggle()
- }
- }
- }
- }
- OpeningPrice(pricePoints: pricePoints.isEmpty ? tempPoints : pricePoints, openingPrice: openingPrice)
- .stroke(style: StrokeStyle( lineWidth: 1, dash: [4]))
- .foregroundColor(dailyChange.getPriceChangeColor())
- .clipped()
- .opacity(pricePoints.isEmpty ? 0 : 1)
- LineGraph(pricePoints: pricePoints.isEmpty ? tempPoints : pricePoints)
- .stroke(dailyChange.getPriceChangeColor(), style: StrokeStyle(lineWidth: 2, lineCap: .round, lineJoin: .round))
- .clipped()
- }
- .onAppear(perform: {
- if pricePoints.isEmpty {
- tempPoints = getRandomPoints()
- }
- })
- }
- func getRandomPoints() -> [CGFloat] {
- var pointsArray: [CGFloat] = []
- var previousValue = CGFloat.random(in: 0.1...0.9)
- for _ in (0...75) {
- previousValue = CGFloat.random(in: max(0.1, (previousValue - 0.01))...min((previousValue + 0.01), 0.9))
- pointsArray.append(previousValue)
- }
- return pointsArray
- }
- }
- extension Double {
- func getPriceChangeColor() -> Color {
- let roundedDouble = self.roundTo(places: 2)
- if roundedDouble > 0 {
- return Color.mainGreen
- } else if roundedDouble < 0 {
- return Color.mainRed
- } else {
- return Color.mainGray
- }
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment