StackGenVis: Alignment of Data, Algorithms, and Models for Stacking Ensemble Learning Using Performance Metrics
https://doi.org/10.1109/TVCG.2020.3030352
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
274 lines
5.9 KiB
274 lines
5.9 KiB
import Interaction from "../core/Interaction.js";
|
|
import { Scope } from "../core/scope.js";
|
|
import * as utils from "../utils/index.js";
|
|
import PointerEvent from "./PointerEvent.js";
|
|
const defaults = {
|
|
holdDuration: 600,
|
|
ignoreFrom: null,
|
|
allowFrom: null,
|
|
origin: {
|
|
x: 0,
|
|
y: 0
|
|
}
|
|
};
|
|
const pointerEvents = {
|
|
id: 'pointer-events/base',
|
|
install,
|
|
listeners: {
|
|
'interactions:new': addInteractionProps,
|
|
'interactions:update-pointer': addHoldInfo,
|
|
'interactions:move': moveAndClearHold,
|
|
'interactions:down': (arg, scope) => {
|
|
downAndStartHold(arg, scope);
|
|
fire(arg, scope);
|
|
},
|
|
'interactions:up': (arg, scope) => {
|
|
clearHold(arg);
|
|
fire(arg, scope);
|
|
tapAfterUp(arg, scope);
|
|
},
|
|
'interactions:cancel': (arg, scope) => {
|
|
clearHold(arg);
|
|
fire(arg, scope);
|
|
}
|
|
},
|
|
PointerEvent,
|
|
fire,
|
|
collectEventTargets,
|
|
defaults,
|
|
types: ['down', 'move', 'up', 'cancel', 'tap', 'doubletap', 'hold']
|
|
};
|
|
|
|
function fire(arg, scope) {
|
|
const {
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
type,
|
|
targets = collectEventTargets(arg, scope)
|
|
} = arg;
|
|
const pointerEvent = new PointerEvent(type, pointer, event, eventTarget, interaction, scope.now());
|
|
scope.fire('pointerEvents:new', {
|
|
pointerEvent
|
|
});
|
|
const signalArg = {
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
targets,
|
|
type,
|
|
pointerEvent
|
|
};
|
|
|
|
for (let i = 0; i < targets.length; i++) {
|
|
const target = targets[i];
|
|
|
|
for (const prop in target.props || {}) {
|
|
pointerEvent[prop] = target.props[prop];
|
|
}
|
|
|
|
const origin = utils.getOriginXY(target.eventable, target.node);
|
|
|
|
pointerEvent._subtractOrigin(origin);
|
|
|
|
pointerEvent.eventable = target.eventable;
|
|
pointerEvent.currentTarget = target.node;
|
|
target.eventable.fire(pointerEvent);
|
|
|
|
pointerEvent._addOrigin(origin);
|
|
|
|
if (pointerEvent.immediatePropagationStopped || pointerEvent.propagationStopped && i + 1 < targets.length && targets[i + 1].node !== pointerEvent.currentTarget) {
|
|
break;
|
|
}
|
|
}
|
|
|
|
scope.fire('pointerEvents:fired', signalArg);
|
|
|
|
if (type === 'tap') {
|
|
// if pointerEvent should make a double tap, create and fire a doubletap
|
|
// PointerEvent and use that as the prevTap
|
|
const prevTap = pointerEvent.double ? fire({
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
type: 'doubletap'
|
|
}, scope) : pointerEvent;
|
|
interaction.prevTap = prevTap;
|
|
interaction.tapTime = prevTap.timeStamp;
|
|
}
|
|
|
|
return pointerEvent;
|
|
}
|
|
|
|
function collectEventTargets({
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
type
|
|
}, scope) {
|
|
const pointerIndex = interaction.getPointerIndex(pointer);
|
|
const pointerInfo = interaction.pointers[pointerIndex]; // do not fire a tap event if the pointer was moved before being lifted
|
|
|
|
if (type === 'tap' && (interaction.pointerWasMoved || // or if the pointerup target is different to the pointerdown target
|
|
!(pointerInfo && pointerInfo.downTarget === eventTarget))) {
|
|
return [];
|
|
}
|
|
|
|
const path = utils.dom.getPath(eventTarget);
|
|
const signalArg = {
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
type,
|
|
path,
|
|
targets: [],
|
|
node: null
|
|
};
|
|
|
|
for (const node of path) {
|
|
signalArg.node = node;
|
|
scope.fire('pointerEvents:collect-targets', signalArg);
|
|
}
|
|
|
|
if (type === 'hold') {
|
|
signalArg.targets = signalArg.targets.filter(target => target.eventable.options.holdDuration === interaction.pointers[pointerIndex].hold.duration);
|
|
}
|
|
|
|
return signalArg.targets;
|
|
}
|
|
|
|
function addInteractionProps({
|
|
interaction
|
|
}) {
|
|
interaction.prevTap = null; // the most recent tap event on this interaction
|
|
|
|
interaction.tapTime = 0; // time of the most recent tap event
|
|
}
|
|
|
|
function addHoldInfo({
|
|
down,
|
|
pointerInfo
|
|
}) {
|
|
if (!down && pointerInfo.hold) {
|
|
return;
|
|
}
|
|
|
|
pointerInfo.hold = {
|
|
duration: Infinity,
|
|
timeout: null
|
|
};
|
|
}
|
|
|
|
function clearHold({
|
|
interaction,
|
|
pointerIndex
|
|
}) {
|
|
if (interaction.pointers[pointerIndex].hold) {
|
|
clearTimeout(interaction.pointers[pointerIndex].hold.timeout);
|
|
}
|
|
}
|
|
|
|
function moveAndClearHold({
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
duplicate
|
|
}, scope) {
|
|
const pointerIndex = interaction.getPointerIndex(pointer);
|
|
|
|
if (!duplicate && (!interaction.pointerIsDown || interaction.pointerWasMoved)) {
|
|
if (interaction.pointerIsDown) {
|
|
clearTimeout(interaction.pointers[pointerIndex].hold.timeout);
|
|
}
|
|
|
|
fire({
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget: eventTarget,
|
|
type: 'move'
|
|
}, scope);
|
|
}
|
|
}
|
|
|
|
function downAndStartHold({
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
pointerIndex
|
|
}, scope) {
|
|
const timer = interaction.pointers[pointerIndex].hold;
|
|
const path = utils.dom.getPath(eventTarget);
|
|
const signalArg = {
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget,
|
|
type: 'hold',
|
|
targets: [],
|
|
path,
|
|
node: null
|
|
};
|
|
|
|
for (const node of path) {
|
|
signalArg.node = node;
|
|
scope.fire('pointerEvents:collect-targets', signalArg);
|
|
}
|
|
|
|
if (!signalArg.targets.length) {
|
|
return;
|
|
}
|
|
|
|
let minDuration = Infinity;
|
|
|
|
for (const target of signalArg.targets) {
|
|
const holdDuration = target.eventable.options.holdDuration;
|
|
|
|
if (holdDuration < minDuration) {
|
|
minDuration = holdDuration;
|
|
}
|
|
}
|
|
|
|
timer.duration = minDuration;
|
|
timer.timeout = setTimeout(() => {
|
|
fire({
|
|
interaction,
|
|
eventTarget,
|
|
pointer,
|
|
event,
|
|
type: 'hold'
|
|
}, scope);
|
|
}, minDuration);
|
|
}
|
|
|
|
function tapAfterUp({
|
|
interaction,
|
|
pointer,
|
|
event,
|
|
eventTarget
|
|
}, scope) {
|
|
if (!interaction.pointerWasMoved) {
|
|
fire({
|
|
interaction,
|
|
eventTarget,
|
|
pointer,
|
|
event,
|
|
type: 'tap'
|
|
}, scope);
|
|
}
|
|
}
|
|
|
|
function install(scope) {
|
|
scope.pointerEvents = pointerEvents;
|
|
scope.defaults.actions.pointerEvents = pointerEvents.defaults;
|
|
}
|
|
|
|
export default pointerEvents;
|
|
//# sourceMappingURL=base.js.map
|