cs193p – Project #3 Assignment #3 Task #7

von Florian Schäffer (Eigenes Werk) [CC BY-SA 4.0 (http://creativecommons.org/licenses/by-sa/4.0)], via Wikimedia Commons

Please note, this blog entry is from a previous course. You might want to check out the current one.

As part of your implementation, you are required write a generic x vs. y graphing UIView. In other words, the UIView that does the graphing should be designed in such a way that it is completely independent of the Calculator (and could be reused in some other completely different application that wanted to draw an x vs. y graph).

Download the axis-drawing helper from Stanford and add it to the project.

Create a new graph view class as subclass of UIView. For now we draw only the axis using the content scale factor of the device and the bounds of the view, and two properties to be defined below:

    override func drawRect(rect: CGRect) {
        AxesDrawer(contentScaleFactor: contentScaleFactor)
            .drawAxesInRect(bounds, origin: origin, pointsPerUnit: scale)
    }

Hint #2 notes it would be nice to mimic the API of the axis-drawing helper. Therefore we add the two public properties mentioned above. The scale equals the points-per-unit variable, its value does not really matter as it is only the default value which we will change in task #11 dynamically. Hint #8 wants to center the axis by default. It would have been nice if could just have used center in the declaration. However center is not initialized and does not exist yet, and even it was the geometrics of the current device would not be set yet. Nevertheless every time somebody changes those properties we want to redraw the view:

    var scale: CGFloat = 50.0 { didSet { setNeedsDisplay() } }
    var origin: CGPoint = CGPoint() { didSet { setNeedsDisplay() } }

For the actual drawing methods the geometrics are set and we can set the origin to the center of the view. … but only if has not been set another way (e.g. by panning the view). Create private helper variable which is true if the origin should be reset to the center, and otherwise false:

    var origin:CGPoint = CGPoint() {
        didSet {
            resetOrigin = false
            setNeedsDisplay()
        }
    }
    private var resetOrigin: Bool = true {
        didSet {
            if resetOrigin {
                setNeedsDisplay()                
            }
        }
    }
    
    override func drawRect(rect: CGRect) {
        if resetOrigin {
            origin = center
        }
        ...
    }

Finally add a new view to the graph view controller in story board – don’t forget to set its autolayout contraints – and connect it to the newly create graph-view class.

The complete code for the task #7 is available on GitHub.

FacebooktwitterredditpinterestlinkedintumblrmailFacebooktwitterredditpinterestlinkedintumblrmail

16 thoughts on “cs193p – Project #3 Assignment #3 Task #7”

  1. I’ve got everything working as the AxesDrawer displays fine but when I enter a function it doesn’t draw anything. As an example I will enter a function such as cos(m) where m = 6 and I get nothing. In fact it doesn’t matter what the value of m is. Any clues? Thanks. Tom

    1. First, I would set a break point in drawing function to see if it gets called, then in the calculator brain … and don’t forget that my code was for a previous version of Swift … it might need some tweaks …

  2. Hi
    I don’t understand why you use center instead
    convertPoint(center, fromView: superview)
    like was in the 5 lecture?
    It was sad not to use it because it is center of view.
    Why then it is all perfectly working in your code?

    Thank you for all help

    1. Sorry, I don’t understand your question, and cannot really recall what was mentioned in lecture five about that.
      convertPoint gets the position of a point in the coordinate system of the calling view, which I don’t need here because I stay in the drawing view.

  3. Thanks for answer.
    Sorry but I still don’t understand.
    When the face is drawn the center is avoided only converted from the view.
    If I understand you take center from drawing view.
    In lecture it is said to avoid center only convert it from the view…
    In the lecture 5 (time 29.51 to 33.30 and 1.03 to 1.05) he gives argument to avoid center in the code.

    Maybe in new Xcode is different or maybe I don’t understand

    Please help me

      1. He said that center is only referring to view(superview) coordinates.
        Therefore in project Happiness – center of the face is:
        var faceCenter:CGPoint{
        return convertPoint(center, fromView: superview)
        }

        That is how I understand but maybe I ma not right or maybe there are some changes in Xcode?

        Thank you

        1. … sorry for the long delay and the confusion on my part. You are right, and of course the instructor is totally right!

          center provides the center coordinates of the frame in the coordinate system of its super view. The drawing happens in the coordinate system of the of the view. My solutions will only work as long as the bounds of the view equal the frame of the view. It will stop working when the view is not filling the compete super view. e. g. if it is filling only half of the screen and is shifted to the right.

          My version is working (for now), but it is not correct. Especially if you use the class later on in another project where the view does not fill the complete screen …

  4. Hi

    I am sorry for asking but if you would find a time to answer, could you please tell me how would you implement convertPoint in your code?

    Please
    Thank you

  5. Thank you thanks…
    by the way it is advisable to learn AxesDrawer to make iOS apps, games?
    Thanks for all answers

  6. Please I don’t understand.
    In AxesDrawer.

    What is a point with
    var startingHashmarkRadius and var startingHashmarkRadius
    and all that code (with bbox) when startingHashmarkRadius is always 1!!
    What is a point to make that box and so many lines of code?
    Please help I don’t understand.

  7. By the way shouldn’t be
    bbox.inset(dx: +pointsPerHashmark

    I try to work on that but it is difficult.
    I think that the code from Stanford has many mistakes.
    It is drawing ok but is memory leaking.
    How to make that code properly?
    Thanks for help

    1. The code from Stanford was from a previous version of Swift. Swift is new, alive and evolving, and not always backwards compatible. However, I don’t think it is causing memory leaks. I guess, it is a very good exercise learning what it does and adapting it to the current Swift version. If you find memory leaks in the code, please let us know!

  8. Ok but that code doesn’t seem to be good

    let leftx = max(origin.x – bounds.minX, 0)
    let rightx = max(bounds.maxX – origin.x, 0)
    let downy = max(origin.y – bounds.minY, 0)
    let upy = max(bounds.maxY – origin.y, 0)
    startingHashmarkRadius = min(min(leftx, rightx), min(downy, upy)) / pointsPerHashmark + 1

    The graph looks ok but the code no
    Please check it

    I get

    let leftx = max(bounds.minX – origin.x, 0)
    let rightx = max(origin.x – bounds.maxX, 0)
    let upy = max(bounds.minY – origin.y, 0)
    let downy = max(origin.y – bounds.maxY,0)

    Graph is still ok but I don’t know if the code is.

    Please look on that and tell me if that solve the problem
    Thank you

Leave a Reply

Your email address will not be published.