• Jump To … +
    ./source/core/animationloop.js ./source/core/component.js ./source/core/document.js ./source/core/events.js ./source/core/init.js ./source/core/library.js ./source/core/userInteraction.js ./source/core/utilities.js ./source/factory/action.js ./source/factory/anchor.js ./source/factory/animation.js ./source/factory/bezier.js ./source/factory/block.js ./source/factory/canvas.js ./source/factory/cell.js ./source/factory/cog.js ./source/factory/color.js ./source/factory/coordinate.js ./source/factory/element.js ./source/factory/emitter.js ./source/factory/filter.js ./source/factory/fontAttributes.js ./source/factory/gradient.js ./source/factory/grid.js ./source/factory/group.js ./source/factory/imageAsset.js ./source/factory/line.js ./source/factory/loom.js ./source/factory/mesh.js ./source/factory/net.js ./source/factory/noise.js ./source/factory/oval.js ./source/factory/palette.js ./source/factory/particle.js ./source/factory/particleForce.js ./source/factory/particleHistory.js ./source/factory/particleSpring.js ./source/factory/particleWorld.js ./source/factory/pattern.js ./source/factory/phrase.js ./source/factory/picture.js ./source/factory/polygon.js ./source/factory/polyline.js ./source/factory/quadratic.js ./source/factory/quaternion.js ./source/factory/radialGradient.js ./source/factory/rectangle.js ./source/factory/renderAnimation.js ./source/factory/shape.js ./source/factory/spiral.js ./source/factory/spriteAsset.js ./source/factory/stack.js ./source/factory/star.js ./source/factory/state.js ./source/factory/tetragon.js ./source/factory/ticker.js ./source/factory/tracer.js ./source/factory/tween.js ./source/factory/unstackedElement.js ./source/factory/vector.js ./source/factory/videoAsset.js ./source/factory/wheel.js ./source/mixin/anchor.js ./source/mixin/asset.js ./source/mixin/assetConsumer.js ./source/mixin/base.js ./source/mixin/cascade.js ./source/mixin/delta.js ./source/mixin/displayShape.js ./source/mixin/dom.js ./source/mixin/entity.js ./source/mixin/filter.js ./source/mixin/mimic.js ./source/mixin/path.js ./source/mixin/pattern.js ./source/mixin/pivot.js ./source/mixin/position.js ./source/mixin/shapeBasic.js ./source/mixin/shapeCurve.js ./source/mixin/shapePathCalculation.js ./source/mixin/styles.js ./source/mixin/tween.js ./source/worker/filter-string.js ./source/worker/filter.js
  • ¶

    Spring factory

    The Scrawl-canvas particle physics engine is a simple system designed to allow developers a way to add particle-based effects to their canvas animation scenes. The physics engine is built on top of the following components:

    • Particle objects, which represent a 3-dimensional coordinate - based on a Scrawl-canvas Vector object - and include a history of recent positions which we can use to determine how to display that particle on screen.
    • History arrays which can be pooled (reused) to cut down on Array creation and distruction during the animation.
    • Force objects which define the general and occasional forces to be applied to each particle in the system as the animation progresses - a gravity force object is pre-defined by Scrawl-canvas.
    • Spring objects used to define a constraint (connection) between two particles in a system.
    • World objects where we can store attributes and values used by various objects; these attributes can be set up so that they will be inherited by clones of the World object. We can also influence the speed of the physics animation here.

    We do not have to handle particle generation and manipulation ourselves. Instead, Scrawl-canvas gives us three dedicated entitys which we use to add particle animation effects to the canvas scene. These entitys are:

    • Tracer - this entity generates a single non-recycled (in other words: long lasting) particle with a history, which we can use to display trace effects in the animation.
    • Emitter - an entity which generates a stream of short-lived, recycled particles, each with its own history. Emitters are highly versatile entitys which can generate a wide range of effects.
    • Net - a (generally) larger entity which uses both forces and springs to manage the animation of its non-recycled particles. Note that other artefacts can use Net particles as a reference for their own positioning.

    Particle physics

    The Scrawl-canvas particle physics engine system is based on a fairly classical understanding of particle kinetics (applying forces and constraints to a small, spherical object in 3D space) and kinematics (the movement of the small object in response to the forces and constraints applied to it).

    A Scrawl-canvas Spring object connects together two Particle objects, linking them together with a set of constraints which together exert a spring force on the Particles.

    • Currently Scrawl-canvas offers only the spring constraint for connecting Particles; it does not (yet) define joint or other types of constraint.
    • The Net entity is, at the moment, the only entity which makes use of Spring objects.

    The Spring factory uses the Base mixin, thus Spring objects can be cloned and killed like other Scrawl-canvas objects. Spring objects are stored in the scrawl.library.spring section of the Scrawl-canvas library object.

  • ¶

    Demos:

    • particles-008 - Net entity: generation and basic functionality, including Spring objects
    • particles-009 - Net particles: drag-and-drop functionality
    • particles-010 - Net entity: using a shape path as a net template
  • ¶

    Imports

    import { constructors, particle } from '../core/library.js';
    import { mergeOver, pushUnique, λnull } from '../core/utilities.js';
    
    import { requestVector, releaseVector } from './vector.js';
    
    import baseMix from '../mixin/base.js';
  • ¶

    Spring constructor

    const Spring = function (items = {}) {
    
        this.makeName(items.name);
        this.register();
    
        this.set(this.defs);
    
        this.set(items);
    
        if (!this.action) this.action = λnull;
    
        return this;
    };
  • ¶

    Spring prototype

    let P = Spring.prototype = Object.create(Object.prototype);
    P.type = 'Spring';
    P.lib = 'spring';
    P.isArtefact = false;
    P.isAsset = false;
  • ¶

    Mixins

    P = baseMix(P);
  • ¶

    Spring attributes

    • Attributes defined in the base mixin: name.
    let 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

    let S = P.setters;
  • ¶

    particleFrom, particleTo

    S.particleFrom = function (item) {
    
        if (item.substring) item = particle[item];
    
        if (item && item.type === 'Particle') this.particleFrom = item;
    };
    S.particleTo = function (item) {
    
        if (item.substring) item = particle[item];
    
        if (item && item.type === 'Particle') this.particleTo = item;
    };
  • ¶

    Prototype functions

    applySpring - internal function

    P.applySpring = function () {
    
        let {particleFrom, particleTo, particleFromIsStatic, particleToIsStatic, springConstant, damperConstant, restLength} = this;
    
        if (particleFrom && particleTo) {
    
            let {position: fromPosition, velocity: fromVelocity, load: fromLoad} = particleFrom;
            let {position: toPosition, velocity: toVelocity, load: toLoad} = particleTo;
    
            let dVelocity = requestVector(toVelocity).vectorSubtract(fromVelocity),
                dPosition = requestVector(toPosition).vectorSubtract(fromPosition);
    
            let firstNorm = requestVector(dPosition).normalize(),
                secondNorm = requestVector(firstNorm);
    
            firstNorm.scalarMultiply(springConstant * (dPosition.getMagnitude() - restLength));
            dVelocity.vectorMultiply(secondNorm).scalarMultiply(damperConstant).vectorMultiply(secondNorm);
    
            let 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();
    const makeSpring = function (items) {
        return new Spring(items);
    };
    
    constructors.Spring = Spring;
  • ¶

    Exports

    export {
        makeSpring,
    };