diff --git a/superset/assets/backendSync.json b/superset/assets/backendSync.json index ba91b47cde46c..9e1ce4cd893bd 100644 --- a/superset/assets/backendSync.json +++ b/superset/assets/backendSync.json @@ -2214,6 +2214,20 @@ "default": false, "description": "Whether to apply filter when table cell is clicked" }, + "align_pn": { + "type": "CheckboxControl", + "label": "Align +/-", + "renderTrigger": true, + "default": false, + "description": "Whether to align the background chart for +/- values" + }, + "color_pn": { + "type": "CheckboxControl", + "label": "Color +/-", + "renderTrigger": true, + "default": true, + "description": "Whether to color +/- values" + }, "show_bubbles": { "type": "CheckboxControl", "label": "Show Bubbles", @@ -2974,4 +2988,4 @@ "description": "Partitions whose height to parent height proportions are below this value are pruned" } } -} \ No newline at end of file +} diff --git a/superset/assets/javascripts/explore/stores/controls.jsx b/superset/assets/javascripts/explore/stores/controls.jsx index 1a5b554297627..ec4522be884fb 100644 --- a/superset/assets/javascripts/explore/stores/controls.jsx +++ b/superset/assets/javascripts/explore/stores/controls.jsx @@ -1325,6 +1325,22 @@ export const controls = { description: t('Whether to apply filter when table cell is clicked'), }, + align_pn: { + type: 'CheckboxControl', + label: t('Align +/-'), + renderTrigger: true, + default: false, + description: t('Whether to align the background chart for +/- values'), + }, + + color_pn: { + type: 'CheckboxControl', + label: t('Color +/-'), + renderTrigger: true, + default: true, + description: t('Whether to color +/- values'), + }, + show_bubbles: { type: 'CheckboxControl', label: t('Show Bubbles'), diff --git a/superset/assets/javascripts/explore/stores/visTypes.js b/superset/assets/javascripts/explore/stores/visTypes.js index a4ffe4d22e97b..836da7b9cd690 100644 --- a/superset/assets/javascripts/explore/stores/visTypes.js +++ b/superset/assets/javascripts/explore/stores/visTypes.js @@ -770,6 +770,7 @@ export const visTypes = { ['table_timestamp_format'], ['row_limit', 'page_length'], ['include_search', 'table_filter'], + ['align_pn', 'color_pn'], ], }, ], diff --git a/superset/assets/visualizations/table.js b/superset/assets/visualizations/table.js index 6af73ca46505c..d00ba2af80899 100644 --- a/superset/assets/visualizations/table.js +++ b/superset/assets/visualizations/table.js @@ -30,8 +30,14 @@ function tableVis(slice, payload) { return arr; } const maxes = {}; + const mins = {}; for (let i = 0; i < metrics.length; i += 1) { - maxes[metrics[i]] = d3.max(col(metrics[i])); + if (fd.align_pn) { + maxes[metrics[i]] = d3.max(col(metrics[i]).map(Math.abs)); + } else { + maxes[metrics[i]] = d3.max(col(metrics[i])); + mins[metrics[i]] = d3.min(col(metrics[i])); + } } const tsFormatter = d3TimeFormatPreset(fd.table_timestamp_format); @@ -100,12 +106,27 @@ function tableVis(slice, payload) { .append('td') .style('background-image', function (d) { if (d.isMetric) { - const perc = Math.round((d.val / maxes[d.col]) * 100); + const r = (fd.color_pn && d.val < 0) ? 150 : 0; + if (fd.align_pn) { + const perc = Math.abs(Math.round((d.val / maxes[d.col]) * 100)); + // The 0.01 to 0.001 is a workaround for what appears to be a + // CSS rendering bug on flat, transparent colors + return ( + `linear-gradient(to right, rgba(${r},0,0,0.2), rgba(${r},0,0,0.2) ${perc}%, ` + + `rgba(0,0,0,0.01) ${perc}%, rgba(0,0,0,0.001) 100%)` + ); + } + const posExtent = Math.abs(Math.max(maxes[d.col], 0)); + const negExtent = Math.abs(Math.min(mins[d.col], 0)); + const tot = posExtent + negExtent; + const perc1 = Math.round((Math.min(negExtent + d.val, negExtent) / tot) * 100); + const perc2 = Math.round((Math.abs(d.val) / tot) * 100); // The 0.01 to 0.001 is a workaround for what appears to be a // CSS rendering bug on flat, transparent colors return ( - `linear-gradient(to left, rgba(0,0,0,0.2), rgba(0,0,0,0.2) ${perc}%, ` + - `rgba(0,0,0,0.01) ${perc}%, rgba(0,0,0,0.001) 100%)` + `linear-gradient(to right, rgba(0,0,0,0.01), rgba(0,0,0,0.001) ${perc1}%, ` + + `rgba(${r},0,0,0.2) ${perc1}%, rgba(${r},0,0,0.2) ${perc1 + perc2}%, ` + + `rgba(0,0,0,0.01) ${perc1 + perc2}%, rgba(0,0,0,0.001) 100%)` ); } return null;