javascript - Canvas Marching Squares Glitch / Scroll Integration -
i'm attempting teach myself how work canvas — , i'm in way on head — thought i'd ask if has solution issue came across.
as lesson decided try start metaball idea: http://codepen.io/ge1doot/pen/rndwqb
and rework metaballs stationary move upwards @ varying rates 1 scrolls down page.
i sort of got working here — displays better on fiddle below. https://jsfiddle.net/l7cr46px/2/
function getscrolloffsets() { var doc = document, w = window; var x, y, docel; if ( typeof w.pageyoffset === 'number' ) { x = w.pagexoffset; y = w.pageyoffset; } else { docel = (doc.compatmode && doc.compatmode === 'css1compat')? doc.documentelement: doc.body; x = docel.scrollleft; y = docel.scrolltop; } return {x:x, y:y}; } var lava, balldata; balldata = new array(); (function() { var metablobby = metablobby || { screen: { elem: null, callback: null, ctx: null, width: 0, height: 0, left: 0, top: 0, init: function (id, callback, initres) { this.elem = document.getelementbyid(id); this.callback = callback || null; if (this.elem.tagname == "canvas") this.ctx = this.elem.getcontext("2d"); window.addeventlistener('resize', function () { this.resize(); }.bind(this), false); this.elem.onselectstart = function () { return false; } this.elem.ondrag = function () { return false; } initres && this.resize(); return this; }, resize: function () { var o = this.elem; this.width = o.offsetwidth; this.height = o.offsetheight; for (this.left = 0, this.top = 0; o != null; o = o.offsetparent) { this.left += o.offsetleft; this.top += o.offsettop; } if (this.ctx) { this.elem.width = this.width; this.elem.height = this.height; } this.callback && this.callback(); }, pointer: { screen: null, elem: null, callback: null, pos: {x:0, y:0}, mov: {x:0, y:0}, drag: {x:0, y:0}, start: {x:0, y:0}, end: {x:0, y:0}, active: false, touch: false, move: function (e, touch) { //this.active = true; this.touch = touch; e.preventdefault(); var pointer = touch ? e.touches[0] : e; this.mov.x = pointer.clientx - this.screen.left; this.mov.y = pointer.clienty - this.screen.top; if (this.active) { this.pos.x = this.mov.x; this.pos.y = this.mov.y; this.drag.x = this.end.x - (this.pos.x - this.start.x); this.drag.y = this.end.y - (this.pos.y - this.start.y); this.callback.move && this.callback.move(); } }, scroll: function(e, touch){ run(); }, init: function (callback) { this.screen = metablobby.screen; this.elem = this.screen.elem; this.callback = callback || {}; if ('ontouchstart' in window) { // touch this.elem.ontouchstart = function (e) { this.down(e, true); }.bind(this); this.elem.ontouchmove = function (e) { this.move(e, true); }.bind(this); this.elem.ontouchend = function (e) { this.up(e, true); }.bind(this); this.elem.ontouchcancel = function (e) { this.up(e, true); }.bind(this); } document.addeventlistener("mousemove", function (e) { this.move(e, false); }.bind(this), true); document.addeventlistener("scroll", function (e) { this.scroll(e, false); }.bind(this), true); return this; } }, } } // ==== point constructor ==== var point = function(x, y) { this.x = x; this.y = y; this.magnitude = x * x + y * y; this.computed = 0; this.force = 0; } point.prototype.add = function(p) { return new point(this.x + p.x, this.y + p.y); } // ==== ball constructor ==== var ball = function(parent,i) { var x = math.floor(math.random() * window.innerwidth) + 1; var y = math.floor(math.random() * (window.innerheight)*5) + 1; var radius = (math.floor(math.random() * 65) + 15) var drift = math.random(); balldata[i]=[x,y,radius, drift]; this.vel = new point(0,0); this.pos = new point(x,y); this.size = radius; this.width = parent.width; this.height = parent.height; } // ==== move balls ==== ball.prototype.move = function(i) { // ---- interact pointer ---- if (pointer.active) { var dx = pointer.pos.x - this.pos.x; var dy = pointer.pos.y - this.pos.y; var = math.atan2(dy, dx); var v = -math.min( 10, 500 / math.sqrt(dx * dx + dy * dy) ); this.pos = this.pos.add( new point( math.cos(a) * v, math.sin(a) * v ) ); } var drift = balldata[i-1][3]; var pageoffset = getscrolloffsets().y; this.pos.y = balldata[i-1][1] - (pageoffset*drift); this.vel.y = 0 - (pageoffset*drift); this.pos = this.pos.add(this.vel); } // ==== lavalamp constructor ==== var lavalamp = function(width, height, numballs) { this.step = 4; this.width = width; this.height = height; this.wh = math.min(width, height); this.sx = math.floor(this.width / this.step); this.sy = math.floor(this.height / this.step); this.paint = false; this.metafill = '#000000'; this.plx = [0, 0, 1, 0, 1, 1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 0]; this.ply = [0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 1, 0, 1, 0, 1]; this.mscases = [0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 0, 2, 1, 1, 0]; this.ix = [1, 0, -1, 0, 0, 1, 0, -1, -1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1]; this.grid = []; this.balls = []; this.iter = 0; this.sign = 1; // ---- init grid ---- for (var = 0; < (this.sx + 2) * (this.sy + 2); i++) { this.grid[i] = new point( (i % (this.sx + 2)) * this.step, (math.floor(i / (this.sx + 2))) * this.step ) } // ---- create metaballs ---- for (var = 0; < 50; i++) { this.balls[i] = new ball(this,i); } } // ==== compute cell force ==== lavalamp.prototype.computeforce = function(x, y, idx) { var force; var id = idx || x + y * (this.sx + 2); if (x === 0 || y === 0 || x === this.sx || y === this.sy) { var force = 0.6 * this.sign; } else { var cell = this.grid[id]; var force = 0; var = 0, ball; while (ball = this.balls[i++]) { force += ball.size * ball.size / (-2 * cell.x * ball.pos.x - 2 * cell.y * ball.pos.y + ball.pos.magnitude + cell.magnitude); } force *= this.sign } this.grid[id].force = force; return force; } // ---- compute cell ---- lavalamp.prototype.marchingsquares = function(next) { var x = next[0]; var y = next[1]; var pdir = next[2]; var id = x + y * (this.sx + 2); if(typeof this.grid[id] !== "undefined"){ if (this.grid[id].computed === this.iter) return false; var dir, mscase = 0; // ---- neighbors force ---- for (var = 0; < 4; i++) { var idn = (x + this.ix[i + 12]) + (y + this.ix[i + 16]) * (this.sx + 2); var force = this.grid[idn].force; if ((force > 0 && this.sign < 0) || (force < 0 && this.sign > 0) || !force) { // ---- compute force if not in buffer ---- force = this.computeforce( x + this.ix[i + 12], y + this.ix[i + 16], idn ); } if (math.abs(force) > 1) mscase += math.pow(2, i); } if (mscase === 15) { // --- inside --- return [x, y - 1, false]; } else { // ---- ambiguous cases ---- if (mscase === 5) dir = (pdir === 2) ? 3 : 1; else if (mscase === 10) dir = (pdir === 3) ? 0 : 2; else { // ---- lookup ---- dir = this.mscases[mscase]; this.grid[id].computed = this.iter; } // ---- draw line ---- var ix = this.step / ( math.abs(math.abs(this.grid[(x + this.plx[4 * dir + 2]) + (y + this.ply[4 * dir + 2]) * (this.sx + 2)].force) - 1) / math.abs(math.abs(this.grid[(x + this.plx[4 * dir + 3]) + (y + this.ply[4 * dir + 3]) * (this.sx + 2)].force) - 1) + 1 ); ctx.lineto( this.grid[(x + this.plx[4 * dir + 0]) + (y + this.ply[4 * dir + 0]) * (this.sx + 2)].x + this.ix[dir] * ix, this.grid[(x + this.plx[4 * dir + 1]) + (y + this.ply[4 * dir + 1]) * (this.sx + 2)].y + this.ix[dir + 4] * ix ); this.paint = true; // ---- next ---- return [ x + this.ix[dir + 4], y + this.ix[dir + 8], dir ]; } } } lavalamp.prototype.rendermetaballs = function() { var = 0, ball; while (ball = this.balls[i++]) ball.move(i); // ---- reset grid ---- this.iter++; this.sign = -this.sign; this.paint = false; ctx.fillstyle = '#ff0000'; ctx.beginpath(); // ---- compute metaballs ---- i = 0; while (ball = this.balls[i++]) { // ---- first cell ---- var next = [ math.round(ball.pos.x / this.step), math.round(ball.pos.y / this.step), false ]; // ---- marching squares ---- do { next = this.marchingsquares(next); } while (next); // ---- fill , close path ---- if (this.paint) { ctx.fill(); ctx.closepath(); ctx.beginpath(); this.paint = false; } } } // ==== main loop ==== var run = function() { //requestanimationframe(run); ctx.clearrect(0, 0, screen.width, screen.height); lava.rendermetaballs(); } // ---- canvas ---- var screen = metablobby.screen.init("thedots", null, true), ctx = screen.ctx, pointer = screen.pointer.init(); screen.resize(); // ---- create lavalamps ---- lava = new lavalamp(screen.width, screen.height, 10); // ---- start engine ---- run(); })();
html,body { height: 100%; width: 100%; background-color: white; } body { height: 500vh; } #thedots { position: fixed; top: 0; left: 0; width: 100vw; height: 100vh; z-index: 100; pointer-events: none; }
<canvas id="thedots" width="1203" height="363"></canvas>
but i'm getting insane rendering bugs you'll see. or maybe they're not rendering bugs , faulty code. appreciated.
thanks!
Comments
Post a Comment