• Jump To … +
    ./demo/canvas-001.js ./demo/canvas-002.js ./demo/canvas-003.js ./demo/canvas-004.js ./demo/canvas-005.js ./demo/canvas-006.js ./demo/canvas-007.js ./demo/canvas-008.js ./demo/canvas-009.js ./demo/canvas-010.js ./demo/canvas-011.js ./demo/canvas-012.js ./demo/canvas-013.js ./demo/canvas-014.js ./demo/canvas-015.js ./demo/canvas-016.js ./demo/canvas-017.js ./demo/canvas-018.js ./demo/canvas-019.js ./demo/canvas-020.js ./demo/canvas-021.js ./demo/canvas-022.js ./demo/canvas-023.js ./demo/canvas-024.js ./demo/canvas-025.js ./demo/canvas-026.js ./demo/canvas-027.js ./demo/canvas-028.js ./demo/canvas-029.js ./demo/canvas-030.js ./demo/canvas-031.js ./demo/canvas-032.js ./demo/canvas-033.js ./demo/canvas-034.js ./demo/canvas-035.js ./demo/canvas-036.js ./demo/canvas-037.js ./demo/canvas-038.js ./demo/canvas-039.js ./demo/canvas-040.js ./demo/canvas-041.js ./demo/canvas-042.js ./demo/canvas-043.js ./demo/canvas-044.js ./demo/canvas-045.js ./demo/canvas-046.js ./demo/canvas-047.js ./demo/component-001.js ./demo/component-002.js ./demo/component-003.js ./demo/component-004.js ./demo/component-005.js ./demo/component-006.js ./demo/component-007.js ./demo/core-001.js ./demo/dom-001.js ./demo/dom-002.js ./demo/dom-003.js ./demo/dom-004.js ./demo/dom-005.js ./demo/dom-006.js ./demo/dom-007.js ./demo/dom-008.js ./demo/dom-009.js ./demo/dom-010.js ./demo/dom-011.js ./demo/dom-012.js ./demo/dom-013.js ./demo/dom-014a.js ./demo/dom-014b.js ./demo/dom-014c.js ./demo/dom-015.js ./demo/dom-016.js ./demo/filters-001.js ./demo/filters-002.js ./demo/filters-003.js ./demo/filters-004.js ./demo/filters-005.js ./demo/filters-006.js ./demo/filters-007.js ./demo/filters-008.js ./demo/filters-009.js ./demo/filters-010.js ./demo/filters-011.js ./demo/filters-012.js ./demo/filters-013.js ./demo/filters-014.js ./demo/filters-015.js ./demo/filters-016.js ./demo/filters-017.js ./demo/filters-018.js ./demo/filters-019.js ./demo/filters-020.js ./demo/filters-501.js ./demo/filters-502.js ./demo/filters-503.js ./demo/filters-504.js ./demo/filters-505.js ./demo/particles-001.js ./demo/particles-002.js ./demo/particles-003.js ./demo/particles-004.js ./demo/particles-005.js ./demo/particles-006.js ./demo/particles-007.js ./demo/particles-008.js ./demo/particles-009.js ./demo/particles-010.js ./demo/particles-011.js ./demo/particles-012.js ./demo/particles-013.js ./demo/particles-014.js ./demo/particles-015.js ./demo/particles-016.js ./demo/temp-001.js ./demo/temp-inkscapeSvgFilters.js
  • ¶

    Demo DOM 007

    Animate a DOM element using the delta attribute object; dynamically change classes on a DOM element

  • ¶

    Run code

    import scrawl from '../source/scrawl.js'
  • ¶

    Scene setup

    let artefact = scrawl.library.artefact,
        stack = artefact.mystack,
        flower = artefact.flower,
        leftbox = artefact.leftbox,
        rightbox = artefact.rightbox,
        deltaX = 0.4,
        deltaY = -0.3,
        currentClass = '';
  • ¶

    Create a new Group for the box elements, against which we will be checking for hits

    • the box elements have been imported already and assigned to the Stack’s default group, but we can move them to the new Group using .set()
    let hitgroup = scrawl.makeGroup({
        name: 'hitareas',
        host: 'mystack',
    });
  • ¶

    Update the Stack

    stack.set({
        width: 600,
        height: 400,
  • ¶

    This gets the browser to add a drag icon to the stack element’s lower right corner, which in turn allows the user to drag-resize the element in real time.

        css: {
            overflow: 'hidden',
            resize: 'both'
        },
  • ¶

    Switch on automated element resize capture and processing

        checkForResize: true,
    });
  • ¶

    Update the boxes

    rightbox.set({
        group: 'hitareas',
    
        startX: '55%',
        startY: '15%',
        roll: 10,
    
        css: { backgroundColor: 'red' },
    });
    
    leftbox.set({
        group: hitgroup.name,
    
        startX: '10%',
        startY: '35%',
    
        css: { backgroundColor: 'blue' },
    });
  • ¶

    Batch-update the box artefacts using their shared Group

    hitgroup.setArtefacts({
        width: '25%',
        height: '50%',
    
        css: { opacity: '0.4' },
    });
  • ¶

    Update the flower wheel

    flower.set({
        width: 200,
        height: 200,
        startX: '50%',
        startY: '50%',
        handleX: 'center',
        handleY: 'center',
        classes: 'make_round',
        delta: {
            startX: `${deltaX}%`,
            startY: `${deltaY}%`,
            roll: 0.5,
        },
    });
  • ¶

    Scene animation

    Boundary checking can get very messy very quickly, particularly when using delta animation. The following boilerplate will work in many situations:

    1. check to see if the artefact has crossed the boundary. If it has, then…
    2. reverse the artefact away from the boundary along the path it has just travelled along
    3. check to see which of the delta values needs to be updated - for bouncing an artefact around an enclosed box, reversing the sign on the appropriate delta value is often enough
    4. move the artefact forward using its new delta values
    let checkForFlowerBoundaryCollisions = function () {
  • ¶

    Step 0 - determine the current boundary values (in this case they are dynamic, relative to the current dimensions of the Stack) and the current position of the flower element (again, a dynamic coordinate relative to Stack dimensions)

        let [x, y] = flower.get('start'),
            [minX, minY] = stack.get('dimensions');
    
        minX /= 10;
        minY /= 10;
    
        let maxX = minX * 9,
            maxY = minY * 9;
  • ¶

    Step 1 - check for boundary crossings

        if (x < minX || x > maxX || y < minY || y > maxY) {
  • ¶

    Step 2 - reverse out of danger

            flower.reverseByDelta();
  • ¶

    Step 3 - update the appropriate delta values for the flower

            let changes = {};
    
            if (x < minX || x > maxX) {
    
                deltaX = -deltaX;
                changes.startX = `${deltaX}%`;
            }
            if (y < minY || y > maxY) {
    
                deltaY = -deltaY;
                changes.startY = `${deltaY}%`;
            }
    
            flower.set({
                delta: changes
            });
  • ¶

    Step 4 - move forward away from the boundary

            flower.updateByDelta();
        }
    };
  • ¶

    Updating the flower’s DOM element’s class attribute

    let checkForFlowerClassUpdates = function () {
    
        let current = hitgroup.getArtefactAt([flower.get('start')]).artefact;
    
        if (current && !currentClass) {
    
            currentClass = (current.name === 'leftbox') ? 'make_blue' : 'make_red';
            flower.addClasses(currentClass);
        }
        else if (!current && currentClass) {
    
            flower.removeClasses(currentClass);
            currentClass = '';
        }
    };
  • ¶

    Combining the two check functions above into a single function

    let commenceActions = function () {
    
        checkForFlowerBoundaryCollisions();
        checkForFlowerClassUpdates();
    };
  • ¶

    Function to display frames-per-second data, and other information relevant to the demo

    let report = function () {
    
        let testTicker = Date.now(),
            testTime, testNow,
            testMessage = document.querySelector('#reportmessage');
    
        return function () {
    
            testNow = Date.now();
            testTime = testNow - testTicker;
            testTicker = testNow;
    
            testMessage.textContent = `Screen refresh: ${Math.ceil(testTime)}ms; fps: ${Math.floor(1000 / testTime)}
    Current classes: "${flower.get('classes')}"`;
        };
    }();
  • ¶

    Create the Display cycle animation

    scrawl.makeRender({
    
        name: 'demo-animation',
        commence: commenceActions,
        target: stack,
        afterShow: report,
  • ¶

    We need to finalize the stack’s display after the first Display cycle completes

    • Tweaking thge stack’s height attribute should cascade through to its constituent elements, so that they can finalize their own dimensions and positioning (which in this case are both set relative to the stack’s dimensions).
    • We also need to force the system to propagate the changes once; DOM element resize actions get processed only when mouse/touch cursor movements are detected, or a scroll or viewport resize event fires. To trigger this programmatically, we restart the Scrawl-canvas core listeners.
        afterCreated: () => {
            stack.set({height: 400.1});
            scrawl.startCoreListeners();
        },
    });