cartodb/lib/assets/javascripts/deep-insights/api/create-dashboard.js
2020-06-15 10:58:47 +08:00

176 lines
5.7 KiB
JavaScript

var _ = require('underscore');
var cdb = require('internal-carto.js');
var Dashboard = require('deep-insights/api/dashboard.js');
var DashboardView = require('deep-insights/dashboard-view');
var WidgetsCollection = require('deep-insights/widgets/widgets-collection');
var WidgetsService = require('deep-insights/widgets-service');
var URLHelper = require('deep-insights/api/url-helper');
/**
* Translates a vizJSON v3 datastructure into a working dashboard which will be rendered in given selector.
*
* @param {String} selector e.g. "#foobar-id", ".some-class"
* @param {Object} vizJSON JSON datastructure
* @param {Object} opts (Optional) flags, see 3rd param for cdb.createVis for available ones. Keys used here:
* renderMenu: {Boolean} If true (default), render a top-level menu on the left side.
* @return {Object} with keys:
* dashboardView: root (backbone) view of the dashboard
* vis: the instantiated vis map, same result as given from cdb.createVis()
*/
var createDashboard = function (selector, vizJSON, opts, callback) {
var dashboardEl = document.querySelector(selector);
if (!dashboardEl) throw new Error('no element found with selector ' + selector);
// Default options
opts = opts || {};
opts.renderMenu = _.isBoolean(opts.renderMenu)
? opts.renderMenu
: true;
opts.autoStyle = _.isBoolean(opts.autoStyle)
? opts.autoStyle
: false;
var widgets = new WidgetsCollection();
var model = new cdb.core.Model({
title: vizJSON.title,
description: vizJSON.description,
updatedAt: vizJSON.updated_at,
userName: vizJSON.user.fullname,
userProfileURL: vizJSON.user.profile_url,
userAvatarURL: vizJSON.user.avatar_url,
renderMenu: opts.renderMenu,
autoStyle: opts.autoStyle,
showLogo: opts.cartodb_logo,
initialPosition: {
bounds: vizJSON.bounds
}
});
var dashboardView = new DashboardView({
el: dashboardEl,
widgets: widgets,
model: model
});
var dashboardState = opts.state || URLHelper.getStateFromCurrentURL();
if (dashboardState && !_.isEmpty(dashboardState.map)) {
if (_.isArray(dashboardState.map.center)) {
vizJSON.center = dashboardState.map.center;
}
if (_.isNumber(dashboardState.map.zoom)) {
vizJSON.zoom = dashboardState.map.zoom;
}
if (dashboardState.map.ne && dashboardState.map.sw) {
vizJSON.bounds = [dashboardState.map.ne, dashboardState.map.sw];
}
}
var vis = cdb.createVis(dashboardView.$('#map'), vizJSON, _.extend(opts, {
skipMapInstantiation: true
}));
vis.once('load', function (vis) {
var widgetsState = (dashboardState && dashboardState.widgets) || {};
// Create widgets
var widgetsService = new WidgetsService(widgets, vis.dataviews);
var widgetModelsMap = {
formula: widgetsService.createFormulaModel.bind(widgetsService),
histogram: widgetsService.createHistogramModel.bind(widgetsService),
'time-series': widgetsService.createTimeSeriesModel.bind(widgetsService),
category: widgetsService.createCategoryModel.bind(widgetsService)
};
vizJSON.widgets.forEach(function (widget) {
// Flatten the data structure given in vizJSON, the widgetsService will use whatever it needs and ignore the rest
var attrs = _.extend({}, widget, widget.options);
var newWidgetModel = widgetModelsMap[widget.type];
var state = widgetsState[widget.id];
if (_.isFunction(newWidgetModel)) {
// Find the Layer that the Widget should be created for.
var layer;
var source;
if (widget.layer_id) {
layer = vis.map.layers.get(widget.layer_id);
} else if (Number.isInteger(widget.layerIndex)) {
// TODO Since namedmap doesn't have ids we need to map in another way, here using index
// should we solve this in another way?
layer = vis.map.layers.at(widget.layerIndex);
}
if (widget.source && widget.source.id) {
source = vis.analysis.findNodeById(widget.source.id);
attrs.source = source;
}
newWidgetModel(attrs, layer, state);
} else {
cdb.log.error('No widget found for type ' + widget.type);
}
});
dashboardView.render();
var callbackObj = {
dashboardView: dashboardView,
widgets: widgetsService,
areWidgetsInitialised: function () {
var widgetsCollection = widgetsService.getCollection();
if (widgetsCollection.size() > 0) {
return widgetsCollection.hasInitialState();
}
return true;
},
vis: vis
};
vis.instantiateMap({
success: function () {
callback && callback(null, callbackObj);
},
error: function (errorMessage) {
callback && callback(new Error(errorMessage), callbackObj);
}
});
});
};
module.exports = function (selector, vizJSON, opts, callback) {
var args = arguments;
var fn = args[args.length - 1];
if (_.isFunction(fn)) {
callback = fn;
}
function _load (vizJSON) {
createDashboard(selector, vizJSON, opts, function (error, dashboard) {
var _dashboard = new Dashboard(dashboard);
if (opts.share_urls) {
_dashboard.onStateChanged(
_.debounce(
function (state, url) {
window.history.replaceState('Object', 'Title', url);
},
500
)
);
}
callback && callback(error, _dashboard);
});
}
if (typeof vizJSON === 'string') {
cdb.core.Loader.get(vizJSON, function (data) {
if (data) {
_load(data, opts);
} else {
callback && callback(new Error('Error fetching viz.json file: ' + vizJSON));
}
});
} else {
_load(vizJSON, opts);
}
};