• 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 Canvas 027

    Video control and manipulation; chroma-based hit zone

  • ¶

    Run code

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

    Scene setup

    let canvas = scrawl.library.canvas.mycanvas;
    
    
    canvas.set({
    
        checkForResize: true,
  • ¶

    The base-matches-display approach

    • TODO: the swan hit detection is flaky
    • TODO: issues with Phrase positioning picking up on canvas dimensions changes
    • On the positive side, text doesn’t distort
  • ¶

    isComponent: true,

  • ¶

    The fit-base-into-display approach

    • Positives - collision detection is a lot better
    • ‘fill’ - distorts display
    • ‘cover’, ‘none’ - leads to situations where controls disappear from view
    • ‘contain’ - at more extreme letterbox/chimney displays the text gets too small to be useful
        fit: 'fill',
  • ¶

    Comment setBase out for base-matches-display approach

    }).setBase({
    
        width: 640,
        height: 360
    
    }).setAsCurrentCanvas();
  • ¶

    Importing the video file programmatically

    let myvideo = scrawl.makePicture({
    
        name: 'test-video',
    
        videoSource: 'img/swans.mp4',
    
        width: '100%',
        height: '100%',
    
        copyWidth: '100%',
        copyHeight: '100%',
    });
    
    let initialVideoStart = scrawl.addListener('up', () => {
    
        myvideo.set({
    
            video_muted: true,
            video_loop: true,
        });
  • ¶

    Get rid of the event listener after invocation - it’s a one-time-only action

        initialVideoStart();
    
    }, canvas.domElement);
  • ¶

    canvas-based buttons

    scrawl.makePhrase({
    
        name: 'test-button-play-pause',
        order: 2,
    
        text: 'PLAY',
    
        family: 'sans-serif',
        size: '2rem',
    
        startX: '75%',
        handleX: 'center',
        startY: '90%',
    
        letterSpacing: 2,
        underlinePosition: 0.75,
    
        fillStyle: 'yellow',
    
        underlineStyle: 'yellow',
    
        onEnter: function () {
    
            canvas.set({
                css: {
                    cursor: 'pointer',
                }
            });
  • ¶

    ‘§UNDERLINE§’ is a section class marker which makes subsequent letters underlined

            this.set({
                text: `§UNDERLINE§${this.text}`,
            });
        },
    
        onLeave: function () {
    
            canvas.set({
                css: {
                    cursor: 'auto',
                }
            });
    
            this.set({
                text: this.text.replace('§UNDERLINE§', ''),
            });
        },
    
        onUp: function () {
    
            if (myvideo.get('video_paused')) {
    
                this.set({
                    text: 'PAUSE',
                });
    
                myvideo.videoPlay();
            }
            else {
    
                this.set({
                    text: 'PLAY',
                });
    
                myvideo.videoPause();
            }
        },
    
    }).clone({
    
        name: 'test-button-listen-mute',
    
        text: 'LISTEN',
    
        startX: '25%',
    
        onUp: function () {
    
            if (myvideo.get('video_muted')) {
    
                this.set({
                    text: 'MUTE',
                });
    
                myvideo.set({
                    video_muted: false,
                });
            }
            else {
    
                this.set({
                    text: 'LISTEN',
                });
    
                myvideo.set({
                    video_muted: true,
                });
            }
        },
    });
  • ¶

    Turn the swans pink

    scrawl.makeFilter({
    
        name: 'swan-mask',
    
        actions: [
            {
                action: 'threshold',
                level: 200,
                low: [0, 0, 0],
                high: [255, 0, 0],
            },
            {
                action: 'channels-to-alpha',
                includeGreen: false,
                includeBlue: false,
            },
        ],
    });
    
    scrawl.makePicture({
    
        name: 'test-swan-image',
    
        asset: 'swans',
    
        width: '100%',
        height: '55%',
    
        startY: '25%',
    
        copyWidth: '100%',
        copyHeight: '55%',
    
        copyStartY: '25%',
    
        filters: ['swan-mask'],
    
        globalAlpha: 0.01,
    
        onEnter: function () {
    
            this.set({
                globalAlpha: 0.1,
            });
    
            canvas.set({
                css: {
                    cursor: 'pointer',
                }
            });
        },
    
        onLeave: function () {
    
            this.set({
                globalAlpha: 0.01,
            });
    
            canvas.set({
                css: {
                    cursor: 'auto',
                }
            });
        },
    
        onUp: function () {
    
            this.clickAnchor();
        },
    
        anchor: {
            name: 'wikipedia-swan-link',
            href: 'https://en.wikipedia.org/wiki/Swan',
            description: 'Link to the Wikipedia article on swans',
    
            focusAction: true,
            blurAction: true,
        },
    
        checkHitIgnoreTransparency: true,
    });
  • ¶

    Ticker

    let myticker = scrawl.makeTicker({
    
        name: 'test-video-ticker',
        duration: '22.55s',
        cycles: 0,
    });
    
    let myLocalTweenFactory = function (name, ticker, target, data) {
    
        for (let i = 0, iz = data.length; i < iz; i++) {
    
            let [start, duration, x0, y0, x1, y1] = data[i];
    
            scrawl.makeTween({
    
                name: `${name}-${i}`,
    
                ticker: ticker,
    
                targets: [target],
    
                time: start,
                duration: duration,
    
                definitions: [
                    {
                        attribute: 'startX',
                        start: x0,
                        end: x1,
                    },
                    {
                        attribute: 'startY',
                        start: y0,
                        end: y1,
                    },
                ],
            });
        }
    };
  • ¶

    Goose 1

    let mygoose = scrawl.makeBlock({
    
        name: 'test-goose1-hitzone',
        order: 1,
    
        width: '15%',
        height: '15%',
    
        handleX: 'center',
        handleY: 'center',
    
        lineWidth: 2,
        strokeStyle: 'yellow',
    
        method: 'none',
    
        onEnter: function () {
    
            canvas.set({
                css: {
                    cursor: 'pointer',
                }
            });
    
            this.set({
                method: 'draw',
            });
        },
    
        onLeave: function () {
    
            canvas.set({
                css: {
                    cursor: 'auto',
                }
            });
    
            this.set({
                method: 'none',
            });
        },
    
        onUp: function () {
    
            this.clickAnchor();
        },
    
        anchor: {
            name: 'wikipedia-goose-link',
            href: 'https://en.wikipedia.org/wiki/Goose',
            description: 'Link to the Wikipedia article on geese',
    
            focusAction: true,
            blurAction: true,
        },
    });
    
    myLocalTweenFactory('test-goose1-tween', 'test-video-ticker', 'test-goose1-hitzone', [
    
        [0, '3s', '27%', '73%', '12%', '66%'],
        ['3s', '3s', '12%', '66%', '-3%', '68%']
    ]);
    
    scrawl.makeAction({
    
        name: 'test-goose1-action-show',
    
        ticker: 'test-video-ticker',
    
        time: 0,
    
        targets: ['test-goose1-hitzone'],
    
        action: function () { 
    
            this.targets[0].set({
    
                visibility: true,
            });
        },
    
    }).clone({
    
        name: 'test-goose1-action-hide',
        time: '6s',
    
        action: function () { 
    
            this.targets[0].set({
    
                visibility: false,
            });
        },
    });
  • ¶

    Goose 2

    mygoose.clone({
    
        name: 'test-goose2-hitzone',
    
        width: '22%',
        height: '16%',
    
        onUp: function () {
    
            mygoose.clickAnchor();
        },
    
        anchor: null,
    });
    
    myLocalTweenFactory('test-goose2-tween', 'test-video-ticker', 'test-goose2-hitzone', [
    
        [0,       '4s',   '89%', '89%', '77%', '80%'],
        ['4s',    '4s',   '77%', '80%', '65%', '80%'],
        ['8s',    '2.5s', '65%', '80%', '63%', '74%'],
        ['10.5s', '6s',   '63%', '74%', '43%', '68%'],
        ['16.5s', '3s',   '43%', '68%', '33%', '66%'],
        ['19.5s', '3s',   '33%', '66%', '31%', '64%']
    ]);
    
    scrawl.addListener('move', () => canvas.cascadeEventAction('move'), canvas.domElement);
    scrawl.addNativeListener('click', () => canvas.cascadeEventAction('up'), canvas.domElement);
  • ¶

    Video time bar

    let vtBackground = scrawl.makeBlock({
    
        name: 'test-video-time-background',
    
        width: '100%',
        height: 10,
    
        fillStyle: 'white',
    });
    
    let vtTime = vtBackground.clone({
    
        name: 'test-video-time-bar',
    
        width: 0,
        fillStyle: 'red',
    })
    
    let vtPhrase = scrawl.makePhrase({
    
        name: 'test-video-time-phrase',
    
        family: 'monospace',
        size: '1em',
        weight: '700',
    
        startX: '1%',
        startY: '4%',
        width: '40%',
    
        fillStyle: 'yellow',
    });
    
    let videoTimeBar = function () {
    
        let currentVideoTime,
            videoDuration;
    
        return function () {
    
            currentVideoTime = myvideo.get('video_currentTime');
    
            if (!videoDuration) videoDuration = myvideo.get('video_duration');
    
            if (videoDuration) {
    
                vtTime.set({
    
                    width: `${(currentVideoTime * 100) / videoDuration}%`,
                });
    
                vtPhrase.set({
    
                    text: ` ${currentVideoTime.toFixed(2)} / ${videoDuration.toFixed(2)}`,
                });
    
                myticker.seekTo(currentVideoTime * 1000, true);
            }
        };
    }();
    
    
    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)}`;
        };
    }();
    
    scrawl.makeRender({
        name: 'test-animation',
        target: canvas,
    
        commence: videoTimeBar,
        afterShow: report,
    });
    
    console.log(scrawl.library);