| <!doctype html> | |
| <html> | |
| <head> | |
| <meta charset='utf-8'> | |
| <style> | |
| * { | |
| box-sizing: border-box; | |
| } | |
| body, | |
| svg, | |
| canvas { | |
| margin: 0; | |
| padding: 0; | |
| } | |
| #container, | |
| svg, | |
| canvas, | |
| #overlay { | |
| position: fixed; | |
| top: 0; | |
| left: 0; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div id='container'></div> | |
| <div id='overlay'></div> | |
| <script src='https://d3js.org/d3.v3.min.js' charset='utf-8'></script> | |
| <script> | |
| let w = window.innerWidth, | |
| h = window.innerHeight | |
| let canvas = d3.select('#container').append('canvas').attr({width: w, height: h}), | |
| ctx = canvas.node().getContext('2d') | |
| ctx.strokeStyle = '#000' | |
| </script> | |
| <script> | |
| class Agent { | |
| constructor () { | |
| this._x = Math.random() | |
| this._y = Math.random() | |
| this._angle = Math.random() | |
| } | |
| pos (x, y) { | |
| if (!arguments.length) { | |
| return [this._x, this._y] | |
| } | |
| [this._x, this._y] = [x, y] | |
| return this | |
| } | |
| dxy (x, y) { | |
| return [x - this._x, y - this._y] | |
| } | |
| dist (x, y) { | |
| let [dx, dy] = this.dxy(x, y) | |
| return Math.sqrt(dx*dx + dy*dy) | |
| } | |
| getAngle (x, y) { | |
| if (!arguments.length) return this._angle | |
| let [dx, dy] = this.dxy(x, y) | |
| return Math.atan2(dy, dx) | |
| } | |
| setAngle (angle) { | |
| this._angle = angle | |
| } | |
| } | |
| </script> | |
| <script> | |
| let qs = window.location.search.substr(1).split('&'), | |
| args = qs.reduce((argz, arg) => { | |
| arg = arg.split('=') | |
| argz[arg[0]] = +arg[1] | |
| return argz | |
| }, {}) | |
| const SPEED = args.speed || 0.007, | |
| INFLUENCE = args.infl || 0.00005, | |
| INFL_EXP = args.infl_exp || 2.0, | |
| INFL_MAX_ANGLE = args.max_angle || 0.5, | |
| circleDefaults = [10, 0, 2 * Math.PI] | |
| const n = 20, | |
| agents = d3.range(n).map(d => new Agent()) | |
| function render () { | |
| requestAnimationFrame(render) | |
| let i = n || agents.length | |
| while (i--) { | |
| let a1 = agents[i], | |
| a1Pos = a1.pos(), | |
| j = n || agents.length, | |
| angle = a1.getAngle() | |
| while (j--) { | |
| if (i !== j) { | |
| let a2 = agents[j], | |
| a2Pos = a2.pos(), | |
| dist = a1.dist(...a2Pos), | |
| deltaAngle = a1.getAngle(...a2Pos), | |
| weight = INFLUENCE / Math.pow(dist, INFL_EXP) | |
| angle += Math.max(-INFL_MAX_ANGLE, Math.min(INFL_MAX_ANGLE, deltaAngle * weight)) | |
| } | |
| } | |
| a1.setAngle(angle) | |
| let [x, y] = [a1Pos[0] + Math.cos(angle) * SPEED, a1Pos[1] + Math.sin(angle) * SPEED] | |
| if (x < 0) x += 1 | |
| if (x > 1) x -= 1 | |
| if (y < 0) y += 1 | |
| if (y > 1) y -= 1 | |
| a1.pos(x, y) | |
| // console.log(x, y) | |
| } | |
| update(agents) | |
| } | |
| render() | |
| function update (agents) { | |
| ctx.clearRect(0, 0, w, h) | |
| let i = n || agents.length | |
| while (i--) { | |
| let pos = agents[i].pos() | |
| ctx.beginPath() | |
| ctx.arc(pos[0] * w, pos[1] * h, ...circleDefaults) | |
| ctx.stroke() | |
| } | |
| } | |
| </script> | |
| </body> | |
| </html> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment