Ember Canvas View



I have been working on an ember based application where I’m doing some custom drawing in a canvas element. Working on my canvas backed view I realized that there is some potential boilerplate code involved that could be turned into a canvas view.

I noticed that when I was clicking rapidly in my canvas view other text/elements within the page were being selected. I experimented with different solutions, and the one I found most elegant was returning false from selectStart, en event that is not part of the events that ember dispatches so I added that to the event dispatcher as well.

The Canvas View that I wrote is very similar to the way drawing works in Cocoa & UIKit views. There is a drawRect(rect) function that gets called whenever you need to redraw your view. It also provides you with a rectangle containing the region that you should redraw.

A view can be marked as dirty / needing an update by calling one of these two functions: - setNeedsDisplay() - setNeedsDisplayInRect(dirtyRect) Calling either of these functions ensures your drawRect(dirtyRect) function will be called in the next iteration of the runloop.

The setNeedsDisplayInRect(dirtyRect) function marks the view as needing update inside that rect. It also ensures that the canvas will be clipped to that rect before drawRect(dirtyRect) will be called, so that if you are lazy and don’t want to implement code for doing partial updates it will at least minimize the performance impact of doing a full update by making the canvas ignore drawing outside of that region automatically for you. This can be disabled by setting clipsCanvasToDrawRect = false.

Using the canvas element in my situation involved getting the location of a click within the bounds of my view. The code required to do this is something I considered could be turned into a locationInView(view) helper function attached to every event object dispatched. That way you could easily get the location within the bounds of your view or any other view.

The code for my additions is inside the ember-canvas-view and event+locationInView branches in my fork of ember.js.

Here’s a link to my commit in ember-canvas-view containing the CanvasView.

Here’s a link to my commit in ember+locationInView containing the location view helper and the additions to the event dispatcher.

I just realized while writing this that there is a possible enhancement to the setNeedsDisplayInRect(dirtyRect) function that would make it more useful: if multiple calls are made before a calls are made within the same iteration of the runloop / before draw is called. It could combine the dirtyRects and create one big dirty rect that contains all the dirtyRects. I’m open to suggestions on this as I am for anything related to this.

Let me know what you’re thoughts are and if this would be welcome, I’d be glad to submit a pull request :slight_smile: