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.
351 lines
10 KiB
351 lines
10 KiB
4 years ago
|
import Vue from '../../utils/vue';
|
||
|
import getScopId from '../../utils/get-scope-id';
|
||
|
import { isArray, arrayIncludes } from '../../utils/array';
|
||
|
import { getComponentConfig } from '../../utils/config';
|
||
|
import { isString, isUndefinedOrNull } from '../../utils/inspect';
|
||
|
import { HTMLElement, SVGElement } from '../../utils/safe-types';
|
||
|
import { BVTooltip } from './helpers/bv-tooltip';
|
||
|
var NAME = 'BTooltip'; // @vue/component
|
||
|
|
||
|
export var BTooltip =
|
||
|
/*#__PURE__*/
|
||
|
Vue.extend({
|
||
|
name: NAME,
|
||
|
props: {
|
||
|
title: {
|
||
|
type: String // default: undefined
|
||
|
|
||
|
},
|
||
|
// Added in by BPopover
|
||
|
// content: {
|
||
|
// type: String,
|
||
|
// default: undefined
|
||
|
// },
|
||
|
target: {
|
||
|
// String ID of element, or element/component reference
|
||
|
// Or function that returns one of the above
|
||
|
type: [String, HTMLElement, SVGElement, Function, Object],
|
||
|
// default: undefined,
|
||
|
required: true
|
||
|
},
|
||
|
triggers: {
|
||
|
type: [String, Array],
|
||
|
default: 'hover focus'
|
||
|
},
|
||
|
placement: {
|
||
|
type: String,
|
||
|
default: 'top'
|
||
|
},
|
||
|
fallbackPlacement: {
|
||
|
type: [String, Array],
|
||
|
default: 'flip',
|
||
|
validator: function validator(value) {
|
||
|
return isArray(value) && value.every(function (v) {
|
||
|
return isString(v);
|
||
|
}) || arrayIncludes(['flip', 'clockwise', 'counterclockwise'], value);
|
||
|
}
|
||
|
},
|
||
|
variant: {
|
||
|
type: String,
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'variant');
|
||
|
}
|
||
|
},
|
||
|
customClass: {
|
||
|
type: String,
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'customClass');
|
||
|
}
|
||
|
},
|
||
|
delay: {
|
||
|
type: [Number, Object, String],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'delay');
|
||
|
}
|
||
|
},
|
||
|
boundary: {
|
||
|
// String: scrollParent, window, or viewport
|
||
|
// Element: element reference
|
||
|
// Object: Vue component
|
||
|
type: [String, HTMLElement, Object],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'boundary');
|
||
|
}
|
||
|
},
|
||
|
boundaryPadding: {
|
||
|
type: [Number, String],
|
||
|
default: function _default() {
|
||
|
return getComponentConfig(NAME, 'boundaryPadding');
|
||
|
}
|
||
|
},
|
||
|
offset: {
|
||
|
type: [Number, String],
|
||
|
default: 0
|
||
|
},
|
||
|
noFade: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
container: {
|
||
|
// String: HTML ID of container, if null body is used (default)
|
||
|
// HTMLElement: element reference reference
|
||
|
// Object: Vue Component
|
||
|
type: [String, HTMLElement, Object] // default: undefined
|
||
|
|
||
|
},
|
||
|
show: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
noninteractive: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
disabled: {
|
||
|
type: Boolean,
|
||
|
default: false
|
||
|
},
|
||
|
id: {
|
||
|
// ID to use for tooltip element
|
||
|
// If not provided on will automatically be generated
|
||
|
type: String,
|
||
|
default: null
|
||
|
}
|
||
|
},
|
||
|
data: function data() {
|
||
|
return {
|
||
|
localShow: this.show,
|
||
|
localTitle: '',
|
||
|
localContent: ''
|
||
|
};
|
||
|
},
|
||
|
computed: {
|
||
|
templateData: function templateData() {
|
||
|
// Data that will be passed to the template and popper
|
||
|
return {
|
||
|
// We use massaged versions of the title and content props/slots
|
||
|
title: this.localTitle,
|
||
|
content: this.localContent,
|
||
|
// Pass these props as is
|
||
|
target: this.target,
|
||
|
triggers: this.triggers,
|
||
|
placement: this.placement,
|
||
|
fallbackPlacement: this.fallbackPlacement,
|
||
|
variant: this.variant,
|
||
|
customClass: this.customClass,
|
||
|
container: this.container,
|
||
|
boundary: this.boundary,
|
||
|
boundaryPadding: this.boundaryPadding,
|
||
|
delay: this.delay,
|
||
|
offset: this.offset,
|
||
|
noFade: this.noFade,
|
||
|
interactive: !this.noninteractive,
|
||
|
disabled: this.disabled,
|
||
|
id: this.id
|
||
|
};
|
||
|
},
|
||
|
templateTitleContent: function templateTitleContent() {
|
||
|
// Used to watch for changes to the title and content props
|
||
|
return {
|
||
|
title: this.title,
|
||
|
content: this.content
|
||
|
};
|
||
|
}
|
||
|
},
|
||
|
watch: {
|
||
|
show: function show(_show, oldVal) {
|
||
|
if (_show !== oldVal && _show !== this.localShow && this.$_bv_toolpop) {
|
||
|
if (_show) {
|
||
|
this.$_bv_toolpop.show();
|
||
|
} else {
|
||
|
// We use `forceHide()` to override any active triggers
|
||
|
this.$_bv_toolpop.forceHide();
|
||
|
}
|
||
|
}
|
||
|
},
|
||
|
disabled: function disabled(newVal) {
|
||
|
if (newVal) {
|
||
|
this.doDisable();
|
||
|
} else {
|
||
|
this.doEnable();
|
||
|
}
|
||
|
},
|
||
|
localShow: function localShow(newVal) {
|
||
|
// TODO: May need to be done in a `$nextTick()`
|
||
|
this.$emit('update:show', newVal);
|
||
|
},
|
||
|
templateData: function templateData() {
|
||
|
var _this = this;
|
||
|
|
||
|
this.$nextTick(function () {
|
||
|
if (_this.$_bv_toolpop) {
|
||
|
_this.$_bv_toolpop.updateData(_this.templateData);
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
// Watchers for title/content props (prop changes do not trigger the `updated()` hook)
|
||
|
templateTitleContent: function templateTitleContent() {
|
||
|
this.$nextTick(this.updateContent);
|
||
|
}
|
||
|
},
|
||
|
created: function created() {
|
||
|
// Non reactive properties
|
||
|
this.$_bv_toolpop = null;
|
||
|
},
|
||
|
updated: function updated() {
|
||
|
// Update the `propData` object
|
||
|
// Done in a `$nextTick()` to ensure slot(s) have updated
|
||
|
this.$nextTick(this.updateContent);
|
||
|
},
|
||
|
beforeDestroy: function beforeDestroy() {
|
||
|
// Shutdown our local event listeners
|
||
|
this.$off('open', this.doOpen);
|
||
|
this.$off('close', this.doClose);
|
||
|
this.$off('disable', this.doDisable);
|
||
|
this.$off('enable', this.doEnable); // Destroy the tip instance
|
||
|
|
||
|
this.$_bv_toolpop && this.$_bv_toolpop.$destroy();
|
||
|
this.$_bv_toolpop = null;
|
||
|
},
|
||
|
mounted: function mounted() {
|
||
|
var _this2 = this;
|
||
|
|
||
|
// Instantiate a new BVTooltip instance
|
||
|
// Done in a `$nextTick()` to ensure DOM has completed rendering
|
||
|
// so that target can be found
|
||
|
this.$nextTick(function () {
|
||
|
// Load the on demand child instance
|
||
|
var Component = _this2.getComponent(); // Ensure we have initial content
|
||
|
|
||
|
|
||
|
_this2.updateContent(); // Pass down the scoped style attribute if available
|
||
|
|
||
|
|
||
|
var scopeId = getScopId(_this2) || getScopId(_this2.$parent); // Create the instance
|
||
|
|
||
|
var $toolpop = _this2.$_bv_toolpop = new Component({
|
||
|
parent: _this2,
|
||
|
// Pass down the scoped style ID
|
||
|
_scopeId: scopeId || undefined
|
||
|
}); // Set the initial data
|
||
|
|
||
|
$toolpop.updateData(_this2.templateData); // Set listeners
|
||
|
|
||
|
$toolpop.$on('show', _this2.onShow);
|
||
|
$toolpop.$on('shown', _this2.onShown);
|
||
|
$toolpop.$on('hide', _this2.onHide);
|
||
|
$toolpop.$on('hidden', _this2.onHidden);
|
||
|
$toolpop.$on('disabled', _this2.onDisabled);
|
||
|
$toolpop.$on('enabled', _this2.onEnabled); // Initially disabled?
|
||
|
|
||
|
if (_this2.disabled) {
|
||
|
// Initially disabled
|
||
|
_this2.doDisable();
|
||
|
} // Listen to open signals from others
|
||
|
|
||
|
|
||
|
_this2.$on('open', _this2.doOpen); // Listen to close signals from others
|
||
|
|
||
|
|
||
|
_this2.$on('close', _this2.doClose); // Listen to disable signals from others
|
||
|
|
||
|
|
||
|
_this2.$on('disable', _this2.doDisable); // Listen to enable signals from others
|
||
|
|
||
|
|
||
|
_this2.$on('enable', _this2.doEnable); // Initially show tooltip?
|
||
|
|
||
|
|
||
|
if (_this2.localShow) {
|
||
|
_this2.$_bv_toolpop && _this2.$_bv_toolpop.show();
|
||
|
}
|
||
|
});
|
||
|
},
|
||
|
methods: {
|
||
|
getComponent: function getComponent() {
|
||
|
// Overridden by BPopover
|
||
|
return BVTooltip;
|
||
|
},
|
||
|
updateContent: function updateContent() {
|
||
|
// Overridden by BPopover
|
||
|
// Tooltip: Default slot is `title`
|
||
|
// Popover: Default slot is `content`, `title` slot is title
|
||
|
// We pass a scoped slot function reference by default (Vue v2.6x)
|
||
|
// And pass the title prop as a fallback
|
||
|
this.setTitle(this.$scopedSlots.default || this.title);
|
||
|
},
|
||
|
// Helper methods for `updateContent()`
|
||
|
setTitle: function setTitle(val) {
|
||
|
val = isUndefinedOrNull(val) ? '' : val; // We only update the value if it has changed
|
||
|
|
||
|
if (this.localTitle !== val) {
|
||
|
this.localTitle = val;
|
||
|
}
|
||
|
},
|
||
|
setContent: function setContent(val) {
|
||
|
val = isUndefinedOrNull(val) ? '' : val; // We only update the value if it has changed
|
||
|
|
||
|
if (this.localContent !== val) {
|
||
|
this.localContent = val;
|
||
|
}
|
||
|
},
|
||
|
// --- Template event handlers ---
|
||
|
onShow: function onShow(bvEvt) {
|
||
|
// Placeholder
|
||
|
this.$emit('show', bvEvt);
|
||
|
|
||
|
if (bvEvt) {
|
||
|
this.localShow = !bvEvt.defaultPrevented;
|
||
|
}
|
||
|
},
|
||
|
onShown: function onShown(bvEvt) {
|
||
|
// Tip is now showing
|
||
|
this.localShow = true;
|
||
|
this.$emit('shown', bvEvt);
|
||
|
},
|
||
|
onHide: function onHide(bvEvt) {
|
||
|
this.$emit('hide', bvEvt);
|
||
|
},
|
||
|
onHidden: function onHidden(bvEvt) {
|
||
|
// Tip is no longer showing
|
||
|
this.$emit('hidden', bvEvt);
|
||
|
this.localShow = false;
|
||
|
},
|
||
|
onDisabled: function onDisabled(bvEvt) {
|
||
|
// Prevent possible endless loop if user mistakenly
|
||
|
// fires `disabled` instead of `disable`
|
||
|
if (bvEvt && bvEvt.type === 'disabled') {
|
||
|
this.$emit('update:disabled', true);
|
||
|
this.$emit('disabled', bvEvt);
|
||
|
}
|
||
|
},
|
||
|
onEnabled: function onEnabled(bvEvt) {
|
||
|
// Prevent possible endless loop if user mistakenly
|
||
|
// fires `enabled` instead of `enable`
|
||
|
if (bvEvt && bvEvt.type === 'enabled') {
|
||
|
this.$emit('update:disabled', false);
|
||
|
this.$emit('enabled', bvEvt);
|
||
|
}
|
||
|
},
|
||
|
// --- Local event listeners ---
|
||
|
doOpen: function doOpen() {
|
||
|
!this.localShow && this.$_bv_toolpop && this.$_bv_toolpop.show();
|
||
|
},
|
||
|
doClose: function doClose() {
|
||
|
this.localShow && this.$_bv_toolpop && this.$_bv_toolpop.hide();
|
||
|
},
|
||
|
doDisable: function doDisable() {
|
||
|
this.$_bv_toolpop && this.$_bv_toolpop.disable();
|
||
|
},
|
||
|
doEnable: function doEnable() {
|
||
|
this.$_bv_toolpop && this.$_bv_toolpop.enable();
|
||
|
}
|
||
|
},
|
||
|
render: function render(h) {
|
||
|
// Always renders a comment node
|
||
|
// TODO:
|
||
|
// Future: Possibly render a target slot (single root element)
|
||
|
// which we can apply the listeners to (pass `this.$el` to BVTooltip)
|
||
|
return h();
|
||
|
}
|
||
|
});
|