<div id="vizzu-container" style="width: 720px; height: 430px"></div>
import Vizzu from 'https://cdn.jsdelivr.net/npm/vizzu@latest/dist/vizzu.min.js';
class Vector {
constructor(x, y) {
this.x = x;
this.y = y;
}
static Random() {
return new Vector(Math.random(), Math.random());
}
mul(multiplier) {
return new Vector(
this.x * (multiplier?.x || multiplier),
this.y * (multiplier?.y || multiplier));
}
add(other) {
return new Vector(this.x + other.x, this.y + other.y);
}
}
class BouncingBall {
static lastIndex = 0;
constructor(massToSize) {
this.index = BouncingBall.lastIndex++;
this.position = Vector.Random();
this.speed = (Vector.Random()).mul(new Vector(3, 5));
this.mass = Math.random();
this.radius = Math.sqrt(this.mass)*massToSize;
}
update(timeStep) {
const g = 9.81;
const friction = 0.5;
let acceleration = this.speed.mul(-friction * this.mass).add(new Vector(0, -g));
this.speed = this.speed.add(acceleration.mul(timeStep));
this.position = this.position.add(this.speed.mul(timeStep));
this.collision('y', v => v);
this.collision('x', v => v);
this.collision('x', v => 1 - v);
}
collision(coordinate, conversion) {
const collisionDumping = 0.6;
let side = conversion(this.position[coordinate]) - this.radius;
if (side < 0) {
this.position[coordinate] = conversion(- side + this.radius);
this.speed[coordinate] *= -collisionDumping;
}
}
}
class Model {
constructor(chart, ballCount = 150) {
let massToSize = chart.getComputedStyle().plot.marker.circleMaxRadius;
this.time = 0;
this.balls = [];
for (let i = 0; i < ballCount; i++)
this.balls.push(new BouncingBall(massToSize));
}
update(timeStep)
{
for (let ball of this.balls) ball.update(timeStep);
this.time += timeStep;
}
}
function getDataFromModel(model) {
return {
series: [
{ name: 'index', type: 'dimension', values: model.balls.map(ball => `${ball.index}`) },
{ name: 'x', type: 'measure', values: model.balls.map(ball => ball.position.x) },
{ name: 'y', type: 'measure', values: model.balls.map(ball => ball.position.y) },
{ name: 'size', type: 'measure', values: model.balls.map(ball => ball.mass) }
]
};
}
function getChartConfig() {
return {
title: 'Bouncing balls realtime simulation',
x: { set: 'x', range: { min: 0, max: 1} },
y: { set: 'y', range: { min: 0, max: 1} },
color: 'index',
size: 'size',
geometry: 'circle',
legend: null
};
}
let vizzu = new Vizzu('vizzu-container');
function update(model, chart)
{
const timeStep = 0.01;
model.update(timeStep);
if (model.time < 4)
return chart.animate({
data: getDataFromModel(model),
config: getChartConfig()
}, timeStep)
.then(chart => update(model, chart));
}
vizzu.initializing.then(chart => {
let model = new Model(chart);
return update(model, chart);
});
This Pen doesn't use any external CSS resources.
This Pen doesn't use any external JavaScript resources.