scrawl-canvas
Version:
Version 8.9.4 - 19 Nov 2022
293 lines (201 loc) • 7.03 kB
JavaScript
// # Demo Canvas 035
// Pattern style functionality
// [Run code](../../demo/canvas-035.html)
import * as scrawl from '../source/scrawl.js'
import { reportSpeed } from './utilities.js';
// #### Scene setup
let canvas = scrawl.library.artefact.mycanvas,
styles = scrawl.library.styles,
cells = scrawl.library.cell;
canvas.base.set({
compileOrder: 1,
});
// Create image-based patterns
scrawl.makePattern({
name: 'bunny-pattern',
imageSource: 'img/bunny.png',
}).clone({
name: 'water-pattern',
imageSource: 'img/water.png',
}).clone({
name: 'leaves-pattern',
imageSource: 'img/leaves.png',
});
// Create video-based pattern
const videoPattern = scrawl.makePattern({
name: 'video-pattern',
videoSource: 'img/Sea - 4006.mp4',
});
// The video can't play until we detect some form of user interaction
scrawl.addListener('up', () => {
if (videoPattern.get('video_paused')) {
videoPattern.set({
video_muted: true,
video_loop: true,
}).videoPlay();
}
}, canvas.domElement);
// Create a Cell to use as a pattern
canvas.buildCell({
name: 'cell-pattern',
width: 50,
height: 50,
backgroundColor: 'lightblue',
shown: false,
useAsPattern: true,
});
scrawl.makeBlock({
name: 'cell-pattern-block',
group: 'cell-pattern',
width: 40,
height: 40,
startX: 'center',
startY: 'center',
handleX: 'center',
handleY: 'center',
method: 'fill',
fillStyle: 'water-pattern',
delta: {
roll: -0.3
},
});
// Create a spritesheet-based pattern
// + As defined in the [CanvasPattern API](https://developer.mozilla.org/en-US/docs/Web/API/CanvasPattern) the pattern constructor takes an image source (<img>, SVG <image>, <video>, <canvas>, ImageBitmap, or OffscreenCanvas) as its argument, but is not able to use just a part of that source for the pattern.
// + To use a spritesheet as a source, we need to work around this limitation by putting a Picture entity using the spritesheet into a Cell, then using the Cell as the pattern's source.
canvas.buildCell({
name: 'cat-pattern',
width: 150,
height: 75,
shown: false,
useAsPattern: true,
});
scrawl.makePicture({
name: 'cell-pattern-sprite',
group: 'cat-pattern',
width: '100%',
height: '100%',
spriteSource: 'img/cat-sprite.png',
spriteTrack: 'walk',
spriteFrameDuration: 100,
}).playSprite();
// We'll display the patterns in a Block entity which users can update and interact with, for testing
const myBlock = scrawl.makeBlock({
name: 'test-block',
start: ['center', 'center'],
handle: ['center', 'center'],
dimensions: [300, 200],
fillStyle: 'bunny-pattern',
lineWidth: 6,
strokeStyle: 'black',
method: 'fillThenDraw',
});
// #### Scene animation
// Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage', function () {
let matrix = styles['bunny-pattern'].patternMatrix;
if (matrix) return ` Matrix: [${matrix.a}, ${matrix.b}, ${matrix.c}, ${matrix.d}, ${matrix.e}, ${matrix.f}]
stretchX: ${matrix.a}, stretchY: ${matrix.d}
skewX: ${matrix.c}, skewY: ${matrix.b}
shiftX: ${matrix.e}, shiftY: ${matrix.f}`;
return 'Matrix not available'
});
// Create the Display cycle animation
scrawl.makeRender({
name: 'demo-animation',
target: canvas,
afterShow: report,
});
// #### User interaction
// Create the drag-and-drop zone
scrawl.makeDragZone({
zone: canvas,
endOn: ['up', 'leave'],
preventTouchDefaultWhenDragging: true,
});
// Setup form observer functionality for display block
scrawl.observeAndUpdate({
event: ['input', 'change'],
origin: '.controlItem',
target: myBlock,
useNativeListener: true,
preventDefault: true,
updates: {
relativeWidth: ['width', '%'],
absoluteWidth: ['width', 'round'],
relativeHeight: ['height', '%'],
absoluteHeight: ['height', 'round'],
handle_xPercent: ['handleX', '%'],
handle_xAbsolute: ['handleX', 'round'],
handle_yPercent: ['handleY', '%'],
handle_yAbsolute: ['handleY', 'round'],
offset_xPercent: ['offsetX', '%'],
offset_xAbsolute: ['offsetX', 'round'],
offset_yPercent: ['offsetY', '%'],
offset_yAbsolute: ['offsetY', 'round'],
roll: ['roll', 'float'],
scale: ['scale', 'float'],
scaleOutline: ['scaleOutline', 'boolean'],
upend: ['flipUpend', 'boolean'],
reverse: ['flipReverse', 'boolean'],
pattern: ['fillStyle', 'raw'],
},
});
// Setup form observer functionality for patterns
// + we'll cascade form updates to all patterns, and Cells used as patterns
const myPatterns = [styles['bunny-pattern'], styles['leaves-pattern'], styles['video-pattern'], cells['cell-pattern'], cells['cat-pattern']];
let updateRepeat = (e) => {
e.preventDefault();
e.returnValue = false;
let val = e.target.value;
myPatterns.forEach(p => p.set({repeat: val}));
};
scrawl.addNativeListener(['input', 'change'], updateRepeat, '#repeat');
let updateMatrix = (e) => {
e.preventDefault();
e.returnValue = false;
let val = e.target.value,
id = e.target.id;
myPatterns.forEach(p => p.set({[id]: parseFloat(val)}));
};
scrawl.addNativeListener(['input', 'change'], updateMatrix, '.matrix');
// Setup form
// @ts-expect-error
document.querySelector('#relativeWidth').value = 50;
// @ts-expect-error
document.querySelector('#absoluteWidth').value = 300;
// @ts-expect-error
document.querySelector('#relativeHeight').value = 50;
// @ts-expect-error
document.querySelector('#absoluteHeight').value = 200;
// @ts-expect-error
document.querySelector('#handle_xPercent').value = 50;
// @ts-expect-error
document.querySelector('#handle_yPercent').value = 50;
// @ts-expect-error
document.querySelector('#handle_xAbsolute').value = 150;
// @ts-expect-error
document.querySelector('#handle_yAbsolute').value = 100;
// @ts-expect-error
document.querySelector('#offset_xPercent').value = 0;
// @ts-expect-error
document.querySelector('#offset_yPercent').value = 0;
// @ts-expect-error
document.querySelector('#offset_xAbsolute').value = 0;
// @ts-expect-error
document.querySelector('#offset_yAbsolute').value = 0;
// @ts-expect-error
document.querySelector('#roll').value = 0;
// @ts-expect-error
document.querySelector('#scale').value = 1;
// @ts-expect-error
document.querySelector('#upend').options.selectedIndex = 0;
// @ts-expect-error
document.querySelector('#reverse').options.selectedIndex = 0;
// @ts-expect-error
document.querySelector('#scaleOutline').options.selectedIndex = 1;
// @ts-expect-error
document.querySelector('#pattern').options.selectedIndex = 0;
// @ts-expect-error
document.querySelector('#repeat').options.selectedIndex = 0;
// #### Development and testing
console.log(scrawl.library);