Git Repo

Download Script requires Hammer JS for mobile

Initialization

Instializing this as an object with the new keyword is necesarry, but saving the object to a variable is not, since all functions will be applied to the DomElement directly.

var DomElement = document.getElementById('myCanvas'), ConfigObject = {}; new Canvas(DomElement, ConfigObject);

If no element is given a canvas will be created and appended to the body. If the element is not a canvas it will be taken as a container, and any canvases within it will be used as layers. All functions will be applied to the container element given, not the canvases within.

To set the draw loop function, simply define a draw, beforeDraw, or afterDraw function.

var canvas = document.getElementById('myCanvas'); new Canvas(canvas); canvas.draw = function () { canvas.beginPath(); canvas.rect(0,0,50,40); canvas.fill('#0f0'); }

Because the draw function is in the same scope as the context functions they can be called using this

canvas.draw = function () { this.fillRect(0,0,50,40,'#0f0'); this.fillCircle(100,120,30,'#00f'); }

Default Options

Name Default Values Description
zoom 1 Number between 0 and... infinity zoom > 0 Zoom level, or scale factor of the canvas drawing.
center {x:0,y:0} x, y coordinate object The offset, or translation of the canvas drawing. This should only be gotten after initialization, and should be set using canvas.setCenter({x:0,y:0}) after that.
inverseY false Boolean: true/false Inverts the Y axis, as the pre-flipping of it can be an annoyance
inverseZ false Boolean: true/false Inverts the scrolling direction, for those who prefer OSx style scrolling. This does not effect touch-screen pinch zooming.
zoomMin 1/34000 Number between 0 and 1 0 < zoomMin <= 1 The minimum magnification (zoom out) of the canvas.
zoomMax 34000 Number between 1 and infinity zoomMax >= 1 The maximum magnification (zoom in) of the canvas. At values greater than 34000 lines begin to disappear, text acts funny and the zoom algorithm may jitter.
scrollSpeed 1/1000 Number between 0 and 1 0 < scrollSpeed < 1 The magnification factor of scrolling
shapeOrigin false "top", "bottom", "left", "right", "center"
or any pair of horizontal and vertical positions
The position of the point given to a shape function relative to the shape drawn. Normal value for rectangles and text would be "top left".
If only one position is defined, e.g. "left" then the other position will be the shape's default: center for arcs; and the top for rectangles and text.
clearBeforeDraw true Boolean: true/false Clearing the canvas before the draw loop can be disabled if you require a difference-based render method.
panning true Boolean: true/false The ability to pan the canvas can be disabled by this switch
zooming true Boolean: true/false The ability to zoom the canvas can be disabled by this switch
zoomPanning true Boolean: true/false The ability to change the center of origin while zooming can be disabled by this switch. If this is off while panning is on, then you will always zoom into the center of the current view, regardless of mouse position, while still being able to change the center by panning.
minShapeZoom 0 Number between 0 and 1 0 <= minShapeZoom < 1 The zoom (out) level that objects will begin to retain their size at, instead of continuing to get smaller.

Example

Slight lag is due to repeated text rendering

var canv = new Canvas(), C = document.getElementsByTagName('canvas')[0]; C.draw = function () { for (var x=-400;x<400;x+=30) { for (var y=-400;y<400;y+=30) { var r = (x*y)/8000, c = '#f00'; if (r < 0) { r = -r; c = '#00f'; } this.fillSquare(x,y,r*2,'#0f0'); this.paintCircle(x,y,r,c); this.setCtx('font',"5px sans-serif") this.fillText(x+":"+y,x,y,'#000'); } } }; C.onclick = function (ev) { console.log( this.unPosition({x:ev.offsetX, y:ev.offsetY})); } C.size({ height:function () { return window.innerHeight; }, width:function () { return window.innerWidth; } })

Utility Functions

The canvas can start an animaion loop for you using requestAnimationFrame to control it. Use the animate function to start and the stop function to end

canvas.animate() canvas.stop()

The drawSpace function can be called outside of the animation loop to re-draw the canvas entirely. The clear function clears the entire canvas, and should be called before drawSpace.

canvas.clear() canvas.drawSpace()

You can reset the canvas state, incuding position and scale; Get the current translation offset, accounting for zoom; Set the current view center, updating the offset; And set the current drawing layer.

canvas.reset() canvas.getOffset(position) canvas.setCenter(position) canvas.setLayer(index)

The size function can be passed a {width:w,height:h} object, or can be passed the property and value separately. This will in turn run the Width or Height functions, which can be pased a number or a function that will update on window resize.

canvas.size(object OR prop, val) canvas.Width(val) canvas.Height(val)

To fill the screen with the canvas you might use this object.

canavs.size({ height:function () { return window.innerHeight; }, width:function () { return window.innerWidth; } })

You can set and get properties from the canvas element using the config function, which will in turn call get or set. The config function can be passed an object to set multiple values at once, or a single property or name value pair to get or set it.

canvas.config(object OR prop, val) canvas.set(prop, val) canvas.get(prop)

To set context properties, such as fillStyle, use the configCtx, setCtx or getCtx functions. These functions provide many synonyms and abbreviations for common values, for strokeStyle: stroke-style, stroke_style, stroke, line, lineStyle,..

canvas.configCtx(object OR prop, val) canvas.setCtx(prop, val) canvas.getCtx(prop)

Pass a {x:0,y:0} coordinate to either function, the position function will translate the real coordiante to a canvas coordinate - but there is no need to transform these numbers with any of the drawing functions while in the draw loop. The unPosition function will take a canvas coordiate (such as a mouse click) and output the corresponding real-space coordinate.

canvas.position(position) canvas.unPosition(position)

Context Functions

All functions that can be called from the context can now be called from the canvas element (or container). Drawing shapes from the canvas element will apply a transformation based on an offset and a zoom level - or a translation and a scale (though canvas translation is not used as it's buggy with large values). The context is not modified, and can still be used in the normal way. See this list of context methods for duplicated functions.

Missing Context Functions

All shapes now have a paint(Shape) function, which fills and strokes a shape. fill(Shape) and stroke(Shape) functions can be called with an aditional style argument that will set the fillStyle or strokeStyle of the context.

canvas.paintRect(x, y, w, h, fillStyle, strokeStyle) canvas.fillRect(x, y, w, h, style) canvas.strokeRect(x, y, w, h, style)

There are also additional shapes that help avoid predictable duplication on your part. In the square functions bellow the third argument r is the length of any side.

canvas.square(x, y, r) canvas.fillSquare(x, y, r, style) canvas.strokeSquare(x, y, r, style) canvas.clearSquare(x, y, r) canvas.paintSquare(x, y, r, fillStyle, strokeStyle)

The arc has been given its own fill and stroke functions, and the circle function simply assumes angles a and b are 0 and 2 * PI.

canvas.fillArc(x, y, r, a, b, style) canvas.strokeArc(x, y, r, a, b, style) canvas.paintArc(x, y, r, a, b, fillStyle, strokeStyle) canvas.circle(x, y, r) canvas.fillCircle(x, y, r, style) canvas.strokeCircle(x, y, r, style canvas.paintCircle(x, y, r, fillStyle, strokeStyle)

The curveTo function takes between 2 and 6 arguments to define a lineTo(2 args), quadraticCurveTo(4 args), arcTo(5 args), or bezierCurveTo(6 args).
Normally the quadraticCurveTo and bezierCurveTo functions take the endpoint x, y last, but in this mapping they take that point first, and the cp arguments after in normal order.

canvas.curveTo(*args*)

The path function takes a list of points (as lists of coordinates), and can take many lists in unlimited arguments, or the points as the list of arguments.
This nesting also means you can pass more complicated lists of lists of lists, but each layer should be similarly nested, because it will assume all arguments are of the same type as the first (a line or point).
This function runs context.beginPath before each line.

canvas.path(path, path2,..)

The closedPath function will run the path function above, and then context.closePath.

canvas.closedPath(path, path2,..)

You can also treat the closed path like any other shape and fill or stroke it directly.

canvas.fillPath(path, style) canvas.strokePath(path, style) canvas.paintPath(path, fillStyle, strokeStyle)

The line functions below are maped directly to the path functions above.

canvas.line(path, path2,..) canvas.closedLine(path, path2,..) canvas.fillLine(path, style) canvas.strokeLine(path, style) canvas.paintLine(path, fillStyle, strokeStyle)

Layering

If a container element is given with several canvases within, then they will be taken as layers, zero-indexed in the order the dom will be traversed, and can also be refered to by element id when setting the current layer:

container.setLayer(0) container.setLayer(1) container.setLayer("my-layer-id")

All drawing functions will be applied to the current context at container.context (canvas.context in other examples), and the setLayer function simply sets this variable to the correct context, allowing you to switch layers at any time, and draw using the same functions and variables.

container.setLayer(0) var a = container.context; container.setLayer(1) // a != container.context

This will initialise with the first canvas' context, if an unknown value is passed to setLayer then it will also default to the first context. If an index is given greater than possible then it will default to the last layer's context.

Events and Handling

The canvas has events for the actions: Panning, Zooming and Resize-ing and will automatically make the canvas navigable and responsive.
Each action has three events: Start, Step and Stop, and each event has three callbacks: before, during and after. E.g.

canvas.beforePanStop = function () {} canvas.zoomStep = function () {} canvas.afterResizeStart = function () {}

Each actions runs the events and callbacks in this order:

Start

before(Action)Start() set action state (action)Start() STEP() start animating event.preventDefault after(Action)Start()

Step

before(Action)Step() action logic (action)Step() event.preventDefault after(Action)Step()

Stop

before(Action)Stop() unset action state (action)Stop() stop animating event.preventDefault after(Action)Stop()

Hammer JS is also used to apply touch-screen panning and zooming, and works accurately with no intervention.

The PC-browser panning and zooming are set directly to the canvas.onmousedown and canvas.onmousewheel functions so can be easily overridden if necessary.