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
197 lines (141 loc) • 5.03 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, λnull, Ω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);
if (!this.action) this.action = λnull;
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) {
const {position: fromPosition, velocity: fromVelocity, load: fromLoad} = particleFrom;
const {position: toPosition, velocity: toVelocity, load: toLoad} = particleTo;
const dVelocity = requestVector(toVelocity).vectorSubtract(fromVelocity),
dPosition = requestVector(toPosition).vectorSubtract(fromPosition);
const firstNorm = requestVector(dPosition).normalize(),
secondNorm = requestVector(firstNorm);
firstNorm.scalarMultiply(springConstant * (dPosition.getMagnitude() - restLength));
dVelocity.vectorMultiply(secondNorm).scalarMultiply(damperConstant).vectorMultiply(secondNorm);
const force = requestVector(firstNorm).vectorAdd(dVelocity);
if (!particleFromIsStatic) fromLoad.vectorAdd(force);
if (!particleToIsStatic) toLoad.vectorSubtract(force);
releaseVector(dVelocity, dPosition, firstNorm, secondNorm, 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;