import * as scrawl from '../source/scrawl.js';
import { reportSpeed, addImageDragAndDrop } from './utilities.js';import * as scrawl from '../source/scrawl.js';
import { reportSpeed, addImageDragAndDrop } from './utilities.js';const canvas = scrawl.library.canvas.mycanvas;The base cell needs to compile after the helper cells we’re about to create
canvas.setBase({
compileOrder: 1,
});We display the gradients in a Block entity, in a dedicated Cell
const patternCell = canvas.buildCell({
name: 'bar-cell-pattern',
dimensions: [80, 80],
shown: false,
useAsPattern: true,
skewX: 0,
stretchX: 1,
shiftX: 0,
skewY: 0,
stretchY: 1,
shiftY: 0,
});
const barGradient = scrawl.makeGradient({
name: 'bar-cell-gradient',
endX: '100%',
colors: [
[0, 'transparent'],
[199, 'transparent'],
[499, 'white'],
[799, 'transparent'],
[999, 'transparent'],
],
});
const ringGradient = scrawl.makeRadialGradient({
name: 'ring-cell-gradient',
startX: '50%',
startY: '50%',
endX: '50%',
endY: '50%',
startRadius: '0%',
endRadius: '50%',
colors: [
[0, 'transparent'],
[199, 'transparent'],
[499, 'white'],
[799, 'transparent'],
[999, 'transparent'],
],
});
const updateGradients = (items) => {
barGradient.set(items);
ringGradient.set(items);
};
const filterBlock = scrawl.makeBlock({
name: 'bar-cell-box',
group: 'bar-cell-pattern',
dimensions: ['100%', '100%'],
fillStyle: 'bar-cell-gradient',
});We can use anything that generates image data as part of our filter
fillStyle attributeconst filterCell = canvas.buildCell({
name: 'bar-cell',
dimensions: ['100%', '100%'],
shown: false,
});
scrawl.makeBlock({
name: 'bar-base-box',
group: 'bar-cell',
dimensions: ['100%', '100%'],
fillStyle: 'bar-cell-pattern',
});const glassBarsFilter = scrawl.makeFilter({ name: 'glass-bars' }),
displaceBarsFilter = scrawl.makeFilter({ name: 'displace-bars' }),
etchingFilter = scrawl.makeFilter({ name: 'etching' }),
greenMonitorFilter = scrawl.makeFilter({ name: 'green-monitor' });We define some variables and helper functions here, to cut down on code
let fOffsetX = 0,
fOffsetY = 0,
fOpacity = 1,
fBlend = 'multiply',
fDisplaceX = 10,
fDisplaceY = 10;All the examples make use of the gradient pattern; this filter loads it into the engine
const getProcessImageFilter = () => {
return [{
action: 'process-image',
asset: 'bar-cell',
width: '100%',
height: '100%',
copyWidth: '100%',
copyHeight: '100%',
lineOut: 'bars',
}];
};Three of the examples use a blend filter to merge the gradient pattern into the image
const getBlendFilter = () => {
return [{
action: 'blend',
lineMix: 'bars',
blend: fBlend,
offsetX: fOffsetX,
offsetY: fOffsetY,
opacity: fOpacity,
}];
};This uses the gradient pattern as a displacement map for the displace filter
const getDisplaceFilter = () => {
return [{
action: 'displace',
lineMix: 'bars',
offsetX: fOffsetX,
offsetY: fOffsetY,
opacity: fOpacity,
scaleX: fDisplaceX,
scaleY: fDisplaceY,
}];
};Several filters require the image to be grayscaled at the start of the processing chain
const getGrayscaleFilter = () => {
return [{
action: 'grayscale',
}];
};Filters to configure the image (make it green) before applying the blend filter
const getMonitorFilter = () => {
return [{
action: 'modulate-channels',
red: 0,
green: 1.3,
blue: 0,
}];
};Filters to configure the image (give it a black-white drawing effect) before applying the blend filter
const getEtchFilter = () => {
return [{
action: 'gaussian-blur',
radius: 1,
}, {
action: 'matrix',
weights: [1, 1, 1, 1, -8, 1, 1, 1, 1],
}, {
action: 'invert-channels',
}, {
action: 'threshold',
level: 252,
}];
};Helper function to update filter action arrays with user choices
const updateFilters = () => {
glassBarsFilter.set({
actions: [
...getProcessImageFilter(),
...getBlendFilter(),
],
});
displaceBarsFilter.set({
actions: [
...getProcessImageFilter(),
...getDisplaceFilter(),
],
});
etchingFilter.set({
actions: [
...getProcessImageFilter(),
...getGrayscaleFilter(),
...getEtchFilter(),
...getBlendFilter(),
],
});
greenMonitorFilter.set({
actions: [
...getProcessImageFilter(),
...getGrayscaleFilter(),
...getMonitorFilter(),
...getBlendFilter(),
],
});
};Initial filter build
updateFilters();scrawl.importDomImage('.flowers');We need something to apply our filters to
const target = scrawl.makePicture({
name: 'target-image',
asset: 'iris',
width: '100%',
height: '100%',
copyWidth: '100%',
copyHeight: '100%',
method: 'fill',
filters: ['glass-bars'],
});Add some Drag-and-Drop image loading functionality
addImageDragAndDrop(canvas, '#my-image-store', target);Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage', function () {@ts-expect-error
return ` Filter dimensions - \n width: ${filterWidth.value}%; height: ${filterHeight.value}%\n Filter offset - \n x: ${filterOffsetX.value}px; y: ${filterOffsetY.value}px\n Pattern dimensions - \n width: ${patternWidth.value}px; height: ${patternHeight.value}px\n Pattern matrix -\n shiftX: ${shiftX.value}; shiftY: ${shiftY.value}\n skewX: ${skewX.value}; skewY: ${skewY.value}\n stretchX: ${stretchX.value}; stretchY: ${stretchY.value}\n Displace filter scaling - \n x: ${filterScaleX.value}; y: ${filterScaleY.value}\n Opacity: ${opacity.value}`;
});Create the Display cycle animation
const demoAnimation = scrawl.makeRender({
name: "demo-animation",
target: canvas,
afterShow: report,
});scrawl.observeAndUpdate({
event: ['change', 'input'],
origin: '.patternCell',
target: patternCell,
useNativeListener: true,
preventDefault: true,
updates: {
'pattern-width': ['width', 'round'],
'pattern-height': ['height', 'round'],
shiftX: ['shiftX', 'round'],
shiftY: ['shiftY', 'round'],
skewX: ['skewX', 'float'],
skewY: ['skewY', 'float'],
stretchX: ['stretchX', 'float'],
stretchY: ['stretchY', 'float'],
},
});Update filter dimensions
scrawl.observeAndUpdate({
event: ['change', 'input'],
origin: '.filterCell',
target: filterCell,
useNativeListener: true,
preventDefault: true,
updates: {
'filter-width': ['width', '%'],
'filter-height': ['height', '%'],
},
});Update gradient choice
scrawl.observeAndUpdate({
event: ['change', 'input'],
origin: '.filterBlock',
target: filterBlock,
useNativeListener: true,
preventDefault: true,
updates: {
patternGradient: ['fillStyle', 'raw'],
},
});Update filter offset, opacity, blend choices
scrawl.addNativeListener(['change', 'input'], (e) => {
const t = e.target,
value = t.value;
switch (t.id) {
case 'filter-offset-x' :
fOffsetX = parseInt(value, 10);
break;
case 'filter-offset-y' :
fOffsetY = parseInt(value, 10);
break;
case 'filter-scale-x' :
fDisplaceX = parseInt(value, 10);
break;
case 'filter-scale-y' :
fDisplaceY = parseInt(value, 10);
break;
case 'opacity' :
fOpacity = parseFloat(value);
break;
case 'blend' :
fBlend = value;
break;
}
updateFilters();
}, '.filterObject');Update gradient easing
scrawl.addNativeListener(['change', 'input'], (e) => {
const t = e.target,
value = t.value;
updateGradients({
easing: value,
});
}, '.gradient');We do quite a bit of work here to set things up for the example’s initial display
scrawl.addNativeListener(['change', 'input'], (e) => {
const t = e.target,
value = t.value;
switch (value) {
case 'glass-bars' :
fOffsetX = 0;
fOffsetY = 0;
fOpacity = 1;
fBlend = 'multiply';
fDisplaceX = 10;
fDisplaceY = 10;
patternCell.set({
width: 80,
height: 80,
shiftX: 0,
shiftY: 0,
skewX: 0,
skewY: 0,
stretchX: 1,
stretchY: 1,
});
filterBlock.set({
fillStyle: 'bar-cell-gradient',
});@ts-expect-error
skewX.value = 0;@ts-expect-error
skewY.value = 0;@ts-expect-error
stretchX.value = 1;@ts-expect-error
stretchY.value = 1;@ts-expect-error
shiftX.value = 0;@ts-expect-error
shiftY.value = 0;@ts-expect-error
filterBlend.value = 'multiply';@ts-expect-error
patternGradient.value = 'bar-cell-gradient';@ts-expect-error
patternWidth.value = 80;@ts-expect-error
patternHeight.value = 80;
break;
case 'displace-bars' :
fOffsetX = 0;
fOffsetY = 0;
fOpacity = 1;
fBlend = 'multiply';
fDisplaceX = 10;
fDisplaceY = 10;
patternCell.set({
width: 80,
height: 80,
shiftX: 0,
shiftY: 0,
skewX: 0,
skewY: 0,
stretchX: 1,
stretchY: 1,
});
filterBlock.set({
fillStyle: 'ring-cell-gradient',
});@ts-expect-error
skewX.value = 0;@ts-expect-error
skewY.value = 0;@ts-expect-error
stretchX.value = 1;@ts-expect-error
stretchY.value = 1;@ts-expect-error
shiftX.value = 0;@ts-expect-error
shiftY.value = 0;@ts-expect-error
filterBlend.value = 'multiply';@ts-expect-error
patternGradient.value = 'ring-cell-gradient';@ts-expect-error
patternWidth.value = 80;@ts-expect-error
patternHeight.value = 80;
break;
case 'etching' :
fOffsetX = 0;
fOffsetY = 0;
fOpacity = 1;
fBlend = 'screen';
fDisplaceX = 10;
fDisplaceY = 10;
patternCell.set({
width: 80,
height: 80,
shiftX: 0,
shiftY: 0,
skewX: -0.65,
skewY: -0.31,
stretchX: 1,
stretchY: 0.26,
});
filterBlock.set({
fillStyle: 'bar-cell-gradient',
});@ts-expect-error
skewX.value = -0.65;@ts-expect-error
skewY.value = -0.31;@ts-expect-error
stretchX.value = 1;@ts-expect-error
stretchY.value = 0.26;@ts-expect-error
shiftX.value = 0;@ts-expect-error
shiftY.value = 0;@ts-expect-error
filterBlend.value = 'screen';@ts-expect-error
patternGradient.value = 'bar-cell-gradient';@ts-expect-error
patternWidth.value = 80;@ts-expect-error
patternHeight.value = 80;
break;
case 'green-monitor' :
fOffsetX = 0;
fOffsetY = 0;
fOpacity = 1;
fBlend = 'luminosity';
fDisplaceX = 10;
fDisplaceY = 10;
patternCell.set({
width: 80,
height: 80,
shiftX: 0,
shiftY: 0,
skewX: 1.04,
skewY: 0.05,
stretchX: 0.35,
stretchY: 0,
});
filterBlock.set({
fillStyle: 'bar-cell-gradient',
});@ts-expect-error
skewX.value = 1.04;@ts-expect-error
skewY.value = 0.05;@ts-expect-error
stretchX.value = 0.35;@ts-expect-error
stretchY.value = 0;@ts-expect-error
shiftX.value = 0;@ts-expect-error
shiftY.value = 0;@ts-expect-error
filterBlend.value = 'luminosity';@ts-expect-error
patternGradient.value = 'bar-cell-gradient';@ts-expect-error
patternWidth.value = 80;@ts-expect-error
patternHeight.value = 80;
break;
}
filterCell.set({
width: '100%',
height: '100%',
});
updateFilters();
updateGradients({
easing: 'linear',
});@ts-expect-error
opacity.value = 1;@ts-expect-error
filterWidth.value = 100;@ts-expect-error
filterHeight.value = 100;@ts-expect-error
filterOffsetX.value = 0;@ts-expect-error
filterOffsetY.value = 0;@ts-expect-error
filterScaleX.value = 10;@ts-expect-error
filterScaleY.value = 10;@ts-expect-error
easing.value = 'linear';@ts-expect-error
target.clearFilters().addFilters(value);
}, '.filterEffect');const opacity = document.querySelector('#opacity');
const skewX = document.querySelector('#skewX');
const skewY = document.querySelector('#skewY');
const stretchX = document.querySelector('#stretchX');
const stretchY = document.querySelector('#stretchY');
const shiftX = document.querySelector('#shiftX');
const shiftY = document.querySelector('#shiftY');
const patternWidth = document.querySelector('#pattern-width');
const patternHeight = document.querySelector('#pattern-height');
const filterWidth = document.querySelector('#filter-width');
const filterHeight = document.querySelector('#filter-height');
const filterOffsetX = document.querySelector('#filter-offset-x');
const filterOffsetY = document.querySelector('#filter-offset-y');
const filterScaleX = document.querySelector('#filter-scale-x');
const filterScaleY = document.querySelector('#filter-scale-y');
const filterBlend = document.querySelector('#blend');
const patternGradient = document.querySelector('#patternGradient');
const easing = document.querySelector('#easing');@ts-expect-error
opacity.value = 1;@ts-expect-error
skewX.value = 0;@ts-expect-error
skewY.value = 0;@ts-expect-error
stretchX.value = 1;@ts-expect-error
stretchY.value = 1;@ts-expect-error
shiftX.value = 0;@ts-expect-error
shiftY.value = 0;@ts-expect-error
patternWidth.value = 80;@ts-expect-error
patternHeight.value = 80;@ts-expect-error
filterWidth.value = 100;@ts-expect-error
filterHeight.value = 100;@ts-expect-error
filterOffsetX.value = 0;@ts-expect-error
filterOffsetY.value = 0;@ts-expect-error
filterScaleX.value = 10;@ts-expect-error
filterScaleY.value = 10;@ts-expect-error
filterBlend.value = 'multiply';@ts-expect-error
patternGradient.value = 'bar-cell-gradient';@ts-expect-error
easing.value = 'linear';@ts-expect-error
document.querySelector('#filterEffect').value = 'glass-bars';console.log(scrawl.library);