scrawl-canvas
Version:
Version 8.9.4 - 19 Nov 2022
429 lines (324 loc) • 9.66 kB
JavaScript
// # Demo Canvas 024
// Loom entity functionality
// [Run code](../../demo/canvas-024.html)
import * as scrawl from '../source/scrawl.js'
import { reportSpeed, addImageDragAndDrop } from './utilities.js';
// #### Scene setup
let canvas = scrawl.library.canvas.mycanvas;
// Import image from DOM
scrawl.importDomImage('.flowers');
// Define some filters to play with
scrawl.makeFilter({
name: 'grayscale',
method: 'grayscale',
}).clone({
name: 'sepia',
method: 'sepia',
}).clone({
name: 'cyan',
method: 'cyan',
}).clone({
name: 'pixelate',
method: 'pixelate',
tileWidth: 8,
tileHeight: 8,
});
// Define the artefacts that will be used as `pivots` and `paths` before the artefacts that use them as such
scrawl.makeWheel({
name: 'pin-1',
order: 2,
startX: 100,
startY: 100,
handleX: 'center',
handleY: 'center',
radius: 10,
fillStyle: 'blue',
strokeStyle: 'darkgray',
lineWidth: 2,
method: 'fillAndDraw',
}).clone({
name: 'pin-2',
startY: 300,
}).clone({
name: 'pin-3',
startY: 500,
}).clone({
name: 'pin-4',
fillStyle: 'green',
startX: 500,
startY: 100,
}).clone({
name: 'pin-5',
startY: 230,
}).clone({
name: 'pin-6',
startY: 370,
}).clone({
name: 'pin-7',
startY: 500,
});
// Make an object to hold functions we'll use for UI
const setCursorTo = {
auto: () => {
canvas.set({
css: {
cursor: 'auto',
},
});
},
pointer: () => {
canvas.set({
css: {
cursor: 'pointer',
},
});
},
grabbing: () => {
canvas.set({
css: {
cursor: 'grabbing',
},
});
},
};
// Create a Group to hold the draggable artefacts, for easier user action collision detection
let pins = scrawl.makeGroup({
name: 'my-pins',
host: canvas.base.name,
checkForEntityHover: true,
onEntityHover: setCursorTo.pointer,
onEntityNoHover: setCursorTo.auto,
}).addArtefacts('pin-1', 'pin-2', 'pin-3', 'pin-4', 'pin-5', 'pin-6', 'pin-7');
// Create the Shape entitys the Loom will use as its tracks - `fromPath`, `toPath`
scrawl.makeQuadratic({
name: 'my-quad',
pivot: 'pin-1',
lockTo: 'pivot',
useStartAsControlPoint: true,
precision: 0.05,
controlPivot: 'pin-2',
controlLockTo: 'pivot',
endPivot: 'pin-3',
endLockTo: 'pivot',
method: 'none',
minimumBoundingBoxDimensions: 0,
useAsPath: true,
});
let myBez = scrawl.makeBezier({
name: 'my-bezier',
pivot: 'pin-4',
lockTo: 'pivot',
useStartAsControlPoint: true,
precision: 0.05,
startControlPivot: 'pin-5',
startControlLockTo: 'pivot',
endControlPivot: 'pin-6',
endControlLockTo: 'pivot',
endPivot: 'pin-7',
endLockTo: 'pivot',
method: 'none',
minimumBoundingBoxDimensions: 0,
useAsPath: true,
});
// Every Loom needs a source image
let piccy = scrawl.makePicture({
name: 'myFlower',
asset: 'iris',
copyStartX: 0,
copyStartY: 0,
copyWidth: '100%',
copyHeight: '100%',
visibility: false,
});
// ___The Loom entity definition___
let myLoom = scrawl.makeLoom({
name: 'display-loom',
// Check to see that paths can be loaded either as picture name strings, or as the entity itself
fromPath: 'my-quad',
toPath: myBez,
source: 'myFlower',
lineWidth: 2,
lineCap: 'round',
strokeStyle: 'orange',
boundingBoxColor: 'red',
showBoundingBox: true,
method: 'fillThenDraw',
// @ts-expect-error
onEnter: function () { this.set({ lineWidth: 6 }) },
// @ts-expect-error
onLeave: function () { this.set({ lineWidth: 2 }) },
});
// #### User interaction
// Mouse movement over and away from the Loom (emulates CSS element `hover` functionality)
let interactions = function () { canvas.cascadeEventAction('move') };
scrawl.addListener('move', interactions, canvas.domElement);
// Create the drag-and-drop zone
scrawl.makeDragZone({
zone: canvas,
collisionGroup: pins,
endOn: ['up', 'leave'],
exposeCurrentArtefact: true,
preventTouchDefaultWhenDragging: true,
updateOnStart: setCursorTo.grabbing,
updateOnEnd: setCursorTo.pointer,
});
// #### Scene animation
// Function to display frames-per-second data, and other information relevant to the demo
const report = reportSpeed('#reportmessage');
// Create the Display cycle animation
scrawl.makeRender({
name: 'demo-animation',
target: canvas,
afterShow: report,
});
// #### Drag-and-Drop image loading functionality
addImageDragAndDrop(canvas, '#my-image-store', piccy);
// #### More user interaction
// Loom functionality
scrawl.observeAndUpdate({
event: ['input', 'change'],
origin: '.controlItem',
target: myLoom,
useNativeListener: true,
preventDefault: true,
updates: {
fromStart: ['fromPathStart', 'float'],
fromEnd: ['fromPathEnd', 'float'],
toStart: ['toPathStart', 'float'],
toEnd: ['toPathEnd', 'float'],
sync: ['synchronizePathCursors', 'boolean'],
looping: ['loopPathCursors', 'boolean'],
rendering: ['isHorizontalCopy', 'boolean'],
method: ['method', 'raw'],
},
});
// Delta animation controls handler
let updateAnimation = (e) => {
e.preventDefault();
e.returnValue = false;
let val = e.target.value;
switch (val) {
case 'off' :
myLoom.set({ delta: {
fromPathStart: 0,
fromPathEnd: 0,
toPathStart: 0,
toPathEnd: 0,
}});
break;
case 'posDelta' :
myLoom.set({ delta: {
fromPathStart: 0.002,
fromPathEnd: 0.002,
toPathStart: 0.002,
toPathEnd: 0.002,
}});
break;
case 'negDelta' :
myLoom.set({ delta: {
fromPathStart: -0.002,
fromPathEnd: -0.002,
toPathStart: -0.002,
toPathEnd: -0.002,
}});
break;
}
};
scrawl.addNativeListener(['input', 'change'], updateAnimation, '#animation');
// Picture entity filters
let updateFilter = (e) => {
e.preventDefault();
e.returnValue = false;
let val = e.target.value;
piccy.clearFilters();
if (val) piccy.addFilters(val);
// Loom will not pickup changes to picture attributes, need to trigger its output for the changes to be instantaneous
myLoom.update();
};
scrawl.addNativeListener(['input', 'change'], updateFilter, '#filter');
// Picture entity copy start and copy dimensions
scrawl.observeAndUpdate({
event: ['input', 'change'],
origin: '.controlItem',
target: piccy,
useNativeListener: true,
preventDefault: true,
updates: {
copy_start_xPercent: ['copyStartX', '%'],
copy_start_xAbsolute: ['copyStartX', 'round'],
copy_start_yPercent: ['copyStartY', '%'],
copy_start_yAbsolute: ['copyStartY', 'round'],
copy_dims_widthPercent: ['copyWidth', '%'],
copy_dims_widthAbsolute: ['copyWidth', 'round'],
copy_dims_heightPercent: ['copyHeight', '%'],
copy_dims_heightAbsolute: ['copyHeight', 'round'],
},
callback: () => myLoom.update(),
});
// Setup form
// @ts-expect-error
document.querySelector('#fromStart').value = 0;
// @ts-expect-error
document.querySelector('#fromEnd').value = 1;
// @ts-expect-error
document.querySelector('#toStart').value = 0;
// @ts-expect-error
document.querySelector('#toEnd').value = 1;
// @ts-expect-error
document.querySelector('#sync').options.selectedIndex = 1;
// @ts-expect-error
document.querySelector('#looping').options.selectedIndex = 1;
// @ts-expect-error
document.querySelector('#rendering').options.selectedIndex = 0;
// @ts-expect-error
document.querySelector('#animation').options.selectedIndex = 0;
// @ts-expect-error
document.querySelector('#filter').options.selectedIndex = 0;
// @ts-expect-error
document.querySelector('#method').options.selectedIndex = 4;
// @ts-expect-error
document.querySelector('#copy_start_xPercent').value = 0;
// @ts-expect-error
document.querySelector('#copy_start_yPercent').value = 0;
// @ts-expect-error
document.querySelector('#copy_dims_widthPercent').value = 100;
// @ts-expect-error
document.querySelector('#copy_dims_widthAbsolute').value = 400;
// @ts-expect-error
document.querySelector('#copy_start_xAbsolute').value = 0;
// @ts-expect-error
document.querySelector('#copy_start_yAbsolute').value = 0;
// @ts-expect-error
document.querySelector('#copy_dims_heightPercent').value = 100;
// @ts-expect-error
document.querySelector('#copy_dims_heightAbsolute').value = 400;
// #### Development and testing
// Test packet functionality
console.log(myLoom.saveAsPacket());
// ```
// RESULT:
// [
// "display-loom",
// "Loom",
// "entity",
// {
// "name":"display-loom",
// "showBoundingBox":true,
// "boundingBoxColor":"red",
// "method":"fillThenDraw",
// "onEnter":"~~~ this.set({ lineWidth: 6 }) ",
// "onLeave":"~~~ this.set({ lineWidth: 2 }) ",
// "onDown":"~~~",
// "onUp":"~~~",
// "delta":{},
// "fromPath":"my-quad",
// "toPath":"my-bezier",
// "source":"myFlower",
// "group":"mycanvas_base",
// "strokeStyle":"orange",
// "lineWidth":2,
// "lineCap":"round"
// }
// ]
// ```
console.log(scrawl.library);