Compare commits
4 Commits
4e718461bc
...
1a2ec17275
Author | SHA1 | Date | |
---|---|---|---|
|
1a2ec17275 | ||
|
89d217562f | ||
|
45d380010a | ||
|
0af8878ae9 |
@ -9,6 +9,7 @@
|
|||||||
"parcel": "^2.9.3"
|
"parcel": "^2.9.3"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"konva": "^9.2.1"
|
"konva": "^9.2.1",
|
||||||
|
"victor": "^1.1.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,6 +8,9 @@ dependencies:
|
|||||||
konva:
|
konva:
|
||||||
specifier: ^9.2.1
|
specifier: ^9.2.1
|
||||||
version: 9.2.1
|
version: 9.2.1
|
||||||
|
victor:
|
||||||
|
specifier: ^1.1.0
|
||||||
|
version: 1.1.0
|
||||||
|
|
||||||
devDependencies:
|
devDependencies:
|
||||||
parcel:
|
parcel:
|
||||||
@ -1875,6 +1878,10 @@ packages:
|
|||||||
engines: {node: '>= 4'}
|
engines: {node: '>= 4'}
|
||||||
dev: true
|
dev: true
|
||||||
|
|
||||||
|
/victor@1.1.0:
|
||||||
|
resolution: {integrity: sha512-s+EQHqIs5TNgLa3HHPr8oCpWFulQZzDX/PLaskVDeWXqEW12l54H5XD+cZ3gXrgvdOscqEcdAMXgEUZlJckQ4w==}
|
||||||
|
dev: false
|
||||||
|
|
||||||
/weak-lru-cache@1.2.2:
|
/weak-lru-cache@1.2.2:
|
||||||
resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==}
|
resolution: {integrity: sha512-DEAoo25RfSYMuTGc9vPJzZcZullwIqRDSI9LOy+fkCJPi6hykCnfKaXTuPBDuXAUcqHXyOgFtHNp/kB2FjYHbw==}
|
||||||
dev: true
|
dev: true
|
||||||
|
532
src/gravity-points-extern/app.js
Normal file
532
src/gravity-points-extern/app.js
Normal file
@ -0,0 +1,532 @@
|
|||||||
|
/**
|
||||||
|
* requestAnimationFrame
|
||||||
|
*/
|
||||||
|
window.requestAnimationFrame = (function(){
|
||||||
|
return window.requestAnimationFrame ||
|
||||||
|
window.webkitRequestAnimationFrame ||
|
||||||
|
window.mozRequestAnimationFrame ||
|
||||||
|
window.oRequestAnimationFrame ||
|
||||||
|
window.msRequestAnimationFrame ||
|
||||||
|
function (callback) {
|
||||||
|
window.setTimeout(callback, 1000 / 60);
|
||||||
|
};
|
||||||
|
})();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Vector
|
||||||
|
*/
|
||||||
|
function Vector(x, y) {
|
||||||
|
this.x = x || 0;
|
||||||
|
this.y = y || 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
Vector.add = function(a, b) {
|
||||||
|
return new Vector(a.x + b.x, a.y + b.y);
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector.sub = function(a, b) {
|
||||||
|
return new Vector(a.x - b.x, a.y - b.y);
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector.scale = function(v, s) {
|
||||||
|
return v.clone().scale(s);
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector.random = function() {
|
||||||
|
return new Vector(
|
||||||
|
Math.random() * 2 - 1,
|
||||||
|
Math.random() * 2 - 1
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Vector.prototype = {
|
||||||
|
set: function(x, y) {
|
||||||
|
if (typeof x === 'object') {
|
||||||
|
y = x.y;
|
||||||
|
x = x.x;
|
||||||
|
}
|
||||||
|
this.x = x || 0;
|
||||||
|
this.y = y || 0;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
add: function(v) {
|
||||||
|
this.x += v.x;
|
||||||
|
this.y += v.y;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
sub: function(v) {
|
||||||
|
this.x -= v.x;
|
||||||
|
this.y -= v.y;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
scale: function(s) {
|
||||||
|
this.x *= s;
|
||||||
|
this.y *= s;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
length: function() {
|
||||||
|
return Math.sqrt(this.x * this.x + this.y * this.y);
|
||||||
|
},
|
||||||
|
|
||||||
|
lengthSq: function() {
|
||||||
|
return this.x * this.x + this.y * this.y;
|
||||||
|
},
|
||||||
|
|
||||||
|
normalize: function() {
|
||||||
|
var m = Math.sqrt(this.x * this.x + this.y * this.y);
|
||||||
|
if (m) {
|
||||||
|
this.x /= m;
|
||||||
|
this.y /= m;
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
angle: function() {
|
||||||
|
return Math.atan2(this.y, this.x);
|
||||||
|
},
|
||||||
|
|
||||||
|
angleTo: function(v) {
|
||||||
|
var dx = v.x - this.x,
|
||||||
|
dy = v.y - this.y;
|
||||||
|
return Math.atan2(dy, dx);
|
||||||
|
},
|
||||||
|
|
||||||
|
distanceTo: function(v) {
|
||||||
|
var dx = v.x - this.x,
|
||||||
|
dy = v.y - this.y;
|
||||||
|
return Math.sqrt(dx * dx + dy * dy);
|
||||||
|
},
|
||||||
|
|
||||||
|
distanceToSq: function(v) {
|
||||||
|
var dx = v.x - this.x,
|
||||||
|
dy = v.y - this.y;
|
||||||
|
return dx * dx + dy * dy;
|
||||||
|
},
|
||||||
|
|
||||||
|
lerp: function(v, t) {
|
||||||
|
this.x += (v.x - this.x) * t;
|
||||||
|
this.y += (v.y - this.y) * t;
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
|
||||||
|
clone: function() {
|
||||||
|
return new Vector(this.x, this.y);
|
||||||
|
},
|
||||||
|
|
||||||
|
toString: function() {
|
||||||
|
return '(x:' + this.x + ', y:' + this.y + ')';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GravityPoint
|
||||||
|
*/
|
||||||
|
function GravityPoint(x, y, radius, targets) {
|
||||||
|
Vector.call(this, x, y);
|
||||||
|
this.radius = radius;
|
||||||
|
this.currentRadius = radius * 0.5;
|
||||||
|
|
||||||
|
this._targets = {
|
||||||
|
particles: targets.particles || [],
|
||||||
|
gravities: targets.gravities || []
|
||||||
|
};
|
||||||
|
this._speed = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
GravityPoint.RADIUS_LIMIT = 65;
|
||||||
|
GravityPoint.interferenceToPoint = true;
|
||||||
|
|
||||||
|
GravityPoint.prototype = (function(o) {
|
||||||
|
var s = new Vector(0, 0), p;
|
||||||
|
for (p in o) s[p] = o[p];
|
||||||
|
return s;
|
||||||
|
})({
|
||||||
|
gravity: 0.05,
|
||||||
|
isMouseOver: false,
|
||||||
|
dragging: false,
|
||||||
|
destroyed: false,
|
||||||
|
_easeRadius: 0,
|
||||||
|
_dragDistance: null,
|
||||||
|
_collapsing: false,
|
||||||
|
|
||||||
|
hitTest: function(p) {
|
||||||
|
return this.distanceTo(p) < this.radius;
|
||||||
|
},
|
||||||
|
|
||||||
|
startDrag: function(dragStartPoint) {
|
||||||
|
this._dragDistance = Vector.sub(dragStartPoint, this);
|
||||||
|
this.dragging = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
drag: function(dragToPoint) {
|
||||||
|
this.x = dragToPoint.x - this._dragDistance.x;
|
||||||
|
this.y = dragToPoint.y - this._dragDistance.y;
|
||||||
|
},
|
||||||
|
|
||||||
|
endDrag: function() {
|
||||||
|
this._dragDistance = null;
|
||||||
|
this.dragging = false;
|
||||||
|
},
|
||||||
|
|
||||||
|
addSpeed: function(d) {
|
||||||
|
this._speed = this._speed.add(d);
|
||||||
|
},
|
||||||
|
|
||||||
|
collapse: function(e) {
|
||||||
|
this.currentRadius *= 1.75;
|
||||||
|
this._collapsing = true;
|
||||||
|
},
|
||||||
|
|
||||||
|
render: function(ctx) {
|
||||||
|
if (this.destroyed) return;
|
||||||
|
|
||||||
|
var particles = this._targets.particles,
|
||||||
|
i, len;
|
||||||
|
|
||||||
|
for (i = 0, len = particles.length; i < len; i++) {
|
||||||
|
particles[i].addSpeed(Vector.sub(this, particles[i]).normalize().scale(this.gravity));
|
||||||
|
}
|
||||||
|
|
||||||
|
this._easeRadius = (this._easeRadius + (this.radius - this.currentRadius) * 0.07) * 0.95;
|
||||||
|
this.currentRadius += this._easeRadius;
|
||||||
|
if (this.currentRadius < 0) this.currentRadius = 0;
|
||||||
|
|
||||||
|
if (this._collapsing) {
|
||||||
|
this.radius *= 0.75;
|
||||||
|
if (this.currentRadius < 1) this.destroyed = true;
|
||||||
|
this._draw(ctx);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var gravities = this._targets.gravities,
|
||||||
|
g, absorp,
|
||||||
|
area = this.radius * this.radius * Math.PI, garea;
|
||||||
|
|
||||||
|
for (i = 0, len = gravities.length; i < len; i++) {
|
||||||
|
g = gravities[i];
|
||||||
|
|
||||||
|
if (g === this || g.destroyed) continue;
|
||||||
|
|
||||||
|
if (
|
||||||
|
(this.currentRadius >= g.radius || this.dragging) &&
|
||||||
|
this.distanceTo(g) < (this.currentRadius + g.radius) * 0.85
|
||||||
|
) {
|
||||||
|
g.destroyed = true;
|
||||||
|
this.gravity += g.gravity;
|
||||||
|
|
||||||
|
absorp = Vector.sub(g, this).scale(g.radius / this.radius * 0.5);
|
||||||
|
this.addSpeed(absorp);
|
||||||
|
|
||||||
|
garea = g.radius * g.radius * Math.PI;
|
||||||
|
this.currentRadius = Math.sqrt((area + garea * 3) / Math.PI);
|
||||||
|
this.radius = Math.sqrt((area + garea) / Math.PI);
|
||||||
|
}
|
||||||
|
|
||||||
|
g.addSpeed(Vector.sub(this, g).normalize().scale(this.gravity));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (GravityPoint.interferenceToPoint && !this.dragging)
|
||||||
|
this.add(this._speed);
|
||||||
|
|
||||||
|
this._speed = new Vector();
|
||||||
|
|
||||||
|
if (this.currentRadius > GravityPoint.RADIUS_LIMIT) this.collapse();
|
||||||
|
|
||||||
|
this._draw(ctx);
|
||||||
|
},
|
||||||
|
|
||||||
|
_draw: function(ctx) {
|
||||||
|
var grd, r;
|
||||||
|
|
||||||
|
ctx.save();
|
||||||
|
|
||||||
|
grd = ctx.createRadialGradient(this.x, this.y, this.radius, this.x, this.y, this.radius * 5);
|
||||||
|
grd.addColorStop(0, 'rgba(0, 0, 0, 0.1)');
|
||||||
|
grd.addColorStop(1, 'rgba(0, 0, 0, 0)');
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.radius * 5, 0, Math.PI * 2, false);
|
||||||
|
ctx.fillStyle = grd;
|
||||||
|
ctx.fill();
|
||||||
|
|
||||||
|
r = Math.random() * this.currentRadius * 0.7 + this.currentRadius * 0.3;
|
||||||
|
grd = ctx.createRadialGradient(this.x, this.y, r, this.x, this.y, this.currentRadius);
|
||||||
|
grd.addColorStop(0, 'rgba(0, 0, 0, 1)');
|
||||||
|
grd.addColorStop(1, Math.random() < 0.2 ? 'rgba(255, 196, 0, 0.15)' : 'rgba(103, 181, 191, 0.75)');
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(this.x, this.y, this.currentRadius, 0, Math.PI * 2, false);
|
||||||
|
ctx.fillStyle = grd;
|
||||||
|
ctx.fill();
|
||||||
|
ctx.restore();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Particle
|
||||||
|
*/
|
||||||
|
function Particle(x, y, radius) {
|
||||||
|
Vector.call(this, x, y);
|
||||||
|
this.radius = radius;
|
||||||
|
|
||||||
|
this._latest = new Vector();
|
||||||
|
this._speed = new Vector();
|
||||||
|
}
|
||||||
|
|
||||||
|
Particle.prototype = (function(o) {
|
||||||
|
var s = new Vector(0, 0), p;
|
||||||
|
for (p in o) s[p] = o[p];
|
||||||
|
return s;
|
||||||
|
})({
|
||||||
|
addSpeed: function(d) {
|
||||||
|
this._speed.add(d);
|
||||||
|
},
|
||||||
|
|
||||||
|
update: function() {
|
||||||
|
if (this._speed.length() > 12) this._speed.normalize().scale(12);
|
||||||
|
|
||||||
|
this._latest.set(this);
|
||||||
|
this.add(this._speed);
|
||||||
|
}
|
||||||
|
|
||||||
|
// render: function(ctx) {
|
||||||
|
// if (this._speed.length() > 12) this._speed.normalize().scale(12);
|
||||||
|
|
||||||
|
// this._latest.set(this);
|
||||||
|
// this.add(this._speed);
|
||||||
|
|
||||||
|
// ctx.save();
|
||||||
|
// ctx.fillStyle = ctx.strokeStyle = '#fff';
|
||||||
|
// ctx.lineCap = ctx.lineJoin = 'round';
|
||||||
|
// ctx.lineWidth = this.radius * 2;
|
||||||
|
// ctx.beginPath();
|
||||||
|
// ctx.moveTo(this.x, this.y);
|
||||||
|
// ctx.lineTo(this._latest.x, this._latest.y);
|
||||||
|
// ctx.stroke();
|
||||||
|
// ctx.beginPath();
|
||||||
|
// ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
|
||||||
|
// ctx.fill();
|
||||||
|
// ctx.restore();
|
||||||
|
// }
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Initialize
|
||||||
|
|
||||||
|
(function() {
|
||||||
|
|
||||||
|
// Configs
|
||||||
|
|
||||||
|
var BACKGROUND_COLOR = 'rgba(11, 51, 56, 1)',
|
||||||
|
PARTICLE_RADIUS = 1,
|
||||||
|
G_POINT_RADIUS = 10,
|
||||||
|
G_POINT_RADIUS_LIMITS = 65;
|
||||||
|
|
||||||
|
|
||||||
|
// Vars
|
||||||
|
|
||||||
|
var canvas, context,
|
||||||
|
bufferCvs, bufferCtx,
|
||||||
|
screenWidth, screenHeight,
|
||||||
|
mouse = new Vector(),
|
||||||
|
gravities = [],
|
||||||
|
particles = [],
|
||||||
|
grad,
|
||||||
|
gui, control;
|
||||||
|
|
||||||
|
|
||||||
|
// Event Listeners
|
||||||
|
|
||||||
|
function resize(e) {
|
||||||
|
screenWidth = canvas.width = window.innerWidth;
|
||||||
|
screenHeight = canvas.height = window.innerHeight;
|
||||||
|
bufferCvs.width = screenWidth;
|
||||||
|
bufferCvs.height = screenHeight;
|
||||||
|
context = canvas.getContext('2d');
|
||||||
|
bufferCtx = bufferCvs.getContext('2d');
|
||||||
|
|
||||||
|
var cx = canvas.width * 0.5,
|
||||||
|
cy = canvas.height * 0.5;
|
||||||
|
|
||||||
|
grad = context.createRadialGradient(cx, cy, 0, cx, cy, Math.sqrt(cx * cx + cy * cy));
|
||||||
|
grad.addColorStop(0, 'rgba(0, 0, 0, 0)');
|
||||||
|
grad.addColorStop(1, 'rgba(0, 0, 0, 0.35)');
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseMove(e) {
|
||||||
|
mouse.set(e.clientX, e.clientY);
|
||||||
|
|
||||||
|
var i, g, hit = false;
|
||||||
|
for (i = gravities.length - 1; i >= 0; i--) {
|
||||||
|
g = gravities[i];
|
||||||
|
if ((!hit && g.hitTest(mouse)) || g.dragging)
|
||||||
|
g.isMouseOver = hit = true;
|
||||||
|
else
|
||||||
|
g.isMouseOver = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas.style.cursor = hit ? 'pointer' : 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseDown(e) {
|
||||||
|
for (var i = gravities.length - 1; i >= 0; i--) {
|
||||||
|
if (gravities[i].isMouseOver) {
|
||||||
|
gravities[i].startDrag(mouse);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
gravities.push(new GravityPoint(e.clientX, e.clientY, G_POINT_RADIUS, {
|
||||||
|
particles: particles,
|
||||||
|
gravities: gravities
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
function mouseUp(e) {
|
||||||
|
for (var i = 0, len = gravities.length; i < len; i++) {
|
||||||
|
if (gravities[i].dragging) {
|
||||||
|
gravities[i].endDrag();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doubleClick(e) {
|
||||||
|
for (var i = gravities.length - 1; i >= 0; i--) {
|
||||||
|
if (gravities[i].isMouseOver) {
|
||||||
|
gravities[i].collapse();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Functions
|
||||||
|
|
||||||
|
function addParticle(num) {
|
||||||
|
var i, p;
|
||||||
|
for (i = 0; i < num; i++) {
|
||||||
|
p = new Particle(
|
||||||
|
Math.floor(Math.random() * screenWidth - PARTICLE_RADIUS * 2) + 1 + PARTICLE_RADIUS,
|
||||||
|
Math.floor(Math.random() * screenHeight - PARTICLE_RADIUS * 2) + 1 + PARTICLE_RADIUS,
|
||||||
|
PARTICLE_RADIUS
|
||||||
|
);
|
||||||
|
p.addSpeed(Vector.random());
|
||||||
|
particles.push(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeParticle(num) {
|
||||||
|
if (particles.length < num) num = particles.length;
|
||||||
|
for (var i = 0; i < num; i++) {
|
||||||
|
particles.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GUI Control
|
||||||
|
|
||||||
|
control = {
|
||||||
|
particleNum: 100
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// Init
|
||||||
|
|
||||||
|
canvas = document.getElementById('c');
|
||||||
|
bufferCvs = document.createElement('canvas');
|
||||||
|
|
||||||
|
window.addEventListener('resize', resize, false);
|
||||||
|
resize(null);
|
||||||
|
|
||||||
|
addParticle(control.particleNum);
|
||||||
|
|
||||||
|
canvas.addEventListener('mousemove', mouseMove, false);
|
||||||
|
canvas.addEventListener('mousedown', mouseDown, false);
|
||||||
|
canvas.addEventListener('mouseup', mouseUp, false);
|
||||||
|
canvas.addEventListener('dblclick', doubleClick, false);
|
||||||
|
|
||||||
|
|
||||||
|
// GUI
|
||||||
|
|
||||||
|
gui = new dat.GUI();
|
||||||
|
gui.add(control, 'particleNum', 0, 500).step(1).name('Particle Num').onChange(function() {
|
||||||
|
var n = (control.particleNum | 0) - particles.length;
|
||||||
|
if (n > 0)
|
||||||
|
addParticle(n);
|
||||||
|
else if (n < 0)
|
||||||
|
removeParticle(-n);
|
||||||
|
});
|
||||||
|
gui.add(GravityPoint, 'interferenceToPoint').name('Interference Between Point');
|
||||||
|
gui.close();
|
||||||
|
|
||||||
|
|
||||||
|
// Start Update
|
||||||
|
|
||||||
|
var loop = function() {
|
||||||
|
var i, len, g, p;
|
||||||
|
|
||||||
|
context.save();
|
||||||
|
context.fillStyle = BACKGROUND_COLOR;
|
||||||
|
context.fillRect(0, 0, screenWidth, screenHeight);
|
||||||
|
context.fillStyle = grad;
|
||||||
|
context.fillRect(0, 0, screenWidth, screenHeight);
|
||||||
|
context.restore();
|
||||||
|
|
||||||
|
for (i = 0, len = gravities.length; i < len; i++) {
|
||||||
|
g = gravities[i];
|
||||||
|
if (g.dragging) g.drag(mouse);
|
||||||
|
g.render(context);
|
||||||
|
if (g.destroyed) {
|
||||||
|
gravities.splice(i, 1);
|
||||||
|
len--;
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bufferCtx.save();
|
||||||
|
bufferCtx.globalCompositeOperation = 'destination-out';
|
||||||
|
bufferCtx.globalAlpha = 0.35;
|
||||||
|
bufferCtx.fillRect(0, 0, screenWidth, screenHeight);
|
||||||
|
bufferCtx.restore();
|
||||||
|
|
||||||
|
// パーティクルをバッファに描画
|
||||||
|
// for (i = 0, len = particles.length; i < len; i++) {
|
||||||
|
// particles[i].render(bufferCtx);
|
||||||
|
// }
|
||||||
|
len = particles.length;
|
||||||
|
bufferCtx.save();
|
||||||
|
bufferCtx.fillStyle = bufferCtx.strokeStyle = '#fff';
|
||||||
|
bufferCtx.lineCap = bufferCtx.lineJoin = 'round';
|
||||||
|
bufferCtx.lineWidth = PARTICLE_RADIUS * 2;
|
||||||
|
bufferCtx.beginPath();
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
p = particles[i];
|
||||||
|
p.update();
|
||||||
|
bufferCtx.moveTo(p.x, p.y);
|
||||||
|
bufferCtx.lineTo(p._latest.x, p._latest.y);
|
||||||
|
}
|
||||||
|
bufferCtx.stroke();
|
||||||
|
bufferCtx.beginPath();
|
||||||
|
for (i = 0; i < len; i++) {
|
||||||
|
p = particles[i];
|
||||||
|
bufferCtx.moveTo(p.x, p.y);
|
||||||
|
bufferCtx.arc(p.x, p.y, p.radius, 0, Math.PI * 2, false);
|
||||||
|
}
|
||||||
|
bufferCtx.fill();
|
||||||
|
bufferCtx.restore();
|
||||||
|
|
||||||
|
// バッファをキャンバスに描画
|
||||||
|
context.drawImage(bufferCvs, 0, 0);
|
||||||
|
|
||||||
|
requestAnimationFrame(loop);
|
||||||
|
};
|
||||||
|
loop();
|
||||||
|
|
||||||
|
})();
|
||||||
|
|
15
src/gravity-points-extern/index.html
Normal file
15
src/gravity-points-extern/index.html
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8"/>
|
||||||
|
<title>Fizzy Sparks</title>
|
||||||
|
<link href="style.css" rel="stylesheet" />
|
||||||
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.5/dat.gui.min.js"></script>
|
||||||
|
<script type="module" src="app.js"></script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<canvas id="mainCanvas"></canvas>
|
||||||
|
<div class="info">Click to add gravity point.</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
28
src/gravity-points-extern/style.css
Normal file
28
src/gravity-points-extern/style.css
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
body {
|
||||||
|
font-family: Helvetica sans-serif;
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
background-color: #222;
|
||||||
|
overflow: hidden;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-o-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
padding: 5px 15px;
|
||||||
|
color: #eee;
|
||||||
|
font-size: 13px;
|
||||||
|
background-color: rgba(0, 0, 0, .5);
|
||||||
|
}
|
@ -1,532 +1,40 @@
|
|||||||
/**
|
const Victor = require("victor");
|
||||||
* requestAnimationFrame
|
|
||||||
*/
|
|
||||||
window.requestAnimationFrame = (function(){
|
|
||||||
return window.requestAnimationFrame ||
|
|
||||||
window.webkitRequestAnimationFrame ||
|
|
||||||
window.mozRequestAnimationFrame ||
|
|
||||||
window.oRequestAnimationFrame ||
|
|
||||||
window.msRequestAnimationFrame ||
|
|
||||||
function (callback) {
|
|
||||||
window.setTimeout(callback, 1000 / 60);
|
|
||||||
};
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
// TODO cycle this bkg color
|
||||||
|
const BACKGROUND_COLOR = 'rgba(11, 51, 56, 1)';
|
||||||
|
const PARTICLE_RADIUS = 1;
|
||||||
|
const G_POINT_RADIUS = 10;
|
||||||
|
const G_POINT_RADIUS_LIMITS = 65;
|
||||||
|
|
||||||
/**
|
const canvas = document.getElementById("mainCanvas");
|
||||||
* Vector
|
const bufferCvs = document.createElement("canvas");
|
||||||
*/
|
const context = canvas.getContext('2d');
|
||||||
function Vector(x, y) {
|
const bufferCtx = bufferCvs.getContext('2d');
|
||||||
this.x = x || 0;
|
|
||||||
this.y = y || 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
Vector.add = function(a, b) {
|
const screenWidth = canvas.width = window.innerWidth;
|
||||||
return new Vector(a.x + b.x, a.y + b.y);
|
const screenHeight = canvas.height = window.innerHeight;
|
||||||
};
|
|
||||||
|
|
||||||
Vector.sub = function(a, b) {
|
console.log("Finished initting");
|
||||||
return new Vector(a.x - b.x, a.y - b.y);
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector.scale = function(v, s) {
|
const loop = (timestamp) => {
|
||||||
return v.clone().scale(s);
|
window.requestAnimationFrame(loop);
|
||||||
};
|
|
||||||
|
|
||||||
Vector.random = function() {
|
const cx = canvas.width / 2;
|
||||||
return new Vector(
|
const cy = canvas.height / 2;
|
||||||
Math.random() * 2 - 1,
|
|
||||||
Math.random() * 2 - 1
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Vector.prototype = {
|
context.save();
|
||||||
set: function(x, y) {
|
context.fillStyle = BACKGROUND_COLOR;
|
||||||
if (typeof x === 'object') {
|
context.fillRect(0, 0, screenWidth, screenHeight);
|
||||||
y = x.y;
|
|
||||||
x = x.x;
|
|
||||||
}
|
|
||||||
this.x = x || 0;
|
|
||||||
this.y = y || 0;
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
add: function(v) {
|
// create circular gradient that fills the screen
|
||||||
this.x += v.x;
|
const grad = context.createRadialGradient(cx, cy, 0, cx, cy, Math.sqrt(cx * cx + cy * cy));
|
||||||
this.y += v.y;
|
grad.addColorStop(0, 'rgba(0, 0, 0, 0)');
|
||||||
return this;
|
grad.addColorStop(1, 'rgba(0, 0, 0, 0.35)');
|
||||||
},
|
|
||||||
|
|
||||||
sub: function(v) {
|
context.fillStyle = grad;
|
||||||
this.x -= v.x;
|
context.fillRect(0, 0, screenWidth, screenHeight);
|
||||||
this.y -= v.y;
|
context.restore();
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
scale: function(s) {
|
|
||||||
this.x *= s;
|
|
||||||
this.y *= s;
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
length: function() {
|
|
||||||
return Math.sqrt(this.x * this.x + this.y * this.y);
|
|
||||||
},
|
|
||||||
|
|
||||||
lengthSq: function() {
|
|
||||||
return this.x * this.x + this.y * this.y;
|
|
||||||
},
|
|
||||||
|
|
||||||
normalize: function() {
|
|
||||||
var m = Math.sqrt(this.x * this.x + this.y * this.y);
|
|
||||||
if (m) {
|
|
||||||
this.x /= m;
|
|
||||||
this.y /= m;
|
|
||||||
}
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
angle: function() {
|
|
||||||
return Math.atan2(this.y, this.x);
|
|
||||||
},
|
|
||||||
|
|
||||||
angleTo: function(v) {
|
|
||||||
var dx = v.x - this.x,
|
|
||||||
dy = v.y - this.y;
|
|
||||||
return Math.atan2(dy, dx);
|
|
||||||
},
|
|
||||||
|
|
||||||
distanceTo: function(v) {
|
|
||||||
var dx = v.x - this.x,
|
|
||||||
dy = v.y - this.y;
|
|
||||||
return Math.sqrt(dx * dx + dy * dy);
|
|
||||||
},
|
|
||||||
|
|
||||||
distanceToSq: function(v) {
|
|
||||||
var dx = v.x - this.x,
|
|
||||||
dy = v.y - this.y;
|
|
||||||
return dx * dx + dy * dy;
|
|
||||||
},
|
|
||||||
|
|
||||||
lerp: function(v, t) {
|
|
||||||
this.x += (v.x - this.x) * t;
|
|
||||||
this.y += (v.y - this.y) * t;
|
|
||||||
return this;
|
|
||||||
},
|
|
||||||
|
|
||||||
clone: function() {
|
|
||||||
return new Vector(this.x, this.y);
|
|
||||||
},
|
|
||||||
|
|
||||||
toString: function() {
|
|
||||||
return '(x:' + this.x + ', y:' + this.y + ')';
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
/**
|
loop();
|
||||||
* GravityPoint
|
|
||||||
*/
|
|
||||||
function GravityPoint(x, y, radius, targets) {
|
|
||||||
Vector.call(this, x, y);
|
|
||||||
this.radius = radius;
|
|
||||||
this.currentRadius = radius * 0.5;
|
|
||||||
|
|
||||||
this._targets = {
|
|
||||||
particles: targets.particles || [],
|
|
||||||
gravities: targets.gravities || []
|
|
||||||
};
|
|
||||||
this._speed = new Vector();
|
|
||||||
}
|
|
||||||
|
|
||||||
GravityPoint.RADIUS_LIMIT = 65;
|
|
||||||
GravityPoint.interferenceToPoint = true;
|
|
||||||
|
|
||||||
GravityPoint.prototype = (function(o) {
|
|
||||||
var s = new Vector(0, 0), p;
|
|
||||||
for (p in o) s[p] = o[p];
|
|
||||||
return s;
|
|
||||||
})({
|
|
||||||
gravity: 0.05,
|
|
||||||
isMouseOver: false,
|
|
||||||
dragging: false,
|
|
||||||
destroyed: false,
|
|
||||||
_easeRadius: 0,
|
|
||||||
_dragDistance: null,
|
|
||||||
_collapsing: false,
|
|
||||||
|
|
||||||
hitTest: function(p) {
|
|
||||||
return this.distanceTo(p) < this.radius;
|
|
||||||
},
|
|
||||||
|
|
||||||
startDrag: function(dragStartPoint) {
|
|
||||||
this._dragDistance = Vector.sub(dragStartPoint, this);
|
|
||||||
this.dragging = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
drag: function(dragToPoint) {
|
|
||||||
this.x = dragToPoint.x - this._dragDistance.x;
|
|
||||||
this.y = dragToPoint.y - this._dragDistance.y;
|
|
||||||
},
|
|
||||||
|
|
||||||
endDrag: function() {
|
|
||||||
this._dragDistance = null;
|
|
||||||
this.dragging = false;
|
|
||||||
},
|
|
||||||
|
|
||||||
addSpeed: function(d) {
|
|
||||||
this._speed = this._speed.add(d);
|
|
||||||
},
|
|
||||||
|
|
||||||
collapse: function(e) {
|
|
||||||
this.currentRadius *= 1.75;
|
|
||||||
this._collapsing = true;
|
|
||||||
},
|
|
||||||
|
|
||||||
render: function(ctx) {
|
|
||||||
if (this.destroyed) return;
|
|
||||||
|
|
||||||
var particles = this._targets.particles,
|
|
||||||
i, len;
|
|
||||||
|
|
||||||
for (i = 0, len = particles.length; i < len; i++) {
|
|
||||||
particles[i].addSpeed(Vector.sub(this, particles[i]).normalize().scale(this.gravity));
|
|
||||||
}
|
|
||||||
|
|
||||||
this._easeRadius = (this._easeRadius + (this.radius - this.currentRadius) * 0.07) * 0.95;
|
|
||||||
this.currentRadius += this._easeRadius;
|
|
||||||
if (this.currentRadius < 0) this.currentRadius = 0;
|
|
||||||
|
|
||||||
if (this._collapsing) {
|
|
||||||
this.radius *= 0.75;
|
|
||||||
if (this.currentRadius < 1) this.destroyed = true;
|
|
||||||
this._draw(ctx);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var gravities = this._targets.gravities,
|
|
||||||
g, absorp,
|
|
||||||
area = this.radius * this.radius * Math.PI, garea;
|
|
||||||
|
|
||||||
for (i = 0, len = gravities.length; i < len; i++) {
|
|
||||||
g = gravities[i];
|
|
||||||
|
|
||||||
if (g === this || g.destroyed) continue;
|
|
||||||
|
|
||||||
if (
|
|
||||||
(this.currentRadius >= g.radius || this.dragging) &&
|
|
||||||
this.distanceTo(g) < (this.currentRadius + g.radius) * 0.85
|
|
||||||
) {
|
|
||||||
g.destroyed = true;
|
|
||||||
this.gravity += g.gravity;
|
|
||||||
|
|
||||||
absorp = Vector.sub(g, this).scale(g.radius / this.radius * 0.5);
|
|
||||||
this.addSpeed(absorp);
|
|
||||||
|
|
||||||
garea = g.radius * g.radius * Math.PI;
|
|
||||||
this.currentRadius = Math.sqrt((area + garea * 3) / Math.PI);
|
|
||||||
this.radius = Math.sqrt((area + garea) / Math.PI);
|
|
||||||
}
|
|
||||||
|
|
||||||
g.addSpeed(Vector.sub(this, g).normalize().scale(this.gravity));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (GravityPoint.interferenceToPoint && !this.dragging)
|
|
||||||
this.add(this._speed);
|
|
||||||
|
|
||||||
this._speed = new Vector();
|
|
||||||
|
|
||||||
if (this.currentRadius > GravityPoint.RADIUS_LIMIT) this.collapse();
|
|
||||||
|
|
||||||
this._draw(ctx);
|
|
||||||
},
|
|
||||||
|
|
||||||
_draw: function(ctx) {
|
|
||||||
var grd, r;
|
|
||||||
|
|
||||||
ctx.save();
|
|
||||||
|
|
||||||
grd = ctx.createRadialGradient(this.x, this.y, this.radius, this.x, this.y, this.radius * 5);
|
|
||||||
grd.addColorStop(0, 'rgba(0, 0, 0, 0.1)');
|
|
||||||
grd.addColorStop(1, 'rgba(0, 0, 0, 0)');
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(this.x, this.y, this.radius * 5, 0, Math.PI * 2, false);
|
|
||||||
ctx.fillStyle = grd;
|
|
||||||
ctx.fill();
|
|
||||||
|
|
||||||
r = Math.random() * this.currentRadius * 0.7 + this.currentRadius * 0.3;
|
|
||||||
grd = ctx.createRadialGradient(this.x, this.y, r, this.x, this.y, this.currentRadius);
|
|
||||||
grd.addColorStop(0, 'rgba(0, 0, 0, 1)');
|
|
||||||
grd.addColorStop(1, Math.random() < 0.2 ? 'rgba(255, 196, 0, 0.15)' : 'rgba(103, 181, 191, 0.75)');
|
|
||||||
ctx.beginPath();
|
|
||||||
ctx.arc(this.x, this.y, this.currentRadius, 0, Math.PI * 2, false);
|
|
||||||
ctx.fillStyle = grd;
|
|
||||||
ctx.fill();
|
|
||||||
ctx.restore();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Particle
|
|
||||||
*/
|
|
||||||
function Particle(x, y, radius) {
|
|
||||||
Vector.call(this, x, y);
|
|
||||||
this.radius = radius;
|
|
||||||
|
|
||||||
this._latest = new Vector();
|
|
||||||
this._speed = new Vector();
|
|
||||||
}
|
|
||||||
|
|
||||||
Particle.prototype = (function(o) {
|
|
||||||
var s = new Vector(0, 0), p;
|
|
||||||
for (p in o) s[p] = o[p];
|
|
||||||
return s;
|
|
||||||
})({
|
|
||||||
addSpeed: function(d) {
|
|
||||||
this._speed.add(d);
|
|
||||||
},
|
|
||||||
|
|
||||||
update: function() {
|
|
||||||
if (this._speed.length() > 12) this._speed.normalize().scale(12);
|
|
||||||
|
|
||||||
this._latest.set(this);
|
|
||||||
this.add(this._speed);
|
|
||||||
}
|
|
||||||
|
|
||||||
// render: function(ctx) {
|
|
||||||
// if (this._speed.length() > 12) this._speed.normalize().scale(12);
|
|
||||||
|
|
||||||
// this._latest.set(this);
|
|
||||||
// this.add(this._speed);
|
|
||||||
|
|
||||||
// ctx.save();
|
|
||||||
// ctx.fillStyle = ctx.strokeStyle = '#fff';
|
|
||||||
// ctx.lineCap = ctx.lineJoin = 'round';
|
|
||||||
// ctx.lineWidth = this.radius * 2;
|
|
||||||
// ctx.beginPath();
|
|
||||||
// ctx.moveTo(this.x, this.y);
|
|
||||||
// ctx.lineTo(this._latest.x, this._latest.y);
|
|
||||||
// ctx.stroke();
|
|
||||||
// ctx.beginPath();
|
|
||||||
// ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2, false);
|
|
||||||
// ctx.fill();
|
|
||||||
// ctx.restore();
|
|
||||||
// }
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Initialize
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
// Configs
|
|
||||||
|
|
||||||
var BACKGROUND_COLOR = 'rgba(11, 51, 56, 1)',
|
|
||||||
PARTICLE_RADIUS = 1,
|
|
||||||
G_POINT_RADIUS = 10,
|
|
||||||
G_POINT_RADIUS_LIMITS = 65;
|
|
||||||
|
|
||||||
|
|
||||||
// Vars
|
|
||||||
|
|
||||||
var canvas, context,
|
|
||||||
bufferCvs, bufferCtx,
|
|
||||||
screenWidth, screenHeight,
|
|
||||||
mouse = new Vector(),
|
|
||||||
gravities = [],
|
|
||||||
particles = [],
|
|
||||||
grad,
|
|
||||||
gui, control;
|
|
||||||
|
|
||||||
|
|
||||||
// Event Listeners
|
|
||||||
|
|
||||||
function resize(e) {
|
|
||||||
screenWidth = canvas.width = window.innerWidth;
|
|
||||||
screenHeight = canvas.height = window.innerHeight;
|
|
||||||
bufferCvs.width = screenWidth;
|
|
||||||
bufferCvs.height = screenHeight;
|
|
||||||
context = canvas.getContext('2d');
|
|
||||||
bufferCtx = bufferCvs.getContext('2d');
|
|
||||||
|
|
||||||
var cx = canvas.width * 0.5,
|
|
||||||
cy = canvas.height * 0.5;
|
|
||||||
|
|
||||||
grad = context.createRadialGradient(cx, cy, 0, cx, cy, Math.sqrt(cx * cx + cy * cy));
|
|
||||||
grad.addColorStop(0, 'rgba(0, 0, 0, 0)');
|
|
||||||
grad.addColorStop(1, 'rgba(0, 0, 0, 0.35)');
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseMove(e) {
|
|
||||||
mouse.set(e.clientX, e.clientY);
|
|
||||||
|
|
||||||
var i, g, hit = false;
|
|
||||||
for (i = gravities.length - 1; i >= 0; i--) {
|
|
||||||
g = gravities[i];
|
|
||||||
if ((!hit && g.hitTest(mouse)) || g.dragging)
|
|
||||||
g.isMouseOver = hit = true;
|
|
||||||
else
|
|
||||||
g.isMouseOver = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
canvas.style.cursor = hit ? 'pointer' : 'default';
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseDown(e) {
|
|
||||||
for (var i = gravities.length - 1; i >= 0; i--) {
|
|
||||||
if (gravities[i].isMouseOver) {
|
|
||||||
gravities[i].startDrag(mouse);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
gravities.push(new GravityPoint(e.clientX, e.clientY, G_POINT_RADIUS, {
|
|
||||||
particles: particles,
|
|
||||||
gravities: gravities
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
function mouseUp(e) {
|
|
||||||
for (var i = 0, len = gravities.length; i < len; i++) {
|
|
||||||
if (gravities[i].dragging) {
|
|
||||||
gravities[i].endDrag();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function doubleClick(e) {
|
|
||||||
for (var i = gravities.length - 1; i >= 0; i--) {
|
|
||||||
if (gravities[i].isMouseOver) {
|
|
||||||
gravities[i].collapse();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Functions
|
|
||||||
|
|
||||||
function addParticle(num) {
|
|
||||||
var i, p;
|
|
||||||
for (i = 0; i < num; i++) {
|
|
||||||
p = new Particle(
|
|
||||||
Math.floor(Math.random() * screenWidth - PARTICLE_RADIUS * 2) + 1 + PARTICLE_RADIUS,
|
|
||||||
Math.floor(Math.random() * screenHeight - PARTICLE_RADIUS * 2) + 1 + PARTICLE_RADIUS,
|
|
||||||
PARTICLE_RADIUS
|
|
||||||
);
|
|
||||||
p.addSpeed(Vector.random());
|
|
||||||
particles.push(p);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function removeParticle(num) {
|
|
||||||
if (particles.length < num) num = particles.length;
|
|
||||||
for (var i = 0; i < num; i++) {
|
|
||||||
particles.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// GUI Control
|
|
||||||
|
|
||||||
control = {
|
|
||||||
particleNum: 100
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
// Init
|
|
||||||
|
|
||||||
canvas = document.getElementById('c');
|
|
||||||
bufferCvs = document.createElement('canvas');
|
|
||||||
|
|
||||||
window.addEventListener('resize', resize, false);
|
|
||||||
resize(null);
|
|
||||||
|
|
||||||
addParticle(control.particleNum);
|
|
||||||
|
|
||||||
canvas.addEventListener('mousemove', mouseMove, false);
|
|
||||||
canvas.addEventListener('mousedown', mouseDown, false);
|
|
||||||
canvas.addEventListener('mouseup', mouseUp, false);
|
|
||||||
canvas.addEventListener('dblclick', doubleClick, false);
|
|
||||||
|
|
||||||
|
|
||||||
// GUI
|
|
||||||
|
|
||||||
gui = new dat.GUI();
|
|
||||||
gui.add(control, 'particleNum', 0, 500).step(1).name('Particle Num').onChange(function() {
|
|
||||||
var n = (control.particleNum | 0) - particles.length;
|
|
||||||
if (n > 0)
|
|
||||||
addParticle(n);
|
|
||||||
else if (n < 0)
|
|
||||||
removeParticle(-n);
|
|
||||||
});
|
|
||||||
gui.add(GravityPoint, 'interferenceToPoint').name('Interference Between Point');
|
|
||||||
gui.close();
|
|
||||||
|
|
||||||
|
|
||||||
// Start Update
|
|
||||||
|
|
||||||
var loop = function() {
|
|
||||||
var i, len, g, p;
|
|
||||||
|
|
||||||
context.save();
|
|
||||||
context.fillStyle = BACKGROUND_COLOR;
|
|
||||||
context.fillRect(0, 0, screenWidth, screenHeight);
|
|
||||||
context.fillStyle = grad;
|
|
||||||
context.fillRect(0, 0, screenWidth, screenHeight);
|
|
||||||
context.restore();
|
|
||||||
|
|
||||||
for (i = 0, len = gravities.length; i < len; i++) {
|
|
||||||
g = gravities[i];
|
|
||||||
if (g.dragging) g.drag(mouse);
|
|
||||||
g.render(context);
|
|
||||||
if (g.destroyed) {
|
|
||||||
gravities.splice(i, 1);
|
|
||||||
len--;
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bufferCtx.save();
|
|
||||||
bufferCtx.globalCompositeOperation = 'destination-out';
|
|
||||||
bufferCtx.globalAlpha = 0.35;
|
|
||||||
bufferCtx.fillRect(0, 0, screenWidth, screenHeight);
|
|
||||||
bufferCtx.restore();
|
|
||||||
|
|
||||||
// パーティクルをバッファに描画
|
|
||||||
// for (i = 0, len = particles.length; i < len; i++) {
|
|
||||||
// particles[i].render(bufferCtx);
|
|
||||||
// }
|
|
||||||
len = particles.length;
|
|
||||||
bufferCtx.save();
|
|
||||||
bufferCtx.fillStyle = bufferCtx.strokeStyle = '#fff';
|
|
||||||
bufferCtx.lineCap = bufferCtx.lineJoin = 'round';
|
|
||||||
bufferCtx.lineWidth = PARTICLE_RADIUS * 2;
|
|
||||||
bufferCtx.beginPath();
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
p = particles[i];
|
|
||||||
p.update();
|
|
||||||
bufferCtx.moveTo(p.x, p.y);
|
|
||||||
bufferCtx.lineTo(p._latest.x, p._latest.y);
|
|
||||||
}
|
|
||||||
bufferCtx.stroke();
|
|
||||||
bufferCtx.beginPath();
|
|
||||||
for (i = 0; i < len; i++) {
|
|
||||||
p = particles[i];
|
|
||||||
bufferCtx.moveTo(p.x, p.y);
|
|
||||||
bufferCtx.arc(p.x, p.y, p.radius, 0, Math.PI * 2, false);
|
|
||||||
}
|
|
||||||
bufferCtx.fill();
|
|
||||||
bufferCtx.restore();
|
|
||||||
|
|
||||||
// バッファをキャンバスに描画
|
|
||||||
context.drawImage(bufferCvs, 0, 0);
|
|
||||||
|
|
||||||
requestAnimationFrame(loop);
|
|
||||||
};
|
|
||||||
loop();
|
|
||||||
|
|
||||||
})();
|
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<script type="module" src="app.js"></script>
|
<script type="module" src="app.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<canvas id="c"></canvas>
|
<canvas id="mainCanvas"></canvas>
|
||||||
<div class="info">Click to add gravity point.</div>
|
<div class="info">Click to add gravity point.</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
@ -1,20 +1,15 @@
|
|||||||
body {
|
body {
|
||||||
font-family: Helvetica sans-serif;
|
font-family: "Fira Sans", Helvetica, sans-serif;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
margin: 0;
|
margin: 0;
|
||||||
background-color: #222;
|
background-color: #222;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
-webkit-user-select: none;
|
|
||||||
-moz-user-select: none;
|
|
||||||
-o-user-select: none;
|
|
||||||
-ms-user-select: none;
|
|
||||||
user-select: none;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
canvas {
|
canvas {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 10;
|
||||||
left: 0;
|
left: 10;
|
||||||
}
|
}
|
||||||
|
|
||||||
.info {
|
.info {
|
||||||
|
@ -15,7 +15,8 @@
|
|||||||
<li> <a href="./orbital-trails/index.html">Orbital Trails (mine)</a>
|
<li> <a href="./orbital-trails/index.html">Orbital Trails (mine)</a>
|
||||||
<li> <a href="./bokeh/index.html">Bokeh effect (their)</a>
|
<li> <a href="./bokeh/index.html">Bokeh effect (their)</a>
|
||||||
<li> <a href="./sparks/index.html">Sparks (theirs)</a>
|
<li> <a href="./sparks/index.html">Sparks (theirs)</a>
|
||||||
<li> <a href="./gravity-points/index.html">Gravity Points (theirs)</a>
|
<li> <a href="./gravity-points-extern/index.html">Gravity Points (theirs)</a>
|
||||||
|
<li> <a href="./gravity-points/index.html">Gravity Points (mine)</a>
|
||||||
</ul>
|
</ul>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user