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.
476 lines
14 KiB
476 lines
14 KiB
4 years ago
|
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
|
||
|
|
||
|
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
|
||
|
|
||
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||
|
|
||
|
import Vue from '../../utils/vue';
|
||
|
import { Portal, Wormhole } from 'portal-vue';
|
||
|
import BVTransition from '../../utils/bv-transition';
|
||
|
import { BvEvent } from '../../utils/bv-event.class';
|
||
|
import { getComponentConfig } from '../../utils/config';
|
||
|
import { requestAF } from '../../utils/dom';
|
||
|
import { EVENT_OPTIONS_NO_CAPTURE, eventOnOff } from '../../utils/events';
|
||
|
import { toInteger } from '../../utils/number';
|
||
|
import idMixin from '../../mixins/id';
|
||
|
import listenOnRootMixin from '../../mixins/listen-on-root';
|
||
|
import normalizeSlotMixin from '../../mixins/normalize-slot';
|
||
|
import scopedStyleAttrsMixin from '../../mixins/scoped-style-attrs';
|
||
|
import { BToaster } from './toaster';
|
||
|
import { BButtonClose } from '../button/button-close';
|
||
|
import { BLink } from '../link/link'; // --- Constants ---
|
||
|
|
||
|
var NAME = 'BToast';
|
||
|
var MIN_DURATION = 1000; // --- Props ---
|
||
|
|
||
|
export var props = {
|
||
|
id: {
|
||
|
// Even though the ID prop is provided by idMixin, we
|
||
|
// add it here for $bvToast props filtering
|
||
|
type: String,
|
||
|
default: null
|
||
|
},
|
||
|
title: {
|
||
|
type: String,
|
||
|
default: null
|
||
|
},
|
||
|
toaster: {
|
||
|
type: String,
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'toaster');
|
||
|
}
|
||
|
},
|
||
|
visible: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
variant: {
|
||
|
type: String,
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'variant');
|
||
|
}
|
||
|
},
|
||
|
isStatus: {
|
||
|
// Switches role to 'status' and aria-live to 'polite'
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
appendToast: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
noAutoHide: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
autoHideDelay: {
|
||
|
type: [Number, String],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'autoHideDelay');
|
||
|
}
|
||
|
},
|
||
|
noCloseButton: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
noFade: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
noHoverPause: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
solid: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
toastClass: {
|
||
|
type: [String, Object, Array],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'toastClass');
|
||
|
}
|
||
|
},
|
||
|
headerClass: {
|
||
|
type: [String, Object, Array],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'headerClass');
|
||
|
}
|
||
|
},
|
||
|
bodyClass: {
|
||
|
type: [String, Object, Array],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'bodyClass');
|
||
|
}
|
||
|
},
|
||
|
href: {
|
||
|
type: String,
|
||
|
default: null
|
||
|
},
|
||
|
to: {
|
||
|
type: [String, Object],
|
||
|
default: null
|
||
|
},
|
||
|
static: {
|
||
|
// Render the toast in place, rather than in a portal-target
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
}
|
||
|
}; // @vue/component
|
||
|
|
||
|
export var BToast =
|
||
|
/*#__PURE__*/
|
||
|
Vue.extend({
|
||
|
name: NAME,
|
||
|
mixins: [idMixin, listenOnRootMixin, normalizeSlotMixin, scopedStyleAttrsMixin],
|
||
|
inheritAttrs: false,
|
||
|
model: {
|
||
|
prop: 'visible',
|
||
|
event: 'change'
|
||
|
},
|
||
|
props: props,
|
||
|
data: function data() {
|
||
|
return {
|
||
|
isMounted: false,
|
||
|
doRender: false,
|
||
|
localShow: false,
|
||
|
isTransitioning: false,
|
||
|
isHiding: false,
|
||
|
order: 0,
|
||
|
timer: null,
|
||
|
dismissStarted: 0,
|
||
|
resumeDismiss: 0
|
||
|
};
|
||
|
},
|
||
|
computed: {
|
||
|
bToastClasses: function bToastClasses() {
|
||
|
return _defineProperty({
|
||
|
'b-toast-solid': this.solid,
|
||
|
'b-toast-append': this.appendToast,
|
||
|
'b-toast-prepend': !this.appendToast
|
||
|
}, "b-toast-".concat(this.variant), this.variant);
|
||
|
},
|
||
|
slotScope: function slotScope() {
|
||
|
return {
|
||
|
hide: this.hide
|
||
|
};
|
||
|
},
|
||
|
computedDuration: function computedDuration() {
|
||
|
// Minimum supported duration is 1 second
|
||
|
return Math.max(toInteger(this.autoHideDelay) || 0, MIN_DURATION);
|
||
|
},
|
||
|
computedToaster: function computedToaster() {
|
||
|
return String(this.toaster);
|
||
|
},
|
||
|
transitionHandlers: function transitionHandlers() {
|
||
|
return {
|
||
|
beforeEnter: this.onBeforeEnter,
|
||
|
afterEnter: this.onAfterEnter,
|
||
|
beforeLeave: this.onBeforeLeave,
|
||
|
afterLeave: this.onAfterLeave
|
||
|
};
|
||
|
}
|
||
|
},
|
||
|
watch: {
|
||
|
visible: function visible(newVal) {
|
||
|
newVal ? this.show() : this.hide();
|
||
|
},
|
||
|
localShow: function localShow(newVal) {
|
||
|
if (newVal !== this.visible) {
|
||
|
this.$emit('change', newVal);
|
||
|
}
|
||
|
},
|
||
|
toaster: function toaster()
|
||
|
/* istanbul ignore next */
|
||
|
{
|
||
|
// If toaster target changed, make sure toaster exists
|
||
|
this.$nextTick(this.ensureToaster);
|
||
|
},
|
||
|
static: function _static(newVal)
|
||
|
/* istanbul ignore next */
|
||
|
{
|
||
|
// If static changes to true, and the toast is showing,
|
||
|
// ensure the toaster target exists
|
||
|
if (newVal && this.localShow) {
|
||
|
this.ensureToaster();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
mounted: function mounted() {
|
||
|
var _this = this;
|
||
|
|
||
|
this.isMounted = true;
|
||
|
this.$nextTick(function () {
|
||
|
if (_this.visible) {
|
||
|
requestAF(function () {
|
||
|
_this.show();
|
||
|
});
|
||
|
}
|
||
|
}); // Listen for global $root show events
|
||
|
|
||
|
this.listenOnRoot('bv::show::toast', function (id) {
|
||
|
if (id === _this.safeId()) {
|
||
|
_this.show();
|
||
|
}
|
||
|
}); // Listen for global $root hide events
|
||
|
|
||
|
this.listenOnRoot('bv::hide::toast', function (id) {
|
||
|
if (!id || id === _this.safeId()) {
|
||
|
_this.hide();
|
||
|
}
|
||
|
}); // Make sure we hide when toaster is destroyed
|
||
|
|
||
|
/* istanbul ignore next: difficult to test */
|
||
|
|
||
|
this.listenOnRoot('bv::toaster::destroyed', function (toaster) {
|
||
|
/* istanbul ignore next */
|
||
|
if (toaster === _this.computedToaster) {
|
||
|
/* istanbul ignore next */
|
||
|
_this.hide();
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
beforeDestroy: function beforeDestroy() {
|
||
|
this.clearDismissTimer();
|
||
|
},
|
||
|
methods: {
|
||
|
show: function show() {
|
||
|
var _this2 = this;
|
||
|
|
||
|
if (!this.localShow) {
|
||
|
this.ensureToaster();
|
||
|
var showEvt = this.buildEvent('show');
|
||
|
this.emitEvent(showEvt);
|
||
|
this.dismissStarted = this.resumeDismiss = 0;
|
||
|
this.order = Date.now() * (this.appendToast ? 1 : -1);
|
||
|
this.isHiding = false;
|
||
|
this.doRender = true;
|
||
|
this.$nextTick(function () {
|
||
|
// We show the toast after we have rendered the portal and b-toast wrapper
|
||
|
// so that screen readers will properly announce the toast
|
||
|
requestAF(function () {
|
||
|
_this2.localShow = true;
|
||
|
});
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
hide: function hide() {
|
||
|
var _this3 = this;
|
||
|
|
||
|
if (this.localShow) {
|
||
|
var hideEvt = this.buildEvent('hide');
|
||
|
this.emitEvent(hideEvt);
|
||
|
this.setHoverHandler(false);
|
||
|
this.dismissStarted = this.resumeDismiss = 0;
|
||
|
this.clearDismissTimer();
|
||
|
this.isHiding = true;
|
||
|
requestAF(function () {
|
||
|
_this3.localShow = false;
|
||
|
});
|
||
|
}
|
||
|
},
|
||
|
buildEvent: function buildEvent(type) {
|
||
|
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
|
||
|
return new BvEvent(type, _objectSpread({
|
||
|
cancelable: false,
|
||
|
target: this.$el || null,
|
||
|
relatedTarget: null
|
||
|
}, options, {
|
||
|
vueTarget: this,
|
||
|
componentId: this.safeId()
|
||
|
}));
|
||
|
},
|
||
|
emitEvent: function emitEvent(bvEvt) {
|
||
|
var type = bvEvt.type;
|
||
|
this.$root.$emit("bv::toast:".concat(type), bvEvt);
|
||
|
this.$emit(type, bvEvt);
|
||
|
},
|
||
|
ensureToaster: function ensureToaster() {
|
||
|
if (this.static) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if (!Wormhole.hasTarget(this.computedToaster)) {
|
||
|
var div = document.createElement('div');
|
||
|
document.body.appendChild(div);
|
||
|
var toaster = new BToaster({
|
||
|
parent: this.$root,
|
||
|
propsData: {
|
||
|
name: this.computedToaster
|
||
|
}
|
||
|
});
|
||
|
toaster.$mount(div);
|
||
|
}
|
||
|
},
|
||
|
startDismissTimer: function startDismissTimer() {
|
||
|
this.clearDismissTimer();
|
||
|
|
||
|
if (!this.noAutoHide) {
|
||
|
this.timer = setTimeout(this.hide, this.resumeDismiss || this.computedDuration);
|
||
|
this.dismissStarted = Date.now();
|
||
|
this.resumeDismiss = 0;
|
||
|
}
|
||
|
},
|
||
|
clearDismissTimer: function clearDismissTimer() {
|
||
|
clearTimeout(this.timer);
|
||
|
this.timer = null;
|
||
|
},
|
||
|
setHoverHandler: function setHoverHandler(on) {
|
||
|
var el = this.$refs['b-toast'];
|
||
|
eventOnOff(on, el, 'mouseenter', this.onPause, EVENT_OPTIONS_NO_CAPTURE);
|
||
|
eventOnOff(on, el, 'mouseleave', this.onUnPause, EVENT_OPTIONS_NO_CAPTURE);
|
||
|
},
|
||
|
onPause: function onPause() {
|
||
|
// Determine time remaining, and then pause timer
|
||
|
if (this.noAutoHide || this.noHoverPause || !this.timer || this.resumeDismiss) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
var passed = Date.now() - this.dismissStarted;
|
||
|
|
||
|
if (passed > 0) {
|
||
|
this.clearDismissTimer();
|
||
|
this.resumeDismiss = Math.max(this.computedDuration - passed, MIN_DURATION);
|
||
|
}
|
||
|
},
|
||
|
onUnPause: function onUnPause() {
|
||
|
// Restart timer with max of time remaining or 1 second
|
||
|
if (this.noAutoHide || this.noHoverPause || !this.resumeDismiss) {
|
||
|
this.resumeDismiss = this.dismissStarted = 0;
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
this.startDismissTimer();
|
||
|
},
|
||
|
onLinkClick: function onLinkClick() {
|
||
|
var _this4 = this;
|
||
|
|
||
|
// We delay the close to allow time for the
|
||
|
// browser to process the link click
|
||
|
this.$nextTick(function () {
|
||
|
requestAF(function () {
|
||
|
_this4.hide();
|
||
|
});
|
||
|
});
|
||
|
},
|
||
|
onBeforeEnter: function onBeforeEnter() {
|
||
|
this.isTransitioning = true;
|
||
|
},
|
||
|
onAfterEnter: function onAfterEnter() {
|
||
|
this.isTransitioning = false;
|
||
|
var hiddenEvt = this.buildEvent('shown');
|
||
|
this.emitEvent(hiddenEvt);
|
||
|
this.startDismissTimer();
|
||
|
this.setHoverHandler(true);
|
||
|
},
|
||
|
onBeforeLeave: function onBeforeLeave() {
|
||
|
this.isTransitioning = true;
|
||
|
},
|
||
|
onAfterLeave: function onAfterLeave() {
|
||
|
this.isTransitioning = false;
|
||
|
this.order = 0;
|
||
|
this.resumeDismiss = this.dismissStarted = 0;
|
||
|
var hiddenEvt = this.buildEvent('hidden');
|
||
|
this.emitEvent(hiddenEvt);
|
||
|
this.doRender = false;
|
||
|
},
|
||
|
makeToast: function makeToast(h) {
|
||
|
var _this5 = this;
|
||
|
|
||
|
// Render helper for generating the toast
|
||
|
// Assemble the header content
|
||
|
var $headerContent = [];
|
||
|
var $title = this.normalizeSlot('toast-title', this.slotScope);
|
||
|
|
||
|
if ($title) {
|
||
|
$headerContent.push($title);
|
||
|
} else if (this.title) {
|
||
|
$headerContent.push(h('strong', {
|
||
|
staticClass: 'mr-2'
|
||
|
}, this.title));
|
||
|
}
|
||
|
|
||
|
if (!this.noCloseButton) {
|
||
|
$headerContent.push(h(BButtonClose, {
|
||
|
staticClass: 'ml-auto mb-1',
|
||
|
on: {
|
||
|
click: function click() {
|
||
|
_this5.hide();
|
||
|
}
|
||
|
}
|
||
|
}));
|
||
|
} // Assemble the header (if needed)
|
||
|
|
||
|
|
||
|
var $header = h();
|
||
|
|
||
|
if ($headerContent.length > 0) {
|
||
|
$header = h('header', {
|
||
|
staticClass: 'toast-header',
|
||
|
class: this.headerClass
|
||
|
}, $headerContent);
|
||
|
} // Toast body
|
||
|
|
||
|
|
||
|
var isLink = this.href || this.to;
|
||
|
var $body = h(isLink ? BLink : 'div', {
|
||
|
staticClass: 'toast-body',
|
||
|
class: this.bodyClass,
|
||
|
props: isLink ? {
|
||
|
to: this.to,
|
||
|
href: this.href
|
||
|
} : {},
|
||
|
on: isLink ? {
|
||
|
click: this.onLinkClick
|
||
|
} : {}
|
||
|
}, [this.normalizeSlot('default', this.slotScope) || h()]); // Build the toast
|
||
|
|
||
|
var $toast = h('div', {
|
||
|
key: "toast-".concat(this._uid),
|
||
|
ref: 'toast',
|
||
|
staticClass: 'toast',
|
||
|
class: this.toastClass,
|
||
|
attrs: _objectSpread({}, this.$attrs, {
|
||
|
tabindex: '0',
|
||
|
id: this.safeId()
|
||
|
})
|
||
|
}, [$header, $body]);
|
||
|
return $toast;
|
||
|
}
|
||
|
},
|
||
|
render: function render(h) {
|
||
|
if (!this.doRender || !this.isMounted) {
|
||
|
return h();
|
||
|
}
|
||
|
|
||
|
var name = "b-toast-".concat(this._uid); // If scoped styles are applied and the toast is not static,
|
||
|
// make sure the scoped style data attribute is applied
|
||
|
|
||
|
var scopedStyleAttrs = !this.static ? this.scopedStyleAttrs : {};
|
||
|
return h(Portal, {
|
||
|
props: {
|
||
|
name: name,
|
||
|
to: this.computedToaster,
|
||
|
order: this.order,
|
||
|
slim: true,
|
||
|
disabled: this.static
|
||
|
}
|
||
|
}, [h('div', {
|
||
|
key: name,
|
||
|
ref: 'b-toast',
|
||
|
staticClass: 'b-toast',
|
||
|
class: this.bToastClasses,
|
||
|
attrs: _objectSpread({}, scopedStyleAttrs, {
|
||
|
id: this.safeId('_toast_outer'),
|
||
|
role: this.isHiding ? null : this.isStatus ? 'status' : 'alert',
|
||
|
'aria-live': this.isHiding ? null : this.isStatus ? 'polite' : 'assertive',
|
||
|
'aria-atomic': this.isHiding ? null : 'true'
|
||
|
})
|
||
|
}, [h(BVTransition, {
|
||
|
props: {
|
||
|
noFade: this.noFade
|
||
|
},
|
||
|
on: this.transitionHandlers
|
||
|
}, [this.localShow ? this.makeToast(h) : h()])])]);
|
||
|
}
|
||
|
});
|