Charming Vector
Charming Vector provides 2D vectors for simulating physical laws, such as positions, velocities and forces. Each operation comes in two forms: a function such as cm.vecAdd(a, b), which returns a new vector, and a method such as vec.add(b), which changes the vector in place and returns it.
(() => {
const renderer = cm.canvas({width: 640, height: 200});
const root = cm.flow().renderer(renderer);
const node = renderer.node();
const mover = {location: cm.vec(320, 50), velocity: cm.vec(3, 0)};
const gravity = cm.vec(0, 0.3);
let started = false;
let frame = requestAnimationFrame(function tick() {
if (!node.isConnected && started) return;
started = true;
mover.velocity.add(gravity);
mover.location.add(mover.velocity);
if (mover.location.y > 180) mover.velocity.setY(-Math.abs(mover.velocity.y) * 0.95);
if (mover.location.x < 20 || mover.location.x > 620) mover.velocity.setX(-mover.velocity.x);
root.append(cm.clear, {fill: "white"});
root.datum(mover).append(cm.circle, {x: (d) => d.location.x, y: (d) => d.location.y, r: 20, fill: "black"});
root.render();
frame = requestAnimationFrame(tick);
});
unsubscribe(() => cancelAnimationFrame(frame));
return node;
})();const mover = {location: cm.vec(320, 50), velocity: cm.vec(3, 0)};
const gravity = cm.vec(0, 0.3);
requestAnimationFrame(function frame() {
mover.velocity.add(gravity);
mover.location.add(mover.velocity);
if (mover.location.y > 180) mover.velocity.setY(-Math.abs(mover.velocity.y) * 0.95);
if (mover.location.x < 20 || mover.location.x > 620) mover.velocity.setX(-mover.velocity.x);
root.append(cm.clear, {fill: "white"});
root.datum(mover).append(cm.circle, {x: (d) => d.location.x, y: (d) => d.location.y, r: 20, fill: "black"});
root.render();
requestAnimationFrame(frame);
});cm.vec([x[, y]])
Returns a vector with the specified x and y components, each defaulting to 0.
cm.vec(); // {x: 0, y: 0}
cm.vec(1); // {x: 1, y: 0}
cm.vec(2, 3); // {x: 2, y: 3}cm.vecFromAngle(angle)
Returns the unit vector at the specified angle in radians.
cm.vecFromAngle(Math.PI / 4); // {x: 0.7071…, y: 0.7071…}cm.vecRandom()
Returns a unit vector in a random direction.
cm.vecRandom().mag(); // 1cm.vecAdd(a, b)
Returns the sum of the vectors a and b.
cm.vecAdd(cm.vec(1, 2), cm.vec(2, 3)); // {x: 3, y: 5}cm.vecSub(a, b)
Returns the difference of the vectors a and b.
cm.vecSub(cm.vec(1, 2), cm.vec(2, 4)); // {x: -1, y: -2}cm.vecMult(a, value)
Returns the vector a multiplied by value.
cm.vecMult(cm.vec(3, 4), 2); // {x: 6, y: 8}cm.vecDiv(a, value)
Returns the vector a divided by value.
cm.vecDiv(cm.vec(3, 4), 0.5); // {x: 6, y: 8}cm.vecMag(a[, value])
With one argument, returns the magnitude of the vector a. With two, returns a vector in the direction of a with magnitude value.
cm.vecMag(cm.vec(3, 4)); // 5
cm.vecMag(cm.vec(3, 4), 10); // {x: 6, y: 8}cm.vecNorm(a)
Returns the unit vector in the direction of a. The zero vector stays the zero vector.
cm.vecNorm(cm.vec(3, 4)); // {x: 0.6, y: 0.8}cm.vecClamp(a, min[, max])
Returns a copy of the vector a with its magnitude constrained to [min, max]. With two arguments, the second is the maximum and the minimum is 0.
cm.vecClamp(cm.vec(3, 4), 10, 15); // {x: 6, y: 8}
cm.vecClamp(cm.vec(6, 8), 5); // {x: 3, y: 4}cm.vecDist(a, b)
Returns the distance between the vectors a and b.
cm.vecDist(cm.vec(4, 6), cm.vec(1, 2)); // 5cm.vecDist2(a, b)
Returns the squared distance between the vectors a and b, which is cheaper to compute when only comparing distances.
cm.vecDist2(cm.vec(4, 6), cm.vec(1, 2)); // 25cm.vecDot(a, b)
Returns the dot product of the vectors a and b.
cm.vecDot(cm.vec(3, 4), cm.vec(1, 2)); // 11cm.vecCross(a, b)
Returns the cross product of the vectors a and b: the z component of their 3D cross product.
cm.vecCross(cm.vec(3, 4), cm.vec(1, 2)); // 2cm.vecAngle(a)
Returns the angle of the vector a in radians.
cm.vecAngle(cm.vec(1, 1)); // Math.PI / 4vec.set(x[, y])
Sets the components to those of the vector x, or to the numbers x and y, and returns this vector. vec.setX(x) and vec.setY(y) set one component.
const a = cm.vec(1, 2);
a.set(cm.vec(3, 4)); // a, {x: 3, y: 4}
a.set(5, 6); // a, {x: 5, y: 6}
a.setX(7); // a, {x: 7, y: 6}vec.clone()
Returns a copy of this vector.
const a = cm.vec(1, 2);
const b = a.clone();
a === b; // falsevec.add(b)
Adds the vector b to this vector, and returns this vector. Likewise, vec.sub(b) subtracts, vec.mult(value) multiplies and vec.div(value) divides.
const a = cm.vec(1, 2);
a.add(cm.vec(3, 4)); // a, {x: 4, y: 6}
a.mult(2); // a, {x: 8, y: 12}vec.mag([value])
Without an argument, returns the magnitude of this vector. With a value, sets the magnitude and returns this vector.
const a = cm.vec(3, 4);
a.mag(); // 5
a.mag(10); // a, {x: 6, y: 8}vec.norm()
Normalizes this vector to magnitude 1, and returns it.
cm.vec(3, 4).norm(); // {x: 0.6, y: 0.8}vec.clamp(min[, max])
Constrains the magnitude of this vector to [min, max], and returns it. With one argument, it's the maximum and the minimum is 0.
cm.vec(6, 8).clamp(5); // {x: 3, y: 4}vec.random()
Sets this vector to a unit vector in a random direction, and returns it.
cm.vec(3, 4).random().mag(); // 1vec.dist(b)
Returns the distance to the vector b. vec.dist2(b) returns the squared distance.
cm.vec(4, 6).dist(cm.vec(1, 2)); // 5
cm.vec(4, 6).dist2(cm.vec(1, 2)); // 25vec.dot(b)
Returns the dot product with the vector b. vec.cross(b) returns the cross product.
cm.vec(3, 4).dot(cm.vec(1, 2)); // 11
cm.vec(3, 4).cross(cm.vec(1, 2)); // 2vec.angle()
Returns the angle of this vector in radians.
cm.vec(1, 1).angle(); // Math.PI / 4