├── src ├── ansii_palette.coffee ├── ease_default.coffee ├── display_container.coffee ├── sprite.coffee ├── bitmap.coffee ├── utils.coffee ├── text_field.coffee ├── tween_command.coffee ├── renderer.coffee ├── display_container_mixin.coffee ├── tween.coffee ├── pixel_sprite.coffee ├── stacked_loader.coffee ├── display_object.coffee ├── shape.coffee └── stage.coffee ├── .rvmrc ├── demos ├── logo.png ├── horse.ogg ├── demo.css ├── demo.html ├── logo.spr ├── demo.coffee └── demo.js ├── Gemfile ├── Guardfile ├── Gemfile.lock ├── make ├── LICENSE └── README.rdoc /src/ansii_palette.coffee: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.rvmrc: -------------------------------------------------------------------------------- 1 | rvm 1.9.3@canvas_library --create 2 | -------------------------------------------------------------------------------- /demos/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkln/canvas_library/HEAD/demos/logo.png -------------------------------------------------------------------------------- /demos/horse.ogg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dkln/canvas_library/HEAD/demos/horse.ogg -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source :rubygems 2 | 3 | group :development do 4 | gem 'guard-coffeescript' 5 | end 6 | -------------------------------------------------------------------------------- /Guardfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/ruby 2 | # 3 | guard 'coffeescript', :input => 'demos' 4 | guard 'coffeescript', :input => 'src', :output => 'lib' 5 | -------------------------------------------------------------------------------- /src/ease_default.coffee: -------------------------------------------------------------------------------- 1 | EaseDefault = (t, b, c, d) -> 2 | -c * (t /= d) * (t - 2) + b 3 | 4 | @CanvasLibrary ||= {} 5 | @CanvasLibrary.EaseDefault = EaseDefault 6 | -------------------------------------------------------------------------------- /src/display_container.coffee: -------------------------------------------------------------------------------- 1 | class DisplayContainer 2 | draw: (context, drawHitarea) -> 3 | true 4 | 5 | include DisplayContainer, CanvasLibrary.DisplayContainerMixin 6 | 7 | @CanvasLibrary ||= {} 8 | @CanvasLibrary.DisplayContainer = DisplayContainer 9 | -------------------------------------------------------------------------------- /src/sprite.coffee: -------------------------------------------------------------------------------- 1 | class Sprite extends CanvasLibrary.Shape 2 | constructor: -> 3 | super() 4 | @children = [] 5 | 6 | include Sprite, CanvasLibrary.DisplayContainerMixin 7 | 8 | @CanvasLibrary ||= {} 9 | @CanvasLibrary.Sprite = Sprite 10 | -------------------------------------------------------------------------------- /demos/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #aaa; 3 | } 4 | 5 | div { 6 | position: absolute; 7 | width: 644px; 8 | height: 484px; 9 | margin-left: -320px; 10 | margin-top: -240px; 11 | left: 50%; 12 | top: 50%; 13 | padding: 2px; 14 | border: solid 2px #fff; 15 | background-color: #fff; 16 | } 17 | -------------------------------------------------------------------------------- /src/bitmap.coffee: -------------------------------------------------------------------------------- 1 | class Bitmap extends CanvasLibrary.DisplayObject 2 | constructor: (@imageData) -> 3 | super() 4 | 5 | draw: (context, drawHitarea) -> 6 | if @imageData 7 | if @drawHitarea 8 | context.rect 0, 0, @imageData.width, @imageData.height 9 | else 10 | context.drawImage @imageData, 0, 0 11 | 12 | @CanvasLibrary ||= {} 13 | @CanvasLibrary.Bitmap = Bitmap 14 | -------------------------------------------------------------------------------- /demos/demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Canvas Lib test 5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 |
14 | 15 | 16 | -------------------------------------------------------------------------------- /demos/logo.spr: -------------------------------------------------------------------------------- 1 | PPPPPP PPPP PPPPPP 2 | PPPPPP PPPP PPPPPP 3 | PPPPPP PPPPPP PPPPPP 4 | PPPPPP PPPPPP PPPPPP 5 | PP PP PPPPPP PP 6 | PP PP PPPPPP PP 7 | 8 | PPPPPP PP PP PP 9 | PPPPPP PP PP PP 10 | PP PP PPPPPP PP 11 | PP PP PPPPPP PP 12 | PPPPPP PPPPPP PP 13 | PPPPPP PPPPPP PP 14 | 15 | PPPPPP PPPPPP PPPPPP 16 | PPPPPP PPPPPP PPPPPP 17 | PPPP PPPPPP PPPPPP 18 | PPPP PPPPPP PPPPPP 19 | PPPPPP PP PP PP 20 | PPPPPP PP PP PP 21 | -------------------------------------------------------------------------------- /Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: http://rubygems.org/ 3 | specs: 4 | coffee-script (2.2.0) 5 | coffee-script-source 6 | execjs 7 | coffee-script-source (1.1.3) 8 | execjs (1.2.12) 9 | multi_json (~> 1.0) 10 | guard (0.8.8) 11 | thor (~> 0.14.6) 12 | guard-coffeescript (0.5.2) 13 | coffee-script (>= 2.2.0) 14 | guard (>= 0.8.3) 15 | multi_json (1.0.4) 16 | thor (0.14.6) 17 | 18 | PLATFORMS 19 | ruby 20 | 21 | DEPENDENCIES 22 | guard-coffeescript 23 | -------------------------------------------------------------------------------- /src/utils.coffee: -------------------------------------------------------------------------------- 1 | class Utils 2 | @hex2rgba: (hex) -> 3 | num = parseInt(hex.slice(1), 16) 4 | [num >> 16 & 255, num >> 8 & 255, num & 255, num >> 24 & 255] 5 | 6 | @angleToRadians: (angle) -> angle * Math.PI / 180 7 | 8 | @firstUpcase: (str) -> 9 | str.substr(0, 1).toUpperCase() + str.substr(1) 10 | 11 | # FIXME not working when scrolled 12 | @offsetPosition: (obj) -> 13 | top = 0 14 | left = 0 15 | 16 | while obj 17 | left += obj.offsetLeft 18 | top += obj.offsetTop 19 | obj = obj.offsetParent 20 | 21 | [left, top] 22 | 23 | @extend = (obj, mixin) -> 24 | for name, method of mixin 25 | obj[name] = method 26 | 27 | @include = (klass, mixin) -> 28 | extend klass.prototype, mixin 29 | 30 | @CanvasLibrary ||= {} 31 | @CanvasLibrary.Utils = Utils 32 | -------------------------------------------------------------------------------- /src/text_field.coffee: -------------------------------------------------------------------------------- 1 | class TextField extends CanvasLibrary.DisplayObject 2 | constructor: -> 3 | @text = '' 4 | @textAlign = 'left' 5 | @strokeStyle = null 6 | @fillStyle = 'rgba(0, 0, 0, 1)' 7 | @fontFace = 'Arial' 8 | @fontSize = 20 9 | @maxWidth = null 10 | super() 11 | 12 | draw: (context, drawHitarea) -> 13 | context.font = @fontSize + 'px ' + @fontFace 14 | context.textBaseline = 'top' 15 | 16 | if drawHitarea 17 | context.beginPath() 18 | context.rect 0, 0, context.measureText(@text).width, @fontSize 19 | context.closePath() 20 | else 21 | context.strokeStyle = @strokeStyle if @strokeStyle 22 | context.fillStyle = @fillStyle if @fillStyle 23 | context.fillText @text, 0, 0 24 | 25 | @CanvasLibrary ||= {} 26 | @CanvasLibrary.TextField = TextField 27 | -------------------------------------------------------------------------------- /src/tween_command.coffee: -------------------------------------------------------------------------------- 1 | class TweenCommand 2 | constructor: (@object, @toParams) -> 3 | @startTime = new Date().getTime() 4 | @duration = 0 5 | @delay = 0 6 | @ease = EaseDefault 7 | @finished = false 8 | @onComplete = null 9 | @startValues = {} 10 | 11 | for property of @toParams 12 | if @object.hasOwnProperty(property) 13 | @startValues[property] = @object[property] 14 | @toParams[property] = @toParams[property] - @object[property] 15 | 16 | update: (updateTime) -> 17 | time = updateTime - @startTime 18 | 19 | if time >= @duration 20 | factor = 1 21 | @finished = true 22 | else 23 | @finished = false 24 | factor = @ease(time, 0, 1, @duration) 25 | 26 | for property of @toParams 27 | @object[property] = @startValues[property] + (factor * @toParams[property]) 28 | 29 | @CanvasLibrary ||= {} 30 | @CanvasLibrary.TweenCommand = TweenCommand 31 | -------------------------------------------------------------------------------- /src/renderer.coffee: -------------------------------------------------------------------------------- 1 | class Renderer 2 | constructor: (stage, fps) -> 3 | @timer = null 4 | @running = false 5 | @frameHandlers = null 6 | @stage = stage 7 | @setFps fps 8 | 9 | setFps: (fps) -> 10 | @interval = 1000 / fps 11 | 12 | run: (fps) -> 13 | @setFps(fps) if fps 14 | @stop() if @running 15 | @running = true 16 | @timer = setInterval(@handleInterval, @interval, this) 17 | 18 | addFrameHandler: (handler) -> 19 | @frameHandlers ||= [] 20 | @frameHandlers.push(handler) if @frameHandlers.indexOf(handler) == -1 21 | this 22 | 23 | handleInterval: (self) -> 24 | if self.frameHandlers 25 | for frameHandler in self.frameHandlers 26 | frameHandler() 27 | 28 | Tween.update() 29 | self.stage.render true 30 | 31 | stop: -> 32 | clearInterval @timer 33 | @running = false 34 | @timer = null 35 | 36 | @CanvasLibrary ||= {} 37 | @CanvasLibrary.Renderer = Renderer 38 | -------------------------------------------------------------------------------- /make: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | coffee -b -p --compile src/utils.coffee > lib/canvas_library.js 3 | coffee -b -p --compile src/display_container_mixin.coffee >> lib/canvas_library.js 4 | coffee -b -p --compile src/display_container.coffee >> lib/canvas_library.js 5 | coffee -b -p --compile src/stage.coffee >> lib/canvas_library.js 6 | coffee -b -p --compile src/display_object.coffee >> lib/canvas_library.js 7 | coffee -b -p --compile src/shape.coffee >> lib/canvas_library.js 8 | coffee -b -p --compile src/sprite.coffee >> lib/canvas_library.js 9 | coffee -b -p --compile src/bitmap.coffee >> lib/canvas_library.js 10 | coffee -b -p --compile src/text_field.coffee >> lib/canvas_library.js 11 | coffee -b -p --compile src/pixel_sprite.coffee >> lib/canvas_library.js 12 | coffee -b -p --compile src/tween.coffee >> lib/canvas_library.js 13 | coffee -b -p --compile src/tween_command.coffee >> lib/canvas_library.js 14 | coffee -b -p --compile src/ease_default.coffee >> lib/canvas_library.js 15 | coffee -b -p --compile src/stacked_loader.coffee >> lib/canvas_library.js 16 | coffee -b -p --compile src/renderer.coffee >> lib/canvas_library.js -------------------------------------------------------------------------------- /src/display_container_mixin.coffee: -------------------------------------------------------------------------------- 1 | class DisplayContainerMixin 2 | @addChild: (child) -> 3 | child.parent.removeChild(child) if child.parent 4 | 5 | @stage.childrenChanged = true if @stage 6 | @determineAncestors child 7 | child.stage = @stage 8 | child.translatedObjects = [child].concat(child.ancestors).reverse() 9 | @children.push child 10 | this 11 | 12 | @removeChild: (child) -> 13 | i = @children.indexOf(child) 14 | 15 | if i == -1 16 | throw 'Child object not found in DisplayList' 17 | else 18 | @stage.childrenChanged = true if @stage 19 | @children.splice i, 1 20 | child.parent = null 21 | child.ancestors = null 22 | child.translatedObjects = null 23 | this 24 | 25 | @determineAncestors: (child) -> 26 | child.parent = this 27 | child.ancestors = [] 28 | 29 | theParent = this 30 | 31 | while theParent 32 | child.ancestors.push theParent 33 | theParent = theParent.parent 34 | 35 | true 36 | 37 | @CanvasLibrary ||= {} 38 | @CanvasLibrary.DisplayContainerMixin = DisplayContainerMixin 39 | -------------------------------------------------------------------------------- /src/tween.coffee: -------------------------------------------------------------------------------- 1 | class Tween 2 | @tweens = [] 3 | 4 | @initTime = new Date().getTime() 5 | 6 | @to: (object, duration, toParams, options) -> 7 | tween = new TweenCommand(object, toParams) 8 | tween.duration = duration 9 | 10 | if options 11 | tween.onComplete = options.onComplete 12 | tween.delay = options.delay || 0 13 | tween.ease = options.ease || EaseDefault 14 | 15 | tween.finished = false 16 | @tweens.push tween 17 | 18 | @kill: (object) -> 19 | i = 0 20 | 21 | while i < @tweens.length 22 | if @tweens[i].object == object 23 | @tweens[i] = null 24 | @tweens.splice i, 1 25 | i = -1 26 | 27 | i++ 28 | 29 | @update: -> 30 | if @tweens.length > 0 31 | i = 0 32 | cleanup = false 33 | time = new Date().getTime() 34 | 35 | for tween in @tweens 36 | tween.update time 37 | 38 | if tween.finished 39 | cleanup = true 40 | tween = null 41 | 42 | @cleanup() if cleanup 43 | 44 | @cleanup: -> 45 | i = 0 46 | 47 | while i < @tweens.length 48 | if !@tweens[i] 49 | @tweens.splice i, 1 50 | i = -1 51 | 52 | i++ 53 | 54 | @CanvasLibrary ||= {} 55 | @CanvasLibrary.Tween = Tween 56 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2010-2011 Diederick Lawson. All rights reserved. 2 | 3 | Redistribution and use in source and binary forms, with or without modification, are 4 | permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, this list of 7 | conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright notice, this list 10 | of conditions and the following disclaimer in the documentation and/or other materials 11 | provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY DIEDERICK LAWSON "AS IS" AND ANY EXPRESS OR IMPLIED 14 | WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 15 | FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DIEDERICK LAWSON OR 16 | CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 17 | CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 18 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 19 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 20 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 21 | ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 | 23 | The views and conclusions contained in the software and documentation are those of the 24 | authors and should not be interpreted as representing official policies, either expressed 25 | or implied, of Diederick Lawson. 26 | 27 | @author D. Lawson -------------------------------------------------------------------------------- /src/pixel_sprite.coffee: -------------------------------------------------------------------------------- 1 | class PixelSprite extends CanvasLibrary.Shape 2 | @defaultColorPalette: [ 'rgba(0, 0, 0, 1)', 3 | 'rgba(170, 0, 0, 1)', 4 | 'rgba(0, 170, 0, 1)', 5 | 'rgba(170, 85, 0, 1)', 6 | 'rgba(0, 0, 170, 1)', 7 | 'rgba(170, 0, 170, 1)', 8 | 'rgba(0, 170, 170, 1)', 9 | 'rgba(170, 170, 170, 1)', 10 | 'rgba(85, 85, 85, 1)', 11 | 'rgba(255, 85, 85, 1)', 12 | 'rgba(82, 255, 85, 1)', 13 | 'rgba(255, 255, 85, 1)', 14 | 'rgba(85, 85, 255, 1)', 15 | 'rgba(255, 85, 255, 1)', 16 | 'rgba(85, 255, 255, 1)', 17 | 'rgba(255, 255, 255, 1)' ] 18 | 19 | constructor: (map) -> 20 | super() 21 | @pixels = [] 22 | @colorPalette = PixelSprite.defaultColorPalette 23 | @pixelSize = 4 24 | @drawPixelMap(map) if map 25 | 26 | drawPixelMap: (map) -> 27 | x = 0 28 | y = 0 29 | 30 | rows = map.split("\n") 31 | 32 | for row in rows 33 | columns = row.split('') 34 | x = 0 35 | 36 | for column in columns 37 | color = column.charCodeAt(0) 38 | @drawPixel(x, y, @colorPalette[color]) if @colorPalette[color] 39 | x++ 40 | y++ 41 | 42 | @submitPixels() 43 | 44 | drawPixel: (x, y, color) -> 45 | @pixels[y] = [] if !@pixels[y] 46 | @pixels[y][x] = color 47 | 48 | removePixel: (x, y) -> 49 | @pixels[y][x] = null 50 | 51 | submitPixels: -> 52 | x = 0 53 | y = 0 54 | 55 | for row in @pixels 56 | x = 0 57 | if row 58 | for column in row 59 | @fillRect(x * @pixelSize, y * @pixelSize, @pixelSize, @pixelSize, column) if column 60 | x++ 61 | y++ 62 | 63 | @CanvasLibrary ||= {} 64 | @CanvasLibrary.PixelSprite = CanvasLibrary.PixelSprite 65 | -------------------------------------------------------------------------------- /src/stacked_loader.coffee: -------------------------------------------------------------------------------- 1 | class StackedLoader 2 | @stack: {} 3 | @loadStack: [] 4 | @toLoad: null 5 | @onCompleteHandlers: [] 6 | @loading: false 7 | 8 | @add: (id, type, url) -> 9 | @remove(id) if @stack[id] 10 | @loadStack.push type: type, url: url, id: id 11 | 12 | @load: (onCompleteHandler) -> 13 | @onCompleteHandlers.push(onCompleteHandler) if onCompleteHandler? 14 | 15 | unless @loading 16 | @loading = true 17 | @loadNext() 18 | 19 | @get: (id) -> 20 | @stack[id] 21 | 22 | @getClonedBitmap: (id) -> 23 | new Bitmap(@stack[@toLoad.id]) 24 | 25 | @loadNext: -> 26 | if @loadStack.length == 0 27 | for onCompleteHandler in @onCompleteHandlers 28 | onCompleteHandler() 29 | 30 | @onCompleteHandlers = [] 31 | @loading = false 32 | else 33 | @toLoad = @loadStack[0] 34 | @['load' + Utils.firstUpcase(@toLoad.type)]() 35 | 36 | 37 | @loadString: -> 38 | @stack[@toLoad.id] = new XMLHttpRequest() 39 | @stack[@toLoad.id].onreadystatechange = => 40 | if @stack[@toLoad.id].readyState == 4 && @stack[@toLoad.id].status == 200 41 | @['handle' + Utils.firstUpcase(@toLoad.type) + 'LoadComplete']() 42 | 43 | @stack[@toLoad.id].open 'GET', @toLoad.url, true 44 | @stack[@toLoad.id].send null 45 | 46 | @loadBitmap: -> 47 | @stack[@toLoad.id] = new Image() 48 | @stack[@toLoad.id].onload = => @handleBitmapLoadComplete() 49 | @stack[@toLoad.id].src = @toLoad.url 50 | 51 | @loadSprite: -> 52 | @loadString() 53 | 54 | @loadAudio: -> 55 | @stack[@toLoad.id] = new Audio() 56 | @stack[@toLoad.id].src = @toLoad.url 57 | @handleAssetLoadComplete() 58 | 59 | @handleBitmapLoadComplete: -> 60 | @stack[@toLoad.id].onload = null 61 | @stack[@toLoad.id] = new Bitmap(@stack[@toLoad.id]) 62 | @stack[@toLoad.id].id = @toLoad.id 63 | 64 | @handleAssetLoadComplete() 65 | 66 | @handleStringLoadComplete: -> 67 | @stack[@toLoad.id].onreadystatechange = null 68 | @stack[@toLoad.id] = @stack[@toLoad.id].responseText 69 | @handleAssetLoadComplete 70 | 71 | @handleSpriteLoadComplete: -> 72 | @stack[@toLoad.id].onreadystatechange = null 73 | @stack[@toLoad.id] = new PixelSprite(@stack[@toLoad.id].responseText) 74 | @handleAssetLoadComplete 75 | 76 | @handleAssetLoadComplete: -> 77 | @loadStack.splice 0, 1 78 | @loadNext() 79 | 80 | @CanvasLibrary ||= {} 81 | @CanvasLibrary.StackedLoader = StackedLoader 82 | -------------------------------------------------------------------------------- /src/display_object.coffee: -------------------------------------------------------------------------------- 1 | class DisplayObject 2 | constructor: -> 3 | @id = '' 4 | 5 | @x = 0 6 | @y = 0 7 | @oldX = null 8 | @oldY = null 9 | @calculatedX = 0 10 | @calculatedY = 0 11 | 12 | @width = 0 13 | @height = 0 14 | 15 | @alpha = 1 16 | @oldAlpha = 1 17 | @calculatedAlpha = 1 18 | 19 | @scaleX = 1 20 | @scaleY = 1 21 | @oldScaleX = null 22 | @oldScaleY = null 23 | @calculatedScaleX = 1 24 | @calculatedScaleY = 1 25 | 26 | @rotation = 0 27 | @oldRotation = null 28 | @calculatedRotation = 0 29 | 30 | @enabled = true 31 | 32 | @visible = true 33 | @oldVisible = null 34 | @calculatedVisibility = true 35 | 36 | @mouseEnabled = false 37 | @mouseDown = false 38 | @useHandCursor = false 39 | 40 | @shadow = false 41 | @shadowBlur = 0 42 | @shadowColor = 0 43 | @shadowOffsetX = 0 44 | @shadowOffsetY = 0 45 | 46 | @onMouseOver = null 47 | @onMouseOut = null 48 | @onMouseDown = null 49 | @onMouseMove = null 50 | @localX = 0 51 | @localY = 0 52 | 53 | @isMouseSetup = false 54 | @mouseDown = false 55 | @lastObjectUnderCursor = null 56 | @stage = null 57 | @parent = null 58 | @ancestors = null 59 | @translatedObjects = null 60 | @childrenChanged = false 61 | 62 | draw: (context, drawHitarea) -> 63 | # do nothing 64 | 65 | calculateCanvasPositions: -> 66 | if @positionChanged() 67 | @oldX = @x 68 | @oldY = @y 69 | @oldVisible = @visible 70 | @oldAlpha = @alpha 71 | 72 | newVars = @getInheritedTranslatedVars() 73 | 74 | @calculatedX = newVars[0] 75 | @calculatedY = newVars[1] 76 | @calculatedVisibility = newVars[2] 77 | @calculatedAlpha = newVars[3] 78 | 79 | getInheritedTranslatedVars: -> 80 | theParent = this 81 | translatedX = 0 82 | translatedY = 0 83 | translatedVisibility = true 84 | translatedAlpha = 1 85 | 86 | while theParent 87 | translatedX += theParent.x 88 | translatedY += theParent.y 89 | translatedVisibility = false if !theParent.visible 90 | translatedAlpha *= theParent.alpha 91 | 92 | theParent = theParent.parent 93 | 94 | [translatedX, translatedY, translatedVisibility, translatedAlpha] 95 | 96 | positionChanged: -> 97 | @x != @oldX || @y != @oldY || @rotation != @oldRotation || @scaleX != @oldScaleX || @scaleY != @oldScaleY || @visible != @old || @ancestorsPositionChanged() 98 | 99 | ancestorsPositionChanged: -> 100 | for ancestor in @ancestors 101 | return true if ancestor.positionChanged() 102 | false 103 | 104 | @CanvasLibrary ||= {} 105 | @CanvasLibrary.DisplayObject = DisplayObject 106 | -------------------------------------------------------------------------------- /demos/demo.coffee: -------------------------------------------------------------------------------- 1 | run = -> 2 | # this is the screen 3 | stage = new CanvasLibrary.Stage('test_canvas') 4 | 5 | logo = null 6 | 7 | # create a rectangle 8 | someShape = new CanvasLibrary.Shape() 9 | someShape.id = "someShape" 10 | someShape.x = 0 11 | someShape.y = 0 12 | 13 | someShape.fillStyle 'rgba(0, 0, 0, 1)' 14 | someShape.fillRect 0, 0, 50, 50 15 | 16 | # create another rectangle 17 | otherShape = new CanvasLibrary.Shape() 18 | otherShape.id = "otherShape" 19 | otherShape.alpha = .5 20 | otherShape.fillStyle 'rgba(255, 0, 0, 1)' 21 | otherShape.fillRect 0, 0, 25, 25 22 | otherShape.x = 10 23 | otherShape.y = 10 24 | otherShape.scaleX = 1 25 | otherShape.scaleY = 1 26 | otherShape.mouseEnabled = true 27 | 28 | otherShape.onMouseOver = => 29 | Tween.to otherShape, 500, { scaleX: 2, scaleY: 2 } 30 | 31 | otherShape.onMouseOut = => 32 | Tween.to otherShape, 500, { scaleX: 1, scaleY: 1 } 33 | 34 | # make this shape follow the mouse 35 | mouseShape = new CanvasLibrary.Shape() 36 | mouseShape.id = "mouseShape" 37 | mouseShape.beginPath() 38 | mouseShape.fillStyle 'rgba(255, 0, 0, 1)' 39 | mouseShape.circle 0, 0, 10 40 | mouseShape.closePath() 41 | mouseShape.fill() 42 | 43 | mouseShape.x = 300 44 | mouseShape.y = 300 45 | 46 | stage.onMouseMove = => 47 | mouseShape.x = stage.mouseX 48 | mouseShape.y = stage.mouseY 49 | 50 | # some text 51 | text = new CanvasLibrary.TextField() 52 | text.id = "text" 53 | text.mouseEnabled = true 54 | text.useHandCursor = true 55 | text.text = "canvas_library demo" 56 | text.x = 10 57 | text.y = 450 58 | 59 | text.onMouseOver = => 60 | text.fillStyle = 'rgba(255, 0, 0, 1)' 61 | 62 | text.onMouseOut = => 63 | text.fillStyle = 'rgba(0, 0, 0, 1)' 64 | 65 | stage.onMouseUp = => 66 | if logo 67 | Tween.kill logo 68 | Tween.to logo, 500, { x: stage.mouseX, y: stage.mouseY } 69 | 70 | moreShapes = new CanvasLibrary.Sprite() 71 | moreShapes.x = 0 72 | moreShapes.y = 0 73 | 74 | moreShape1 = new CanvasLibrary.Shape() 75 | moreShape1.id = "moreShape1" 76 | moreShape1.fillStyle 'rgba(0, 255, 0, 1)' 77 | moreShape1.fillRect 0, 0, 50, 50 78 | 79 | moreShape2 = new CanvasLibrary.Shape() 80 | moreShape2.x = 10 81 | moreShape2.y = 10 82 | moreShape2.fillStyle 'rgba(0, 255, 255, 1)' 83 | moreShape2.fillRect 0, 0, 50, 50 84 | 85 | stage.addChild someShape 86 | stage.addChild otherShape 87 | stage.addChild mouseShape 88 | stage.addChild text 89 | stage.addChild moreShapes 90 | 91 | moreShapes.addChild moreShape1 92 | moreShapes.addChild moreShape2 93 | 94 | Tween.to moreShapes, 5000, { x: 500, y: 10, rotation: 45 } 95 | 96 | # load an external bitmap 97 | StackedLoader.add 'logo', 'bitmap', 'logo.png' 98 | 99 | StackedLoader.load -> 100 | logo = StackedLoader.get('logo') 101 | stage.addChild logo 102 | 103 | logo.alpha = 0 104 | Tween.to logo, 10000, { alpha: 1 } 105 | 106 | # setup renderer and connect it to the stage and run at 25 fps 107 | renderer = new CanvasLibrary.Renderer(stage, 25) 108 | renderer.run() 109 | 110 | # tween some stuff 111 | Tween.to someShape, 5000, { x: 100, y: 100 } 112 | Tween.to otherShape, 20000, { rotation: 180, x: 320, y: 200, alpha: 1, scaleX: 1, scaleY: 1 } 113 | 114 | window.onload = run 115 | -------------------------------------------------------------------------------- /demos/demo.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var run; 3 | 4 | run = function() { 5 | var logo, moreShape1, moreShape2, moreShapes, mouseShape, otherShape, renderer, someShape, stage, text; 6 | var _this = this; 7 | stage = new CanvasLibrary.Stage('test_canvas'); 8 | logo = null; 9 | someShape = new CanvasLibrary.Shape(); 10 | someShape.id = "someShape"; 11 | someShape.x = 0; 12 | someShape.y = 0; 13 | someShape.fillStyle('rgba(0, 0, 0, 1)'); 14 | someShape.fillRect(0, 0, 50, 50); 15 | otherShape = new CanvasLibrary.Shape(); 16 | otherShape.id = "otherShape"; 17 | otherShape.alpha = .5; 18 | otherShape.fillStyle('rgba(255, 0, 0, 1)'); 19 | otherShape.fillRect(0, 0, 25, 25); 20 | otherShape.x = 10; 21 | otherShape.y = 10; 22 | otherShape.scaleX = 1; 23 | otherShape.scaleY = 1; 24 | otherShape.mouseEnabled = true; 25 | otherShape.onMouseOver = function() { 26 | return Tween.to(otherShape, 500, { 27 | scaleX: 2, 28 | scaleY: 2 29 | }); 30 | }; 31 | otherShape.onMouseOut = function() { 32 | return Tween.to(otherShape, 500, { 33 | scaleX: 1, 34 | scaleY: 1 35 | }); 36 | }; 37 | mouseShape = new CanvasLibrary.Shape(); 38 | mouseShape.id = "mouseShape"; 39 | mouseShape.beginPath(); 40 | mouseShape.fillStyle('rgba(255, 0, 0, 1)'); 41 | mouseShape.circle(0, 0, 10); 42 | mouseShape.closePath(); 43 | mouseShape.fill(); 44 | mouseShape.x = 300; 45 | mouseShape.y = 300; 46 | stage.onMouseMove = function() { 47 | mouseShape.x = stage.mouseX; 48 | return mouseShape.y = stage.mouseY; 49 | }; 50 | text = new CanvasLibrary.TextField(); 51 | text.id = "text"; 52 | text.mouseEnabled = true; 53 | text.useHandCursor = true; 54 | text.text = "canvas_library demo"; 55 | text.x = 10; 56 | text.y = 450; 57 | text.onMouseOver = function() { 58 | return text.fillStyle = 'rgba(255, 0, 0, 1)'; 59 | }; 60 | text.onMouseOut = function() { 61 | return text.fillStyle = 'rgba(0, 0, 0, 1)'; 62 | }; 63 | stage.onMouseUp = function() { 64 | if (logo) { 65 | Tween.kill(logo); 66 | return Tween.to(logo, 500, { 67 | x: stage.mouseX, 68 | y: stage.mouseY 69 | }); 70 | } 71 | }; 72 | moreShapes = new CanvasLibrary.Sprite(); 73 | moreShapes.x = 0; 74 | moreShapes.y = 0; 75 | moreShape1 = new CanvasLibrary.Shape(); 76 | moreShape1.id = "moreShape1"; 77 | moreShape1.fillStyle('rgba(0, 255, 0, 1)'); 78 | moreShape1.fillRect(0, 0, 50, 50); 79 | moreShape2 = new CanvasLibrary.Shape(); 80 | moreShape2.x = 10; 81 | moreShape2.y = 10; 82 | moreShape2.fillStyle('rgba(0, 255, 255, 1)'); 83 | moreShape2.fillRect(0, 0, 50, 50); 84 | stage.addChild(someShape); 85 | stage.addChild(otherShape); 86 | stage.addChild(mouseShape); 87 | stage.addChild(text); 88 | stage.addChild(moreShapes); 89 | moreShapes.addChild(moreShape1); 90 | moreShapes.addChild(moreShape2); 91 | Tween.to(moreShapes, 5000, { 92 | x: 500, 93 | y: 10, 94 | rotation: 45 95 | }); 96 | StackedLoader.add('logo', 'bitmap', 'logo.png'); 97 | StackedLoader.load(function() { 98 | logo = StackedLoader.get('logo'); 99 | stage.addChild(logo); 100 | logo.alpha = 0; 101 | return Tween.to(logo, 10000, { 102 | alpha: 1 103 | }); 104 | }); 105 | renderer = new CanvasLibrary.Renderer(stage, 25); 106 | renderer.run(); 107 | Tween.to(someShape, 5000, { 108 | x: 100, 109 | y: 100 110 | }); 111 | return Tween.to(otherShape, 20000, { 112 | rotation: 180, 113 | x: 320, 114 | y: 200, 115 | alpha: 1, 116 | scaleX: 1, 117 | scaleY: 1 118 | }); 119 | }; 120 | 121 | window.onload = run; 122 | 123 | }).call(this); 124 | -------------------------------------------------------------------------------- /src/shape.coffee: -------------------------------------------------------------------------------- 1 | class Shape extends CanvasLibrary.DisplayObject 2 | constructor: -> 3 | super() 4 | @madeChanges = false 5 | @drawingCommands = [] 6 | 7 | clear: -> 8 | @madeChanges = true 9 | @drawingCommands = [] 10 | true 11 | 12 | addColorStops: (gradient, colorStops) -> 13 | for colorStop in colorStops 14 | gradient.addColorStop colorStop[0], colorStop[1] 15 | 16 | gradient 17 | 18 | createRadialGradient: (x1, y1, r1, x2, y2, r2, colorStops) -> 19 | gradient = @stage.backBufferContext.createRadialGradient(x1, y1, r1, x2, y2, r2) 20 | @addColorStops gradient, colorStops 21 | gradient 22 | 23 | createLinearGradient: (x1, y1, x2, y2, colorStops) -> 24 | gradient = @stage.backBufferContext.createLinearGradient(x1, y1, x2, y2) 25 | @addColorStops gradient, colorStops 26 | gradient 27 | 28 | setRadialGradient: (x1, y1, r1, x2, y2, r2, colorStops) -> 29 | @fillStyle @createRadialGradient(x1, y1, r1, x2, y2, r2, colorStops) 30 | this 31 | 32 | setLinearGradient: (x1, y1, x2, y2, colorStops) -> 33 | @fillStyle @createLinearGradient(x1, y1, x2, y2, colorStops) 34 | this 35 | 36 | moveTo: (x, y) -> 37 | @drawingCommands.push [true, 'moveTo', x, y] 38 | this 39 | 40 | lineWidth: (thickness) -> 41 | @drawingCommands.push [true, 'lineWidth', thickness] 42 | this 43 | 44 | lineCap: (cap) -> 45 | @drawingCommands.push [true, 'lineCap', cap] 46 | true 47 | 48 | lineTo: (x,y) -> 49 | @madeChanges = true 50 | @drawingCommands.push [true, 'lineTo', x, y] 51 | this 52 | 53 | bezierCurveTo: (cp1x, cp1y, cp2x, cp2y, x, y) -> 54 | @madeChanges = true 55 | @drawingCommands.push [true, 'bezierCurveTo', cp1x, cp1y, cp2x, cp2y, x, y] 56 | this 57 | 58 | quadraticCurveTo: (cpx, cpy, x, y) -> 59 | @madeChanges = true 60 | @drawingCommands.push [true, 'quadraticCurveTo', cpx, cpy, x, y] 61 | this 62 | 63 | miterLimit: (ratio) -> 64 | @drawingCommands.push [true, 'miterLimit', ratio] 65 | this 66 | 67 | beginPath: -> 68 | @drawingCommands.push [false, 'beginPath'] 69 | this 70 | 71 | closePath: -> 72 | @drawingCommands.push [false, 'closePath'] 73 | this 74 | 75 | fillRect: (x, y, width, height, color) -> 76 | @madeChanges = true 77 | @fillStyle(color) if color 78 | 79 | @drawingCommands.push [true, 'rect', x, y, width, height] 80 | @drawingCommands.push [false, 'fillRect', x, y, width, height] 81 | this 82 | 83 | circle: (x, y, radius) -> 84 | @arc x, y, radius / 2, 0, Math.PI * 2, true 85 | this 86 | 87 | arc: (x, y, r, sr, er, cw) -> 88 | @madeChanges = true 89 | @drawingCommands.push [true, 'arc', x, y, r, sr, er, cw] 90 | this 91 | 92 | strokeRect: (x, y, width, height, color) -> 93 | @madeChanges = true 94 | @drawingCommands.push [true, 'rect', x, y, width, height] 95 | @drawingCommands.push [false, 'strokeRect', x, y, width, height] 96 | this 97 | 98 | clearRect: (x, y, width, height) -> 99 | @madeChanges = true 100 | @drawingCommands.push [true, 'clearRect', x, y, width, height] 101 | 102 | fillStyle: (color) -> 103 | @drawingCommands.push [false, 'fillStyle=', color] 104 | this 105 | 106 | strokeStyle: (color) -> 107 | @drawingCommands.push [false, 'strokeStyle=', color] 108 | this 109 | 110 | globalAlpha: (alpha) -> 111 | @madeChanges = true 112 | @drawingCommands.push [false, 'globalAlpha=', alpha] 113 | this 114 | 115 | fill: -> 116 | @madeChanges = true 117 | @drawingCommands.push [false, 'fill'] 118 | this 119 | 120 | draw: (context, drawHitarea) -> 121 | for command in @drawingCommands 122 | instruction = command[1] 123 | 124 | if !drawHitarea || (drawHitarea && command[0]) 125 | if instruction.substr(-1, 1) == '=' && command.length == 3 126 | context[instruction.substr(0, instruction.length - 1)] = command[2] 127 | 128 | else if command.length > 2 129 | context[instruction].apply context, command.slice(2) 130 | 131 | else if command.length == 2 132 | context[instruction]() 133 | 134 | @madeChanges = false 135 | 136 | @CanvasLibrary ||= {} 137 | @CanvasLibrary.Shape = Shape 138 | -------------------------------------------------------------------------------- /src/stage.coffee: -------------------------------------------------------------------------------- 1 | class Stage 2 | constructor: (@canvasId) -> 3 | @stage = this 4 | @children = [] 5 | @scaleX = 1 6 | @scaleY = 1 7 | @rotation = 0 8 | @visible = true 9 | @x = 0 10 | @y = 0 11 | @alpha = 1 12 | @mouseX = 0 13 | @mouseY = 0 14 | @parent = null 15 | @isMouseSetup = false 16 | @oldMouseX = 0 17 | @oldMouseY = 0 18 | @children = [] 19 | @canvas = document.getElementById(@canvasId) 20 | @context = @canvas.getContext('2d') 21 | @hitBufferCanvas = @cloneCanvas() 22 | @hitBufferContext = @hitBufferCanvas.getContext('2d') 23 | @childrenChanged = false 24 | @allChildren = [] 25 | @canvasOffsetPosition = Utils.offsetPosition(@canvas) 26 | 27 | window.onresize = => @handleWindowResize() 28 | 29 | cloneCanvas: -> 30 | canvas = document.createElement('canvas') 31 | canvas.width = @canvas.width 32 | canvas.height = @canvas.height 33 | canvas 34 | 35 | render: (clear) -> 36 | @setupMouse() 37 | @context.clearRect 0, 0, @canvas.width, @canvas.height 38 | 39 | if @childrenChanged 40 | @findAllChildren() 41 | @childrenChanged = false 42 | 43 | @drawAllChildren() 44 | @handleMouseEventsOfAllChildren() 45 | 46 | setupContext: (context, child) -> 47 | context.globalAlpha = child.calculatedAlpha 48 | 49 | for object in child.translatedObjects 50 | context.translate object.x, object.y 51 | context.rotate Utils.angleToRadians(object.rotation) 52 | context.scale object.scaleX, object.scaleY 53 | 54 | if child.shadow 55 | context.shadowBlur = child.shadowBlur 56 | context.shadowColor = child.shadowColor 57 | context.shadowOffsetX = child.shadowOffsetX 58 | context.shadowOffsetY = child.shadowOffsetY 59 | 60 | drawAllChildren: -> 61 | for child in @allChildren 62 | child.calculateCanvasPositions() 63 | 64 | if child.calculatedVisibility 65 | @context.save() 66 | @setupContext @context, child 67 | child.draw @context 68 | @context.restore() 69 | 70 | # FIXME Not working properly. Every object now is placed under cursor. 71 | getObjectUnderCursor: -> 72 | i = @allChildren.length - 1 73 | 74 | while i >= 0 75 | child = @allChildren[i] 76 | 77 | if child.calculatedVisibility && child.mouseEnabled 78 | @hitBufferContext.clearRect 0, 0, @canvas.width, @canvas.height 79 | @hitBufferContext.save() 80 | 81 | @setupContext @hitBufferContext, child 82 | @hitBufferContext.beginPath() 83 | 84 | child.draw @hitBufferContext, true 85 | 86 | @hitBufferContext.closePath() 87 | 88 | child.localX = @mouseX - child.calculatedX 89 | child.localY = @mouseY - child.calculatedY 90 | 91 | @hitBufferContext.restore() 92 | 93 | if @hitBufferContext.isPointInPath(@mouseX, @mouseY) 94 | return child 95 | 96 | i-- 97 | 98 | null 99 | 100 | findAllChildren: -> 101 | @allChildren = [] 102 | @getChildren this, @allChildren 103 | 104 | getChildren: (fromParent, collectedChildren) -> 105 | for child in fromParent.children 106 | collectedChildren.push child 107 | @getChildren(child, collectedChildren) if child.children? && child.children.length > 0 108 | 109 | collectedChildren 110 | 111 | setupMouse: -> 112 | unless @isMouseSetup 113 | @isMouseSetup = true 114 | @canvas.addEventListener 'mousemove', ((event) => @handleCanvasMouseMove(event)), false 115 | @canvas.addEventListener 'mousedown', ((event) => @handleCanvasMouseDown(event)), false 116 | @canvas.addEventListener 'mouseup', ((event) => @handleCanvasMouseUp(event)), false 117 | 118 | handleCanvasMouseMove: (event) -> 119 | @oldMouseX = @mouseX 120 | @oldMouseY = @mouseY 121 | @mouseX = event.clientX - @canvasOffsetPosition[0] 122 | @mouseY = event.clientY - @canvasOffsetPosition[1] 123 | @onMouseMove() if @onMouseMove 124 | 125 | handleCanvasMouseDown: (event) -> 126 | @onMouseDown() if @onMouseDown && !@mouseDown 127 | @mouseDown = true 128 | 129 | handleCanvasMouseUp: (event) -> 130 | @onMouseUp() if @onMouseUp && @mouseDown 131 | @mouseDown = false 132 | 133 | mouseHasMoved: -> 134 | (@oldMouseX != @mouseX || @oldMouseY != @mouseY) 135 | 136 | setHandCursor: (showHand) -> 137 | @canvas.style.cursor = showHand ? 'pointer' : '' 138 | 139 | # FIXME/TODO not working properly 140 | handleMouseEventsOfAllChildren: -> 141 | objectUnderCursor = @getObjectUnderCursor() 142 | 143 | if @lastObjectUnderCursor != objectUnderCursor 144 | if @lastObjectUnderCursor 145 | @lastObjectUnderCursor.onMouseOut() if @lastObjectUnderCursor.onMouseOut 146 | 147 | if @lastObjectUnderCursor.useHandCursor 148 | @setHandCursor false 149 | 150 | if objectUnderCursor 151 | objectUnderCursor.onMouseOver() if objectUnderCursor.onMouseOver 152 | 153 | if objectUnderCursor.onMouseDown && !objectUnderCursor.mouseDown 154 | objectUnderCursor.mouseDown = true 155 | objectUnderCursor.onMouseDown() 156 | 157 | if objectUnderCursor.onMouseUp && objectUnderCursor.mouseDown 158 | objectUnderCursor.mouseDown = false 159 | objectUnderCursor.onMouseUp() 160 | 161 | @setHandCursor objectUnderCursor.useHandCursor 162 | 163 | else if objectUnderCursor && @mouseHasMoved() && objectUnderCursor.onMouseMove 164 | objectUnderCursor.onMouseMove() 165 | 166 | @lastObjectUnderCursor = objectUnderCursor 167 | 168 | handleWindowResize: -> 169 | @canvasOffsetPosition = Utils.offsetPosition(@canvas) 170 | 171 | positionChanged: -> 172 | false 173 | 174 | include Stage, CanvasLibrary.DisplayContainerMixin 175 | 176 | @CanvasLibrary ||= {} 177 | @CanvasLibrary.Stage = Stage 178 | -------------------------------------------------------------------------------- /README.rdoc: -------------------------------------------------------------------------------- 1 | = HTML Canvas Javascript Library 2 | 3 | == About canvas_library 4 | 5 | canvas_library is written in CoffeeScript. 6 | canvas_library gives you easy drawing, object and animation management for the HTML 5 Canvas element. The API itself looks a lot like the Flash drawing API. 7 | 8 | == Getting started 9 | 10 | A very simple demo: 11 | 12 | HTML: 13 | 14 | 15 | Coffeescript: 16 | run = -> 17 | # this is the screen 18 | stage = new CanvasLibrary.Stage('test_canvas') 19 | 20 | # create a rectangle 21 | someShape = new CanvasLibrary.Shape() 22 | someShape.x = 0 23 | someShape.y = 0 24 | 25 | someShape.fillStyle 'rgba(0, 0, 0, 1)' 26 | someShape.fillRect 0, 0, 50, 50 27 | 28 | # create another rectangle 29 | otherShape = new CanvasLibrary.Shape() 30 | otherShape.alpha = .5 31 | otherShape.fillStyle 'rgba(255, 0, 0, 1)' 32 | otherShape.fillRect 0, 0, 25, 25 33 | otherShape.x = 10 34 | otherShape.y = 10 35 | otherShape.scaleX = 1 36 | otherShape.scaleY = 1 37 | 38 | stage.addChild someShape 39 | stage.addChild otherShape 40 | 41 | # setup renderer and connect it to the stage and run at 25 fps 42 | renderer = new CanvasLibrary.Renderer(stage, 25) 43 | renderer.run() 44 | 45 | # tween some stuff 46 | Tween.to someShape, 5000, { x: 100, y: 100 } 47 | Tween.to otherShape, 20000, { rotation: 180, x: 320, y: 200, alpha: 1, scaleX: 1, scaleY: 1 } 48 | 49 | window.onload = run 50 | 51 | == About DisplayContainer's 52 | 53 | A DisplayContainer is an object that can hold other graphical objects. These graphical objects can be nested in eachother. Just like
's in
's. 54 | 55 | The +x+ and +y+ position of graphical objects are relative and are translated to canvas +x+ and +y+ positions during the rendering process. This rendering process can be triggered by calling the +draw+ function on any displaycontainer. 56 | 57 | Nesting objects: 58 | obj = new CanvasLibrary.Shape() 59 | obj.x = 10 60 | obj.y = 10 61 | 62 | otherObj = new CanvasLibrary.Shape() 63 | otherObj.x = 0 64 | otherObj.y = 0 65 | 66 | obj.addChild otherObj 67 | 68 | yetAnotherObj = new CanvasLibrary.Shape() 69 | yetAnotherObj.x = 0 70 | yetAnotherObj.y = 0 71 | 72 | otherObj.addChild yetAnotherObj 73 | 74 | stage.render 75 | 76 | Note: The stage is the main screen. This object also acts as an DisplayContainer. 77 | 78 | == Drawing shapes 79 | 80 | The drawing API is almost the same as the Canvas drawing API. If you want to draw paths to the canvas, use the +Shape+ class. 81 | 82 | Drawing rectangles: 83 | stage = new CanvasLibrary.Stage("the_screen"); 84 | 85 | rect = new CanvasLibrary.Shape() 86 | rect.x = 0 87 | rect.y = 0 88 | rect.fillStyle "rgb(255, 0, 0, 1)" 89 | rect.fillRect 0, 0, 25, 25 90 | 91 | rect.fillStyle "rgb(0, 255, 0, 0.5)" 92 | rect.fillRect 10, 10, 25, 25 93 | 94 | stage.addChild rect 95 | stage.render 96 | 97 | == Loading and drawing bitmaps 98 | 99 | Bitmaps can easily be loaded with the +canavaslib.StackedLoader+ class. The +StackedLoader+ manages all your assets so you can preload images or audio assets before rendering all your stuff. 100 | screen = new CanvasLibrary.Stage("the_screen") 101 | 102 | CanvasLibrary.StackedLoader.add "image_id", "image", "logo.png" 103 | CanvasLibrary.StackedLoader.add "another_image", "image", "foo.png" 104 | CanvasLibrary.StackedLoader.add "and_another_one", "image", "bar.png" 105 | 106 | CanvasLibrary.StackedLoader.load => 107 | bitmap = CanvasLibrary.StackedLoader.get "image_id" 108 | 109 | screen.addChild bitmap 110 | screen.render 111 | 112 | The +load+ function adds an asset to the loadstack. The +start+ function triggers the StackedLoader to load all assets that are placed in the load stack. 113 | 114 | == Animating objects 115 | 116 | You can use the +Tween+ class to tween objects between two points. 117 | 118 | ... 119 | renderer = new CanvasLibrary.Renderer(stage); 120 | renderer.run 25 121 | 122 | ... 123 | Tween.to someShape, 5000, { x: 100, y: 100 } 124 | 125 | The above example will tween the +x+ & +y+ property of object +someShape+ to coordinate 100 in 5 secs. 126 | 127 | Note: to use the tween engine, you'll need to set up a renderer with +Renderer+ or call the +Tween+ +update+ method yourself: 128 | 129 | Tween.update() 130 | 131 | == Mouse interaction 132 | 133 | You have a couple of mouse events to your disposal: 134 | * onMouseOver 135 | * onMouseOut 136 | 137 | Example of tween and mouse interaction: 138 | shape.onMouseOver = => 139 | Tween.to shape, 500, { alpha: .5 } 140 | 141 | shape.onMouseOut = => 142 | Tween.to shape, 500, { alpha: 1 } 143 | 144 | == Pixel fun 145 | 146 | pixels = new CanvasLibrary.PixelSprite() 147 | pixels.drawPixel 0, 0, 'rgba(128, 128, 128, 1)' 148 | pixels.drawPixel 1, 0, 'rgba(128, 128, 128, 1)' 149 | pixels.drawPixel 2, 0, 'rgba(128, 128, 128, 1)' 150 | pixels.drawPixel 0, 1, 'rgba(128, 128, 128, 1)' 151 | pixels.drawPixel 0, 2, 'rgba(128, 128, 128, 1)' 152 | pixels.drawPixel 0, 3, 'rgba(128, 128, 128, 1)' 153 | 154 | pixels.submitPixel() 155 | 156 | screen.addChild pixels 157 | 158 | Or even better, load a retro sprite file! 159 | 160 | CanvasLibrary.StackedLoader.add 'logo', 'sprite', 'logo.spr' 161 | 162 | CanvasLibrary.StackedLoader.load => 163 | logo = CanvasLibrary.StackedLoader.get 'logo' 164 | screen.addChild logo 165 | 166 | == Development 167 | 168 | Want to extend the library? If you are using rvm that should be a breeze! 169 | 170 | bundle install 171 | guard 172 | 173 | = License and credits 174 | Use it and have fun with it! Comments, cakes and hugs are welcome! Just stick to the license! 175 | 176 | Copyright 2010 - 2011, Diederick Lawson - Altovista. Released under the FreeBSD license. 177 | --------------------------------------------------------------------------------