import { isa_fn, isa_dom, λnull, Ωempty } from "../helper/utilities.js";
import { releaseArray, requestArray } from '../helper/array-pool.js';Each scrawl-canvas stack and canvas can have bespoke Scrawl-canvas listeners attached to them, to track user mouse and touch interactions with that element. Scrawl-canvas defines five bespoke listeners:
The functions all takes the following arguments:
import { isa_fn, isa_dom, λnull, Ωempty } from "../helper/utilities.js";
import { releaseArray, requestArray } from '../helper/array-pool.js';Shared constants
import { _isArray, ADD_EVENT_LISTENER, DOWN, ENTER, FUNCTION, LEAVE, MOUSE_DOWN, MOUSE_ENTER, MOUSE_LEAVE, MOUSE_MOVE, MOUSE_UP, MOVE, POINTER_DOWN, POINTER_ENTER, POINTER_LEAVE, POINTER_MOVE, POINTER_UP, REMOVE_EVENT_LISTENER, TOUCH_END, TOUCH_MOVE, TOUCH_START, UP } from '../helper/shared-vars.js';Local constants
const TOUCH_ENTER = 'touchenter',
TOUCH_FOLLOW = 'touchfollow',
TOUCH_LEAVE = 'touchleave';Exported function (to modules and scrawl object) - scrawl.makeAnimationObserver - function to create and start a DOM IntersectionObserver object.
The function expects 3 arguments, in the following order:
root, rootMargin, thresholdThe function returns a function which, when invoked, will disconnect the observer from the DOM.
export const makeAnimationObserver = function (anim, wrapper, specs = Ωempty) {
if (typeof window.IntersectionObserver === FUNCTION && anim && anim.run) {
const observer = new IntersectionObserver((entries) => {
let i, iz, entry;
for (i = 0, iz = entries.length; i < iz; i++) {
entry = entries[i];
if (entry.isIntersecting && !anim.isRunning()) anim.run();
else if (!entry.isIntersecting && anim.isRunning()) anim.halt();
}
}, specs);
if (wrapper && wrapper.domElement) {
observer.observe(wrapper.domElement);
}
return function () {
observer.disconnect();
}
}
return λnull;
}Exported function (to modules and scrawl object) - scrawl.addListener. Returns a kill function which, when invoked (no arguments required), will remove the event listener(s) from all DOM elements to which they have been attached.
export const addListener = function (evt, fn, targ) {
if (evt && isa_fn(fn) && targ) {
actionListener(evt, fn, targ, REMOVE_EVENT_LISTENER);
actionListener(evt, fn, targ, ADD_EVENT_LISTENER);
return function () {
removeListener(evt, fn, targ);
};
}
return λnull;
};Exported function (to modules and scrawl object) - scrawl.removeListener. The counterpart to ‘addListener’ is removeListener which removes Scrawl-canvas event listeners from DOM elements in a similar way
export const removeListener = function (evt, fn, targ) {
if (evt && isa_fn(fn) && targ) actionListener(evt, fn, targ, REMOVE_EVENT_LISTENER);
};Because devices and browsers differ in their approach to user interaction (mouse vs pointer vs touch), the actual functionality for adding and removing the event listeners associated with each approach is handled by dedicated actionXXXListener functions
TODO: code up the functionality to manage touch events
const actionListener = function (evt, fn, targ, action) {
const events = requestArray(),
targets = requestArray();
if (_isArray(evt)) events.push(...evt);
else events.push(evt);
if (targ.substring) targets.push(...document.body.querySelectorAll(targ));
else if (_isArray(targ)) targets.push(...targ);
else targets.push(targ);
if (navigator.pointerEnabled || navigator.msPointerEnabled) actionPointerListener(events, fn, targets, action);
else actionMouseListener(events, fn, targets, action);
releaseArray(targets, events);
};
const actionMouseListener = function (events, fn, targets, action) {
let i, iz, j, jz, e, t;
for (i = 0, iz = events.length; i < iz; i++) {
e = events[i];
for (j = 0, jz = targets.length; j < jz; j++) {
t = targets[j];
if (isa_dom(t) || t.document || t.characterSet) {
switch (e) {
case MOVE:
t[action](MOUSE_MOVE, fn, false);
t[action](TOUCH_MOVE, fn, {passive: false});
t[action](TOUCH_FOLLOW, fn, {passive: false});
break;
case UP:
t[action](MOUSE_UP, fn, false);
t[action](TOUCH_END, fn, {passive: false});
break;
case DOWN:
t[action](MOUSE_DOWN, fn, false);
t[action](TOUCH_START, fn, {passive: false});
break;
case LEAVE:
t[action](MOUSE_LEAVE, fn, false);
t[action](TOUCH_LEAVE, fn, {passive: false});
break;
case ENTER:
t[action](MOUSE_ENTER, fn, false);
t[action](TOUCH_ENTER, fn, {passive: false});
break;
}
}
}
}
};
const actionPointerListener = function (events, fn, targets, action) {
let i, iz, j, jz, e, t;
for (i = 0, iz = events.length; i < iz; i++) {
e = events[i];
for (j = 0, jz = targets.length; j < jz; j++) {
t = targets[j];
if (isa_dom(t) || t.document || t.characterSet) {
switch (e) {
case MOVE:
t[action](POINTER_MOVE, fn, false);
break;
case UP:
t[action](POINTER_UP, fn, false);
break;
case DOWN:
t[action](POINTER_DOWN, fn, false);
break;
case LEAVE:
t[action](POINTER_LEAVE, fn, false);
break;
case ENTER:
t[action](POINTER_ENTER, fn, false);
break;
}
}
}
}
};Any event listener can be added to a Scrawl-canvas stack or canvas DOM element.
The scrawl.addNativeListener function makes adding and removing these ‘native’ listeners a little easier: multiple event listeners (which all trigger the same function) can be added to multiple DOM elements (that have been registered in the Scrawl-canvas library) in a single function call.
The function requires three arguments:
window and ``Exported function (to modules and scrawl object). Returns a kill function which, when invoked (no arguments required), will remove the event listener(s) from all DOM elements to which they have been attached.
export const addNativeListener = function (evt, fn, targ) {
if (evt && isa_fn(fn) && targ) {
actionNativeListener(evt, fn, targ, REMOVE_EVENT_LISTENER);
actionNativeListener(evt, fn, targ, ADD_EVENT_LISTENER);
return function () {
removeNativeListener(evt, fn, targ);
};
}
return λnull;
};Exported function (to modules and scrawl object). The counterpart to ‘addNativeListener’ is scrawl.removeNativeListener which removes event listeners from DOM elements in a similar way
export const removeNativeListener = function (evt, fn, targ) {
if (evt && isa_fn(fn) && targ) actionNativeListener(evt, fn, targ, REMOVE_EVENT_LISTENER);
};
const actionNativeListener = function (evt, fn, targ, action) {
const events = requestArray(),
targets = requestArray();
let i, iz, j, jz, e, t;
if (_isArray(evt)) events.push(...evt);
else events.push(evt);
if (targ.substring) targets.push(...document.body.querySelectorAll(targ));
else if (_isArray(targ)) targets.push(...targ);
else targets.push(targ);
for (i = 0, iz = events.length; i < iz; i++) {
e = events[i];
for (j = 0, jz = targets.length; j < jz; j++) {
t = targets[j];
if (isa_dom(t) || t.document || t.characterSet) t[action](e, fn, false);
}
}
releaseArray(targets, events);
};