• 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
  • ¶

    Tracer 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.
  • ¶

    Demos:

    • particles-011 - Tracer entity: basic functionality
    • particles-012 - Use Net entity particles as reference coordinates for other artefacts
  • ¶

    Imports

    import { constructors, tween, artefact, group } from '../core/library.js';
    import { pushUnique, mergeOver, λnull, isa_fn, isa_obj, xta } from '../core/utilities.js';
    import { currentGroup } from '../core/document.js';
    
    import { makeParticle } from './particle.js';
    import { requestVector, releaseVector } from './vector.js';
    
    import baseMix from '../mixin/base.js';
    import entityMix from '../mixin/entity.js';
  • ¶

    Tracer constructor

    const Tracer = function (items = {}) {
    
        this.makeName(items.name);
        this.register();
        this.initializePositions();
        this.set(this.defs);
  • ¶

    The entity has a hit zone which can be used for drag-and-drop, and other user interactions. Thus the onXYZ UI functions remain relevant.

        this.onEnter = λnull;
        this.onLeave = λnull;
        this.onDown = λnull;
        this.onUp = λnull;
  • ¶

    As part of its stamp functionality the Net entity will invoke the stampAction function. If not supplied, the entity will not display anything on the canvas.

        this.stampAction = λnull;
  • ¶

    Tracer entitys use just one Particle, which gets initialized here and stored in the trace attribute

        this.trace = makeParticle(items);
    
        if (!items.group) items.group = currentGroup;
    
        this.set(items);
    
        if (this.purge) this.purgeArtefact(this.purge);
    
        return this;
    };
  • ¶

    Tracer prototype

    let P = Tracer.prototype = Object.create(Object.prototype);
    
    P.type = 'Tracer';
    P.lib = 'entity';
    P.isArtefact = true;
    P.isAsset = false;
  • ¶

    Mixins

    P = baseMix(P);
    P = entityMix(P);
  • ¶

    Tracer attributes

    • Attributes defined in the base mixin: name.
    • Attributes defined in the position mixin: group, visibility, order, start, startX, startY, handle, handleX, handleY, offset, offsetX, offsetY, dimensions, width, height, pivoted, mimicked, lockTo, lockXTo, lockYTo, scale, roll, noUserInteraction, noPositionDependencies, noCanvasEngineUpdates, noFilters, noPathUpdates, purge, bringToFrontOnDrag.
    • Attributes defined in the delta mixin: delta, noDeltaUpdates.
    • Attributes defined in the pivot mixin: pivot, pivotCorner, addPivotHandle, addPivotOffset, addPivotRotation.
    • Attributes defined in the mimic mixin: mimic, useMimicDimensions, useMimicScale, useMimicStart, useMimicHandle, useMimicOffset, useMimicRotation, useMimicFlip, addOwnDimensionsToMimic, addOwnScaleToMimic, addOwnStartToMimic, addOwnHandleToMimic, addOwnOffsetToMimic, addOwnRotationToMimic.
    • Attributes defined in the path mixin: path, pathPosition, addPathHandle, addPathOffset, addPathRotation, constantPathSpeed.
    • Attributes defined in the entity mixin: method, pathObject, winding, flipReverse, flipUpend, scaleOutline, lockFillStyleToEntity, lockStrokeStyleToEntity, onEnter, onLeave, onDown, onUp, fillStyle, strokeStyle, globalAlpha, globalCompositeOperation, lineWidth, lineCap, lineJoin, lineDash, lineDashOffset, miterLimit, shadowOffsetX, shadowOffsetY, shadowBlur, shadowColor, filter.
    • Attributes defined in the anchor mixin: anchor.
    • Attributes defined in the filter mixin: filters, isStencil.
    let defaultAttributes = {
  • ¶

    Note that Tracer entitys, unlike Emitters or Nets, do not need or use World objects; they are not affected by Forces or springs. They are - effectively - entitys that record their location coordinate, with the ability to remember a history of its recent locations.

    artefact - In theory, any Scrawl-canvas object whose isArtefact flag is set to true can be assigned to this attribute. However this has not been tested on non-entity artefacts. For now, stick to Scrawl-canvas entity objects.

    • Can be set using the String name of an artefact object, or the artefact object itself.
        artefact: null,
  • ¶

    historyLength - positive integer Number - every Particle will keep a record of its recent state, in a set of ParticleHistory arrays stored in the Particle’s history Array. The Emitter entity will set the maximum permitted length of the history array whenever it generates a new Particle.

        historyLength: 1,
  • ¶

    Note that the hitRadius attribute is tied directly to the width and height attributes (which are effectively meaningless for this entity)

    • This attribute is absolute - unlike other Scrawl-canvas radius attributes it cannot be set using a percentage String value
        hitRadius: 10,
  • ¶

    We can tell the entity to display its hit zone by setting the showHitRadius flag. The hit zone outline color attribute hitRadiusColor accepts any valid CSS color String value

        showHitRadius: false,
        hitRadiusColor: '#000000',
  • ¶
    Not defined in the defs object, but set up in the constructor and setters
  • ¶

    trace - the entity’s Particle object

  • ¶

    stampAction - define all major rendering actions in this function. The function receives the following arguments: (artefact, trace, host) - where artefact is the Tracer entity’s artefact object (if any has been defined/set); trace is the entity’s Particle object whose history needs to be rendered onto the canvas; and host is the Cell wrapper on which we will draw our graphics

    };
    P.defs = mergeOver(P.defs, defaultAttributes);
  • ¶

    Packet management

    P.packetExclusions = pushUnique(P.packetExclusions, []);
    P.packetExclusionsByRegex = pushUnique(P.packetExclusionsByRegex, []);
    P.packetCoordinates = pushUnique(P.packetCoordinates, []);
    P.packetObjects = pushUnique(P.packetObjects, ['artefact', 'particle']);
    P.packetFunctions = pushUnique(P.packetFunctions, ['stampAction']);
    
    P.finalizePacketOut = function (copy, items) {
    
        return copy;
    };
  • ¶

    Clone management

    P.postCloneAction = function(clone, items) {
    
        clone.trace = makeParticle({
            name: clone.name,
            historyLength: items.historyLength || this.historyLength || 1,
        });
    
        return clone;
    };
  • ¶

    Kill management

    P.factoryKill = function (killArtefact) {
    
        if (killArtefact) this.artefact.kill();
        this.trace.kill();
    };
  • ¶

    Get, Set, deltaSet

    let G = P.getters,
        S = P.setters,
        D = P.deltaSetters;
    
    S.stampAction = function (item) {
    
        if (isa_fn(item)) this.stampAction = item;
    };
    
    S.artefact = function (item) {
    
        let art;
    
        if (item.substring) art = artefact[item];
        else if (isa_obj(item) && item.isArtefact) art = item;
    
        if (art) this.artefact = art;
    };
  • ¶

    Prototype functions

  • ¶

    regularStampSynchronousActions - overwriters the functionality defined in the entity.js mixin

    P.regularStampSynchronousActions = function () {
    
        let {artefact, trace, stampAction, showHitRadius, hitRadius, hitRadiusColor, currentStampPosition} = this;
    
        let host = this.currentHost;
    
        trace.set({
            position: currentStampPosition,
        });
    
        trace.manageHistory(0, host);
        stampAction.call(this, artefact, trace, host);
    
        if (showHitRadius) {
    
            let engine = host.engine;
    
            engine.save();
            engine.lineWidth = 1;
            engine.strokeStyle = hitRadiusColor;
    
            engine.setTransform(1, 0, 0, 1, 0, 0);
            engine.beginPath();
            engine.arc(currentStampPosition[0], currentStampPosition[1], hitRadius, 0, Math.PI * 2);
            engine.stroke();
    
            engine.restore();
        }
    };
  • ¶

    checkHit - overwrites the function defined in mixin/position.js

    • The Tracer entity’s hit area is a circle centred on the entity’s rotation/reflection (start) position or, where the entity’s position is determined by reference (pivot, mimic, path, etc), the reference’s current position.
    • Tracer entitys can be dragged and dropped around a canvas display like any other Scrawl-canvas artefact.
    P.checkHit = function (items = [], mycell) {
    
        if (this.noUserInteraction) return false;
    
        let tests = (!Array.isArray(items)) ?  [items] : items;
    
        let currentStampPosition = this.currentStampPosition,
            res = false,
            tx, ty;
    
        if (tests.some(test => {
    
            if (Array.isArray(test)) {
    
                tx = test[0];
                ty = test[1];
            }
            else if (xta(test, test.x, test.y)) {
    
                tx = test.x;
                ty = test.y;
            }
            else return false;
    
            if (!tx.toFixed || !ty.toFixed || isNaN(tx) || isNaN(ty)) return false;
    
            let v = requestVector(currentStampPosition).vectorSubtract(test);
    
            if (v.getMagnitude() < this.hitRadius) res = true;
    
            releaseVector(v);
    
            return res;
    
        }, this)) {
    
            let r = this.checkHitReturn(tx, ty, mycell);
    
            return r;
        }
        return false;
    };
  • ¶

    Factory

    const makeTracer = function (items) {
        return new Tracer(items);
    };
    
    constructors.Tracer = Tracer;
  • ¶

    Exports

    export {
        makeTracer,
    };