• 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-074.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/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-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 Canvas 014

    Line, Quadratic and Bezier entitys - control lock alternatives

  • §

    Run code

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

    Scene setup

    Get a handle to the Canvas wrapper

    const canvas = scrawl.findCanvas('mycanvas');
  • §

    Namespacing boilerplate

    const namespace = canvas.name;
    const name = (n) => `${namespace}-${n}`;
    
    
    scrawl.importDomImage('.mypatterns');
    
    scrawl.makeGradient({
    
        name: name('stroke-gradient'),
        endX: '33%',
        spread: 'reflect',
        operations: [{
            operation: 'add-noise',
            stage: 'after-spread',
            parameters: {
                noise: 'bluenoise',
                strength: 0.08,
            },
        }],
        colors: [
            [0, 'blue'],
            [489, 'red'],
            [490, 'yellow'],
            [509, 'yellow'],
            [510, 'red'],
            [999, 'green']
        ],
    });
    
    scrawl.makePattern({
    
        name: name('stroke-pattern'),
        asset: 'brick',
    });
  • §

    Define the entitys that will be used as pivots and paths before the entitys that use them as such

    scrawl.makeWheel({
    
        name: name('pin-1'),
        order: 2,
    
        startX: 100,
        startY: 100,
    
        handleX: 'center',
        handleY: 'center',
    
        radius: 10,
        fillStyle: 'blue',
        strokeStyle: 'darkgray',
        lineWidth: 2,
        method: 'fillAndDraw',
    
    }).clone({
        name: name('pin-2'),
        startY: 300,
    
    }).clone({
        name: name('pin-3'),
        startY: 500,
    
    }).clone({
        name: name('pin-4'),
        fillStyle: 'green',
        startX: 500,
        startY: 100,
    
    }).clone({
        name: name('pin-5'),
        startY: 230,
    
    }).clone({
        name: name('pin-6'),
        startY: 370,
    
    }).clone({
        name: name('pin-7'),
        startY: 500,
    });
  • §

    Create a group to hold the draggable artefacts, for easier user action collision detection

    const pins = scrawl.makeGroup({
    
        name: name('my-pins'),
        host: canvas.get('baseName'),
    
    }).addArtefacts(
        name('pin-1'),
        name('pin-2'),
        name('pin-3'),
        name('pin-4'),
        name('pin-5'),
        name('pin-6'),
        name('pin-7'),
    );
  • §

    Now start defining the Shape lines. Bezier, Quadratic and Line Shapes can pivot and path their control coordinates to other artefacts, similar to how start coordinates operate.

    scrawl.makeQuadratic({
    
        name: name('my-quad'),
    
        pivot: name('pin-1'),
        lockTo: 'pivot',
  • §

    The normal action when the Start coordinates for Bezier, Quadratic and Line Shapes change is that the entire shape moves to the new coordinates. In this demo, we don’t want that; when a user drags the wheel on which the shape’s start coordinates pivots, we want the shape to ‘change shape’. We can make sure this happens by setting its useStartAsControlPoint attribute to true.

        useStartAsControlPoint: true,
    
        controlPivot: name('pin-2'),
        controlLockTo: 'pivot',
    
        endPivot: name('pin-3'),
        endLockTo: 'pivot',
    
        lineWidth: 5,
        lineCap: 'round',
        strokeStyle: 'darkblue',
        method: 'draw',
    
        useAsPath: true,
    });
    
    scrawl.makeBezier({
    
        name: name('my-bezier'),
    
        pivot: name('pin-4'),
        lockTo: 'pivot',
        useStartAsControlPoint: true,
    
        startControlPivot: name('pin-5'),
        startControlLockTo: 'pivot',
    
        endControlPivot: name('pin-6'),
        endControlLockTo: 'pivot',
    
        endPivot: name('pin-7'),
        endLockTo: 'pivot',
    
        lineWidth: 5,
        lineCap: 'round',
        strokeStyle: 'darkgreen',
        method: 'draw',
    
        useAsPath: true,
    });
  • §

    The ‘path-line’ shape uses the quadratic and bezier curves as paths for its start and end coordinates

    scrawl.makeLine({
    
        name: name('path-line'),
    
        path: name('my-quad'),
        pathPosition: 0,
        lockTo: 'path',
        useStartAsControlPoint: true,
    
        endPath: name('my-bezier'),
        endPathPosition: 0,
        endLockTo: 'path',
    
        constantSpeedAlongPath: true,
    
        lineWidth: 5,
        lineCap: 'round',
        strokeStyle: 'black',
        method: 'draw',
  • §

    Delta animate the path-line entity along the lengths of the bezier and quadratic Shape entitys

        delta: {
            pathPosition: 0.0015,
            endPathPosition: 0.0015,
        },
    
        useAsPath: true,
    });
  • §

    the ‘mouse-line’ shape has its start coordinates permanently fixed to the center of the screen, while its end coordinates alternate between tracking a point along the ‘path-line’ shape, and the mouse cursor when it is moving over the canvas

    scrawl.makeLine({
    
        name: name('mouse-line'),
    
        startX: 'center',
        startY: 'center',
        useStartAsControlPoint: true,
    
        endPath: name('path-line'),
        endPathPosition: 0.5,
        endLockTo: 'path',
    
        lineWidth: 5,
        lineCap: 'round',
        strokeStyle: 'darkred',
        method: 'draw',
    
        useAsPath: true,
    });
  • §

    Decorate the ‘mouse-line’ shape with other artefacts to turn it into an arrow

    scrawl.makeTetragon({
    
        name: name('arrowhead'),
    
        order: 2,
    
        fillStyle: 'darkred',
        method: 'fill',
    
        radius: 10,
        intersectY: 1.2,
    
        handleX: 'center',
        handleY: '20%',
        roll: 90,
    
        path: name('mouse-line'),
        pathPosition: 1,
        lockTo: 'path',
        addPathRotation: true,
    });
    
    scrawl.makeWheel({
    
        name: name('arrowbase'),
    
        order: 2,
    
        fillStyle: 'darkred',
        method: 'fill',
    
        radius: 20,
        startAngle: 90,
        endAngle: -90,
    
        handleX: 'center',
        handleY: 'center',
    
        path: name('mouse-line'),
        pathPosition: 0,
        lockTo: 'path',
        addPathRotation: true,
    });
  • §

    We can always grab a handle to any canvas entity by reference to its entry in the Scrawl-canvas library. Entitys are stored in both the artefact and the entity sections of the library

    const arrow = scrawl.findEntity(name('mouse-line')),
        quaddy = scrawl.findEntity(name('my-quad'));
    
    let bezzy = scrawl.findEntity(name('my-bezier'));
  • §

    Testing to make sure artefacts stick to their paths, even when those paths are animated or manipulated in various ways

    scrawl.makePicture({
    
        name: name('bunny1'),
        imageSource: 'img/bunny.png',
    
        width: 26,
        height: 37,
    
        copyWidth: 26,
        copyHeight: 37,
    
        handleX: 'center',
        handleY: 'center',
    
        path: name('path-line'),
        pathPosition: 0.1,
        addPathRotation: true,
        lockTo: 'path',
    
    }).clone({
    
        name: name('bunny2'),
        pathPosition: 0.9,
    });
  • §

    User interaction

    Create the drag-and-drop zone

    scrawl.makeDragZone({
    
        zone: canvas,
        collisionGroup: pins,
        endOn: ['up', 'leave'],
        exposeCurrentArtefact: true,
        preventTouchDefaultWhenDragging: true,
    });
  • §

    Function to check whether mouse cursor is over canvas, and lock the arrow’s end point accordingly

    const mouseCheck = function () {
    
        let active = false;
    
        return function () {
    
            if (canvas.here.active !== active) {
    
                active = canvas.here.active;
    
                arrow.set({
                    endLockTo: (active) ? 'mouse' : 'path'
                });
            }
        };
    }();
  • §

    Scene animation

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

    const report = reportSpeed('#reportmessage');
  • §

    Create the Display cycle animation

    scrawl.makeRender({
    
        name: name('animation'),
        target: canvas,
        commence: mouseCheck,
        afterShow: report,
    });
  • §

    Development and testing

    scrawl.makeUpdater({
    
        event: 'change',
        origin: '.linear',
    
        target: arrow,
    
        useNativeListener: true,
        preventDefault: true,
    
        updates: {
            ['linear-stroke-style']: ['strokeStyle', 'raw'],
            ['linear-style-lock']: ['lockStrokeStyleToEntity', 'boolean'],
        },
    });
    
    scrawl.makeUpdater({
    
        event: 'change',
        origin: '.quadratic',
    
        target: quaddy,
    
        useNativeListener: true,
        preventDefault: true,
    
        updates: {
            ['quadratic-stroke-style']: ['strokeStyle', 'raw'],
            ['quadratic-style-lock']: ['lockStrokeStyleToEntity', 'boolean'],
        },
    });
    
    const tempUpdater = scrawl.makeUpdater({
    
        event: 'change',
        origin: '.bezier',
    
        target: bezzy,
    
        useNativeListener: true,
        preventDefault: true,
    
        updates: {
            ['bezier-stroke-style']: ['strokeStyle', 'raw'],
            ['bezier-style-lock']: ['lockStrokeStyleToEntity', 'boolean'],
        },
    });
    
    scrawl.initializeDomInputs([
        ['select', 'linear-stroke-style', 0],
        ['select', 'linear-style-lock', 0],
        ['select', 'quadratic-stroke-style', 0],
        ['select', 'quadratic-style-lock', 0],
        ['select', 'bezier-stroke-style', 0],
        ['select', 'bezier-style-lock', 0],
    ]);
    
    
    console.log(scrawl.library);
    
    console.log('Performing tests ...');
    
    killArtefact(scrawl, canvas, name('pin-1'), 2000, () => {
    
        pins.addArtefacts(name('pin-1'));
    
        scrawl.findEntity(name('my-quad')).set({
            pivot: name('pin-1'),
            lockTo: 'pivot',
        });
    });
    
    killArtefact(scrawl, canvas, name('pin-5'), 3000, () => {
    
        pins.addArtefacts(name('pin-5'));
    
        scrawl.findEntity(name('my-bezier')).set({
            startControlPivot: name('pin-5'),
            startControlLockTo: 'pivot',
        });
    });
    
    killArtefact(scrawl, canvas, name('pin-7'), 4000, () => {
    
        pins.addArtefacts(name('pin-7'));
    
        scrawl.findEntity(name('my-bezier')).set({
            endPivot: name('pin-7'),
            endLockTo: 'pivot',
        });
    });
    
    killArtefact(scrawl, canvas, name('my-bezier'), 5000, () => {
    
        scrawl.findEntity(name('path-line')).set({
            endPath: name('my-bezier'),
            endLockTo: 'path',
        });
    
        bezzy = scrawl.findEntity(name('my-bezier'));
    
        tempUpdater();
    
        scrawl.makeUpdater({
    
            event: 'change',
            origin: '.bezier',
    
            target: bezzy,
    
            useNativeListener: true,
            preventDefault: true,
    
            updates: {
                ['bezier-stroke-style']: ['strokeStyle', 'raw'],
                ['bezier-style-lock']: ['lockStrokeStyleToEntity', 'boolean'],
            },
        });
    });