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.
201 lines
5.2 KiB
201 lines
5.2 KiB
'use strict';
|
|
|
|
var debug = require('debug')('base:templates:layout');
|
|
var utils = require('../utils');
|
|
|
|
module.exports = function(proto) {
|
|
|
|
/**
|
|
* Apply a layout to the given `view`.
|
|
*
|
|
* @name .applyLayout
|
|
* @param {Object} `view`
|
|
* @return {Object} Returns a `view` object.
|
|
*/
|
|
|
|
proto.applyLayout = function(view) {
|
|
debug('applying layout to view "%s"', view.path);
|
|
if (view.options.layoutApplied) {
|
|
return view;
|
|
}
|
|
|
|
// handle pre-layout middleware
|
|
this.handleOnce('preLayout', view);
|
|
|
|
// get the name of the first layout
|
|
var name = this.resolveLayout(view);
|
|
var str = view.content;
|
|
var app = this;
|
|
|
|
var opts = {};
|
|
utils.extend(opts, this.options);
|
|
utils.extend(opts, view.options);
|
|
if (typeof view.context === 'function') {
|
|
utils.extend(opts, view.context());
|
|
}
|
|
|
|
// if no layout is defined, `app.options.layout`
|
|
if (typeof name === 'undefined' && utils.isRenderable(view)) {
|
|
name = this.option('layout');
|
|
}
|
|
|
|
// if still no layout is defined, bail out
|
|
if (utils.isFalsey(name)) {
|
|
return view;
|
|
}
|
|
|
|
// Handle each layout before it's applied to a view
|
|
function handleLayout(obj, stats, depth) {
|
|
var layoutName = obj.layout.basename;
|
|
debug('applied layout (#%d) "%s", to view "%s"', depth, layoutName, view.path);
|
|
|
|
view.currentLayout = obj.layout;
|
|
view.define('layoutStack', stats.history);
|
|
app.handleOnce('onLayout', view);
|
|
delete view.currentLayout;
|
|
}
|
|
|
|
try {
|
|
// build the layout stack
|
|
var stack = buildStack(this, name, view);
|
|
|
|
// actually apply the layout
|
|
var res = utils.layouts(str, name, stack, opts, handleLayout);
|
|
view.enable('layoutApplied');
|
|
view.option('layoutStack', res.history);
|
|
view.contents = new Buffer(res.result);
|
|
|
|
// handle post-layout middleware
|
|
this.handleOnce('postLayout', view);
|
|
} catch (err) {
|
|
if (this.hasListeners('error')) {
|
|
this.emit('error', err);
|
|
} else {
|
|
throw err;
|
|
}
|
|
}
|
|
return view;
|
|
};
|
|
|
|
/**
|
|
* Asynchronously apply a layout to the given `view`.
|
|
*
|
|
* @name .applyLayoutAsync
|
|
* @param {Object} `view`
|
|
* @param {Function} `callback`
|
|
*/
|
|
|
|
proto.applyLayoutAsync = function(view, cb) {
|
|
debug('applying layout to view "%s"', view.path);
|
|
var app = this;
|
|
|
|
if (view.options.layoutApplied) {
|
|
cb(null, view);
|
|
return;
|
|
}
|
|
|
|
// handle pre-layout middleware
|
|
this.handleOnce('preLayout', view, function(err, file) {
|
|
if (err) return cb(err);
|
|
|
|
// get the name of the first layout
|
|
var name = app.resolveLayout(file);
|
|
var str = file.content;
|
|
|
|
var opts = {};
|
|
utils.extend(opts, app.options);
|
|
utils.extend(opts, file.options);
|
|
utils.extend(opts, file.context());
|
|
|
|
// if no layout is defined, `app.options.layout`
|
|
if (typeof name === 'undefined' && utils.isRenderable(file)) {
|
|
name = app.option('layout');
|
|
}
|
|
|
|
// if still no layout is defined, bail out
|
|
if (utils.isFalsey(name)) {
|
|
cb(null, file);
|
|
return;
|
|
}
|
|
|
|
// Handle each layout before it's applied to a file
|
|
function handleLayout(obj, stats, depth) {
|
|
var layoutName = obj.layout.basename;
|
|
debug('applied layout (#%d) "%s", to file "%s"', depth, layoutName, file.path);
|
|
|
|
file.currentLayout = obj.layout;
|
|
file.define('layoutStack', stats.history);
|
|
app.handleOnce('onLayout', file);
|
|
delete file.currentLayout;
|
|
}
|
|
|
|
try {
|
|
|
|
// build the layout stack
|
|
var stack = buildStack(app, name, file);
|
|
|
|
// actually apply the layout
|
|
var res = utils.layouts(str, name, stack, opts, handleLayout);
|
|
file.enable('layoutApplied');
|
|
file.option('layoutStack', res.history);
|
|
file.contents = new Buffer(res.result);
|
|
|
|
} catch (err) {
|
|
if (app.hasListeners('error')) {
|
|
app.emit('error', err);
|
|
}
|
|
cb(err);
|
|
return;
|
|
}
|
|
|
|
// handle post-layout middleware
|
|
app.handleOnce('postLayout', file, cb);
|
|
});
|
|
};
|
|
|
|
/**
|
|
* Get the layout stack by creating an object from all
|
|
* collections with the "layout" `viewType`
|
|
*
|
|
* @param {Object} `app`
|
|
* @param {String} `name` The starting layout name
|
|
* @param {Object} `view`
|
|
* @return {Object} Returns the layout stack.
|
|
*/
|
|
|
|
function buildStack(app, name, view) {
|
|
var layoutExists = false;
|
|
var registered = 0;
|
|
var layouts = {};
|
|
|
|
// get all collections with `viewType` layout
|
|
var collections = app.viewTypes.layout;
|
|
var len = collections.length;
|
|
var idx = -1;
|
|
|
|
while (++idx < len) {
|
|
var collection = app[collections[idx]];
|
|
|
|
// detect if at least one of the collections has
|
|
// our starting layout
|
|
if (!layoutExists && collection.getView(name)) {
|
|
layoutExists = true;
|
|
}
|
|
|
|
// add the collection views to the layouts object
|
|
for (var key in collection.views) {
|
|
layouts[key] = collection.views[key];
|
|
registered++;
|
|
}
|
|
}
|
|
|
|
if (registered === 0) {
|
|
throw app.formatError('layouts', 'registered', name, view);
|
|
}
|
|
|
|
if (layoutExists === false) {
|
|
throw app.formatError('layouts', 'notfound', name, view);
|
|
}
|
|
return layouts;
|
|
}
|
|
};
|
|
|