5. What is this talk?
• Actually less about Canvas API and more
about patterns in which it can be used...
• No Ruby! (Sorry Rubyists).
• Play along! https://github.com/massivelyfun/
canvas-playground
• ...in 5 / 7 / 5.
14. Simple, no?
cvs = document.getElementById("canvas")
ctx = cvs.getContext("2D")
# ctx has all your draw methods...
ctx.fillText("Hello!", 100, 100, 200)
15. Simple, no?
cvs = document.getElementById("canvas")
ctx = cvs.getContext("2D")
# ctx has all your draw methods...
ctx.fillText("Hello!", 100, 100, 200)
You’ll only see this from here out.
31. Simple Game
Entity
• Respond to update call
• Manage position, height, width
• Delegate draw calls
32. # Game level object
class Entity
# Rect is a drawing primitive
constructor: (options = {}) ->
@rect = options.rect ? null
{x, y} = options
@position = {x: x, y: y}
update: (tick) ->
# override and do something interesting here.
draw: (ctx) ->
# delegate to your drawing primitive!
@rect.draw(ctx)
module.exports = Entity
33. # Game level object
class Entity
# Rect is a drawing primitive
constructor: (options = {}) ->
@rect = options.rect ? null
{x, y} = options
@position = {x: x, y: y}
update: (tick) ->
# override and do something interesting here.
draw: (ctx) ->
# delegate to your drawing primitive!
@rect.draw(ctx)
module.exports = Entity
Game level logic, once per tick
34. # Game level object
class Entity
# Rect is a drawing primitive
constructor: (options = {}) ->
@rect = options.rect ? null
{x, y} = options
@position = {x: x, y: y}
update: (tick) ->
# override and do something interesting here.
draw: (ctx) ->
# delegate to your drawing primitive!
@rect.draw(ctx)
module.exports = Entity
DELEGATE!!!!!
35. Simple Draw
Primitive
• Associated with Entity
• Responds to draw() call
• Has actual CanvasContext2D drawing calls
• You can determine containment here
(image hit detection, for instance)
36. #
# Rect: Drawing primitive for canvas.
class Rect
constructor: (options = {}) ->
@width = options?.width ? 1
@height = options?.height ? 1
{x, y} = options
@position = {x: x, y: y}
draw: (canvasCtx) ->
throw new Error("Implement draw()")
module.exports = Rect
37. #
# Rect: Drawing primitive for canvas.
class Rect
constructor: (options = {}) ->
@width = options?.width ? 1
@height = options?.height ? 1
{x, y} = options
@position = {x: x, y: y}
draw: (canvasCtx) ->
throw new Error("Implement draw()")
module.exports = Rect
Your *simple* interface
38. Rect = require "rect"
# Sometimes we just need the simple things.
# Make a simple box subclass.
class Box extends Rect
constructor: (options = {}) ->
super(options)
draw: (ctx) ->
{x, y} = @position.get()
ctx.fillRect(x, y, @width, @height)
module.exports = Box
39. Rect = require "rect"
# Sometimes we just need the simple things.
# Make a simple box subclass.
class Box extends Rect
constructor: (options = {}) ->
super(options)
draw: (ctx) ->
{x, y} = @position.get()
ctx.fillRect(x, y, @width, @height)
module.exports = Box
Implement draw
40. Rect = require "rect"
# Sometimes we just need the simple things.
# Make a simple box subclass.
class Box extends Rect
constructor: (options = {}) ->
super(options)
draw: (ctx) ->
{x, y} = @position.get()
ctx.fillRect(x, y, @width, @height)
module.exports = Box
Do work on CanvasContext2D
41. Canvas tests are hard;
The one true way is to cheat.
Stub, Stub, stub the world.
42. CanvasRenderingContext2D.prototype.__update = function () {
var args = Array.prototype.slice.call(arguments);
this.__lastUpdateTime = new Date();
this.__updateCount++;
}
CanvasRenderingContext2D.prototype.__fill = function () {
var args = Array.prototype.slice.call(arguments);
this.__lastFillTime = new Date();
this.__fillCount++;
}
// Stub out the real methods. I'm explicitly returning undefined
// in cases where the API calls for void return, so as to be clear
// about the intent. This is a simple sub-set of the API focused
// on operations for images. TODO: implement transforms and state.
CanvasRenderingContext2D.prototype.arcTo = function (x1, y1, x2, y2, radius) {
this.__openSubpath = true;
this.__curX = x2;
this.__curY = y2;
return undefined;
...etc.
};