UNPKG

@domoinc/legend-connector

Version:

LegendConnector - Domo Widget

295 lines (268 loc) 9.2 kB
var defaultWidthRatio = 0.375; var defaultHeightRatio = 0.075; /** * depending on when you merge the legend configs, you can change its order in the ADS */ function getLegendConfigs(daTheme2) { return { showLegend: { name: 'Show Legend', description: 'Show or hide the legend', type: 'select', value: {name: 'Hide', value: false}, options: [ {name: 'Show', value: true}, {name: 'Hide', value: false}, ] }, numberOfLegendItems: { name: 'Number Of Legend Items', description: 'Maximum number of items to display in the legend', type: 'number', value: 6 }, legendWidth: { name: 'Legend Width', description: 'Width of the legend', value: 150, type: 'number', units: 'px' }, legendRowHeight: { name: 'Legend Row Height', description: 'Height of each row in the legend', value: 30, type: 'number', units: 'px' }, legendFontFamily: daTheme2.themeElements.legendFontFamily(), legendFontColor: daTheme2.themeElements.legendFontColor(), legendPosition: { description: 'Position object to position the legend properly when pulling from the artboard' } }; } /** * add or remove legend group and widget * depending on if show legend config is set to true or false */ function initializeLegend(_Chart, Legend, colorScale) { //remove legend if config is set to hide if (!_Chart.c('showLegend').value) { _Chart._layerGroup.select('.legend').remove(); _Chart._legendGroup = undefined; return; } //if the legend group is not there yet, add it if (_Chart._legendGroup === undefined) { _Chart._legendGroup = _Chart._layerGroup.append('g') .classed('legend', true) .attr({ id: 'Legend', 'transform': 'translate(' + _Chart.c('legendPosition').left + ', ' + _Chart.c('legendPosition').top + ')' }); _Chart._legend = new Legend(_Chart._legendGroup); } updateLegend(_Chart, colorScale); } /** * update legend configs */ function updateLegend(_Chart, colorScale) { //set configs for legend _Chart._legend.c({ 'colorScale': colorScale, 'legendWidth': _Chart.c('legendWidth'), 'rowWidth': _Chart.c('legendWidth'), 'rowHeight': _Chart.c('legendRowHeight'), 'numberOfItemsToShow': _Chart.c('numberOfLegendItems'), 'fontFamily': _Chart.c('legendFontFamily'), 'textColor': _Chart.c('legendFontColor'), 'icons': function(container) { container.each(function(d, i) { d3.select(this) .append('rect') .attr({ x: 0, y: 0, height: _Chart.c('legendRowHeight')/2, width: _Chart.c('legendRowHeight')/2 }); }); return container; } }) } /** * get the series from the data and * pass that data into draw legend */ function drawLegend(_Chart, data, seriesAccessor) { if (_Chart.c('showLegend').value) { var legendData = []; var set = d3.set(); data.forEach(function(line) { set.add(seriesAccessor(line)); }); var values = set.values(); for (var i = 0; i < values.length; i++) { legendData.push([values[i]]); } _Chart._legend.draw(legendData); } } /** * get an object for legend position comparable to getBoundingClientRect * if there is no legend chartbounds, then create a default legend group * * the legend width and height in the config page are set by the legend width and height configs * the legend width and height when pulling from artboard are set by the chartbounds of the legend on the artboard */ function getLegendPosition(container) { if (container.selectAll('[id^=legendChartBounds]').node()) { var widgetClient = container.select('[id^=chartBounds]') .node() .getBoundingClientRect(); var legendClient = container.selectAll('[id^=legendChartBounds]') .node() .getBoundingClientRect(); //make an object copy of the clientRect so it is mutable var legendClientClone = {}; for (var key in legendClient) { legendClientClone[key] = legendClient[key]; } // The legend position must be countertranslated by the left or top of the widgets chartbounds to be placed correctly // If this is removed, adding the legend to the left or top of the widget and pulling it from artboard will place the legend at left = 0 or top = 0 legendClientClone.top -= widgetClient.top; legendClientClone.left -= widgetClient.left; return legendClientClone; } return; } /** * legendPosition is undefined if no legendChartBounds existed * create a default legend position object if undefinied */ function setLegendPosition(widget, legendPosition) { if (legendPosition) { widget.c('legendPosition', legendPosition); } else { var legendHeight = widget.c('legendRowHeight') * widget.c('numberOfLegendItems'); var defaultLegendPosition = { width: 0, height: 0, left: widget.c('width') + widget.c('width')*0.2, //widget.c('width')*0.2 is padding between the widget and legend top: widget.c('height')/2 - legendHeight/2 }; widget.c({ legendPosition: defaultLegendPosition, legendWidth: widget.c('width')*defaultWidthRatio, legendRowHeight: widget.c('height')*defaultHeightRatio, //default the new legend width and height to these ratios }) } } /** * add chartbounds for the widget * if add legend config is set to true, add legendchartbounds as well */ function prepareForArtboard(widget, seriesAccessor) { return function() { if (widget.base) { widget.base.selectAll('[id^=chartBounds]').remove(); widget.base.insert('rect', ':first-child') .attr({ id: 'chartBounds', height: widget.c('height'), width: widget.c('width'), }) .style('fill', 'none'); if (widget.c('showLegend').value) { var numRows = getNumRows(widget, seriesAccessor); var legendWidth = widget.c('legendWidth'); var legendHeight = numRows * widget.c('legendRowHeight'); widget.base.selectAll('[id^=legendChartBounds]').remove(); widget.base.select('[id^=Legend]') .insert('rect', ':first-child') .attr({ id: 'legendChartBounds', width: legendWidth, height: legendHeight, }) .style('fill', 'none'); } } } } /** * check to see if widget is being pulled from artboard * if it is, update the legend configs via the configs stored in AutoWidgets * updating via widgets.c() will not work in ADS if value is changed on artboard */ function pullFromArtboard(AutoWidgets, widget, seriesAccessor) { for (var key in AutoWidgets.configs) { if (AutoWidgets.configs[key].config && AutoWidgets.configs[key].config.widgetName.value === widget.dataName()) { var config = AutoWidgets.configs[key].config; //update number of legend items to get the right number of rows widget.c('numberOfLegendItems', config.numberOfLegendItems.value); var numRows = getNumRows(widget, seriesAccessor); //update legend dimensions //if legend dimensions are 0 or legend chartbounds are deleted, will change value to default legend dimensions var legendPosition = widget.c('legendPosition'); config.legendWidth.value = legendPosition.width ? legendPosition.width : widget.c('width')*defaultWidthRatio; config.legendRowHeight.value = legendPosition.height ? legendPosition.height / numRows : widget.c('height')*defaultHeightRatio; } } } /** * calculate the number of rows to display * it will be the lesser of the number of series * or the legend config, numberOfLegendItems */ function getNumRows(widget, seriesAccessor) { //get unique series var dataSchema = widget._dataSchema; var set = d3.set(); for (var key in dataSchema) { dataSchema[key].data.forEach(function(line) { set.add(seriesAccessor(line)); }); } var seriesLength = set.values().length; //calculate number of rows to show var maxNumLegendRows = widget.c('numberOfLegendItems'); var numRows = d3.min([seriesLength, maxNumLegendRows]); return numRows; } // screenshot the legend seperate from the rest of the widget function rasterizeNodes(widget) { return function() { var nodes = []; var children = widget._layerGroup.node().childNodes; for (var i = 0; i < children.length; i++) { var node = children[i]; if (node.classList && node.classList.contains('legend')) { nodes.push({ node: node.querySelector('.layer-group') }); } else { nodes.push({ node: node }); } } return nodes; }; } module.exports = { //Widget.js functions getLegendConfigs: getLegendConfigs, initializeLegend: initializeLegend, drawLegend: drawLegend, //DomoWidget.js functions getLegendPosition: getLegendPosition, setLegendPosition: setLegendPosition, prepareForArtboard: prepareForArtboard, pullFromArtboard: pullFromArtboard, rasterizeNodes: rasterizeNodes }