Hi Caroline!
Thank you for the amazing tutorial!
Iām taking it and improving it a bit for my code, but Iām facing some issues.
Basically Iām using the graphics inside a UiViewCollection cell, but I want different Graphs, so Iām adding the graph programmatically like the code below:
Hi, I downloaded your completed project and it appears a function declaration may be missing?
Line 74 of GraphView.Swift reads: let maxValue = maxElement(graphPoints); however, I donāt see a function defined for maxElement and the compiler is throwing an unresolved identifier error on it. Itās also referenced in ViewController.swift and has the same error. Am I missing something?
Hi, againāhad another question that Iām hoping you might be able to help with! Iāve added a tap touch gesture to the graph and would like to update the color of the graph circle that Iāve tapped on (the UIBezierPath). Iām having problems doing this. I have an array of UIBezierPath called graphCircles which stores them when theyāre set up in -drawRect:, and I pull out the specific one I want to update in my tap gesture handler when the touch falls inside the graph circle point. Iām trying to update the color like this:
UIColor.white.setFill()
self.graphCircles[idx].fill() // UIBezierpath that was tapped
However, I get this error and nothing happens: āCGContextSetFillColorWithColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.ā
Can I update the UIBezierPath outside of -drawRect:? Iāve tried saving a reference to the CGContext I have in drawRect: and then loading it in my tap gesture handler method using UIGraphicsPushContext(self.savedContext!) but that doesnāt work. This is the only thing I want to update when this happens, so Iām hoping I can do it in a standalone fashion and not have to call -setNeedsDisplay to redraw the whole view. Iāve searched all over and canāt seem to find an easy or working way to do this.
Ah, that explains a lot! Thank you! Should I go off a bool in draw(_:) that I set in my tap gesture handling method so that when I pass in the rect for my circle that I want to change the color on in setNeedsDisplayInRect(_:) it doesnāt go through the rest of the regular graph drawing code that you have in draw(_:)? Like:
override func draw(_ rect: CGRect) {
let context = UIGraphicsGetCurrentContext()
if self.redrawGraphCircle {
// Update graph circle color
} else {
// Regular graph drawing code that we don't need to go through again
}
@roth - On reflection, I think I was wrong. Youād still have to draw the background gradient if you used setNeedsDisplayInRect(_:), as the whole rect needs to be redrawn.
If you are interacting with circles, then you could make them views. That would make the touch code easy as well as the draw code.
So you could have seven circular custom views. When one is tapped, call the viewās delegate to deselect the other views and select this one.
Yes, I think I saw that behavior occur when I tried to implement your suggestionāI could get the UIBezierPath circle to change color but the edges of its rect were white, which was probably, as you said, because the background gradient for it would need to get redrawn. Doing UIView circles was going to be my backup if I couldnāt get this to work. Thanks for all your help!
I tried to implement your code but its not working on simulator (6 and above ),i am implementing graph View on scrollview and 120+ graph points over graph view.its showing on 3D view and iOS Device but does not visible on simulator.
Hi @robbeyroad - the only green in the graph view is the initial IBOutlet setting for endColor so I assume thatās what you mean?
The class is IBDesignable and the property is IBInspectable, so this can be changed in the storyboard. Have a look at the storyboard and find the graph view. Thatās where the endColor is actually set.
I am sorry for the confusion, I was talking about the green that you were temporarily using under the graph before replacing it (in the section āA Gradient Graphā). I just realized that you are actually using the same gradient.
Could you please clarify this piece of code? Instead of your code, which was written, I assume for Swift 1:
//4 - get today's day number
let dateFormatter = NSDateFormatter()
let calendar = NSCalendar.currentCalendar()
let componentOptions:NSCalendarUnit = .CalendarUnitWeekday
let components = calendar.components(componentOptions,
fromDate: NSDate())
var weekday = components.weekday
let days = ["S", "S", "M", "T", "W", "T", "F"]
//5 - set up the day name labels with correct day
for i in reverse(1...days.count) {
if let labelView = graphView.viewWithTag(i) as? UILabel {
if weekday == 7 {
weekday = 0
}
labelView.text = days[weekday--]
if weekday < 0 {
weekday = days.count - 1
}
}
}
I am using this (Swift 3):
// 4 - get today's day number
let dateFormatter = DateFormatter()
let calendar = Calendar.current
let componentOptions:NSCalendar.Unit = .weekday
let components = (calendar as NSCalendar).components(componentOptions,
from: Date())
var weekday = components.weekday
let days = ["S", "S", "M", "T", "W", "T", "F"]
// 5 - set up the day name labels with correct day
for i in (1...days.count).reversed() {
if let labelView = graphView.viewWithTag(i) as? UILabel {
if weekday == 7 {
weekday = 0
}
labelView.text = days[i-1] // instead of days[weekday--]
if weekday! < 0 {
weekday = days.count - 1
}
}
}
So, what confuses me here is the weekday variable, because I donāt see how this would change the value inside the for loop??? When I use labelView.text = days[weekday-1] I get the same value for all the weekday labels.
I would appreciate if you could clarify this, thank you very much!