import * as scrawl from '../source/scrawl.js'
import { reportSpeed } from './utilities.js';
import * as scrawl from '../source/scrawl.js'
import { reportSpeed } from './utilities.js';
const canvas = scrawl.findCanvas('mycanvas');
Namespacing boilerplate
const namespace = canvas.name;
const name = (n) => `${namespace}-${n}`;
Define some filters
scrawl.makeFilter({
name: name('grayscale'),
method: 'grayscale',
}).clone({
name: name('invert'),
method: 'invert',
});
scrawl.makeFilter({
name: name('tint'),
method: 'tint',
redInRed: 0.5, redInGreen: 1, redInBlue: 0.9,
greenInRed: 0, greenInGreen: 0.3, greenInBlue: 0.8,
blueInRed: 0.8, blueInGreen: 0.8, blueInBlue: 0.4,
});
scrawl.makeFilter({
name: name('matrix'),
method: 'matrix',
weights: [-1, -1, 0, -1, 1, 1, 0, 1, 1],
});
For this Demo, we are creating a sheet and pinning its top row to a rail. This is the rail.
scrawl.makeLine({
name: name('topline'),
startX: '10%',
startY: '5%',
endX: '90%',
endY: '5%',
lineWidth: 20,
lineCap: 'round',
strokeStyle: 'brown',
method: 'draw',
});
const bigball = scrawl.makeWheel({
name: name('big-ball'),
radius: 80,
handle: ['center', 'center'],
start: ['center', 320],
fillStyle: 'coral',
strokeStyle: 'orange',
lineWidth: 3,
method: 'fillThenDraw',
Default action is for a dragged entity to attempt to place itself over all other entitys (in its Group). We can prevent this by setting the bringToFrontOnDrag
to false
bringToFrontOnDrag: false,
});
The repeller force
scrawl.makeForce({
name: name('wheel-repellor'),
/* eslint-disable-next-line */
action: (particle, world, host) => {
const {load, position} = particle;
const ballPosition = bigball.get('position');
We are using Scrawl-canvas Pool vectors for this calculation, which we need to request before we can use them.
const v = scrawl.requestVector(ballPosition).vectorSubtract(position);
const mag = v.getMagnitude();
if (mag && mag < bigball.get('radius')) {
v.scalarMultiply(1 / (mag / 1000));
load.vectorSubtract(v)
}
When we are finished with the vector, we MUST release it back to the pool!
scrawl.releaseVector(v);
},
});
Create a World object which we can then assign to the Net entity
const myWorld = scrawl.makeWorld({
name: name('my-world'),
tickMultiplier: 2,
});
Create the Net entity
const myNet = scrawl.makeNet({
name: name('test-net'),
world: myWorld,
pivot: name('topline'),
lockTo: 'pivot',
generate: 'weak-net',
postGenerate: function () {
We want to make all of the top row Particles visually different, and static
const regex = RegExp('-0-[0-9]+$');
/** @ts-expect-error */
this.particleStore.forEach(p => {
if (regex.test(p.name)) {
p.set({
fill: 'lightgrey',
stroke: 'red',
forces: [],
});
/** @ts-expect-error */
this.springs.forEach(s => {
if (s && s.particleFrom && s.particleFrom.name === p.name) {
s.particleFromIsStatic = true;
}
if (s && s.particleTo && s.particleTo.name === p.name) {
s.particleToIsStatic = true;
}
})
}
});
},
rows: 15,
columns: 17,
rowDistance: 25,
columnDistance: 30,
showSprings: true,
showSpringsColor: 'azure',
forces: ['gravity', name('wheel-repellor')],
mass: 3,
springConstant: 100,
engine: 'runge-kutta',
artefact: scrawl.makeWheel({
name: name('particle-wheel'),
radius: 7,
handle: ['center', 'center'],
method: 'fillThenDraw',
fillStyle: 'yellow',
strokeStyle: 'gold',
visibility: false,
noUserInteraction: true,
noPositionDependencies: true,
noFilters: true,
noDeltaUpdates: true,
}),
stampAction: function (artefact, particle, host) {
const [ , , ...start] = particle.history[0];
artefact.simpleStamp(host, {
start,
fillStyle: particle.fill,
strokeStyle: particle.stroke,
});
},
Make all of the Net entity’s Particles draggable
particlesAreDraggable: true,
});
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: name('animation'),
target: canvas,
afterShow: report,
});
scrawl.makeGroup({
name: name('my-draggable-group'),
}).addArtefacts(name('test-net'), name('big-ball'));
scrawl.makeDragZone({
zone: canvas,
collisionGroup: name('my-draggable-group'),
endOn: ['up', 'leave'],
preventTouchDefaultWhenDragging: true,
});
When we set a filter on a Net entity, all the entity’s visual output will be filtered
const filterChoice = function (e) {
if (e && e.target) {
e.preventDefault();
e.returnValue = false;
const val = e.target.value;
myNet.clearFilters();
if (val) myNet.addFilters(name(val));
}
};
scrawl.addNativeListener(['input', 'change'], filterChoice, '#filter');
Set DOM form initial input values
/** @ts-expect-error */
document.querySelector('#filter').value = '';
console.log(scrawl.library);