• 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/canvas-048.js ./demo/canvas-049.js ./demo/canvas-050.js ./demo/canvas-051.js ./demo/canvas-052.js ./demo/canvas-053.js ./demo/canvas-054.js ./demo/canvas-055.js ./demo/canvas-056.js ./demo/canvas-057.js ./demo/canvas-058.js ./demo/canvas-059.js ./demo/canvas-060.js ./demo/canvas-061.js ./demo/canvas-062.js ./demo/canvas-063.js ./demo/canvas-064.js ./demo/canvas-065.js ./demo/canvas-066.js ./demo/canvas-067.js ./demo/canvas-068.js ./demo/canvas-069.js ./demo/canvas-070.js ./demo/canvas-071.js ./demo/canvas-072.js ./demo/canvas-073.js ./demo/canvas-201.js ./demo/canvas-202.js ./demo/canvas-203.js ./demo/canvas-204.js ./demo/canvas-205.js ./demo/canvas-206.js ./demo/canvas-207.js ./demo/canvas-208.js ./demo/canvas-209.js ./demo/canvas-210.js ./demo/canvas-211.js ./demo/canvas-212.js ./demo/delaunator-001.js ./demo/delaunator-002.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-015.js ./demo/dom-016.js ./demo/dom-017.js ./demo/dom-018.js ./demo/dom-019.js ./demo/dom-020.js ./demo/dom-021.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-021.js ./demo/filters-022.js ./demo/filters-023.js ./demo/filters-024.js ./demo/filters-025.js ./demo/filters-026.js ./demo/filters-027.js ./demo/filters-028.js ./demo/filters-029.js ./demo/filters-030.js ./demo/filters-031.js ./demo/filters-032.js ./demo/filters-033.js ./demo/filters-034.js ./demo/filters-035.js ./demo/filters-036.js ./demo/filters-037.js ./demo/filters-038.js ./demo/filters-039.js ./demo/filters-040.js ./demo/filters-041.js ./demo/filters-042.js ./demo/filters-101.js ./demo/filters-102.js ./demo/filters-103.js ./demo/filters-104.js ./demo/filters-105.js ./demo/filters-501.js ./demo/filters-502.js ./demo/filters-503.js ./demo/filters-504.js ./demo/filters-505.js ./demo/mediapipe-001.js ./demo/mediapipe-002.js ./demo/mediapipe-003.js ./demo/modules-001.js ./demo/modules-002.js ./demo/modules-003.js ./demo/modules-004.js ./demo/modules-005.js ./demo/modules-006.js ./demo/packets-001.js ./demo/packets-002.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/particles-017.js ./demo/snippets-001.js ./demo/snippets-002.js ./demo/snippets-003.js ./demo/snippets-004.js ./demo/snippets-005.js ./demo/snippets-006.js ./demo/temp-001.js ./demo/temp-shape-scale-investigation.js ./demo/tensorflow-001.js ./demo/tensorflow-002.js ./demo/utilities.js
  • §

    Demo DOM 017

    Testing getCanvas(), getStack() functionality

  • §

    Run code

    import * as scrawl from '../source/scrawl.js';
    
    import { reportSpeed, reportFullLibrary } from './utilities.js';
  • §

    Scene setup

    const canvasParent = document.querySelector('#canvas-parent');
    const canvasSwitchButton = document.querySelector('#canvas-switch');
    const canvasReplaceButton = document.querySelector('#canvas-replace');
    const canvasRemoveButton = document.querySelector('#canvas-remove');
    
    const stackParent = document.querySelector('#stack-parent');
    const stackSwitchButton = document.querySelector('#stack-switch');
    const stackReplaceButton = document.querySelector('#stack-replace');
    const stackRemoveButton = document.querySelector('#stack-remove');
  • §

    KeyboardZones and DragZones don’t integrate with their canvas/stack parents - they’re useful add-ons rather than an integrated part of the system. So we need to have an elegant way to handle them.

    const dragZones = {};
  • §

    User interaction (CANVAS test)

    Switch canvas

  • §

    Load a new canvas with a different namespace into the parent element. Emulates a react component render when the component details have changed. For example:

    • Start with the square canvas - onboard and capture details about that canvas and associated artefacts/objects in the libarary
    • Switch to the round canvas - capture details about that canvas and associated artefacts/objects in the libarary. Details about the square canvas will not be removed from the library without specific instruction even though the related DOM canvas no longer exists
    • Switch back to the square canvas - it is at this point that SC should recognise the details it holds about the previous canvas are no longer relevant, purge everything related to that old canvas from the library, and then repopulate with new data
    • Existing functionality for Canvas.kill() is to delete the associated DOM data structures for that canvas from the page - though the canvas itself was removed some time prior and SC did nothing about it. Make sure that any errors emerging from that activity are properly captured and handled
  • §

    Replace canvas

  • §

    Load a new canvas with the same namespace into the parent element. Emulates a react component render when the component details have NOT changed - the component is rendered again because something else in the page has triggered a more general render. For example:

    • Start with the square canvas - onboard and capture details about that canvas and associated artefacts/objects in the libarary
    • Replace that canvas with another square canvas. SC needs to identify that while details about the canvas still exist, that canvas has gone and the new canvas needs to be processed and data about it - and all related artefacts/objects - stored in the library
  • §

    Remove canvas

  • §

    Purge everything relating to the current canvas’s namespace from the SC library

    
    const insertCanvas = (element, parent) => {
        console.log('inserting a canvas into the DOM parent');
    
        parent.innerHTML = element;
    };
    
    const buildSquareCanvas = (namespace) => {
        console.log('build a new square canvas element', namespace);
    
        const name = n => `${namespace}-${n}`;
  • §

    build canvas

        const c = `
        <canvas 
          id=${namespace}
          width="400"
          height="400"
          data-base-background-color="aliceblue"
        ></canvas>
        `;
  • §

    insert and capture

        insertCanvas(c, canvasParent);
    
        const canvas = captureCanvasIntoLibrary(namespace);
  • §

    create required artefacts/objects

        if (canvas != null) {
    
            scrawl.makeGradient({
                name: name('gradient'),
                end: ['100%', '100%'],
                colors: [
                    [0, 'red'],
                    [999, 'blue'],
                ],
                colorSpace: 'OKLAB',
            });
    
            scrawl.makeFilter({
                name: name('filter'),
                method: 'randomNoise',
                width: 20,
                height: 20,
                level: 1,
            });
    
            scrawl.makeBlock({
                name: name('block'),
                start: ['center', 'center'],
                handle: ['center', 'center'],
                dimensions: ['50%', '50%'],
                fillStyle: name('gradient'),
                lockFillStyleToEntity: true,
                lineWidth: 2,
                method: 'fillThenDraw',
                delta: {
                    roll: 0.2,
                },
                filters: [name('filter')],
                anchor: {
                    name: name('wikipedia-link'),
                    href: 'https://en.wikipedia.org/wiki/Square',
                    description: 'Link to the Wikipedia article on squares (opens in new tab)',
                },
    /** @this {import('../source/scrawl.js').BlockInstance} */
                onEnter: function () { this.set({ lineWidth: 6 }) },
    /** @this {import('../source/scrawl.js').BlockInstance} */
                onLeave: function () { this.set({ lineWidth: 2 }) },
    /** @this {import('../source/scrawl.js').BlockInstance} */
                onUp: function () { this.clickAnchor() },
            });
    
            scrawl.addListener('move', () => canvas.cascadeEventAction('move'), canvas.domElement);
    
            scrawl.addNativeListener('click', () => {
                if (canvas.here.active) canvas.cascadeEventAction('up');
            }, canvas.domElement);
    
            scrawl.makeRender({
                name: name('animation'),
                target: canvas,
                observer: true,
            });
    
            scrawl.makeTween({
                name: name('tween'),
                cycles: 0,
                duration: 5000,
                targets: name('block'),
                definitions: [{
                    attribute: 'scale',
                    start: 0.8,
                    end: 1.2,
                    engine: 'easeOutIn',
                }],
                reverseOnCycleEnd: true,
                observer: name('animation'),
            }).run();
        }
    };
    
    const buildCircleCanvas = (namespace) => {
        console.log('build a new circle canvas element', namespace);
    
        const name = n => `${namespace}-${n}`;
  • §

    build canvas

        const c = `
        <canvas 
          id=${namespace}
          width="400"
          height="400"
          data-base-background-color="aliceblue"
        ></canvas>
        `;
  • §

    insert and capture

        insertCanvas(c, canvasParent);
    
        const canvas = captureCanvasIntoLibrary(namespace);
  • §

    create required artefacts/objects

        if (canvas != null) {
    
            scrawl.makeGradient({
                name: name('gradient'),
                end: ['100%', '100%'],
                colors: [
                    [0, 'green'],
                    [999, 'orange'],
                ],
                colorSpace: 'OKLAB',
            });
    
            scrawl.makeFilter({
                name: name('filter'),
                method: 'randomNoise',
                width: 20,
                height: 20,
                level: 1,
            });
    
            scrawl.makeWheel({
                name: name('wheel'),
                start: ['center', 'center'],
                handle: ['center', 'center'],
                startAngle: 30,
                endAngle: -30,
                radius: '25%',
                fillStyle: name('gradient'),
                lockFillStyleToEntity: true,
                lineWidth: 2,
                method: 'fillThenDraw',
                delta: {
                    roll: 0.2,
                },
                filters: [name('filter')],
                anchor: {
                    name: name('wikipedia-link'),
                    href: 'https://en.wikipedia.org/wiki/Circle',
                    description: 'Link to the Wikipedia article on circles (opens in new tab)',
                },
    /** @this {import('../source/scrawl.js').WheelInstance} */
                onEnter: function () { this.set({ lineWidth: 6 }) },
    /** @this {import('../source/scrawl.js').WheelInstance} */
                onLeave: function () { this.set({ lineWidth: 2 }) },
    /** @this {import('../source/scrawl.js').WheelInstance} */
                onUp: function () { this.clickAnchor() },
            });
    
            scrawl.addListener('move', () => canvas.cascadeEventAction('move'), canvas.domElement);
    
            scrawl.addNativeListener('click', () => {
                if (canvas.here.active) canvas.cascadeEventAction('up');
            }, canvas.domElement);
    
            scrawl.makeRender({
                name: name('animation'),
                target: canvas,
                observer: true,
            });
    
            scrawl.makeTween({
                name: name('tween'),
                cycles: 0,
                duration: 5000,
                targets: name('wheel'),
                definitions: [{
                    attribute: 'scale',
                    start: 0.8,
                    end: 1.2,
                    engine: 'easeOutIn',
                }],
                reverseOnCycleEnd: true,
                observer: name('animation'),
            }).run();
        }
    };
    
    const captureCanvasIntoLibrary = (namespace) => {
        console.log('capture the new canvas into the library:', namespace);
    
        return scrawl.getCanvas(namespace);
    };
    
    const swapCanvases = () => {
        console.log('swap the canvases!');
    
        if (currentCanvas === squareCanvasNamespace) {
    
            currentCanvas = circleCanvasNamespace;
            buildCircleCanvas(currentCanvas);
        }
        else {
    
            currentCanvas = squareCanvasNamespace;
            buildSquareCanvas(currentCanvas);
        }
    };
    
    const reloadCanvas = () => {
        console.log('reload the current canvas:', currentCanvas);
    
        if (currentCanvas === squareCanvasNamespace) buildSquareCanvas(currentCanvas);
        else if (currentCanvas === circleCanvasNamespace) buildCircleCanvas(currentCanvas);
        else console.log('nothing to reload');
    };
    
    const removeCanvas = () => {
        console.log('remove the current canvas:', currentCanvas);
    
        scrawl.purge(currentCanvas);
        currentCanvas = noCanvas;
    };
  • §

    Initial display

    const squareCanvasNamespace = 'my-square-canvas';
    const circleCanvasNamespace = 'my-circle-canvas';
    const noCanvas = '';
    
    let currentCanvas = squareCanvasNamespace;
    
    buildSquareCanvas(squareCanvasNamespace);
    
    scrawl.addNativeListener('click', swapCanvases, canvasSwitchButton);
    scrawl.addNativeListener('click', reloadCanvas, canvasReplaceButton);
    scrawl.addNativeListener('click', removeCanvas, canvasRemoveButton);
  • §

    User interaction (STACK test)

    Switch stack

  • §

    Load a new stack with a different namespace into the parent element. Emulates a react component render when the component details have changed. For example:

    • Start with the stack1 - onboard and capture details about that stack and associated artefacts/objects in the libarary
    • Switch to the stack2 - capture details about that stack and associated artefacts/objects in the libarary. Details about the stack1 will not be removed from the library without specific instruction even though the related DOM stack no longer exists
    • Switch back to the stack1 - it is at this point that SC should recognise the details it holds about the previous stack are no longer relevant, purge everything related to that old stack from the library, and then repopulate with new data
    • Existing functionality for Stack.kill() is to delete the associated DOM data structures for that stack from the page - though the stack itself was removed some time prior and SC did nothing about it. Make sure that any errors emerging from that activity are properly captured and handled
  • §

    Replace stack

  • §

    Load a new stack with the same namespace into the parent element. Emulates a react component render when the component details have NOT changed - the component is rendered again because something else in the page has triggered a more general render. For example:

    • Start with the stack1 - onboard and capture details about that stack and associated artefacts/objects in the libarary
    • Replace that stack with another stack1. SC needs to identify that while details about the stack still exist, that stack has gone and the new stack needs to be processed and data about it - and all related artefacts/objects - stored in the library
  • §

    Remove stack

  • §

    Purge everything relating to the current stack’s namespace from the SC library

    const insertStack = (element, parent) => {
        console.log('inserting a stack into the DOM parent');
    
        parent.innerHTML = element;
    };
    
    const buildStack1 = (namespace) => {
        console.log('build a new stack1 element', namespace);
    
        const name = n => `${namespace}-${n}`;
  • §

    build stack

        const s = `
    <div id="${namespace}" data-scrawl-stack>
    
        <div id="${name('simple-svg')}">
            <svg 
                width="200px" 
                height="150px" 
                xmlns="http://www.w3.org/2000/svg"
                viewbox="0 0 400 300">
    
                <rect width="100%" height="100%" fill="red" />
                <circle cx="100%" cy="100%" r="150" fill="blue" stroke="black" />
                <polygon points="120,0 240,225 0,225" fill="green"/>
                <text x="50" y="100" font-family="Verdana" font-size="55" fill="white" stroke="black" stroke-width="2">Hello!</text>
            </svg>
        </div>
        <div id="${name('dom-element')}">
            <p>Drag and drop the elements around the stack.</p>
            <ul>
                <li>Tomatoes</li>
                <li>Cauliflower</li>
                <li>Broccoli</li>
            </ul>
        </div>
    </div>
        `;
  • §

    insert and capture

        insertStack(s, stackParent);
    
        const stack = captureStackIntoLibrary(namespace);
  • §

    create required artefacts/objects

        if (stack != null) {
    
            stack.set({
                dimensions: [400, 400],
                perspectiveZ: 1200,
                css: {
                    margin: '1em auto',
                    backgroundColor: 'lightgray',
                    borderRadius: '10px',
                },
            });
  • §

    Kill any old dragzone

            if (dragZones[namespace]) dragZones[namespace]();
    
            dragZones[namespace] = scrawl.makeDragZone({
                zone: stack,
                endOn: ['up', 'leave'],
                preventTouchDefaultWhenDragging: true,
            });
    
            const svg = scrawl.library.artefact[name('simple-svg')];
            if (svg) {
                svg.set({
                    start: ['10%', '10%'],
                    width: 200,
                    roll: -10,
                    yaw: 40,
                    css: {
                        border: '1px dashed black',
                        boxSizing: 'border-box',
                    },
                });
            }
    
            const domEl = scrawl.library.artefact[name('dom-element')];
            if (domEl) {
                domEl.set({
                    start: ['70%', '70%'],
                    handle: ['50%', '50%'],
                    dimensions: [200, 200],
                    roll: 10,
                    yaw: -35,
                    css: {
                        border: '1px dashed green',
                        padding: '0.5em',
                        borderRadius: '10px',
                        display: 'grid',
                        justifyContents: 'center',
                        alignItems: 'center',
                        backgroundColor: 'beige'
                    },
                });
            }
    
            scrawl.makeRender({
                name: name('animation'),
                target: stack,
                observer: true,
            });
        }
    };
    
    const buildStack2 = (namespace) => {
        console.log('build a new stack1 element', namespace);
    
        const name = n => `${namespace}-${n}`;
  • §

    build stack

        const s = `
    <div id="${namespace}" data-scrawl-stack>
        <canvas 
          id=${name('canvas')}
          width="400"
          height="400"
          data-base-background-color="honeydew"
        ></canvas>
    </div>
        `;
  • §

    insert and capture

        insertStack(s, stackParent);
  • §

    Note: stacks don’t capture any canvases they may contain

        const stack = captureStackIntoLibrary(namespace);
        const canvas = captureCanvasIntoLibrary(name('canvas'));
  • §

    create required artefacts/objects

        if (stack != null && canvas != null) {
    
            stack.set({
                dimensions: [400, 400],
                perspectiveZ: 1200,
                css: {
                    margin: '1em auto',
                    backgroundColor: 'darkslategray',
                    borderRadius: '10px',
                },
            });
    
            canvas.set({
                start: ['center', 'center'],
                handle: ['center', 'center'],
                trackHere: 'local',
                delta: {
                    pitch: 0.25,
                    yaw: 0.1,
                    roll: 0.08,
                },
            });
    
            scrawl.makeBlock({
                name: name('canvas-border'),
                start: ['2.5%', '2.5%'],
                dimensions: ['95%', '95%'],
                lineWidth: 8,
                strokeStyle: 'orange',
                method: 'draw',
                order: 1,
            });
    
            scrawl.makeWheel({
                name: name('canvas-blob'),
                start: ['center', 'center'],
                handle: ['center', 'center'],
                lockTo: 'mouse',
                radius: '15%',
                fillStyle: 'blue',
                lineWidth: 8,
                strokeStyle: 'red',
                method: 'fillThenDraw',
            });
    
            scrawl.makeRender({
                name: name('animation'),
                target: [stack, canvas],
                observer: true,
                afterCreated: () => stack.set({ width: 400 }),
            });
        }
    };
    
    const captureStackIntoLibrary = (namespace) => {
        console.log('capture the new stack into the library:', namespace);
    
        return scrawl.getStack(namespace);
    };
    
    const swapStacks = () => {
        console.log('swap the stacks!');
    
        if (currentStack === stack1Namespace) {
    
            currentStack = stack2Namespace;
            buildStack2(currentStack);
        }
        else {
    
            currentStack = stack1Namespace;
            buildStack1(currentStack);
        }
    };
    
    const reloadStack = () => {
        console.log('reload the current stack:', currentStack);
    
        if (currentStack === stack1Namespace) buildStack1(currentStack);
        else if (currentStack === stack2Namespace) buildStack2(currentStack);
        else console.log('nothing to reload');
    };
    
    const removeStack = () => {
        console.log('remove the current stack:', currentStack);
    
        scrawl.purge(currentStack);
        currentStack = noStack;
    };
  • §

    Initial display

    const stack1Namespace = 'my-first-stack';
    const stack2Namespace = 'my-second-stack';
    const noStack = '';
    
    let currentStack = stack1Namespace;
    
    buildStack1(stack1Namespace);
    
    scrawl.addNativeListener('click', swapStacks, stackSwitchButton);
    scrawl.addNativeListener('click', reloadStack, stackReplaceButton);
    scrawl.addNativeListener('click', removeStack, stackRemoveButton);
  • §

    Scene animation

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

    const report = reportSpeed('#reportmessage', () => reportFullLibrary(scrawl));
  • §

    Create the Display cycle animation

    scrawl.makeRender({
    
        name: "report-animation",
        noTarget: true,
        afterShow: report,
    });
  • §

    Development and testing

    console.log(scrawl.library);