Last active
September 29, 2015 17:17
-
-
Save halfmanhalfdonut/1635771 to your computer and use it in GitHub Desktop.
Keanu Basketball module
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Basketball = (keanu, opts, duration) -> | |
return if not keanu | |
@keanu = keanu | |
@ctx = @keanu.ctx | |
@origin = opts.origin or [] | |
@originX = @origin[0] or 0 | |
@originY = @origin[1] or 0 | |
@originRadius = @origin[2] or 0 | |
@control = opts.control or [] | |
@controlX = @control[0] or 0 | |
@controlY = @control[1] or 0 | |
@controlRadius = @control[2] or 0 | |
@destination = opts.destination or [] | |
@destinationX = @destination[0] or 0 | |
@destinationY = @destination[1] or 0 | |
@destinationRadius = @destination[2] or 0 | |
@trailStates = [] | |
@keepStates = 15 | |
@step = 3 | |
@animationMiddle = opts.animationMiddle or 2 | |
@shape = opts.shape or keanu.circle | |
@styles = opts.styles or {} | |
@zIndex = opts.zIndex or 0 | |
@easeType = opts.easeType or "linear" | |
@callback = opts.callback | |
@useTrail = opts.useTrail or true | |
@duration = duration or 1000 | |
@easing = @keanu.tweens[@easeType] | |
@originX = if @originX is @controlX then @originX + 1 else @originX | |
@originY = if @originY is @controlY then @originY + 1 else @originY | |
@ballX = @trailX = @shadowX = @originX | |
@ballY = @trailY = @shadowY = @originY | |
@ballRadius = @trailRadius = @shadowRadius = @originRadius | |
@xChange = @destinationX - @originX | |
@yChange = @destinationY - @originY | |
@rChange1 = @controlRadius - @originRadius | |
@rChange2 = @destinationRadius - @controlRadius | |
@intervalTime = @keanu.getIntervalTime() | |
@tickerStep = @duration / @intervalTime | |
@frame = 0 | |
@tick = 0 | |
@draw = => | |
@drawShadow() | |
@drawTrail() | |
@drawShot() | |
@frame++ | |
@tick += @intervalTime | |
if @tick >= @duration | |
console.log "callback" | |
keanu.unsubscribe "enterFrame", @draw, @zIndex | |
@trailStates = [] | |
@callback and @callback() | |
true | |
@keanu.subscribe "enterFrame", @draw | |
this | |
Basketball::drawTrail = -> | |
len = @trailStates.length | |
if len > 0 | |
alpha = 0.1 | |
rad = 0.6 | |
i = len - 1 | |
while i >= 0 | |
@drawBall @keanu, | |
x: @trailStates[i][0] or 0 | |
y: @trailStates[i][1] or 0 | |
r: (@trailStates[i][2] * rad) or 0 | |
styles: | |
fillStyle: "rgba(12, 131, 218, #{alpha})" | |
strokeStyle: "rgba(12, 131, 218, #{alpha})" | |
@keanu.setDimensions | |
x: @trailStates[i][0] - (@trailStates[i][2] * rad) | |
y: @trailStates[i][1] - (@trailStates[i][2] * rad) | |
w: @trailStates[i][0] + (@trailStates[i][2] * rad) | |
h: @trailStates[i][1] + (@trailStates[i][2] * rad) | |
alpha += 0.05 | |
rad += 0.02 if rad < 0.98 | |
i-- | |
this | |
Basketball::drawShadow = -> | |
@shadowX = @easing @frame, @originX, @xChange, @tickerStep | |
@shadowY = @easing @frame, @originY, @yChange, @tickerStep | |
@shadowRadius = 2 | |
@drawBall @keanu, | |
x: @shadowX | |
y: @shadowY | |
r: @shadowRadius | |
styles: | |
fillStyle: "#000" | |
strokeStyle: "#000" | |
lineWidth: "0" | |
@keanu.setDimensions | |
x: @shadowX - @shadowRadius | |
y: @shadowY - @shadowRadius | |
w: @shadowX + @shadowRadius | |
h: @shadowY + @shadowRadius | |
this | |
Basketball::handleTrailState = (state) -> | |
temp = [] | |
loopLen = if @trailStates.length >= @keepStates then @keepStates else @trailStates.length | |
temp.push state | |
temp.push @trailStates[i] for i in [0...loopLen] | |
@trailStates = temp | |
this | |
Basketball::drawShot = -> | |
@ballX = @easing @frame, @originX, @xChange, @tickerStep | |
@ballY = @easing @frame, @originY, @yChange, @tickerStep | |
if @frame < @tickerStep / @animationMiddle | |
@ballRadius = @easing @frame, @originRadius, @rChange1, @tickerStep | |
else | |
@ballRadius = @easing @frame, @controlRadius, @rChange2, @tickerStep | |
if @controlX isnt 0 | |
@ballX = @keanu.tweens.quadraticBezierCurve (@originX - @ballX) / (@originX - @destinationX), @originX, @controlX, @destinationX | |
if @controlY isnt 0 | |
@ballY = @keanu.tweens.quadraticBezierCurve (@originY - @ballY) / (@originY - @destinationY), @originY, @controlY, @destinationY | |
@handleTrailState [@ballX, @ballY, @ballRadius] if @frame % @step is 0 | |
@drawBall @keanu, | |
x: @ballX | |
y: @ballY | |
r: @ballRadius | |
styles: | |
fillStyle: @styles.fillStyle or false | |
strokeStyle: @styles.strokeStyle or false | |
lineWidth: @styles.lineWidth or false | |
@keanu.setDimensions | |
x: @ballX - @ballRadius | |
y: @ballY - @ballRadius | |
w: @ballX + @ballRadius | |
h: @ballY + @ballRadius | |
this | |
Basketball::drawBall = (keanu, data) -> | |
data = data or {} | |
data.styles = data.styles or {} | |
x = data.x or 0 | |
y = data.y or 0 | |
r = data.r or 0 | |
isTrail = data.isTrail or false | |
f = data.styles.fillStyle or "#E08428" | |
w = data.styles.lineWidth or 0 | |
s = data.styles.strokeStyle or "#D07317" | |
keanu.ctx.fillStyle = f | |
keanu.ctx.strokeStyle = s | |
keanu.ctx.lineWidth = w | |
keanu.ctx.beginPath() | |
keanu.ctx.arc x, y, r, 0, Math.PI * 2, true | |
keanu.ctx.closePath() | |
keanu.ctx.fill() | |
keanu.ctx.stroke() | |
this | |
window.Keanu.modules.Basketball = Basketball |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var Basketball; | |
Basketball = function(keanu, opts, duration) { | |
var _this = this; | |
if (!keanu) { | |
return; | |
} | |
this.keanu = keanu; | |
this.ctx = this.keanu.ctx; | |
this.origin = opts.origin || []; | |
this.originX = this.origin[0] || 0; | |
this.originY = this.origin[1] || 0; | |
this.originRadius = this.origin[2] || 0; | |
this.control = opts.control || []; | |
this.controlX = this.control[0] || 0; | |
this.controlY = this.control[1] || 0; | |
this.controlRadius = this.control[2] || 0; | |
this.destination = opts.destination || []; | |
this.destinationX = this.destination[0] || 0; | |
this.destinationY = this.destination[1] || 0; | |
this.destinationRadius = this.destination[2] || 0; | |
this.trailStates = []; | |
this.keepStates = 15; | |
this.step = 3; | |
this.animationMiddle = opts.animationMiddle || 2; | |
this.shape = opts.shape || keanu.circle; | |
this.styles = opts.styles || {}; | |
this.zIndex = opts.zIndex || 0; | |
this.easeType = opts.easeType || "linear"; | |
this.callback = opts.callback; | |
this.useTrail = opts.useTrail || true; | |
this.duration = duration || 1000; | |
this.easing = this.keanu.tweens[this.easeType]; | |
this.originX = this.originX === this.controlX ? this.originX + 1 : this.originX; | |
this.originY = this.originY === this.controlY ? this.originY + 1 : this.originY; | |
this.ballX = this.trailX = this.shadowX = this.originX; | |
this.ballY = this.trailY = this.shadowY = this.originY; | |
this.ballRadius = this.trailRadius = this.shadowRadius = this.originRadius; | |
this.xChange = this.destinationX - this.originX; | |
this.yChange = this.destinationY - this.originY; | |
this.rChange1 = this.controlRadius - this.originRadius; | |
this.rChange2 = this.destinationRadius - this.controlRadius; | |
this.intervalTime = this.keanu.getIntervalTime(); | |
this.tickerStep = this.duration / this.intervalTime; | |
this.frame = 0; | |
this.tick = 0; | |
this.draw = function() { | |
_this.drawShadow(); | |
_this.drawTrail(); | |
_this.drawShot(); | |
_this.frame++; | |
_this.tick += _this.intervalTime; | |
if (_this.tick >= _this.duration) { | |
console.log("callback"); | |
keanu.unsubscribe("enterFrame", _this.draw, _this.zIndex); | |
_this.trailStates = []; | |
_this.callback && _this.callback(); | |
return true; | |
} | |
}; | |
this.keanu.subscribe("enterFrame", this.draw); | |
return this; | |
}; | |
Basketball.prototype.drawTrail = function() { | |
var alpha, i, len, rad; | |
len = this.trailStates.length; | |
if (len > 0) { | |
alpha = 0.1; | |
rad = 0.6; | |
i = len - 1; | |
while (i >= 0) { | |
this.drawBall(this.keanu, { | |
x: this.trailStates[i][0] || 0, | |
y: this.trailStates[i][1] || 0, | |
r: (this.trailStates[i][2] * rad) || 0, | |
styles: { | |
fillStyle: "rgba(12, 131, 218, " + alpha + ")", | |
strokeStyle: "rgba(12, 131, 218, " + alpha + ")" | |
} | |
}); | |
this.keanu.setDimensions({ | |
x: this.trailStates[i][0] - (this.trailStates[i][2] * rad), | |
y: this.trailStates[i][1] - (this.trailStates[i][2] * rad), | |
w: this.trailStates[i][0] + (this.trailStates[i][2] * rad), | |
h: this.trailStates[i][1] + (this.trailStates[i][2] * rad) | |
}); | |
alpha += 0.05; | |
if (rad < 0.98) { | |
rad += 0.02; | |
} | |
i--; | |
} | |
} | |
return this; | |
}; | |
Basketball.prototype.drawShadow = function() { | |
this.shadowX = this.easing(this.frame, this.originX, this.xChange, this.tickerStep); | |
this.shadowY = this.easing(this.frame, this.originY, this.yChange, this.tickerStep); | |
this.shadowRadius = 2; | |
this.drawBall(this.keanu, { | |
x: this.shadowX, | |
y: this.shadowY, | |
r: this.shadowRadius, | |
styles: { | |
fillStyle: "#000", | |
strokeStyle: "#000", | |
lineWidth: "0" | |
} | |
}); | |
this.keanu.setDimensions({ | |
x: this.shadowX - this.shadowRadius, | |
y: this.shadowY - this.shadowRadius, | |
w: this.shadowX + this.shadowRadius, | |
h: this.shadowY + this.shadowRadius | |
}); | |
return this; | |
}; | |
Basketball.prototype.handleTrailState = function(state) { | |
var i, loopLen, temp, _i; | |
temp = []; | |
loopLen = this.trailStates.length >= this.keepStates ? this.keepStates : this.trailStates.length; | |
temp.push(state); | |
for (i = _i = 0; 0 <= loopLen ? _i < loopLen : _i > loopLen; i = 0 <= loopLen ? ++_i : --_i) { | |
temp.push(this.trailStates[i]); | |
} | |
this.trailStates = temp; | |
return this; | |
}; | |
Basketball.prototype.drawShot = function() { | |
this.ballX = this.easing(this.frame, this.originX, this.xChange, this.tickerStep); | |
this.ballY = this.easing(this.frame, this.originY, this.yChange, this.tickerStep); | |
if (this.frame < this.tickerStep / this.animationMiddle) { | |
this.ballRadius = this.easing(this.frame, this.originRadius, this.rChange1, this.tickerStep); | |
} else { | |
this.ballRadius = this.easing(this.frame, this.controlRadius, this.rChange2, this.tickerStep); | |
} | |
if (this.controlX !== 0) { | |
this.ballX = this.keanu.tweens.quadraticBezierCurve((this.originX - this.ballX) / (this.originX - this.destinationX), this.originX, this.controlX, this.destinationX); | |
} | |
if (this.controlY !== 0) { | |
this.ballY = this.keanu.tweens.quadraticBezierCurve((this.originY - this.ballY) / (this.originY - this.destinationY), this.originY, this.controlY, this.destinationY); | |
} | |
if (this.frame % this.step === 0) { | |
this.handleTrailState([this.ballX, this.ballY, this.ballRadius]); | |
} | |
this.drawBall(this.keanu, { | |
x: this.ballX, | |
y: this.ballY, | |
r: this.ballRadius, | |
styles: { | |
fillStyle: this.styles.fillStyle || false, | |
strokeStyle: this.styles.strokeStyle || false, | |
lineWidth: this.styles.lineWidth || false | |
} | |
}); | |
this.keanu.setDimensions({ | |
x: this.ballX - this.ballRadius, | |
y: this.ballY - this.ballRadius, | |
w: this.ballX + this.ballRadius, | |
h: this.ballY + this.ballRadius | |
}); | |
return this; | |
}; | |
Basketball.prototype.drawBall = function(keanu, data) { | |
var f, isTrail, r, s, w, x, y; | |
data = data || {}; | |
data.styles = data.styles || {}; | |
x = data.x || 0; | |
y = data.y || 0; | |
r = data.r || 0; | |
isTrail = data.isTrail || false; | |
f = data.styles.fillStyle || "#E08428"; | |
w = data.styles.lineWidth || 0; | |
s = data.styles.strokeStyle || "#D07317"; | |
keanu.ctx.fillStyle = f; | |
keanu.ctx.strokeStyle = s; | |
keanu.ctx.lineWidth = w; | |
keanu.ctx.beginPath(); | |
keanu.ctx.arc(x, y, r, 0, Math.PI * 2, true); | |
keanu.ctx.closePath(); | |
keanu.ctx.fill(); | |
keanu.ctx.stroke(); | |
return this; | |
}; | |
window.Keanu.modules.Basketball = Basketball; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Basketball | |
constructor: (keanu, opts, duration) -> | |
return if not keanu | |
@keanu = keanu | |
@ctx = @keanu.ctx | |
@origin = opts.origin or [] | |
@originX = @origin[0] or 0 | |
@originY = @origin[1] or 0 | |
@originRadius = @origin[2] or 0 | |
@control = opts.control or [] | |
@controlX = @control[0] or 0 | |
@controlY = @control[1] or 0 | |
@controlRadius = @control[2] or 0 | |
@destination = opts.destination or [] | |
@destinationX = @destination[0] or 0 | |
@destinationY = @destination[1] or 0 | |
@destinationRadius = @destination[2] or 0 | |
@trailStates = [] | |
@keepStates = 15 | |
@step = 3 | |
@animationMiddle = opts.animationMiddle or 2 | |
@shape = opts.shape or keanu.circle | |
@styles = opts.styles or {} | |
@zIndex = opts.zIndex or 0 | |
@easeType = opts.easeType or "linear" | |
@callback = opts.callback | |
@useTrail = opts.useTrail or true | |
@duration = duration or 1000 | |
@easing = @keanu.tweens[@easeType] | |
@originX = if @originX is @controlX then @originX + 1 else @originX | |
@originY = if @originY is @controlY then @originY + 1 else @originY | |
@ballX = @trailX = @shadowX = @originX | |
@ballY = @trailY = @shadowY = @originY | |
@ballRadius = @trailRadius = @shadowRadius = @originRadius | |
@xChange = @destinationX - @originX | |
@yChange = @destinationY - @originY | |
@rChange1 = @controlRadius - @originRadius | |
@rChange2 = @destinationRadius - @controlRadius | |
@intervalTime = @keanu.getIntervalTime() | |
@tickerStep = @duration / @intervalTime | |
@frame = 0 | |
@tick = 0 | |
@draw = => | |
@drawShadow() | |
@drawTrail() | |
@drawShot() | |
@frame++ | |
@tick += @intervalTime | |
if @tick >= @duration | |
console.log "callback" | |
keanu.unsubscribe "enterFrame", @draw, @zIndex | |
@trailStates = [] | |
@callback and @callback() | |
true | |
@keanu.subscribe "enterFrame", @draw | |
this | |
drawTrail: -> | |
len = @trailStates.length | |
if len > 0 | |
alpha = 0.1 | |
rad = 0.6 | |
i = len - 1 | |
while i >= 0 | |
@drawBall @keanu, | |
x: @trailStates[i][0] or 0 | |
y: @trailStates[i][1] or 0 | |
r: (@trailStates[i][2] * rad) or 0 | |
styles: | |
fillStyle: "rgba(12, 131, 218, #{alpha})" | |
strokeStyle: "rgba(12, 131, 218, #{alpha})" | |
@keanu.setDimensions | |
x: @trailStates[i][0] - (@trailStates[i][2] * rad) | |
y: @trailStates[i][1] - (@trailStates[i][2] * rad) | |
w: @trailStates[i][0] + (@trailStates[i][2] * rad) | |
h: @trailStates[i][1] + (@trailStates[i][2] * rad) | |
alpha += 0.05 | |
rad += 0.02 if rad < 0.98 | |
i-- | |
this | |
drawShadow: -> | |
@shadowX = @easing @frame, @originX, @xChange, @tickerStep | |
@shadowY = @easing @frame, @originY, @yChange, @tickerStep | |
@shadowRadius = 2 | |
@drawBall @keanu, | |
x: @shadowX | |
y: @shadowY | |
r: @shadowRadius | |
styles: | |
fillStyle: "#000" | |
strokeStyle: "#000" | |
lineWidth: "0" | |
@keanu.setDimensions | |
x: @shadowX - @shadowRadius | |
y: @shadowY - @shadowRadius | |
w: @shadowX + @shadowRadius | |
h: @shadowY + @shadowRadius | |
this | |
handleTrailState: (state) -> | |
temp = [] | |
loopLen = if @trailStates.length >= @keepStates then @keepStates else @trailStates.length | |
temp.push state | |
temp.push @trailStates[i] for i in [0...loopLen] | |
@trailStates = temp | |
this | |
drawShot: -> | |
@ballX = @easing @frame, @originX, @xChange, @tickerStep | |
@ballY = @easing @frame, @originY, @yChange, @tickerStep | |
if @frame < @tickerStep / @animationMiddle | |
@ballRadius = @easing @frame, @originRadius, @rChange1, @tickerStep | |
else | |
@ballRadius = @easing @frame, @controlRadius, @rChange2, @tickerStep | |
if @controlX isnt 0 | |
@ballX = @keanu.tweens.quadraticBezierCurve (@originX - @ballX) / (@originX - @destinationX), @originX, @controlX, @destinationX | |
if @controlY isnt 0 | |
@ballY = @keanu.tweens.quadraticBezierCurve (@originY - @ballY) / (@originY - @destinationY), @originY, @controlY, @destinationY | |
@handleTrailState [@ballX, @ballY, @ballRadius] if @frame % @step is 0 | |
@drawBall @keanu, | |
x: @ballX | |
y: @ballY | |
r: @ballRadius | |
styles: | |
fillStyle: @styles.fillStyle or false | |
strokeStyle: @styles.strokeStyle or false | |
lineWidth: @styles.lineWidth or false | |
@keanu.setDimensions | |
x: @ballX - @ballRadius | |
y: @ballY - @ballRadius | |
w: @ballX + @ballRadius | |
h: @ballY + @ballRadius | |
this | |
drawBall: (keanu, data) -> | |
data = data or {} | |
data.styles = data.styles or {} | |
x = data.x or 0 | |
y = data.y or 0 | |
r = data.r or 0 | |
isTrail = data.isTrail or false | |
f = data.styles.fillStyle or "#E08428" | |
w = data.styles.lineWidth or 0 | |
s = data.styles.strokeStyle or "#D07317" | |
keanu.ctx.fillStyle = f | |
keanu.ctx.strokeStyle = s | |
keanu.ctx.lineWidth = w | |
keanu.ctx.beginPath() | |
keanu.ctx.arc x, y, r, 0, Math.PI * 2, true | |
keanu.ctx.closePath() | |
keanu.ctx.fill() | |
keanu.ctx.stroke() | |
this | |
version: "0.2-coffee" | |
window.Keanu.modules.Basketball = Basketball |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(function() { | |
var Basketball; | |
Basketball = (function() { | |
function Basketball(keanu, opts, duration) { | |
var _this = this; | |
if (!keanu) return; | |
this.keanu = keanu; | |
this.ctx = this.keanu.ctx; | |
this.origin = opts.origin || []; | |
this.originX = this.origin[0] || 0; | |
this.originY = this.origin[1] || 0; | |
this.originRadius = this.origin[2] || 0; | |
this.control = opts.control || []; | |
this.controlX = this.control[0] || 0; | |
this.controlY = this.control[1] || 0; | |
this.controlRadius = this.control[2] || 0; | |
this.destination = opts.destination || []; | |
this.destinationX = this.destination[0] || 0; | |
this.destinationY = this.destination[1] || 0; | |
this.destinationRadius = this.destination[2] || 0; | |
this.trailStates = []; | |
this.keepStates = 15; | |
this.step = 3; | |
this.animationMiddle = opts.animationMiddle || 2; | |
this.shape = opts.shape || keanu.circle; | |
this.styles = opts.styles || {}; | |
this.zIndex = opts.zIndex || 0; | |
this.easeType = opts.easeType || "linear"; | |
this.callback = opts.callback; | |
this.useTrail = opts.useTrail || true; | |
this.duration = duration || 1000; | |
this.easing = this.keanu.tweens[this.easeType]; | |
this.originX = this.originX === this.controlX ? this.originX + 1 : this.originX; | |
this.originY = this.originY === this.controlY ? this.originY + 1 : this.originY; | |
this.ballX = this.trailX = this.shadowX = this.originX; | |
this.ballY = this.trailY = this.shadowY = this.originY; | |
this.ballRadius = this.trailRadius = this.shadowRadius = this.originRadius; | |
this.xChange = this.destinationX - this.originX; | |
this.yChange = this.destinationY - this.originY; | |
this.rChange1 = this.controlRadius - this.originRadius; | |
this.rChange2 = this.destinationRadius - this.controlRadius; | |
this.intervalTime = this.keanu.getIntervalTime(); | |
this.tickerStep = this.duration / this.intervalTime; | |
this.frame = 0; | |
this.tick = 0; | |
this.draw = function() { | |
_this.drawShadow(); | |
_this.drawTrail(); | |
_this.drawShot(); | |
_this.frame++; | |
_this.tick += _this.intervalTime; | |
if (_this.tick >= _this.duration) { | |
console.log("callback"); | |
keanu.unsubscribe("enterFrame", _this.draw, _this.zIndex); | |
_this.trailStates = []; | |
_this.callback && _this.callback(); | |
return true; | |
} | |
}; | |
this.keanu.subscribe("enterFrame", this.draw); | |
this; | |
} | |
Basketball.prototype.drawTrail = function() { | |
var alpha, i, len, rad; | |
len = this.trailStates.length; | |
if (len > 0) { | |
alpha = 0.1; | |
rad = 0.6; | |
i = len - 1; | |
while (i >= 0) { | |
this.drawBall(this.keanu, { | |
x: this.trailStates[i][0] || 0, | |
y: this.trailStates[i][1] || 0, | |
r: (this.trailStates[i][2] * rad) || 0, | |
styles: { | |
fillStyle: "rgba(12, 131, 218, " + alpha + ")", | |
strokeStyle: "rgba(12, 131, 218, " + alpha + ")" | |
} | |
}); | |
this.keanu.setDimensions({ | |
x: this.trailStates[i][0] - (this.trailStates[i][2] * rad), | |
y: this.trailStates[i][1] - (this.trailStates[i][2] * rad), | |
w: this.trailStates[i][0] + (this.trailStates[i][2] * rad), | |
h: this.trailStates[i][1] + (this.trailStates[i][2] * rad) | |
}); | |
alpha += 0.05; | |
if (rad < 0.98) rad += 0.02; | |
i--; | |
} | |
} | |
return this; | |
}; | |
Basketball.prototype.drawShadow = function() { | |
this.shadowX = this.easing(this.frame, this.originX, this.xChange, this.tickerStep); | |
this.shadowY = this.easing(this.frame, this.originY, this.yChange, this.tickerStep); | |
this.shadowRadius = 2; | |
this.drawBall(this.keanu, { | |
x: this.shadowX, | |
y: this.shadowY, | |
r: this.shadowRadius, | |
styles: { | |
fillStyle: "#000", | |
strokeStyle: "#000", | |
lineWidth: "0" | |
} | |
}); | |
this.keanu.setDimensions({ | |
x: this.shadowX - this.shadowRadius, | |
y: this.shadowY - this.shadowRadius, | |
w: this.shadowX + this.shadowRadius, | |
h: this.shadowY + this.shadowRadius | |
}); | |
return this; | |
}; | |
Basketball.prototype.handleTrailState = function(state) { | |
var i, loopLen, temp; | |
temp = []; | |
loopLen = this.trailStates.length >= this.keepStates ? this.keepStates : this.trailStates.length; | |
temp.push(state); | |
for (i = 0; 0 <= loopLen ? i < loopLen : i > loopLen; 0 <= loopLen ? i++ : i--) { | |
temp.push(this.trailStates[i]); | |
} | |
this.trailStates = temp; | |
return this; | |
}; | |
Basketball.prototype.drawShot = function() { | |
this.ballX = this.easing(this.frame, this.originX, this.xChange, this.tickerStep); | |
this.ballY = this.easing(this.frame, this.originY, this.yChange, this.tickerStep); | |
if (this.frame < this.tickerStep / this.animationMiddle) { | |
this.ballRadius = this.easing(this.frame, this.originRadius, this.rChange1, this.tickerStep); | |
} else { | |
this.ballRadius = this.easing(this.frame, this.controlRadius, this.rChange2, this.tickerStep); | |
} | |
if (this.controlX !== 0) { | |
this.ballX = this.keanu.tweens.quadraticBezierCurve((this.originX - this.ballX) / (this.originX - this.destinationX), this.originX, this.controlX, this.destinationX); | |
} | |
if (this.controlY !== 0) { | |
this.ballY = this.keanu.tweens.quadraticBezierCurve((this.originY - this.ballY) / (this.originY - this.destinationY), this.originY, this.controlY, this.destinationY); | |
} | |
if (this.frame % this.step === 0) { | |
this.handleTrailState([this.ballX, this.ballY, this.ballRadius]); | |
} | |
this.drawBall(this.keanu, { | |
x: this.ballX, | |
y: this.ballY, | |
r: this.ballRadius, | |
styles: { | |
fillStyle: this.styles.fillStyle || false, | |
strokeStyle: this.styles.strokeStyle || false, | |
lineWidth: this.styles.lineWidth || false | |
} | |
}); | |
this.keanu.setDimensions({ | |
x: this.ballX - this.ballRadius, | |
y: this.ballY - this.ballRadius, | |
w: this.ballX + this.ballRadius, | |
h: this.ballY + this.ballRadius | |
}); | |
return this; | |
}; | |
Basketball.prototype.drawBall = function(keanu, data) { | |
var f, isTrail, r, s, w, x, y; | |
data = data || {}; | |
data.styles = data.styles || {}; | |
x = data.x || 0; | |
y = data.y || 0; | |
r = data.r || 0; | |
isTrail = data.isTrail || false; | |
f = data.styles.fillStyle || "#E08428"; | |
w = data.styles.lineWidth || 0; | |
s = data.styles.strokeStyle || "#D07317"; | |
keanu.ctx.fillStyle = f; | |
keanu.ctx.strokeStyle = s; | |
keanu.ctx.lineWidth = w; | |
keanu.ctx.beginPath(); | |
keanu.ctx.arc(x, y, r, 0, Math.PI * 2, true); | |
keanu.ctx.closePath(); | |
keanu.ctx.fill(); | |
keanu.ctx.stroke(); | |
return this; | |
}; | |
Basketball.prototype.version = "0.2-coffee"; | |
return Basketball; | |
})(); | |
window.Keanu.modules.Basketball = Basketball; | |
}).call(this); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// So our basketball needs to take some options -- namely if it's using ball trails or not. Yes? Yes. | |
// We also need it to keep track of its own bounding box. That is, the minimum and maximum X/Y values | |
// We can probably reduce mouse trail load by making them one shape rather than multiple circles. | |
(function() { | |
// The only thing I smoke are fools like you on the b-ball court | |
var Basketball = function(keanu, opts, duration) { | |
if (!keanu) return; // Well forget YOU, then. No where to draw this bad boy! | |
var self = this; // let's keep a reference to ourself, shall we? | |
// Add in all of our options here | |
this.keanu = keanu; | |
this.ctx = this.keanu.ctx; | |
// origin -- [x, y, radius] | |
this.origin = opts.origin || []; | |
this.originX = this.origin[0] || 0; | |
this.originY = this.origin[1] || 0; | |
this.originRadius = this.origin[2] || 0; | |
// control points, middle of the curve from origin to destination | |
this.control = opts.control || []; | |
this.controlX = this.control[0] || 0; | |
this.controlY = this.control[1] || 0; | |
this.controlRadius = this.control[2] || 0; | |
// destination -- [x, y, radius] | |
this.destination = opts.destination || []; | |
this.destinationX = this.destination[0] || 0; | |
this.destinationY = this.destination[1] || 0; | |
this.destinationRadius = this.destination[2] || 0; | |
// Our ball trail will just be a collection of previous states | |
// We'll slap lower alpha value on them as they get further away | |
this.trailStates = []; | |
this.keepStates = 15; // How many states do we want to keep? | |
this.step = 3; // How often do we want to save the ball state? | |
this.animationMiddle = opts.animationMiddle || 2; // What are we dividing the length by for a "midpoint?" | |
this.shape = opts.shape || keanu.circle; // default to a circle -- it IS a ball after all | |
this.styles = opts.styles || {}; // Hash of properties, completely unnecessary though | |
this.zIndex = opts.zIndex || 0; // default to the lowest z-index | |
this.easeType = opts.easeType || "linear"; // default to none (linear) | |
this.callback = opts.callback; // When the animation completes, fire it up! Or nothing, whichever | |
this.useTrail = opts.useTrail || true; // This option is for low-end browsers | |
this.duration = duration || 1000; // time in milliseconds | |
// Need to set up some values for this animation, eh? | |
this.easing = this.keanu.tweens[this.easeType]; | |
// The origin and control X/Y values cannot be identical or the curve will wonk out | |
this.originX = this.originX !== this.controlX ? this.originX : this.originX + 1; | |
this.originY = this.originY !== this.controlY ? this.originY : this.originY + 1; | |
// We need to initialize the ball, trail and shadow info. | |
this.ballX = this.trailX = this.shadowX = this.originX; | |
this.ballY = this.trailY = this.shadowY = this.originY; | |
this.ballRadius = this.trailRadius = this.shadowRadius = this.originRadius; | |
// Set up our animation change values - the distance between various points | |
this.xChange = this.destinationX - this.originX; | |
this.yChange = this.destinationY - this.originY; | |
this.rChange1 = this.controlRadius - this.originRadius; | |
this.rChange2 = this.destinationRadius - this.controlRadius; | |
// Set up the timing bits | |
this.intervalTime = this.keanu.getIntervalTime(); | |
this.tickerStep = this.duration / this.intervalTime; | |
this.frame = 0; | |
this.tick = 0; | |
// this is the Keanu enterFrame callback -- it provides the draw state for our basketball at each frame | |
this.draw = function() { | |
self.drawShadow(); | |
self.drawTrail(); | |
self.drawShot(); | |
self.frame++; | |
self.tick += self.intervalTime; | |
if (self.tick >= self.duration) { | |
keanu.unsubscribe("enterFrame", self.draw, self.zIndex); | |
this.trailStates = []; | |
self.callback && self.callback(); | |
} | |
}; | |
// Without this step, Keanu has no idea of our existence.. | |
this.keanu.subscribe("enterFrame", this.draw); | |
}; | |
// This kind of brings the ball to life, no? | |
Basketball.prototype.drawTrail = function() { | |
var len = this.trailStates.length, | |
i; | |
// If we have any previous states, draw them | |
if (len > 0) { | |
var alpha = 0.1, | |
rad = 0.6; | |
// Draw these in reverse order | |
for (i = len - 1; i >= 0; i--) { | |
// Draw this state on the canvas | |
this.drawBall(this.keanu, { | |
x: this.trailStates[i][0] || 0, // x | |
y: this.trailStates[i][1] || 0, // y | |
r: (this.trailStates[i][2] * rad) || 0, // radius | |
styles: { | |
fillStyle: "rgba(12, 131, 218, "+ alpha +")", | |
strokeStyle: "rgba(12, 131, 218, "+ alpha +")" | |
} | |
}); | |
// Give Keanu our bounding box for a given ball | |
this.keanu.setDimensions({ | |
x: this.trailStates[i][0] - (this.trailStates[i][2] * rad), | |
y: this.trailStates[i][1] - (this.trailStates[i][2] * rad), | |
w: this.trailStates[i][0] + (this.trailStates[i][2] * rad), | |
h: this.trailStates[i][1] + (this.trailStates[i][2] * rad) | |
}); | |
// as we get closer to the ball, make it more opaque | |
alpha += 0.05; | |
if (rad < 0.98) rad += 0.02; | |
} | |
} | |
}; | |
// Without this, the ball is nothing. NOTHING. I mean, this just gives it an added dimension. Ask wolfmother. | |
Basketball.prototype.drawShadow = function() { | |
this.shadowX = this.easing(this.frame, this.originX, this.xChange, this.tickerStep); | |
this.shadowY = this.easing(this.frame, this.originY, this.yChange, this.tickerStep); | |
this.shadowRadius = 2; | |
// Draw this state! | |
this.drawBall(this.keanu, { | |
x: this.shadowX, | |
y: this.shadowY, | |
r: this.shadowRadius, | |
styles: { | |
fillStyle: "#000", | |
strokeStyle: "#000", | |
lineWidth: "0" | |
} | |
}); | |
// Let keanu know about the shadow's bounding box | |
this.keanu.setDimensions({ | |
x: this.shadowX - this.shadowRadius, | |
y: this.shadowY - this.shadowRadius, | |
w: this.shadowX + this.shadowRadius, | |
h: this.shadowY + this.shadowRadius | |
}); | |
}; | |
// Handles the trail states for each frame of the animation | |
Basketball.prototype.handleTrailState = function(state) { | |
var temp = [], | |
loopLen = this.trailStates.length >= this.keepStates ? this.keepStates : this.trailStates.length; // use only as many iterations as possible | |
temp.push(state); // add the first state to the top | |
// add the remaining 9 (or less) states | |
for (var i = 0; i < loopLen; i++) { | |
temp.push(this.trailStates[i]); | |
} | |
// Set the trail states to the temp | |
this.trailStates = temp; | |
}; | |
// I suppose if you're not drawing the ball itself, the animations lose their purpose. It's an existential crisis waiting to happen. | |
Basketball.prototype.drawShot = function() { | |
this.ballX = this.easing(this.frame, this.originX, this.xChange, this.tickerStep); | |
this.ballY = this.easing(this.frame, this.originY, this.yChange, this.tickerStep); | |
// If we're just starting out, we need to animate the radius larger | |
if (this.frame < this.tickerStep / this.animationMiddle) { | |
this.ballRadius = this.easing(this.frame, this.originRadius, this.rChange1, this.tickerStep); | |
// otherwise it needs to animate the radius smaller | |
} else { | |
this.ballRadius = this.easing(this.frame, this.controlRadius, this.rChange2, this.tickerStep); | |
} | |
// As long as this has control points, animate towards them | |
if (this.controlX != 0) { | |
this.ballX = this.keanu.tweens.quadraticBezierCurve((this.originX - this.ballX) / (this.originX - this.destinationX), this.originX, this.controlX, this.destinationX); | |
} | |
if (this.controlY != 0) { | |
this.ballY = this.keanu.tweens.quadraticBezierCurve((this.originY - this.ballY) / (this.originY - this.destinationY), this.originY, this.controlY, this.destinationY); | |
} | |
// Every third frame, keep the ball's state. This is preference. Keeping every state makes it look more like a line. | |
// Think of this like a "step" in a drawing program | |
if (this.frame % this.step == 0) this.handleTrailState([this.ballX, this.ballY, this.ballRadius]); | |
// Draw it on the canvas | |
this.drawBall(this.keanu, { | |
x: this.ballX, | |
y: this.ballY, | |
r: this.ballRadius, | |
styles: { | |
fillStyle: this.styles.fillStyle || false, | |
strokeStyle: this.styles.strokeStyle || false, | |
lineWidth: this.styles.lineWidth || false | |
} | |
}); | |
// Let keanu know about our bounding box | |
this.keanu.setDimensions({ | |
x: this.ballX - this.ballRadius, | |
y: this.ballY - this.ballRadius, | |
w: this.ballX + this.ballRadius, | |
h: this.ballY + this.ballRadius | |
}); | |
}; | |
// A basketball! Ok so it's just an orange circle (by default..) | |
Basketball.prototype.drawBall = function(keanu, data) { | |
data = data || {}; | |
data.styles = data.styles || {}; | |
var x = data.x || 0, | |
y = data.y || 0, | |
r = data.r || 0, | |
isTrail = data.isTrail || false, | |
f = data.styles.fillStyle || "#E08428", | |
w = data.styles.lineWidth || 0, | |
s = data.styles.strokeStyle || "#D07317"; | |
keanu.ctx.fillStyle = f; | |
keanu.ctx.strokeStyle = s; | |
keanu.ctx.lineWidth = w; | |
keanu.ctx.beginPath(); | |
keanu.ctx.arc(x, y, r, 0, Math.PI * 2, true); | |
keanu.ctx.closePath(); | |
keanu.ctx.fill(); | |
keanu.ctx.stroke(); | |
}; | |
// This means nothing, but I felt like giving it a version number. | |
Basketball.prototype.version = "0.0.0.0.0.0.1-theta-confirmed"; | |
// Add the Basketball module to Keanu. Yeehaw. | |
Keanu.modules.Basketball = Basketball; | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment