MotionGraphs/GraphSegment.swift
/* |
Copyright (C) 2016 Apple Inc. All Rights Reserved. |
See LICENSE.txt for this sample’s licensing information |
Abstract: |
A `UIView` subclass that represents a segment of data in a `GraphView`. |
*/ |
import UIKit |
import simd |
class GraphSegment: UIView { |
// MARK: Properties |
static let capacity = 32 |
private(set) var dataPoints = [double3]() |
private let startPoint: double3 |
private let valueRanges: [ClosedRange<Double>] |
static let lineColors: [UIColor] = [.red, .green, .blue] |
var gridLinePositions = [CGFloat]() |
var isFull: Bool { |
return dataPoints.count >= GraphSegment.capacity |
} |
// MARK: Initialization |
init(startPoint: double3, valueRanges: [ClosedRange<Double>]) { |
self.startPoint = startPoint |
self.valueRanges = valueRanges |
super.init(frame: CGRect.zero) |
} |
required init?(coder aDecoder: NSCoder) { |
fatalError("init(coder:) has not been implemented") |
} |
func add(_ values: double3) { |
guard dataPoints.count < GraphSegment.capacity else { return } |
dataPoints.append(values) |
setNeedsDisplay() |
} |
// MARK: UIView |
override func draw(_ rect: CGRect) { |
guard let context = UIGraphicsGetCurrentContext() else { return } |
// Fill the background. |
if let backgroundColor = backgroundColor?.cgColor { |
context.setFillColor(backgroundColor) |
context.fill(rect) |
} |
// Draw static lines. |
context.drawGraphLines(in: bounds.size) |
// Plot lines for the 3 sets of values. |
context.setShouldAntialias(false) |
context.translateBy(x: 0, y: bounds.size.height / 2.0) |
for lineIndex in 0..<3 { |
context.setStrokeColor(GraphSegment.lineColors[lineIndex].cgColor) |
// Move to the start point for the current line. |
let value = startPoint[lineIndex] |
let point = CGPoint(x: bounds.size.width, y: scaledValue(for: lineIndex, value: value)) |
context.move(to: point) |
// Draw lines between the data points. |
for (pointIndex, dataPoint) in dataPoints.enumerated() { |
let value = dataPoint[lineIndex] |
let point = CGPoint(x: bounds.size.width - CGFloat(pointIndex + 1), y: scaledValue(for: lineIndex, value: value)) |
context.addLine(to: point) |
} |
context.strokePath() |
} |
} |
private func scaledValue(for lineIndex: Int, value: Double) -> CGFloat { |
// For simplicity, this assumes the range is centered on zero. |
let valueRange = valueRanges[lineIndex] |
let scale = Double(bounds.size.height) / (valueRange.upperBound - valueRange.lowerBound) |
return CGFloat(floor(value * -scale)) |
} |
} |
Copyright © 2017 Apple Inc. All Rights Reserved. Terms of Use | Privacy Policy | Updated: 2017-02-02