• Jump To … +
    ./demo/modules/canvas-minimap.js ./demo/modules/canvas-scene-editor.js ./demo/modules/dom-entity-editor.js ./demo/modules/entity-copy-paste.js ./demo/modules/entity-manipulation-gui.js ./demo/modules/entity-navigation.js ./demo/modules/entity-ring-builder.js ./demo/modules/london-crime-graphic.js ./demo/modules/london-crime-lines.js ./demo/modules/london-crime-stacked-bars.js ./demo/modules/lottie-loader.js ./demo/modules/simple-chart-frame-tests.js ./demo/modules/simple-chart-frame.js ./demo/modules/simple-graph-lines.js ./demo/modules/simple-graph-stacked-bars.js ./demo/modules/wikipedia-views-spiral-chart.js ./demo/snippets/animated-highlight-gradient-text-snippet.js ./demo/snippets/animated-hover-gradient-snippet.js ./demo/snippets/animated-word-gradient-snippet.js ./demo/snippets/before-after-slider-infographic.js ./demo/snippets/bubbles-text-snippet.js ./demo/snippets/green-box-snippet.js ./demo/snippets/jazzy-button-snippet.js ./demo/snippets/page-performance-snippet-test.js ./demo/snippets/page-performance-snippet.js ./demo/snippets/pan-image-snippet.js ./demo/snippets/placeholder-effect-snippet.js ./demo/snippets/ripple-effect-snippet.js ./demo/snippets/risograph-text-gradient-snippet.js ./demo/snippets/spotlight-text-snippet-test.js ./demo/snippets/spotlight-text-snippet.js ./demo/snippets/swirling-stripes-text-snippet.js ./demo/snippets/text-snippet-helper.js ./demo/snippets/word-highlighter-snippet.js ./demo/snippets/worley-text-gradient-snippet.js
  • §

    Demo Snippets 006

    Editable header text colorizer and animation effect snippets

    Related files:

    • Editable header text colorizer and animation effect snippets
    • Text snippet helper

    ‘Animated bubbles effect used to color text’ snippet

    Purpose: Displays text with an animation of rising bubbles over the text fill

    • This snippet supports dark-mode alternative colors
    • This snippet supports high contrast alternative colors
    • This snippet supports an animation effect which can be disabled in an accessible manner

    Function input:

    • the DOM element - generally a block or inline-block element.

    Customisation: The snippet can be customised using the following data- attributes applied using CSS variables, or directly to the HTML header element:

    • data-text-color - any CSS color string
    • data-dark-text-color - any CSS color string
    • data-outline-color - any CSS color string
    • data-dark-outline-color - any CSS color string
    • data-outline-width - (unit % of font size) percentage of the font size for text outline width
    • data-bubble-color - any CSS color string
    • data-dark-bubble-color - any CSS color string
    • data-bubble-outline-color - any CSS color string
    • data-dark-bubble-outline-color - any CSS color string
    • data-bubble-density - the number of bubbles to generate
    • data-contrast-color - any CSS color string, used when user has set prefers-contrast: more
    • data-dark-contrast-color - any CSS color string, used when user has set prefers-contrast: more

    Function output: a Javascript object will be returned, containing the following attributes

    {
        element     // the Scrawl-canvas wrapper for the DOM element supplied to the function
        canvas      // the Scrawl-canvas wrapper for the snippet's canvas
        animation   // the Scrawl-canvas animation object
        demolish    // remove the snippet from the Scrawl-canvas library
    }
    
    Usage example:
    import * as scrawl from 'path/to/scrawl-canvas/library';
    
    import mySnippet from './relative/or/absolute/path/to/this/file.js';
    let myElements = document.querySelectorAll('.some-class');
    myElements.forEach(el => mySnippet(el, scrawl));
    
  • §

    Additional font-specific customisation can be added courtesy of the Text Snippet Helper module

    import { getSnippetData } from './text-snippet-helper.js';
  • §

    Effects on the element:

    • Imports the element’s background color, and sets the element background to transparent
    • Imports the element’s text node text, and sets the text color to transparent
    • Note that canvas text will NEVER be as good as DOM text!
    export default function (el, scrawl) {
  • §

    Apply the snippet to the DOM element

        let snippet = scrawl.makeSnippet({
            domElement: el,
        });
  • §

    Only proceed if the snippet is successfully generated

        if (snippet) {
  • §

    Import data and functionality from the Text Snippet Helper module

            let { canvas, group, dataset, compStyles, name, yOffset, fontSize, lineHeight, initCanvas, initPhrase, textGroup, eternalTweens, responsiveFunctions, contrastMoreActions, contrastOtherActions, colorSchemeDarkActions, colorSchemeLightActions, additionalDemolishActions } = getSnippetData(snippet, scrawl);
  • §

    Initialise the canvas

            initCanvas();
  • §

    Initialize and collect developer-supplied data

            let textColor = '#c213bc',
                darkTextColor = '#fcdeef',
                outlineColor = '#f59dcf',
                darkOutlineColor = '#f59dcf',
                outlineWidth = 0.05,
                bubbleColor = '#fcdeef',
                darkBubbleColor = '#ed5fb0',
                bubbleOutlineColor = '#c213bc',
                darkBubbleOutlineColor = '#c213bc',
                bubbleDensity = 50,
                contrastColor = 'black',
                darkContrastColor = 'white';
    
            if (dataset.textColor) textColor = dataset.textColor;
            else {
                const s = compStyles.getPropertyValue('--data-text-color');
                if (s) textColor = s;
            }
    
            if (dataset.darkTextColor) darkTextColor = dataset.darkTextColor;
            else {
                const s = compStyles.getPropertyValue('--data-dark-text-color');
                if (s) darkTextColor = s;
            }
    
            if (dataset.outlineColor) outlineColor = dataset.outlineColor;
            else {
                const s = compStyles.getPropertyValue('--data-outline-color');
                if (s) outlineColor = s;
            }
    
            if (dataset.darkOutlineColor) darkOutlineColor = dataset.darkOutlineColor;
            else {
                const s = compStyles.getPropertyValue('--data-dark-outline-color');
                if (s) darkOutlineColor = s;
            }
    
            if (dataset.outlineWidth) outlineWidth = parseFloat(dataset.outlineWidth);
            else {
                const s = compStyles.getPropertyValue('--data-outline-width');
                if (s) outlineWidth = parseFloat(s);
            }
    
            if (dataset.bubbleColor) bubbleColor = dataset.bubbleColor;
            else {
                const s = compStyles.getPropertyValue('--data-bubble-color');
                if (s) bubbleColor = s;
            }
    
            if (dataset.darkBubbleColor) darkBubbleColor = dataset.darkBubbleColor;
            else {
                const s = compStyles.getPropertyValue('--data-dark-bubble-color');
                if (s) darkBubbleColor = s;
            }
    
            if (dataset.bubbleOutlineColor) bubbleOutlineColor = dataset.bubbleOutlineColor;
            else {
                const s = compStyles.getPropertyValue('--data-bubble-outline-color');
                if (s) bubbleOutlineColor = s;
            }
    
            if (dataset.darkBubbleOutlineColor) darkBubbleOutlineColor = dataset.darkBubbleOutlineColor;
            else {
                const s = compStyles.getPropertyValue('--data-dark-bubble-outline-color');
                if (s) darkBubbleOutlineColor = s;
            }
    
            if (dataset.bubbleDensity) bubbleDensity = parseFloat(dataset.bubbleDensity);
            else {
                const s = compStyles.getPropertyValue('--data-bubble-density');
                if (s) bubbleDensity = parseFloat(s);
            }
    
            if (dataset.contrastColor) contrastColor = dataset.contrastColor;
            else {
                const s = compStyles.getPropertyValue('--data-contrast-color');
                if (s) contrastColor = s;
            }
    
            if (dataset.darkContrastColor) darkContrastColor = dataset.darkContrastColor;
            else {
                const s = compStyles.getPropertyValue('--data-dark-contrast-color');
                if (s) darkContrastColor = s;
            }
  • §

    Build the text effect

            const bubblesGroup = scrawl.makeGroup({
                name: `${name}-bubbles-group`,
            });
    
            const fizz = scrawl.makeWheel({
                name: `${name}-bubbles-template`,
                group,
                order: 1,
                startY: '100%',
                handleX: 'center',
                handleY: 'center',
                fillStyle: bubbleColor,
                strokeStyle: bubbleOutlineColor,
                method: 'fillThenDraw',
                globalCompositeOperation: 'source-atop',
                noDeltaUpdates: true,
                noPositionDependencies: true,
                noFilters: true,
                noUserInteraction: true,
                purge: 'all',
            });
    
            bubblesGroup.addArtefacts(fizz);
    
            for (let i = 0; i < bubbleDensity; i++) {
    
                const bubble = fizz.clone({
                    name: `${name}-bubble-${i}`,
                    radius: Math.round((Math.random() * (fontSize / 2)) + 4),
                    startX: `${Math.random() * 100}%`,
                    noCanvasEngineUpdates: true,
                    sharedState: true,
                });
    
                bubblesGroup.addArtefacts(bubble);
    
                const myRandom = Math.random();
    
                eternalTweens.push(scrawl.makeTween({
                    name: bubble.name,
                    targets: bubble,
                    duration: Math.round((myRandom * 3000) + 5000),
                    cycles: 0,
                    definitions: [{
                        attribute: 'startY',
                        start: '100%',
                        end: '0%',
                    }, {
                        attribute: 'scale',
                        start: 0.3,
                        end: Math.round((1 - myRandom) * 0.9) + 0.6,
                    }],
                }).run());
            }
    
            const textFill = scrawl.makePhrase({
                name: `${name}-text-stencil`,
                group,
                fillStyle: textColor,
                underlineStyle: 'rgba(0 0 0 / 0)',
                method: 'fill',
                order: 0,
            });
    
            initPhrase(textFill);
    
            const textStroke = textFill.clone({
                name: `${name}-text-outline`,
                order: 2,
                strokeStyle: outlineColor,
                lineWidth: outlineWidth * fontSize,
                underlineStyle: outlineColor,
                method: 'draw',
            });
    
            textGroup.addArtefacts(textFill, textStroke);
  • §

    Accessibility

            colorSchemeLightActions.push(() => {
    
                fizz.set({
                    fillStyle: bubbleColor,
                    strokeStyle: bubbleOutlineColor,
                });
    
                textFill.set({
                    fillStyle: textColor,
                });
    
                textStroke.set({
                    strokeStyle: outlineColor,
                    underlineStyle: outlineColor,
                });
            });
    
            colorSchemeDarkActions.push(() => {
    
                fizz.set({
                    fillStyle: darkBubbleColor,
                    strokeStyle: darkBubbleOutlineColor,
                });
    
                textFill.set({
                    fillStyle: darkTextColor,
                });
    
                textStroke.set({
                    strokeStyle: darkOutlineColor,
                    underlineStyle: darkOutlineColor,
                });
            });
    
            contrastMoreActions.push(() => {
                el.style.color = (canvas.here.prefersDarkColorScheme) ? darkContrastColor : contrastColor;
                textGroup.setArtefacts({
                    visibility: false,
                });
            });
    
            contrastOtherActions.push(() => {
                el.style.color = 'transparent';
                textGroup.setArtefacts({
                    visibility: true,
                });
            });
  • §

    Responsiveness

            responsiveFunctions.push((items = {}) => {
    
                const localFontSize = parseFloat(items.fontSize),
                    localRadius = localFontSize / 2;
    
                textStroke.set({
                    lineWidth: outlineWidth * localFontSize,
                });
    
                bubblesGroup.setArtefacts({
                    radius: Math.round((Math.random() * localRadius) + 4),
                });
            });
  • §

    Cleanup

            additionalDemolishActions.push(() => {
                bubblesGroup.kill();
            });
        }
  • §

    Return the snippet, so coders can access the snippet’s parts - in case they need to tweak the output to meet the web page’s specific requirements

        return snippet;
    };