@domoinc/multiline-chart
Version:
MultiLineChart - Domo Widget
375 lines (345 loc) • 9.49 kB
JavaScript
if (!window.AutoWidgets) {
var AutoWidgets = {
widgetRegistry: []
};
}
AutoWidgets.baseWidget = function(widget) {
widget.dataName = function(dataName) {
if (!arguments.length) return widget._dataName;
var sampleData = widget.sampleData();
var key;
var temp;
var newName;
var re;
if (widget._dataName && sampleData) {
for (key in sampleData) {
temp = sampleData[key];
delete sampleData[key];
re = new RegExp(widget._dataName);
if (re.test(key)) {
newName = key.replace(re, dataName);
sampleData[newName] = temp;
sampleData[newName].name = newName;
}
}
}
widget._dataName = dataName;
return widget;
};
widget.renderWithData = function(d) {
var data = d[widget.dataName()].data;
widget.draw(data);
return widget;
};
widget.sampleData = function(data) {
if (!arguments.length) return widget._dataSchema;
var key;
for (key in data) {
data[key].data = data[key].defaultValue;
}
widget._dataSchema = data;
// TEMPORARY
// This allows widgets converted to the new platform to continue to work on Mason
if (window.$badge) {
createBadgeData(data);
}
return widget;
};
// Can be overwritten in each widget
widget.prepareForArtboard = function() {
if (widget.base) {
widget.base.selectAll('[id^=chartBounds]')
.remove();
widget.base.insert('rect', ':first-child')
.attr('id', 'chartBounds')
.attr({
height: widget.c('height'),
width: widget.c('width')
})
.style('fill', 'none');
}
};
widget.getWidgetContainer = function() {
return widget.__container;
};
widget.getSVG = function() {
widget.prepareForArtboard();
return serialize(widget.getWidgetContainer());
};
function serialize(node) {
var serializer = new XMLSerializer();
return serializer.serializeToString(node);
}
// TEMPORARY
function createBadgeData(data) {
var key;
for (key in data) {
$badge.data[key] = $badge.DataGrid(key, data[key]);
}
}
return widget;
};
AutoWidgets.findWidgets = function(container) {
var widgets = [];
var widget;
var filters = prepareFilters();
for (var i = 0; i < AutoWidgets.widgetRegistry.length; i++) {
var desc = AutoWidgets.widgetRegistry[i];
container.selectAll("[id^=" + desc[0] + "]")
.each(function() {
d3.select(this).attr('data-domo-link', this.parentNode.id);
widget = desc[1](d3.select(this));
widget.__container = this.parentNode;
addConfig(widget);
addData(widget);
widgets.push(widget);
});
}
document.body.style.visibility = 'visible';
widgets.renderAll = function() {
for (var i = 0; i < widgets.length; i++) {
renderWidget(widgets[i]);
}
window.addEventListener('message', function(event) {
var message = JSON.parse(event.data);
// send acknowledgement to prevent autorefresh
var ack = JSON.stringify({
event: 'ack',
alias: message.alias
});
event.source.postMessage(ack, event.origin);
// inform domo app which alias has been updated
for (var i = 0; i < widgets.length; i++) {
if (widgets[i].sampleData()[message.alias]){
renderWidget(widgets[i]);
break;
}
}
});
};
function renderWidget(widget) {
var key;
var requests = [];
var data = {};
var req;
var sampleData = widget.sampleData();
if (widget._notifier) {
widget._notifier.showMessage(false);
widget._notifier.clearSampleDataMessages();
}
for (key in sampleData) {
(function(k) {
req = new Promise(function(resolve, reject) {
d3.text('data/v1/' + k)
.header('Accept', '*/*')
.get(function(err, value) {
if (err) {
if (widget._notifier) {
// widget._notifier.appendMessage(widget.config('chartName'), 'SAMPLE_DATA', 'Using Sample Data', widget._dataDefs, [widget.sampleData()[k].data]);
}
resolve(widget.sampleData()[k]);
} else {
var dataObj = widget.sampleData()[k];
var data = JSON.parse(value);
dataObj = dataToArrays(data, dataObj);
resolve(dataObj);
}
});
})
.then(function(value) {
data[k] = value;
});
requests.push(req);
})(key);
}
Promise.all(requests)
.then(function() {
widget.renderWithData(applyAllFilters(widget, data));
});
}
function dataToArrays(input, dataObj) {
var data = [];
var columns = dataObj.columnNames;
input.map(function(obj) {
var row = [];
columns.map(function(col) {
if (obj.hasOwnProperty(col)) {
row.push(obj[col]);
} else if (obj.hasOwnProperty(col.replace(/\s/g, ''))) {
row.push(obj[col.replace(/\s/g, '')]);
} else {
row.push('');
}
});
data.push(row);
});
dataObj.data = data;
return dataObj;
}
widgets.previewAll = function() {
for (var i = 0; i < widgets.length; i++) {
var widget = widgets[i];
if (widget._notifier) {
widget._notifier.showMessage(false);
}
// TEMPORARY
if (window.$badge) {
renderWithMasonData(widget);
} else {
widget.renderWithData(applyAllFilters(widget, widget.sampleData()));
}
}
};
function prepareFilters() {
var filters = {};
_.map(AutoWidgets.configs, function(widget, name) {
if (widget.categories.indexOf('Controls') >= 0) {
var widgets = {};
_.map(widget.widgets, function(def, id) {
var w = AutoWidgets.configs[id];
if (w) {
var name = w.config.widgetName.value;
widgets[name] = def;
}
});
if(widget.config) {
filters[widget.config.widgetName.value] = {
value: widget.value || [],
widgets: widgets
};
}
}
});
return filters;
}
// TEMPORARY
function renderWithMasonData(widget) {
var key;
var data = {};
var dataName = widget.dataName();
var sampleData = widget.sampleData();
if (sampleData) {
for (key in sampleData) {
data[key] = {};
data[key].columnNames = $badge.data[key].columnNames;
data[key].data = $badge.data[key].val();
}
} else {
data[dataName] = $badge.data[dataName];
data[dataName].data = data[dataName].val();
}
widget.renderWithData(applyAllFilters(widget, data));
}
function addConfig(widget) {
if (AutoWidgets.configs) {
var config = _.find(AutoWidgets.configs, function(d) {
return d.config && d.config.widgetName.value === widget.dataName();
});
if (config) {
// The configure pane currently uses configs differently than the preview
// or live version, so this check makes them both work properly
if (config.config) {
config = config.config;
}
_.map(config, function(item, key) {
if (widget._config[key]) {
_.extend(widget._config[key], item);
}
});
}
}
}
function addData(widget) {
if (AutoWidgets.configs) {
var config = _.find(AutoWidgets.configs, function(d) {
return d.config && d.config.widgetName.value === widget.dataName();
});
if (config) {
var data = config.data;
var key;
if (data) {
for (key in data) {
data[key].data = data[key].defaultValue;
}
widget.sampleData(data);
}
}
}
}
AutoWidgets.filterChange = function(filterName, value) {
var filter;
var col;
var data;
var filteredData;
if (filters[filterName]) {
filter = filters[filterName];
filter.value = value;
_.map(filter.widgets, function(widget) {
if (widget.widget) {
col = widget.column;
data = widget.data;
filteredData = applyAllFilters(widget.widget, data);
widget.widget.renderWithData(filteredData);
}
});
}
}
function applyAllFilters(widget, data) {
var filteredData = removeNullRows(data);
var widgetName = widget.dataName();
var filterColumns;
var tempFilterColumns;
_.map(filters, function(filter, name) {
if (filter.widgets[widgetName]) {
filterColumns = {};
tempFilterColumns = filter.widgets[widgetName];
_.map(tempFilterColumns, function(ds, dsName) {
if (dsName !== 'widget' && dsName !== 'data') {
filterColumns[widgetName + dsName] = ds;
}
});
filter.widgets[widgetName].widget = widget;
filter.widgets[widgetName].data = data;
filteredData = filterData(filteredData, filterColumns, filter.value);
}
});
return filteredData;
}
function filterData(data, filterColumns, values) {
if (!values || values.length === 0) {
return data;
}
var result = {};
_.map(data, function(source, name) {
result[name] = {};
result[name].columnNames = source.columnNames;
if (filterColumns[name]) {
result[name].data = _.filter(source.data, function(row){
return _.include(values, row[filterColumns[name].column]);
});
} else {
result[name].data = source.data;
}
});
return result;
}
function removeNullRows(data) {
_.map(data, function(source) {
source.data = _.filter(source.data, isNotNullRow);
});
return data;
}
function isNotNullRow(row) {
var isNull = true;
_.map(row, function(cell) {
if (cell !== null && cell !== '') {
isNull = false;
}
});
return !isNull;
}
return widgets;
};
AutoWidgets.register = function(svgName, chartFunction) {
AutoWidgets.widgetRegistry.push([svgName, chartFunction]);
};