diff options
Diffstat (limited to 'js')
| -rw-r--r-- | js/draw.js | 67 | ||||
| -rw-r--r-- | js/nopaint/index.js | 165 | ||||
| -rw-r--r-- | js/util.js | 3 | ||||
| -rw-r--r-- | js/vendor/oktween.js | 167 |
4 files changed, 401 insertions, 1 deletions
@@ -27,6 +27,72 @@ var draw = (function(){ last_point[1] = point[1] } + function move_toroidal (e, lex, point) { + var w = canvas.w, h = canvas.h + var src_x_quantile = quantile( last_point[0], w ) + var src_y_quantile = quantile( last_point[1], h ) + var dst_x_quantile = quantile( point[0], w ) + var dst_y_quantile = quantile( point[1], h ) + var src_x_mod = mod( last_point[0], w ) + var src_y_mod = mod( last_point[1], h ) + var dst_x_mod = mod( point[0], w ) + var dst_y_mod = mod( point[1], h ) + // if we've moved across the edge of the board, draw two lines + if (src_x_quantile != dst_x_quantile || src_y_quantile != dst_y_quantile) { + var xa, ya + if (src_x_quantile < dst_x_quantile) { + xa = [ + [src_x_mod, dst_x_mod + w], + [src_x_mod-w, dst_x_mod], + ] + } + else if (src_x_quantile == dst_x_quantile) { + xa = [ + [src_x_mod, dst_x_mod], + [src_x_mod, dst_x_mod], + ] + } + else { + xa = [ + [src_x_mod, dst_x_mod-w], + [src_x_mod+w, dst_x_mod], + ] + } + + if (src_y_quantile < dst_y_quantile) { + ya = [ + [src_y_mod, dst_y_mod + h], + [src_y_mod-h, dst_y_mod], + ] + } + else if (src_y_quantile == dst_y_quantile) { + ya = [ + [src_y_mod, dst_y_mod], + [src_y_mod, dst_y_mod], + ] + } + else { + ya = [ + [src_y_mod, dst_y_mod-h], + [src_y_mod+h, dst_y_mod], + ] + } + line(lex, [ xa[0][0], ya[0][0] ], [ xa[0][1], ya[0][1] ], erasing) + line(lex, [ xa[1][0], ya[1][0] ], [ xa[1][1], ya[1][1] ], erasing) + } + else { + var last_point_mod = [], point_mod = [] + last_point_mod[0] = mod( last_point[0], w ) + last_point_mod[1] = mod( last_point[1], h ) + point_mod[0] = mod( point[0], w ) + point_mod[1] = mod( point[1], h ) + line(lex, last_point_mod, point_mod, erasing) + } + last_point[0] = point[0] + last_point[1] = point[1] + // y = point.y + } + function point (lex, x, y, erasing) { stamp (canvas, brush, x, y, erasing) } @@ -109,6 +175,7 @@ var draw = (function(){ draw.down = down draw.set_last_point = set_last_point draw.move = move + draw.move_toroidal = move_toroidal draw.stamp = stamp draw.line = line draw.point = point diff --git a/js/nopaint/index.js b/js/nopaint/index.js new file mode 100644 index 0000000..6270503 --- /dev/null +++ b/js/nopaint/index.js @@ -0,0 +1,165 @@ +var nopaint = (function(){ + + var is_paint = false + + controls.nopaint = {} + + controls.no = new Checkbox (nopaint_no_el) + controls.no.use = function(state){ + this.update(! nopaint.timeout) + controls.paint.update(false) + undo.undo() + nopaint.play() + } + + controls.paint = new Checkbox (nopaint_paint_el) + controls.paint.use = function(state){ + controls.no.update(false) + nopaint.play() + this.update(!! nopaint.timeout) + } + + // use own stepwise clock to drive tweens + oktween.raf = function(){} + + var nopaint = {} + nopaint.delay = 100 + nopaint.tool = null + nopaint.tools = {} + nopaint.step = 0 + nopaint.time = 0 + nopaint.timeout = false + nopaint.undo = function(){ + undo.undo() + } + nopaint.pause = function(){ + clearTimeout(nopaint.timeout) + nopaint.timeout = 0 + nopaint.step = 0 + } + nopaint.play = function(){ + nopaint.pause() + nopaint.switch_tool() + nopaint.go() + } + nopaint.go = function(){ + nopaint.timeout = setTimeout(nopaint.go, nopaint.delay) + oktween.update(nopaint.time) + nopaint.tool.paint( nopaint.step ) + nopaint.time += 1 + nopaint.step += 1 + } + nopaint.switch_tool = function(){ + undo.new() + last_tool = nopaint.tool + last_tool && last_tool.finish() + nopaint.tool = nopaint.tools[ choice(Object.keys(nopaint.tools)) ] + nopaint.tool.start( last_tool ) + // console.log(nopaint.tool.type) + } + nopaint.add_tool = function(fn){ + nopaint.tools[fn.type] = fn + } + + var NopaintTool = Model({ + type: "none", + init: function(){}, + start: function(){}, + paint: function(t){}, + finish: function(){}, + }) + + var NopaintBrush = NopaintTool.extend({ + type: "brush", + is_brush: true, + init: function(){ + this.p = {x: 0, y: 0} + this.fg = 0 + this.bg = 1 + this.char = " " + this.tweens = [] + }, + + start: function(last_brush){ + this.reset( last_brush ) + this.iterate( last_brush ) + brush.load( this ) + brush.generate() + draw.down({}, null, [this.p.x, this.p.y]) + }, + + paint: function(t){ + this.update( t ) + draw.move_toroidal({}, null, [this.p.x, this.p.y]) + }, + + finish: function(){ + this.tweens.forEach(function(t){ t.cancel() }) + this.tweens = [] + }, + + reorient: function(last_brush){ + var a = {}, b + + if (last_brush) { + this.p.x = a.x = randint(canvas.w) + this.p.y = a.y = randint(canvas.h) + } + else { + a.x = this.p.x + a.y = this.p.y + } + + b = this.get_next_point() + + var tween = oktween.add({ + obj: this.p, + from: a, + to: b, + duration: b.duration, + easing: b.easing, + update: function(o,dt){ + // console.log(o,dt) + }, + finished: function(){ + this.reorient() + }.bind(this) + }) + this.tweens.push(tween) + }, + + + }) + + var easings = "linear circ_out circ_in circ_in_out quad_in quad_out quad_in_out".split(" ") + + var SolidBrush = NopaintBrush.extend({ + type: "solid", + + get_next_point: function(){ + var b = {} + b.duration = randrange(1,7) + b.easing = choice(easings) + b.x = this.p.x + randrange(-10, 10) + b.y = this.p.y + randrange(-10, 10) + return b + }, + + recolor: function(){ + this.fg = this.bg = randint(16) + this.char = " " + }, + reset: function(){ + brush.resize(1,1) + }, + iterate: function( last_brush ){ + this.reorient( last_brush ) + this.recolor( last_brush ) + }, + update: function(t){ + } + }) + + nopaint.add_tool( new SolidBrush ) + +})() @@ -56,7 +56,8 @@ function modi(n,m){ return floor(n-(m * floor(n/m))) } function dist(x0,y0,x1,y1){ return sqrt(pow(x1-x0,2)+pow(y1-y0,2)) } function angle(x0,y0,x1,y1){ return atan2(y1-y0,x1-x0) } function avg(m,n,a){ return (m*(a-1)+n)/a } -function quantize(a,b){ return ~~(a/b)*b } +function quantize(a,b){ return floor(a/b)*b } +function quantile(a,b){ return floor(a/b) } function pixel(x,y){ return 4*(mod(y,actual_h)*actual_w+mod(x,actual_w)) } function rgbpixel(d,x,y){ diff --git a/js/vendor/oktween.js b/js/vendor/oktween.js new file mode 100644 index 0000000..41edbb0 --- /dev/null +++ b/js/vendor/oktween.js @@ -0,0 +1,167 @@ +/* + oktween.add({ + obj: el.style, + units: "px", + from: { left: 0 }, + to: { left: 100 }, + duration: 1000, + easing: oktween.easing.circ_out, + update: function(obj){ + console.log(obj.left) + } + finished: function(){ + console.log("done") + } + }) +*/ + +var oktween = (function(){ + var oktween = {} + var tweens = oktween.tweens = [] + var last_t = 0 + var id = 0 + oktween.speed = 1 + oktween.raf = requestAnimationFrame + oktween.add = function(tween){ + tween.id = id++ + tween.obj = tween.obj || {} + if (tween.easing) { + if (typeof tween.easing == "string") { + tween.easing = oktween.easing[tween.easing] + } + } + else { + tween.easing = oktween.easing.linear + } + if (! ('from' in tween) && ! ('to' in tween)) { + tween.keys = [] + } + else if (! ('from' in tween) ) { + tween.from = {} + tween.keys = Object.keys(tween.to) + tween.keys.forEach(function(prop){ + tween.from[prop] = parseFloat(tween.obj[prop]) + }) + } + else { + tween.keys = Object.keys(tween.from) + } + tween.delay = tween.delay || 0 + tween.start = last_t + tween.delay + tween.done = false + tween.after = tween.after || [] + tween.then = function(fn){ tween.after.push(fn); return tween } + tween.cancel = function(){ + var index = tweens.indexOf(tween) + if (index != -1) tweens.splice(index, 1) + tween.obj = null + tween.after = null + tween.done = null + } + tween.tick = 0 + tween.skip = tween.skip || 1 + tween.dt = 0 + tweens.push(tween) + return tween + } + oktween.update = function(t) { + oktween.raf(oktween.update) + last_t = t * oktween.speed + if (tweens.length == 0) return + var done = false + tweens.forEach(function(tween, i){ + var dt = Math.min(1.0, (t - tween.start) / tween.duration) + tween.tick++ + if (dt < 0 || (dt < 1 && (tween.tick % tween.skip != 0))) return + var ddt = tween.dt = tween.easing(dt) + tween.keys.forEach(function(prop){ + val = lerp( ddt, tween.from[prop], tween.to[prop] ) + if (tween.round) val = Math.round(val) + if (tween.units) val = (Math.round(val)) + tween.units + tween.obj[prop] = val + }) + tween.update && tween.update(tween.obj, dt) + if (dt == 1) { + tween.finished && tween.finished(tween) + if (tween.after.length) { + var twn = tween.after.shift() + twn.obj = twn.obj || tween.obj + twn.after = tween.after + oktween.add(twn) + } + if (tween.loop) { + tween.start = t + tween.delay + } + else { + done = tween.done = true + } + } + }) + if (done) { + tweens = tweens.filter(function(tween){ return ! tween.done }) + } + } + function lerp(n,a,b){ return (b-a)*n+a } + + // requestAnimationFrame(oktween.update) + + oktween.easing = { + linear: function(t){ + return t + }, + circ_out: function(t) { + return Math.sqrt(1 - (t = t - 1) * t) + }, + circ_in: function(t){ + return -(Math.sqrt(1 - (t * t)) - 1) + }, + circ_in_out: function(t) { + return ((t*=2) < 1) ? -0.5 * (Math.sqrt(1 - t * t) - 1) : 0.5 * (Math.sqrt(1 - (t -= 2) * t) + 1) + }, + quad_in: function(n){ + return Math.pow(n, 2) + }, + quad_out: function(n){ + return n * (n - 2) * -1 + }, + quad_in_out: function(n){ + n = n * 2 + if(n < 1){ return Math.pow(n, 2) / 2 } + return -1 * ((--n) * (n - 2) - 1) / 2 + }, + cubic_bezier: function (mX1, mY1, mX2, mY2) { + function A(aA1, aA2) { return 1.0 - 3.0 * aA2 + 3.0 * aA1; } + function B(aA1, aA2) { return 3.0 * aA2 - 6.0 * aA1; } + function C(aA1) { return 3.0 * aA1; } + + // Returns x(t) given t, x1, and x2, or y(t) given t, y1, and y2. + function CalcBezier(aT, aA1, aA2) { + return ((A(aA1, aA2)*aT + B(aA1, aA2))*aT + C(aA1))*aT; + } + + // Returns dx/dt given t, x1, and x2, or dy/dt given t, y1, and y2. + function GetSlope(aT, aA1, aA2) { + return 3.0 * A(aA1, aA2)*aT*aT + 2.0 * B(aA1, aA2) * aT + C(aA1); + } + + function GetTForX(aX) { + // Newton raphson iteration + var aGuessT = aX; + for (var i = 0; i < 10; ++i) { + var currentSlope = GetSlope(aGuessT, mX1, mX2); + if (currentSlope == 0.0) return aGuessT; + var currentX = CalcBezier(aGuessT, mX1, mX2) - aX; + aGuessT -= currentX / currentSlope; + } + return aGuessT; + } + + return function(aX) { + if (mX1 == mY1 && mX2 == mY2) return aX; // linear + return CalcBezier(aX, mY1, mY2); + } + } + } + + return oktween +})() |
