import { getSnippetData } from './text-snippet-helper.js';Editable header text colorizer and animation effect snippets
Related files:
Purpose: This effect is inspired by Risograph printing which uses a limited color palette, stippling colors to create a gradient effect.
Function input:
Customisation: The snippet can be customised using the following data- attributes applied using CSS variables, or directly to the HTML header element:
data-top-color - any CSS color stringdata-dark-top-color - any CSS color stringdata-bottom-color - any CSS color stringdata-dark-bottom-color - any CSS color stringdata-outline-color - any CSS color stringdata-dark-outline-color - any CSS color stringdata-outline-width - (unit % of font size) outline width as a percentage of the font sizedata-random-radius - (0 - 1) the amount of mixing of the top and bottom colorsdata-random-level - (0 - 1) the density of the color mixingdata-contrast-color - any CSS color string, used when user has set prefers-contrast: moredata-dark-contrast-color - any CSS color string, used when user has set prefers-contrast: moreFunction 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
}
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:
transparenttransparentexport 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, fontSize, lineHeight, initCanvas, initPhrase, textGroup, responsiveFunctions, contrastMoreActions, contrastOtherActions, colorSchemeDarkActions, colorSchemeLightActions, additionalDemolishActions } = getSnippetData(snippet, scrawl);Initialise the canvas
initCanvas();
canvas.base.set({
compileOrder: 1,
});Initialize and collect developer-supplied data
let topColor = 'lightblue',
darkTopColor = '#d7e3f5',
bottomColor = 'blue',
darkBottomColor = '#598ad9',
outlineColor = 'black',
darkOutlineColor = '#f4f5d7',
outlineWidth = 0.03,
randomRadius = 0.8,
randomLevel = 1,
contrastColor = 'black',
darkContrastColor = 'white';
if (dataset.topColor) topColor = dataset.topColor;
else {
const s = compStyles.getPropertyValue('--data-top-color');
if (s) topColor = s;
}
if (dataset.darkTopColor) darkTopColor = dataset.darkTopColor;
else {
const s = compStyles.getPropertyValue('--data-dark-top-color');
if (s) darkTopColor = s;
}
if (dataset.bottomColor) bottomColor = dataset.bottomColor;
else {
const s = compStyles.getPropertyValue('--data-bottom-color');
if (s) bottomColor = s;
}
if (dataset.darkBottomColor) darkBottomColor = dataset.darkBottomColor;
else {
const s = compStyles.getPropertyValue('--data-dark-bottom-color');
if (s) darkBottomColor = 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.randomRadius) randomRadius = parseFloat(dataset.randomRadius);
else {
const s = compStyles.getPropertyValue('--data-random-radius');
if (s) randomRadius = parseFloat(s);
}
if (dataset.randomLevel) randomLevel = parseFloat(dataset.randomLevel);
else {
const s = compStyles.getPropertyValue('--data-random-level');
if (s) randomLevel = 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 g1 = scrawl.makeGradient({
name: `${name}-riso-gradient`,
colors: [
[0, 'white'],
[999, 'black'],
],
endY: '100%',
});
const f1 = scrawl.makeFilter({
name: `${name}-random-filter`,
method: 'randomNoise',
height: Math.round(lineHeight * randomRadius),
noWrap: true,
level: randomLevel,
});
const f2 = scrawl.makeFilter({
name: `${name}-threshold-filter`,
method: 'threshold',
level: 127,
lowColor: bottomColor,
highColor: topColor,
});
const cell = canvas.buildCell({
name: `${name}-riso-cell`,
width: 32,
height: lineHeight,
cleared: false,
compiled: false,
shown: false,
useAsPattern: true,
});
scrawl.makeBlock({
name: `${name}-riso-block`,
group: `${name}-riso-cell`,
dimensions: ['100%', '100%'],
fillStyle: `${name}-riso-gradient`,
lockFillStyleToEntity: true,
filters: [`${name}-random-filter`, `${name}-threshold-filter`],
memoizeFilterOutput: true,
});
cell.compile();
const p1 = scrawl.makePattern({
name: `${name}-riso-pattern`,
asset: `${name}-riso-cell`,
matrixF: Math.round(lineHeight / 10),
});
const textFill = scrawl.makePhrase({
name: `${name}-text-stencil`,
group,
order: 0,
});
initPhrase(textFill);
const textStroke = textFill.clone({
name: `${name}-text-outline`,
order: 2,
lineWidth: outlineWidth * fontSize,
strokeStyle: outlineColor,
method: 'draw',
globalCompositeOperation: 'destination-over',
});
textGroup.addArtefacts(textFill, textStroke);
scrawl.makeBlock({
name: `${name}-text-fill`,
group,
order: 1,
width: '100%',
height: '100%',
fillStyle: `${name}-riso-pattern`,
globalCompositeOperation: 'source-in',
});Accessibility
colorSchemeLightActions.push(() => {
f2.set({
lowColor: bottomColor,
highColor: topColor,
});
cell.clear();
cell.compile();
textStroke.set({
strokeStyle: outlineColor,
});
});
colorSchemeDarkActions.push(() => {
f2.set({
lowColor: darkBottomColor,
highColor: darkTopColor,
});
cell.clear();
cell.compile();
textStroke.set({
strokeStyle: 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 localLineHeight = parseFloat(items.lineHeight),
localFontSize = parseFloat(items.fontSize);
cell.set({
height: localLineHeight,
});
cell.clear();
cell.compile();
p1.set({
matrixF: Math.round(localLineHeight / 10),
});
f1.set({
height: Math.round(localLineHeight * randomRadius),
});
textStroke.set({
lineWidth: outlineWidth * localFontSize,
});
});Cleanup
additionalDemolishActions.push(() => {
f1.kill();
f2.kill();
g1.kill();
p1.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;
};