• 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

    ‘Horizontally striped text with swirl animation’ snippet

    Purpose: Paints the text with a striped gradient pattern, and adds a swirl effect when the user moves their browser’s cursor over the text

    • This snippet supports dark-mode alternative colors
    • This snippet does not support 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-main-color - any CSS color string
    • data-dark-main-color - any CSS color string
    • data-stripe-color - any CSS color string
    • data-dark-stripe-color - any CSS color string
    • data-stripe-ratio - (0 - 1) the ratio of stripe to main color; higher values show wider stripes
    • data-swirl-angle - (degrees) higher values lead to a tighter swirl; use negative values to reverse the swirl direction
    • data-gradient-skew-x - (-2 - 2) skew the gradient pattern horizontally
    • data-gradient-skew-y - (-2 - 2) skew the gradient pattern vertically
    • data-gradient-stretch-x - (0 - 4) stretch the gradient pattern horizontally
    • data-gradient-stretch-y - (0 - 4) stretch the gradient pattern vertically

    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, animation, compStyles, dataset, name, height, lineHeight, initCanvas, initPhrase, textGroup, responsiveFunctions, colorSchemeDarkActions, colorSchemeLightActions, animationFunctions, animationEndFunctions, additionalDemolishActions } = getSnippetData(snippet, scrawl);
  • §

    Initialise the canvas

            initCanvas();
  • §

    Initialize and collect developer-supplied data

            let mainColor = 'black',
                darkMainColor = 'white',
                stripeColor = 'red',
                darkStripeColor = '#e34e49',
                stripeRatio = 0.5,
                swirlAngle = 90,
                gradientSkewX = 0,
                gradientSkewY = 0,
                gradientStretchX = 1,
                gradientStretchY = 1;
    
            if (dataset.mainColor) mainColor = dataset.mainColor;
            else {
                const s = compStyles.getPropertyValue('--data-main-color');
                if (s) mainColor = s;
            }
    
            if (dataset.darkMainColor) darkMainColor = dataset.darkMainColor;
            else {
                const s = compStyles.getPropertyValue('--data-main-color');
                if (s) darkMainColor = s;
            }
    
            if (dataset.stripeColor) stripeColor = dataset.stripeColor;
            else {
                const s = compStyles.getPropertyValue('--data-stripe-color');
                if (s) stripeColor = s;
            }
    
            if (dataset.darkStripeColor) darkStripeColor = dataset.darkStripeColor;
            else {
                const s = compStyles.getPropertyValue('--data-stripe-color');
                if (s) darkStripeColor = s;
            }
    
            if (dataset.stripeRatio) stripeRatio = parseFloat(dataset.stripeRatio);
            else {
                const s = compStyles.getPropertyValue('--data-gradient-easing');
                if (s) stripeRatio = parseFloat(s);
            }
    
            if (dataset.swirlAngle) swirlAngle = parseFloat(dataset.swirlAngle);
            else {
                const s = compStyles.getPropertyValue('--data-swirl-angle');
                if (s) swirlAngle = parseFloat(s);
            }
    
            if (dataset.gradientSkewX) gradientSkewX = parseFloat(dataset.gradientSkewX);
            else {
                const s = compStyles.getPropertyValue('--data-gradient-skew-x');
                if (s) gradientSkewX = parseFloat(s);
            }
    
            if (dataset.gradientSkewY) gradientSkewY = parseFloat(dataset.gradientSkewY);
            else {
                const s = compStyles.getPropertyValue('--data-gradient-skew-y');
                if (s) gradientSkewY = parseFloat(s);
            }
    
            if (dataset.gradientStretchX) gradientStretchX = parseFloat(dataset.gradientStretchX);
            else {
                const s = compStyles.getPropertyValue('--data-gradient-stretch-x');
                if (s) gradientStretchX = parseFloat(s);
            }
    
            if (dataset.gradientStretchY) gradientStretchY = parseFloat(dataset.gradientStretchY);
            else {
                const s = compStyles.getPropertyValue('--data-gradient-stretch-y');
                if (s) gradientStretchY = parseFloat(s);
            }
  • §

    Build the text effect

            let gradientChangeAt = Math.floor(stripeRatio * 1000);
            if (gradientChangeAt < 1) gradientChangeAt = 1;
            if (gradientChangeAt > 997) gradientChangeAt = 997;
    
            const myGradient = scrawl.makeGradient({
                name: `${name}-swirlstripe-gradient`,
                colors: [
                    [0, stripeColor],
                    [gradientChangeAt, stripeColor],
                    [gradientChangeAt + 1, mainColor],
                    [999, mainColor],
                ],
                endY: '100%',
                precision: 10,
            });
    
            const cell = canvas.buildCell({
                name: `${name}-swirlstripe-gradient-cell`,
                width: 16,
                height: lineHeight,
                shown: false,
                useAsPattern: true,
            });
    
            scrawl.makeBlock({
                name: `${name}-swirlstripe-gradient-block-0`,
                group: `${name}-swirlstripe-gradient-cell`,
                dimensions: ['100%', '20%'],
                fillStyle: `${name}-swirlstripe-gradient`,
                lockFillStyleToEntity: true,
            }).clone({
                name: `${name}-swirlstripe-gradient-block-1`,
                startY: '20%',
            }).clone({
                name: `${name}-swirlstripe-gradient-block-2`,
                startY: '40%',
            }).clone({
                name: `${name}-swirlstripe-gradient-block-3`,
                startY: '60%',
            }).clone({
                name: `${name}-swirlstripe-gradient-block-4`,
                startY: '80%',
            });
    
            const p1 = scrawl.makePattern({
                name: `${name}-swirlstripe-gradient-pattern`,
                asset: `${name}-swirlstripe-gradient-cell`,
                stretchX: gradientStretchY,
                stretchY: gradientStretchX,
                skewX: gradientSkewY,
                skewY: gradientSkewX,
            });
    
            const textFill = scrawl.makePhrase({
                name: `${name}-text-stencil`,
                group,
                order: 0,
            });
    
            initPhrase(textFill);
    
            textGroup.addArtefacts(textFill);
    
            scrawl.makeBlock({
                name: `${name}-text-fill`,
                group,
                order: 1,
                width: '100%',
                height: '100%',
                fillStyle: `${name}-swirlstripe-gradient-pattern`,
                globalCompositeOperation: 'source-in',
            });
    
            const swirl = scrawl.makeFilter({
                name: `${name}-swirl-filter`,
                method: 'swirl',
                startX: '50%',
                startY: '50%',
                innerRadius: 0,
                outerRadius: Math.ceil(lineHeight * 2),
                easing: 'easeOutIn',
                angle: swirlAngle,
                transparentEdges: true,
            });
    
            canvas.base.set({
                compileOrder: 1,
                memoizeFilterOutput: true,
            });
  • §

    Accessibility

            colorSchemeLightActions.push(() => {
                myGradient.set({
                    colors: [
                        [0, stripeColor],
                        [gradientChangeAt, stripeColor],
                        [gradientChangeAt + 1, mainColor],
                        [999, mainColor],
                    ],
                });
            });
    
            colorSchemeDarkActions.push(() => {
                myGradient.set({
                    colors: [
                        [0, darkStripeColor],
                        [gradientChangeAt, darkStripeColor],
                        [gradientChangeAt + 1, darkMainColor],
                        [999, darkMainColor],
                    ],
                });
            });
  • §

    Responsiveness

            responsiveFunctions.push((items = {}) => {
    
                const localLineHeight = parseFloat(items.lineHeight);
    
                cell.set({
                    height: localLineHeight,
                });
    
                swirl.set({
                    outerRadius: Math.ceil(localLineHeight * 2),
                });
            });
  • §

    Additional animation functionality

            let isActive = false;
    
            animationFunctions.push(() => {
    
                const {x, y, active} = canvas.here;
    
                if (active && !isActive) {
    
                    isActive = true;
    
                    canvas.base.set({
                        filters: [swirl.name],
                    });
                }
                else if (!active && isActive) {
    
                    isActive = false;
    
                    canvas.base.set({
                        filters: [],
                    });
                }
    
                if (isActive) {
    
                    swirl.set({
                        startX: x,
                        startY: y,
                    });
                }
            });
    
            animationEndFunctions.push(() => {
    
                canvas.base.set({
                    filters: [],
                });
            });
  • §

    Cleanup

            additionalDemolishActions.push(() => {
                myGradient.kill();
                p1.kill();
                swirl.kill();
                cell.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;
    };