summaryrefslogtreecommitdiffstats
path: root/bounds2/demo.js
blob: 8f3e1d4e01025dfff9d8583d678a74472c315b84 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
/*global Particle: false, Attractor: false, rAF: false */

var canvas, ctx;
var canvasW, canvasH;
var particle;
var attractors = [];
var maxDistance;

document.addEventListener( 'DOMContentLoaded', init, false );

function init() {
  canvas = document.querySelector('canvas');
  ctx = canvas.getContext('2d');
  // set size
  canvasW = canvas.width = window.innerWidth - 20;
  canvasH = canvas.height = window.innerHeight - 80;
  

  canvas.addEventListener( 'mousedown', onMousedown, false );

  particle = new Particle( canvasW / 2, canvasH / 2 );
  var x0 = canvasW * 0.2;
  var x1 = canvasW * 0.8;
  attractors.push( new Attractor( x0, canvasH / 2 ) );
  attractors.push( new Attractor( x1, canvasH / 2 ) );
  maxDistance = Math.abs( x1 - x0 ) *0.5;

  animate();
}

// -------------------------- animate, render, update -------------------------- //


function animate() {
  // apply force of bounds to particle
  if ( !isDragging ) {
    // left bound
    applyBoundForce( attractors[0].x, 1 );
    // right bound
    applyBoundForce( attractors[1].x, -1 );
  }

  particle.update();

  render();
  rAF( animate );
}

function applyBoundForce( boundX, direction ) {
  // left force
  var distance = boundX - particle.x;
  var force = distance * 0.05;
  force = Math.max( force * direction, 0 ) * direction;
  // prevent particle from bounds too far back
  // don't apply force if particle is returning from outside bounds
  if ( force && particle.velocity * direction > 0 ) {
    // resting position
    var restPosition = particle.getRestingPosition();
    if ( restPosition.x * direction > boundX * direction ) {
      force = ( boundX - particle.x ) / restPosition.frictionSum - particle.velocity;
    }
  }
  particle.applyForce( force );
}


function render() {
  ctx.clearRect( 0, 0, canvasW, canvasH );

  // render particle
  ctx.fillStyle = 'hsla(0, 100%, 50%, 0.5)';
  circle( particle.x, particle.y, 15 );

  // render attractor
  ctx.fillStyle = 'hsla(240, 100%, 50%, 0.5)';
  for ( var i=0, len = attractors.length; i < len; i++ ) {
    var attractor = attractors[i];
    circle( attractor.x, attractor.y, 8 );
  }
}

function circle( x, y, radius ) {
  ctx.beginPath();
  ctx.arc( x, y, radius, 0, Math.PI * 2, true );
  ctx.fill();
  ctx.closePath();
}

// -------------------------- mouse -------------------------- //

var isDragging = false;

function onMousedown( event ) {
  event.preventDefault();
  isDragging = true;
  window.addEventListener( 'mousemove', onMousemove, false );
  window.addEventListener( 'mouseup', onMouseup, false );
  particle.x = event.pageX;
  particle.velocity = 0;
}

var previousX;
var previousTime;
var currentTime;

function onMousemove( event ) {
  // previous
  previousX = particle.x;
  previousTime = currentTime;
  // current
  particle.x = event.pageX;
  currentTime = new Date();
}

function onMouseup( event ) {
  if ( previousX ) {
    particle.velocity = ( particle.x - previousX ) / ( currentTime - previousTime );
    particle.velocity *= 17;
    previousX = null;
  }
  // console.log( particle.velocity );
  isDragging = false;
  window.removeEventListener( 'mousemove', onMousemove, false );
  window.removeEventListener( 'mousemove', onMouseup, false );
}