• 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
  • utilities.js

  • §
    import {
        library as L,
        addNativeListener,
        importDomImage,
    } from '../source/scrawl.js';
  • §

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

    const reportSpeed = function (output = '', xtra = () => '') {
    
        if (!output) return function () {};
    
            let testTicker = Date.now(),
                testTime, testNow,
                testMessage = document.querySelector(output);
    
            let history = [],
                averageTime = 0;
    
            const addTime = (t) => {
    
                if (history.length > 60) history.shift();
                history.push(t);
                averageTime = history.reduce((p, c) => p + c, 0);
                averageTime /= history.length;
            }
    
    
        return function () {
    
            testNow = Date.now();
    
            testTime = testNow - testTicker;
            testTicker = testNow;
    
            addTime(testTime);
    
            let text = `Screen refresh: ${Math.ceil(averageTime)}ms; fps: ${Math.floor(1000 / averageTime)}`;
    
            if (xtra) {
    
                text += `
    ${xtra()}`;
            }
    
            testMessage.textContent = text;
        };
    };
  • §

    Test to check that artefacts are properly killed and resurrected

    const killArtefact = (canvas, name, time, finishResurrection = () => {}) => {
    
        if (canvas && canvas.base && name && time) {
    
            let groupname = canvas.base.name,
                packet;
    
            let checkGroupBucket = (name, groupname) => {
    
                let res = L.group[groupname].artefactCalculateBuckets.filter(e => e.name === name );
                return (res.length) ? 'no' : 'yes';
            };
    
            setTimeout(() => {
    
                console.log(`${name} alive
            removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
            removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
            removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}`);
    
                packet = L.artefact[name].saveAsPacket();
    
                L.artefact[name].kill();
    
                setTimeout(() => {
    
                    console.log(`${name} killed
            removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
            removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
            removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}`);
    
                    canvas.actionPacket(packet);
    
                    setTimeout(() => {
    
                        console.log(`${name} resurrected
            removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
            removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
            removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
            removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}`);
    
                        if (finishResurrection) finishResurrection();
    
                    }, 100);
                }, 100);
            }, time);
        }
        else console.log('killArtefact test invoked improperly');
    };
  • §

    To test styles (Gradient) kill functionality

    const killStyle = (canvas, name, time, finishResurrection = () => {}) => {
    
        if (canvas && canvas.base && name && time) {
    
            let packet;
    
            setTimeout(() => {
    
                console.log(`${name} alive
            removed from styles: ${(L.styles[name]) ? 'no' : 'yes'}
            removed from stylesnames: ${(L.stylesnames.indexOf(name) >= 0) ? 'no' : 'yes'}`);
    
                packet = L.styles[name].saveAsPacket();
    
                L.styles[name].kill();
    
                setTimeout(() => {
    
                    console.log(`${name} killed
            removed from styles: ${(L.styles[name]) ? 'no' : 'yes'}
            removed from stylesnames: ${(L.stylesnames.indexOf(name) >= 0) ? 'no' : 'yes'}`);
    
                    canvas.actionPacket(packet);
    
                    setTimeout(() => {
    
                        console.log(`${name} resurrected
            removed from styles: ${(L.styles[name]) ? 'no' : 'yes'}
            removed from stylesnames: ${(L.stylesnames.indexOf(name) >= 0) ? 'no' : 'yes'}`);
    
                        finishResurrection();
    
                    }, 100);
                }, 100);
            }, time);
        }
        else console.log('killStyle test invoked improperly');
    };
  • §

    To test artefact + anchor kill functionality

    const killArtefactAndAnchor = (canvas, name, anchorname, time, finishResurrection = () => {}) => {
    
        let groupname = 'mycanvas_base',
            packet;
    
        let checkGroupBucket = (name, groupname) => {
    
            let res = L.group[groupname].artefactCalculateBuckets.filter(e => e.name === name );
            return (res.length) ? 'no' : 'yes';
        };
    
        setTimeout(() => {
    
            console.log(`${name} alive
        removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
        removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
        removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}
        anchor removed: ${(L.anchor[anchorname]) ? 'no' : 'yes'}`);
    
            packet = L.artefact[name].saveAsPacket();
    
            L.artefact[name].kill();
    
            setTimeout(() => {
    
                console.log(`${name} killed
        removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
        removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
        removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}
        anchor removed: ${(L.anchor[anchorname]) ? 'no' : 'yes'}`);
    
                canvas.actionPacket(packet);
    
                setTimeout(() => {
    
                    console.log(`${name} resurrected
        removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
        removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
        removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}
        anchor removed: ${(L.anchor[anchorname]) ? 'no' : 'yes'}`);
    
                    finishResurrection();
    
                }, 100);
            }, 100);
        }, time);
    };
  • §

    To test Polyline artefact kill functionality

    const killPolylineArtefact = (canvas, name, time, myline, restore = () => {}) => {
    
        let groupname = 'mycanvas_base',
            packet;
    
        let checkGroupBucket = (name, groupname) => {
    
            let res = L.group[groupname].artefactCalculateBuckets.filter(e => e.name === name );
            return (res.length) ? 'no' : 'yes';
        };
    
        let checkPinsArray = (name) => {
    
            if (myline.pins.indexOf(name) >= 0) return 'no';
    
            let res = myline.pins.filter(e => e && e.name === name );
            return (res.length) ? 'no' : 'yes';
        };
    
        setTimeout(() => {
    
            console.log(`${name} alive
        removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
        removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
        removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from polyline pins array: ${checkPinsArray(name)}
        removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}`);
    
            packet = L.artefact[name].saveAsPacket();
    
            L.artefact[name].kill();
    
            setTimeout(() => {
    
                console.log(`${name} killed
        removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
        removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
        removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from polyline pins array: ${checkPinsArray(name)}
        removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}`);
    
                canvas.actionPacket(packet);
    
                setTimeout(() => {
    
                    if (restore) restore();
    
                    console.log(`${name} resurrected
        removed from artefact: ${(L.artefact[name]) ? 'no' : 'yes'}
        removed from artefactnames: ${(L.artefactnames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from entity: ${(L.entity[name]) ? 'no' : 'yes'}
        removed from entitynames: ${(L.entitynames.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from polyline pins array: ${checkPinsArray(name)}
        removed from group.artefacts: ${(L.group[groupname].artefacts.indexOf(name) >= 0) ? 'no' : 'yes'}
        removed from group.artefactCalculateBuckets: ${checkGroupBucket(name, groupname)}`);
    
                    console.log(myline.saveAsPacket());
    
                }, 500);
            }, 500);
        }, time);
    };
    
    const killTicker = (stack, name, time) => {
    
        let packet;
    
        setTimeout(() => {
    
            console.log(`${name} alive
        removed from tickers: ${(L.animationtickers[name]) ? 'no' : 'yes'}`);
    
            packet = L.animationtickers[name].saveAsPacket();
    
            L.animationtickers[name].kill();
    
            setTimeout(() => {
    
                console.log(`${name} killed
        removed from tickers: ${(L.animationtickers[name]) ? 'no' : 'yes'}`);
    
                stack.actionPacket(packet);
    
                setTimeout(() => {
    
                    console.log(`${name} resurrected
        removed from tickers: ${(L.animationtickers[name]) ? 'no' : 'yes'}`);
                }, 100);
            }, 100);
        }, time);
    };
    
    const addImageDragAndDrop = (canvas, selector, targets, callback = () => {}) => {
  • §

    Drag-and-Drop image loading functionality

        const store = document.querySelector(selector);
        const timeoutDelay = 200;
    
        let counter = 0;
    
        const wrappers = [];
        if (Array.isArray(canvas)) wrappers.push(...canvas);
        else wrappers.push(canvas);
    
        if (!Array.isArray(targets)) targets = [targets];
    
        addNativeListener(['dragenter', 'dragover', 'dragleave'], (e) => {
    
            e.preventDefault();
            e.stopPropagation();
    
        }, wrappers.map(w => w.domElement));
    
        addNativeListener('drop', (e) => {
    
            e.preventDefault();
            e.stopPropagation();
    
            const dt = e.dataTransfer;
    
            if (dt) [...dt.files].forEach(addImageAsset);
    
        }, wrappers.map(w => w.domElement));
    
        const addImageAsset = (file) => {
    
            if (file.type.indexOf('image/') === 0) {
    
                const reader = new FileReader();
    
                reader.readAsDataURL(file);
    
                reader.onloadend = function() {
  • §

    Create a name for our new asset

                    const name = `user-upload-${counter}`;
                    counter++;
  • §

    Add the image to the DOM and create our asset from it

                    const img = document.createElement('img');
  • §

    @ts-expect-error

                    img.src = reader.result;
                    img.id = name;
                    store.appendChild(img);
    
                    importDomImage(`#${name}`);
  • §

    Update our Picture entity’s asset attribute so it displays the new image

                    targets.forEach(target => {
    
                        if (target.type === 'Group') {
    
                            target.setArtefacts({
                                asset: name,
                            });
                        }
                        else {
    
                            target.set({
                                asset: name,
                            });
                        }
                    });
  • §

    HOW TO: set the Picture entity’s copy dimensions to take into account any difference between the old and new image’s dimensions

    • Because of asynch stuff, we need to wait for stuff to complete before performing this functionality
    • The Picture entity copies (for the sake of our sanity) a square part of the image. Thus we shall use the new image’s shorter dimension as the copy dimension and offset the longer copy start so we are viewing the middle of it
                    setTimeout(() => {
    
                        const asset = L.asset[name];
    
                        const width = asset.get('width'),
                            height = asset.get('height');
    
                        let copyStartX = 0,
                            copyStartY = 0,
                            dim = 0;
    
                        if (width > height) {
    
                            copyStartX = (width - height) / 2;
                            dim = height;
                        }
                        else {
    
                            copyStartY = (height - width) / 2;
                            dim = width;
                        }
    
                        targets.forEach(target => {
    
                            if (target.type === 'Group') {
    
                                target.setArtefacts({
                                    copyStartX,
                                    copyStartY,
                                    copyWidth: dim,
                                    copyHeight: dim,
                                });
                            }
                            else {
    
                                target.set({
                                    copyStartX,
                                    copyStartY,
                                    copyWidth: dim,
                                    copyHeight: dim,
                                });
                            }
                        })
    
                        if (callback) setTimeout(callback, timeoutDelay);
                    }, timeoutDelay);
                }
            }
        };
    };
    
    export {
        reportSpeed,
    
        killArtefact,
        killArtefactAndAnchor,
        killPolylineArtefact,
        killStyle,
        killTicker,
    
        addImageDragAndDrop,
    }