scrawl-canvas
Version:
Responsive, interactive and more accessible HTML5 canvas elements. Scrawl-canvas is a JavaScript library designed to make using the HTML5 canvas element easier, and more fun
202 lines (143 loc) • 4.84 kB
JavaScript
// # Spring factory
// Spring objects are used to define a constraint (connection) between two particles in a system.
// #### Imports
import { constructors, particle } from '../core/library.js';
import { doCreate, mergeOver, pushUnique, Ωempty } from '../helper/utilities.js';
import { releaseVector, requestVector } from '../untracked-factory/vector.js';
import baseMix from '../mixin/base.js';
// Shared constants
import { T_PARTICLE } from '../helper/shared-vars.js';
// Local constants
const SPRING = 'spring',
T_SPRING = 'Spring';
// #### Spring constructor
const Spring = function (items = Ωempty) {
this.makeName(items.name);
this.register();
this.set(this.defs);
this.set(items);
return this;
};
// #### Spring prototype
const P = Spring.prototype = doCreate();
P.type = T_SPRING;
P.lib = SPRING;
P.isArtefact = false;
P.isAsset = false;
// #### Mixins
baseMix(P);
// #### Spring attributes
const defaultAttributes = {
// __particleFrom__, __particleTo__ - String name of a Particle, or the Particle object itself. These attributes hold references to the Particle objects involved in this constraint.
particleFrom: null,
particleFromIsStatic: false,
particleTo: null,
particleToIsStatic: false,
// `springConstant` - float Number. Larger values make the spring stiffer. Suggested values: 5 - 300
springConstant: 50,
// `damperConstant` - float Number. Larger values forces the spring to take a longer time to come to equilibrium. Suggested values: 5 - 50
damperConstant: 10,
// `restLength` - The spring's ideal length - the further away from its ideal, the more force the spring will apply to its connected body objects to get them back to their optimal distance
restLength: 1,
};
P.defs = mergeOver(P.defs, defaultAttributes);
// #### Packet management
P.packetObjects = pushUnique(P.packetObjects, ['particleFrom', 'particleTo']);
// #### Clone management
// No additional clone functionality required
// #### Kill management
P.kill = function () {
this.deregister();
return true;
};
// #### Get, Set, deltaSet
const S = P.setters;
// `particleFrom`, `particleTo`
S.particleFrom = function (item) {
if (item.substring) item = particle[item];
if (item && item.type === T_PARTICLE) this.particleFrom = item;
};
S.particleTo = function (item) {
if (item.substring) item = particle[item];
if (item && item.type === T_PARTICLE) this.particleTo = item;
};
// #### Prototype functions
// `applySpring` - internal function
P.applySpring = function () {
const { particleFrom, particleTo, particleFromIsStatic, particleToIsStatic, springConstant, damperConstant, restLength } = this;
if (!(particleFrom && particleTo)) return;
const { position: fromPos, velocity: fromVel, load: fromLoad } = particleFrom;
const { position: toPos, velocity: toVel, load: toLoad } = particleTo;
const dPos = requestVector(toPos).vectorSubtract(fromPos);
const len = dPos.getMagnitude();
if (!len) {
releaseVector(dPos);
return;
}
const n = requestVector(dPos).normalize();
const dVel = requestVector(toVel).vectorSubtract(fromVel);
const force = requestVector(n).scalarMultiply(springConstant * (len - restLength));
const vAlong = dVel.getDot(n);
force.vectorAddScaled(n, damperConstant * vAlong);
if (!particleFromIsStatic)fromLoad.vectorAdd(force);
if (!particleToIsStatic) toLoad.vectorSubtract(force);
releaseVector(dPos, n, dVel, force);
};
// #### Factory
// ```
// scrawl.makeNet({
//
// name: 'test-net',
//
// generate: function () {
//
// let { name, particleStore, springs, springConstant, damperConstant } = this;
//
// let leftParticle, rightParticle;
//
// // generate particles
// leftParticle = makeParticle({
//
// name: `${name}-left`,
//
// positionX: 0,
// positionY: 0,
// });
//
// rightParticle = leftParticle.clone({
//
// name: `${name}-right`,
// positionX: 100,
// });
//
// leftParticle.run(0, 0, false);
// rightParticle.run(0, 0, false);
//
// particleStore.push(leftParticle, rightParticle);
//
// // generate spring
// let mySpring = makeSpring({
//
// name: `${name}-link-${i}-${i+1}`,
//
// particleFrom: leftParticle,
// particleTo: rightParticle,
//
// springConstant,
// damperConstant,
//
// restLength: 100,
// });
//
// springs.push(mySpring);
// },
//
// ...
//
// }).run();
// ```
export const makeSpring = function (items) {
if (!items) return false;
return new Spring(items);
};
constructors.Spring = Spring;