From 3aee0ec7cb63a4ebcb1fe602de73f82eb4deac3f Mon Sep 17 00:00:00 2001
From: Tom Robinson <tlrobinson@gmail.com>
Date: Fri, 19 May 2017 16:22:29 -0700
Subject: [PATCH] Highlight selected dots

---
 .../components/LineAreaBarChart.css           | 17 +++++--
 .../visualizations/lib/LineAreaBarRenderer.js | 19 ++++----
 .../visualizations/lib/graph/addons.js        | 48 +++++++++++++++++++
 3 files changed, 71 insertions(+), 13 deletions(-)
 create mode 100644 frontend/src/metabase/visualizations/lib/graph/addons.js

diff --git a/frontend/src/metabase/visualizations/components/LineAreaBarChart.css b/frontend/src/metabase/visualizations/components/LineAreaBarChart.css
index fd039c40c2a..8f2abd39f5d 100644
--- a/frontend/src/metabase/visualizations/components/LineAreaBarChart.css
+++ b/frontend/src/metabase/visualizations/components/LineAreaBarChart.css
@@ -84,7 +84,7 @@
   opacity: 1 !important;
 }
 
-.LineAreaBarChart .dc-chart .enable-dots .dc-tooltip circle.dot {
+.LineAreaBarChart .dc-chart .enable-dots .dc-tooltip .dot {
   r: 3px !important;
   fill: white;
   stroke: currentColor;
@@ -99,13 +99,14 @@
     stroke: white;
 }
 
-.LineAreaBarChart .dc-chart .enable-dots .dc-tooltip circle.dot:hover,
-.LineAreaBarChart .dc-chart .enable-dots .dc-tooltip circle.dot.hover {
+.LineAreaBarChart .dc-chart .enable-dots .dc-tooltip .dot:hover,
+.LineAreaBarChart .dc-chart .enable-dots .dc-tooltip .dot.hover {
   fill: currentColor;
 }
 
-.LineAreaBarChart .dc-chart .enable-dots-onhover .dc-tooltip circle.dot:hover,
-.LineAreaBarChart .dc-chart .enable-dots-onhover .dc-tooltip circle.dot.hover {
+.LineAreaBarChart .dc-chart .dc-tooltip .dot.selected,
+.LineAreaBarChart .dc-chart .enable-dots-onhover .dc-tooltip .dot:hover,
+.LineAreaBarChart .dc-chart .enable-dots-onhover .dc-tooltip .dot.hover {
   r: 3px !important;
   fill: white;
   stroke: currentColor;
@@ -113,6 +114,12 @@
   fill-opacity: 1 !important;
   stroke-opacity: 1 !important;
 }
+.LineAreaBarChart .dc-chart .dc-tooltip .dot.deselected {
+  opacity: 0;
+}
+.LineAreaBarChart .dc-chart .line.deselected {
+  color: #ccc;
+}
 
 .LineAreaBarChart .dc-chart .area,
 .LineAreaBarChart .dc-chart .bar,
diff --git a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
index caf7ab01f25..e2a79ed02dc 100644
--- a/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
+++ b/frontend/src/metabase/visualizations/lib/LineAreaBarRenderer.js
@@ -87,13 +87,15 @@ function adjustTicksIfNeeded(axis, axisSize: number, minPixelsPerTick: number) {
     }
 }
 
-function getDcjsChartType(cardType) {
+import { lineAddons } from "./graph/addons"
+
+function getDcjsChart(cardType, parent) {
     switch (cardType) {
-        case "line": return "lineChart";
-        case "area": return "lineChart";
-        case "bar":     return "barChart";
-        case "scatter": return "bubbleChart";
-        default:     return "barChart";
+        case "line":    return lineAddons(dc.lineChart(parent));
+        case "area":    return lineAddons(dc.lineChart(parent));
+        case "bar":     return dc.barChart(parent);
+        case "scatter": return dc.bubbleChart(parent);
+        default:        return dc.barChart(parent);
     }
 }
 
@@ -453,7 +455,8 @@ function applyChartTooltips(chart, series, isStacked, isScalarSeries, onHoverCha
                 }
             }
 
-            chart.selectAll(".dot, .area, .bubble")
+            // for some reason interaction with brush requires we use click for .dot and .bubble but mousedown for bar
+            chart.selectAll(".dot, .bubble")
                 .style({ "cursor": "pointer" })
                 .on("click", onClick);
             chart.selectAll(".bar")
@@ -1066,7 +1069,7 @@ export default function lineAreaBar(element, {
     }
 
     let charts = groups.map((group, index) => {
-        let chart = dc[getDcjsChartType(chartType)](parent);
+        let chart = getDcjsChart(chartType, parent);
 
         if (onChangeCardAndRun) {
             initBrush(parent, chart, onBrushChange, onBrushEnd);
diff --git a/frontend/src/metabase/visualizations/lib/graph/addons.js b/frontend/src/metabase/visualizations/lib/graph/addons.js
new file mode 100644
index 00000000000..93a149bc9a5
--- /dev/null
+++ b/frontend/src/metabase/visualizations/lib/graph/addons.js
@@ -0,0 +1,48 @@
+/* @flow weak */
+
+import dc from "dc";
+import moment from "moment";
+
+export const lineAddons = _chart => {
+    _chart.fadeDeselectedArea = function() {
+        var dots = _chart.chartBodyG().selectAll(".dot");
+        var extent = _chart.brush().extent();
+
+        if (_chart.isOrdinal()) {
+            if (_chart.hasFilter()) {
+                dots.classed(dc.constants.SELECTED_CLASS, function(d) {
+                    return _chart.hasFilter(d.x);
+                });
+                dots.classed(dc.constants.DESELECTED_CLASS, function(d) {
+                    return !_chart.hasFilter(d.x);
+                });
+            } else {
+                dots.classed(dc.constants.SELECTED_CLASS, false);
+                dots.classed(dc.constants.DESELECTED_CLASS, false);
+            }
+        } else {
+            if (!_chart.brushIsEmpty(extent)) {
+                var start = extent[0];
+                var end = extent[1];
+                const isSelected = d => {
+                    if (moment.isDate(start)) {
+                        return !(moment(d.x).isBefore(start) ||
+                            moment(d.x).isAfter(end));
+                    } else {
+                        return !(d.x < start || d.x >= end);
+                    }
+                };
+                dots.classed(
+                    dc.constants.DESELECTED_CLASS,
+                    d => !isSelected(d)
+                );
+                dots.classed(dc.constants.SELECTED_CLASS, d => isSelected(d));
+            } else {
+                dots.classed(dc.constants.DESELECTED_CLASS, false);
+                dots.classed(dc.constants.SELECTED_CLASS, false);
+            }
+        }
+    };
+
+    return _chart;
+};
-- 
GitLab