• 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-015a.js ./demo/canvas-016.js ./demo/canvas-017.js ./demo/canvas-018.js ./demo/canvas-019.js ./demo/canvas-019a.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/core-001.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/filters-001.js ./demo/filters-002.js ./demo/filters-002a.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-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/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/rapier-001.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-000.js ./demo/temp-001.js ./demo/temp-001a.js ./demo/temp-002.js ./demo/temp-003.js ./demo/temp-004.js ./demo/temp-005.js ./demo/temp-006.js ./demo/temp-007.js ./demo/temp-008.js ./demo/temp-009.js ./demo/temp-010.js ./demo/temp-011.js ./demo/temp-012.js ./demo/temp-013.js ./demo/temp-014.js ./demo/temp-015.js ./demo/temp-016.js ./demo/temp-017.js ./demo/temp-018.js ./demo/temp-018a.js ./demo/temp-019.js ./demo/temp-020.js ./demo/temp-021.js ./demo/temp-022.js ./demo/temp-023.js ./demo/temp-024.js ./demo/temp-025.js ./demo/temp-026.js ./demo/temp-027.js ./demo/temp-028.js ./demo/temp-029.js ./demo/temp-030.js ./demo/temp-031.js ./demo/temp-032.js ./demo/temp-033.js ./demo/temp-034.js ./demo/temp-035.js ./demo/temp-036.js ./demo/temp-037.js ./demo/temp-100.js ./demo/temp-101.js ./demo/temp-102.js ./demo/temp-103.js ./demo/temp-104.js ./demo/temp-200.js ./demo/temp-201.js ./demo/temp-301.js ./demo/temp-inkscapeSvgFilters.js ./demo/temp-lottie.js ./demo/tensorflow-001.js ./demo/tensorflow-002.js ./demo/utilities.js
  • §

    Demo Filters 002a

    Filters - cache output to improve render speeds

  • §

    Run code

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

    Scene setup

    Create some convenience shortcut variables to various sections of the Scrawl-canvas library

    const canvas = scrawl.library.canvas.mycanvas,
        filters = scrawl.library.filter,
        groups = scrawl.library.group,
        entitys = scrawl.library.entity;
  • §

    Import image from the DOM

    scrawl.importDomImage('.flowers');
  • §

    Create the filters

    scrawl.makeFilter({
        name: 'red',
        method: 'red',
    }).clone({
        name: 'green',
        method: 'green',
    }).clone({
        name: 'blue',
        method: 'blue',
    }).clone({
        name: 'cyan',
        method: 'cyan',
    }).clone({
        name: 'magenta',
        method: 'magenta',
    }).clone({
        name: 'yellow',
        method: 'yellow',
    }).clone({
        name: 'notred',
        method: 'notred',
    }).clone({
        name: 'notgreen',
        method: 'notgreen',
    }).clone({
        name: 'notblue',
        method: 'notblue',
    }).clone({
        name: 'grayscale',
        method: 'grayscale',
    }).clone({
        name: 'sepia',
        method: 'sepia',
    }).clone({
        name: 'invert',
        method: 'invert',
    });
  • §

    Original entitys

    For each filter, we shall create a Picture entity which applies that filter to the source image. To make things easier for us later on, we’ll gather these entitys into their own Group

    const originals = scrawl.makeGroup({
    
        name: 'originals',
        host: canvas.base.name,
    });
    
    scrawl.makePicture({
    
        name: 'red-filter',
        group: 'originals',
        asset: 'iris',
    
        start: [10, 10],
        dimensions: [120, 120],
    
        copyWidth: '100%',
        copyHeight: '100%',
    
        method: 'fill',
    
        filters: ['red'],
    
    }).clone({
    
        name: 'green-filter',
        startX: 140,
        filters: ['green'],
    
    }).clone({
    
        name: 'blue-filter',
        startX: 270,
        filters: ['blue'],
    
    }).clone({
    
        name: 'cyan-filter',
        start: [10, 140],
        filters: ['cyan'],
    
    }).clone({
    
        name: 'magenta-filter',
        startX: 140,
        filters: ['magenta'],
    
    }).clone({
    
        name: 'yellow-filter',
        startX: 270,
        filters: ['yellow'],
    
    }).clone({
    
        name: 'notred-filter',
        start: [10, 270],
        filters: ['notred'],
    
    }).clone({
    
        name: 'notgreen-filter',
        startX: 140,
        filters: ['notgreen'],
    
    }).clone({
    
        name: 'notblue-filter',
        startX: 270,
        filters: ['notblue'],
    
    }).clone({
    
        name: 'grayscale-filter',
        start: [10, 400],
        filters: ['grayscale'],
    
    }).clone({
    
        name: 'sepia-filter',
        startX: 140,
        filters: ['sepia'],
    
    }).clone({
    
        name: 'invert-filter',
        startX: 270,
        filters: ['invert'],
    });
  • §

    Cache entitys

    We delay creating the Picture entitys that make use of the original entitys’ cached output until after the first Display cycle completes. As for the original entitys, we’ll store the cache entitys in their own group to make things easier for us going forward

    const cache = scrawl.makeGroup({
    
        name: 'cache',
        host: canvas.base.name,
    });
    
    const createCachePictures = () => {
  • §

    We can get a lot of the data for each cache entity from the original entity that it’s shadowing. And we can iterate through each original entity using the originals Group object

        originals.artefacts.forEach(name => {
    
            let e = entitys[name];
    
            if (e) {
    
                scrawl.makePicture({
    
                    name: `${name}-cached`,
                    group: 'cache',
                    asset: `${name}-image`,
    
                    start: e.get('start'),
                    handle: e.get('handle'),
                    dimensions: e.get('dimensions'),
                    copyDimensions: ['100%', '100%'],
                });
            }
        });
    };
  • §

    We will also be displaying labels over each Picture entity to let people know which filter we’ve used on the Picture entity. We will position these labels using Picture entitys as pivots.

    const addLabels = () => {
  • §

    The Phrase entitys can go in the canvas element’s default Group. To make sure they display correctly (after the Picture entitys have been stamped) we’ll set the default Group’s order attribute to a higher value

        groups[canvas.base.name].set({
            order: 1,
        });
    
        scrawl.makePhrase({
    
            name: 'red-label',
            text: 'Red',
    
            font: '20px sans-serif',
    
            fillStyle: 'white',
            lineWidth: 4,
    
            method: 'drawThenFill',
    
            pivot: 'red-filter-cached',
            lockTo: 'pivot',
            offset: [5, 5],
    
        }).clone({
    
            name: 'green-label',
            text: 'Green',
            pivot: 'green-filter-cached',
    
        }).clone({
    
            name: 'blue-label',
            text: 'Blue',
            pivot: 'blue-filter-cached',
    
        }).clone({
    
            name: 'cyan-label',
            text: 'Cyan',
            pivot: 'cyan-filter-cached',
    
        }).clone({
    
            name: 'magenta-label',
            text: 'Magenta',
            pivot: 'magenta-filter-cached',
    
        }).clone({
    
            name: 'yellow-label',
            text: 'Yellow',
            pivot: 'yellow-filter-cached',
    
        }).clone({
    
            name: 'notred-label',
            text: 'Notred',
            pivot: 'notred-filter-cached',
    
        }).clone({
    
            name: 'notgreen-label',
            text: 'Notgreen',
            pivot: 'notgreen-filter-cached',
    
        }).clone({
    
            name: 'notblue-label',
            text: 'Notblue',
            pivot: 'notblue-filter-cached',
    
        }).clone({
    
            name: 'grayscale-label',
            text: 'Grayscale',
            pivot: 'grayscale-filter-cached',
    
        }).clone({
    
            name: 'sepia-label',
            text: 'Sepia',
            pivot: 'sepia-filter-cached',
    
        }).clone({
    
            name: 'invert-label',
            text: 'Invert',
            pivot: 'invert-filter-cached',
        });
    };
  • §

    Caching Picture entity output

    Because we need to recapture filter output whenever the user updates the filters’ opacity attribute, we’ll put these calls in a dedicated function

    const cacheAction = () => {
    
        scrawl.createImageFromEntity(entitys['red-filter'], true);
        scrawl.createImageFromEntity(entitys['green-filter'], true);
        scrawl.createImageFromEntity(entitys['blue-filter'], true);
        scrawl.createImageFromEntity(entitys['cyan-filter'], true);
        scrawl.createImageFromEntity(entitys['magenta-filter'], true);
        scrawl.createImageFromEntity(entitys['yellow-filter'], true);
        scrawl.createImageFromEntity(entitys['notred-filter'], true);
        scrawl.createImageFromEntity(entitys['notgreen-filter'], true);
        scrawl.createImageFromEntity(entitys['notblue-filter'], true);
        scrawl.createImageFromEntity(entitys['grayscale-filter'], true);
        scrawl.createImageFromEntity(entitys['sepia-filter'], true);
        scrawl.createImageFromEntity(entitys['invert-filter'], true);
    };
  • §

    Invoke the cache function before the first Display cycle

    cacheAction();
  • §

    Scene animation

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

    const report = reportSpeed('#reportmessage', function () {
  • §

    @ts-expect-error

        return `    Opacity: ${opacity.value}`;
    });
  • §

    Create the Display cycle animation

    const demoAnimation = scrawl.makeRender({
    
        name: "demo-animation",
        target: canvas,
        afterShow: report,
  • §

    Caching (continued)

    Hide the originals group; create the Picture entitys that will display the cached images, alongside the Phrase labels that describe them

        afterCreated: () => {
            originals.set({ visibility: false });
            createCachePictures();
            addLabels();
        },
    });
  • §

    User interaction

    const myFilters = [
        filters.red,
        filters.green,
        filters.blue,
        filters.cyan,
        filters.magenta,
        filters.yellow,
        filters.notred,
        filters.notgreen,
        filters.notblue,
        filters.grayscale,
        filters.sepia,
        filters.invert
    ];
  • §

    Update the opacity attribute for all the filters

    scrawl.addNativeListener(['input', 'change'], (e) => {
    
        let val = parseFloat(e.target.value);
    
        myFilters.forEach(f => f.set({ opacity: val }));
  • §

    To capture the new filtered output we need to make sure the original entitys take part in the next Display cycle. We also need to instruct them to capture the results of that Display cycle

        originals.set({ visibility: true });
        cache.set({ visibility: false });
        cacheAction();
  • §

    We give the Display cycle sufficient time to run before again hiding the original entitys and displaying the cache entitys in their place

        setTimeout(() => {
            originals.set({ visibility: false });
            cache.set({ visibility: true });
        }, 50);
    
    }, '#opacity');
  • §

    Setup form

    const opacity = document.querySelector('#opacity');
  • §

    @ts-expect-error

    opacity.value = 1;
  • §

    Development and testing

    console.log(scrawl.library);