You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@druid.apache.org by fj...@apache.org on 2019/07/31 05:35:43 UTC

[incubator-druid] branch master updated: Web console: segment timeline (#8202)

This is an automated email from the ASF dual-hosted git repository.

fjy pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 645fca5  Web console: segment timeline (#8202)
645fca5 is described below

commit 645fca53d8f76e12d6e0fe390c89046d86d9a7e6
Author: Vadim Ogievetsky <va...@gmail.com>
AuthorDate: Tue Jul 30 22:35:30 2019 -0700

    Web console: segment timeline (#8202)
    
    * Add segment timeline chart
    
    * fix file
    
    * Fix bugs: no data handling & scaling problems
    
    * resolve conflict
    
    * changed package-lock
    
    * do not show by default
    
    * trust the interop
    
    * stricter type fixes
    
    * fix sasslint
---
 web-console/package-lock.json                      | 768 +++++++++++++++++++--
 web-console/package.json                           |   2 +
 web-console/src/components/index.ts                |   1 +
 .../segment-timeline/segment-timeline.scss}        |  43 +-
 .../segment-timeline/segment-timeline.tsx          | 496 +++++++++++++
 .../__snapshots__/datasource-view.spec.tsx.snap    |   7 +-
 .../src/views/datasource-view/datasource-view.scss |  12 +-
 .../src/views/datasource-view/datasource-view.tsx  |  48 +-
 web-console/src/visualization/bar-group.tsx        |  90 +++
 .../bar-unit.scss}                                 |  18 +-
 web-console/src/visualization/bar-unit.tsx         |  55 ++
 .../chart-axis.tsx}                                |  33 +-
 .../stacked-bar-chart.scss}                        |  24 +-
 .../src/visualization/stacked-bar-chart.tsx        | 172 +++++
 14 files changed, 1647 insertions(+), 122 deletions(-)

diff --git a/web-console/package-lock.json b/web-console/package-lock.json
index a93be6d..689c610 100644
--- a/web-console/package-lock.json
+++ b/web-console/package-lock.json
@@ -1439,12 +1439,274 @@
       "integrity": "sha512-MNl+rT5UmZeilaPxAVs6YaPC2m6aA8rofviZbhbxpPpl61uKodfdQVsBtgJGTqGizEf02oW3tsVe7FYB8kK14A==",
       "dev": true
     },
+    "@types/d3": {
+      "version": "5.7.2",
+      "resolved": "https://registry.npmjs.org/@types/d3/-/d3-5.7.2.tgz",
+      "integrity": "sha512-7/wClB8ycneWGy3jdvLfXKTd5SoTg9hji7IdJ0RuO9xTY54YpJ8zlcFADcXhY1J3kCBwxp+/1jeN6a5OMwgYOw==",
+      "dev": true,
+      "requires": {
+        "@types/d3-array": "^1",
+        "@types/d3-axis": "*",
+        "@types/d3-brush": "*",
+        "@types/d3-chord": "*",
+        "@types/d3-collection": "*",
+        "@types/d3-color": "*",
+        "@types/d3-contour": "*",
+        "@types/d3-dispatch": "*",
+        "@types/d3-drag": "*",
+        "@types/d3-dsv": "*",
+        "@types/d3-ease": "*",
+        "@types/d3-fetch": "*",
+        "@types/d3-force": "*",
+        "@types/d3-format": "*",
+        "@types/d3-geo": "*",
+        "@types/d3-hierarchy": "*",
+        "@types/d3-interpolate": "*",
+        "@types/d3-path": "*",
+        "@types/d3-polygon": "*",
+        "@types/d3-quadtree": "*",
+        "@types/d3-random": "*",
+        "@types/d3-scale": "*",
+        "@types/d3-scale-chromatic": "*",
+        "@types/d3-selection": "*",
+        "@types/d3-shape": "*",
+        "@types/d3-time": "*",
+        "@types/d3-time-format": "*",
+        "@types/d3-timer": "*",
+        "@types/d3-transition": "*",
+        "@types/d3-voronoi": "*",
+        "@types/d3-zoom": "*"
+      },
+      "dependencies": {
+        "@types/d3-array": {
+          "version": "1.2.7",
+          "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-1.2.7.tgz",
+          "integrity": "sha512-51vHWuUyDOi+8XuwPrTw3cFqyh2Slg9y8COYkRfjCPG9TfYqY0hoNPzv/8BrcAy0FeQBzqEo/D/8Nk2caOQJnA==",
+          "dev": true
+        }
+      }
+    },
     "@types/d3-array": {
       "version": "2.0.0",
       "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-2.0.0.tgz",
       "integrity": "sha512-rGqfPVowNDTszSFvwoZIXvrPG7s/qKzm9piCRIH6xwTTRu7pPZ3ootULFnPkTt74B6i5lN0FpLQL24qGOw1uZA==",
       "dev": true
     },
+    "@types/d3-axis": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/@types/d3-axis/-/d3-axis-1.0.12.tgz",
+      "integrity": "sha512-BZISgSD5M8TgURyNtcPAmUB9sk490CO1Thb6/gIn0WZTt3Y50IssX+2Z0vTccoqZksUDTep0b+o4ofXslvNbqg==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-brush": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/@types/d3-brush/-/d3-brush-1.0.10.tgz",
+      "integrity": "sha512-J8jREATIrfJaAfhJivqaEKPnJsRlwwrOPje+ABqZFgamADjll+q9zaDXnYyjiGPPsiJEU+Qq9jQi5rECxIOfhg==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-chord": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/@types/d3-chord/-/d3-chord-1.0.9.tgz",
+      "integrity": "sha512-UA6lI9CVW5cT5Ku/RV4hxoFn4mKySHm7HEgodtfRthAj1lt9rKZEPon58vyYfk+HIAm33DtJJgZwMXy2QgyPXw==",
+      "dev": true
+    },
+    "@types/d3-collection": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-collection/-/d3-collection-1.0.8.tgz",
+      "integrity": "sha512-y5lGlazdc0HNO0F3UUX2DPE7OmYvd9Kcym4hXwrJcNUkDaypR5pX+apuMikl9LfTxKItJsY9KYvzBulpCKyvuQ==",
+      "dev": true
+    },
+    "@types/d3-color": {
+      "version": "1.2.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-1.2.2.tgz",
+      "integrity": "sha512-6pBxzJ8ZP3dYEQ4YjQ+NVbQaOflfgXq/JbDiS99oLobM2o72uAST4q6yPxHv6FOTCRC/n35ktuo8pvw/S4M7sw==",
+      "dev": true
+    },
+    "@types/d3-contour": {
+      "version": "1.3.0",
+      "resolved": "https://registry.npmjs.org/@types/d3-contour/-/d3-contour-1.3.0.tgz",
+      "integrity": "sha512-AUCUIjEnC5lCGBM9hS+MryRaFLIrPls4Rbv6ktqbd+TK/RXZPwOy9rtBWmGpbeXcSOYCJTUDwNJuEnmYPJRxHQ==",
+      "dev": true,
+      "requires": {
+        "@types/d3-array": "*",
+        "@types/geojson": "*"
+      }
+    },
+    "@types/d3-dispatch": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-dispatch/-/d3-dispatch-1.0.7.tgz",
+      "integrity": "sha512-M+z84G7UKwK6hEPnGCSccOg8zJ3Nk2hgDQ9sCstHXgsFU0sMxlIZVKqKB5oxUDbALqQG6ucg0G9e8cmOSlishg==",
+      "dev": true
+    },
+    "@types/d3-drag": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/@types/d3-drag/-/d3-drag-1.2.3.tgz",
+      "integrity": "sha512-rWB5SPvkYVxW3sqUxHOJUZwifD0KqvKwvt1bhNqcLpW6Azsd0BJgRNcyVW8GAferaAk5r8dzeZnf9zKlg9+xMQ==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-dsv": {
+      "version": "1.0.36",
+      "resolved": "https://registry.npmjs.org/@types/d3-dsv/-/d3-dsv-1.0.36.tgz",
+      "integrity": "sha512-jbIWQ27QJcBNMZbQv0NSQMHnBDCmxghAxePxgyiPH1XPCRkOsTBei7jcdi3fDrUCGpCV3lKrSZFSlOkhUQVClA==",
+      "dev": true
+    },
+    "@types/d3-ease": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-ease/-/d3-ease-1.0.8.tgz",
+      "integrity": "sha512-VRf8czVWHSJPoUWxMunzpePK02//wHDAswknU8QWzcyrQn6pqe46bHRYi2smSpw5VjsT2CG8k/QeWIdWPS3Bmg==",
+      "dev": true
+    },
+    "@types/d3-fetch": {
+      "version": "1.1.5",
+      "resolved": "https://registry.npmjs.org/@types/d3-fetch/-/d3-fetch-1.1.5.tgz",
+      "integrity": "sha512-o9c0ItT5/Gl3wbNuVpzRnYX1t3RghzeWAjHUVLuyZJudiTxC4f/fC0ZPFWLQ2lVY8pAMmxpV8TJ6ETYCgPeI3A==",
+      "dev": true,
+      "requires": {
+        "@types/d3-dsv": "*"
+      }
+    },
+    "@types/d3-force": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-force/-/d3-force-1.2.1.tgz",
+      "integrity": "sha512-jqK+I36uz4kTBjyk39meed5y31Ab+tXYN/x1dn3nZEus9yOHCLc+VrcIYLc/aSQ0Y7tMPRlIhLetulME76EiiA==",
+      "dev": true
+    },
+    "@types/d3-format": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-1.3.1.tgz",
+      "integrity": "sha512-KAWvReOKMDreaAwOjdfQMm0HjcUMlQG47GwqdVKgmm20vTd2pucj0a70c3gUSHrnsmo6H2AMrkBsZU2UhJLq8A==",
+      "dev": true
+    },
+    "@types/d3-geo": {
+      "version": "1.11.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-1.11.1.tgz",
+      "integrity": "sha512-Ox8WWOG3igDRoep/dNsGbOiSJYdUG3ew/6z0ETvHyAtXZVBjOE0S96zSSmzgl0gqQ3RdZjn2eeJOj9oRcMZPkQ==",
+      "dev": true,
+      "requires": {
+        "@types/geojson": "*"
+      }
+    },
+    "@types/d3-hierarchy": {
+      "version": "1.1.6",
+      "resolved": "https://registry.npmjs.org/@types/d3-hierarchy/-/d3-hierarchy-1.1.6.tgz",
+      "integrity": "sha512-vvSaIDf/Ov0o3KwMT+1M8+WbnnlRiGjlGD5uvk83a1mPCTd/E5x12bUJ/oP55+wUY/4Kb5kc67rVpVGJ2KUHxg==",
+      "dev": true
+    },
+    "@types/d3-interpolate": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-1.3.1.tgz",
+      "integrity": "sha512-z8Zmi08XVwe8e62vP6wcA+CNuRhpuUU5XPEfqpG0hRypDE5BWNthQHB1UNWWDB7ojCbGaN4qBdsWp5kWxhT1IQ==",
+      "dev": true,
+      "requires": {
+        "@types/d3-color": "*"
+      }
+    },
+    "@types/d3-path": {
+      "version": "1.0.8",
+      "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-1.0.8.tgz",
+      "integrity": "sha512-AZGHWslq/oApTAHu9+yH/Bnk63y9oFOMROtqPAtxl5uB6qm1x2lueWdVEjsjjV3Qc2+QfuzKIwIR5MvVBakfzA==",
+      "dev": true
+    },
+    "@types/d3-polygon": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-polygon/-/d3-polygon-1.0.7.tgz",
+      "integrity": "sha512-Xuw0eSjQQKs8jTiNbntWH0S+Xp+JyhqxmQ0YAQ3rDu6c3kKMFfgsaGN7Jv5u3zG6yVX/AsLP/Xs/QRjmi9g43Q==",
+      "dev": true
+    },
+    "@types/d3-quadtree": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/@types/d3-quadtree/-/d3-quadtree-1.0.7.tgz",
+      "integrity": "sha512-0ajFawWicfjsaCLh6NzxOyVDYhQAmMFbsiI3MPGLInorauHFEh9/Cl6UHNf+kt/J1jfoxKY/ZJaKAoDpbvde5Q==",
+      "dev": true
+    },
+    "@types/d3-random": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/@types/d3-random/-/d3-random-1.1.2.tgz",
+      "integrity": "sha512-Jui+Zn28pQw/3EayPKaN4c/PqTvqNbIPjHkgIIFnxne1FdwNjfHtAIsZIBMKlquQNrrMjFzCrlF2gPs3xckqaA==",
+      "dev": true
+    },
+    "@types/d3-scale": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-2.1.1.tgz",
+      "integrity": "sha512-kNTkbZQ+N/Ip8oX9PByXfDLoCSaZYm+VUOasbmsa6KD850/ziMdYepg/8kLg2plHzoLANdMqPoYQbvExevLUHg==",
+      "dev": true,
+      "requires": {
+        "@types/d3-time": "*"
+      }
+    },
+    "@types/d3-scale-chromatic": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-scale-chromatic/-/d3-scale-chromatic-1.3.1.tgz",
+      "integrity": "sha512-Ny3rLbV5tnmqgW7w/poCcef4kXP8mHPo/p8EjTS5d9OUk8MlqAeRaM8eF7Vyv7QMLiIXNE94Pa1cMLSPkXQBoQ==",
+      "dev": true
+    },
+    "@types/d3-selection": {
+      "version": "1.4.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-selection/-/d3-selection-1.4.1.tgz",
+      "integrity": "sha512-bv8IfFYo/xG6dxri9OwDnK3yCagYPeRIjTlrcdYJSx+FDWlCeBDepIHUpqROmhPtZ53jyna0aUajZRk0I3rXNA==",
+      "dev": true
+    },
+    "@types/d3-shape": {
+      "version": "1.3.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-1.3.1.tgz",
+      "integrity": "sha512-usqdvUvPJ7AJNwpd2drOzRKs1ELie53p2m2GnPKr076/ADM579jVTJ5dPsoZ5E/CMNWk8lvPWYQSvilpp6jjwg==",
+      "dev": true,
+      "requires": {
+        "@types/d3-path": "*"
+      }
+    },
+    "@types/d3-time": {
+      "version": "1.0.10",
+      "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-1.0.10.tgz",
+      "integrity": "sha512-aKf62rRQafDQmSiv1NylKhIMmznsjRN+MnXRXTqHoqm0U/UZzVpdrtRnSIfdiLS616OuC1soYeX1dBg2n1u8Xw==",
+      "dev": true
+    },
+    "@types/d3-time-format": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.1.tgz",
+      "integrity": "sha512-tJSyXta8ZyJ52wDDHA96JEsvkbL6jl7wowGmuf45+fAkj5Y+SQOnz0N7/H68OWmPshPsAaWMQh+GAws44IzH3g==",
+      "dev": true
+    },
+    "@types/d3-timer": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/@types/d3-timer/-/d3-timer-1.0.9.tgz",
+      "integrity": "sha512-WvfJ3LFxBbWjqRGz9n7GJt08RrTHPJDVsIwwoCMROlqF+iDacYiAFjf9oqnq0mXpb2juA2N/qjKP+MKdal3YNQ==",
+      "dev": true
+    },
+    "@types/d3-transition": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/@types/d3-transition/-/d3-transition-1.1.4.tgz",
+      "integrity": "sha512-/vsmKVUIXEyCcIXYAlw7bnYkIs9/J/nZbptRJFKUN3FdXq/dF6j9z9xXzerkyU6TDHLrMrwx9eGwdKyTIy/j9w==",
+      "dev": true,
+      "requires": {
+        "@types/d3-selection": "*"
+      }
+    },
+    "@types/d3-voronoi": {
+      "version": "1.1.9",
+      "resolved": "https://registry.npmjs.org/@types/d3-voronoi/-/d3-voronoi-1.1.9.tgz",
+      "integrity": "sha512-DExNQkaHd1F3dFPvGA/Aw2NGyjMln6E9QzsiqOcBgnE+VInYnFBHBBySbZQts6z6xD+5jTfKCP7M4OqMyVjdwQ==",
+      "dev": true
+    },
+    "@types/d3-zoom": {
+      "version": "1.7.4",
+      "resolved": "https://registry.npmjs.org/@types/d3-zoom/-/d3-zoom-1.7.4.tgz",
+      "integrity": "sha512-5jnFo/itYhJeB2khO/lKe730kW/h2EbKMOvY0uNp3+7NdPm4w63DwPEMxifQZ7n902xGYK5DdU67FmToSoy4VA==",
+      "dev": true,
+      "requires": {
+        "@types/d3-interpolate": "*",
+        "@types/d3-selection": "*"
+      }
+    },
     "@types/dom4": {
       "version": "2.0.1",
       "resolved": "https://registry.npmjs.org/@types/dom4/-/dom4-2.0.1.tgz",
@@ -1481,6 +1743,12 @@
       "integrity": "sha512-g1QUuhYVVAamfCifK7oB7G3aIl4BbOyzDOqVyUfEr4tfBKrXfeH+M+Tg7HKCXSrbzxYdhyCP7z9WbKo0R2hBCw==",
       "dev": true
     },
+    "@types/geojson": {
+      "version": "7946.0.7",
+      "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.7.tgz",
+      "integrity": "sha512-wE2v81i4C4Ol09RtsWFAqg3BUitWbHSpSlIo+bNdsCJijO9sjme+zm+73ZMCa/qMC8UEERxzGbvmr1cffo2SiQ==",
+      "dev": true
+    },
     "@types/glob": {
       "version": "7.1.1",
       "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz",
@@ -3237,8 +3505,7 @@
     "commander": {
       "version": "2.20.0",
       "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
-      "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
-      "dev": true
+      "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
     },
     "commondir": {
       "version": "1.0.1",
@@ -3711,11 +3978,305 @@
       "integrity": "sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=",
       "dev": true
     },
+    "d3": {
+      "version": "5.9.7",
+      "resolved": "https://registry.npmjs.org/d3/-/d3-5.9.7.tgz",
+      "integrity": "sha512-jENytrmdXtGPw7HuSK2S4gxRM1eUGjKvWQkQ6ct4yK+DB8SG3VcnVrwesfnsv8rIcxMUg18TafT4Q8mOZUMP4Q==",
+      "requires": {
+        "d3-array": "1",
+        "d3-axis": "1",
+        "d3-brush": "1",
+        "d3-chord": "1",
+        "d3-collection": "1",
+        "d3-color": "1",
+        "d3-contour": "1",
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-dsv": "1",
+        "d3-ease": "1",
+        "d3-fetch": "1",
+        "d3-force": "1",
+        "d3-format": "1",
+        "d3-geo": "1",
+        "d3-hierarchy": "1",
+        "d3-interpolate": "1",
+        "d3-path": "1",
+        "d3-polygon": "1",
+        "d3-quadtree": "1",
+        "d3-random": "1",
+        "d3-scale": "2",
+        "d3-scale-chromatic": "1",
+        "d3-selection": "1",
+        "d3-shape": "1",
+        "d3-time": "1",
+        "d3-time-format": "2",
+        "d3-timer": "1",
+        "d3-transition": "1",
+        "d3-voronoi": "1",
+        "d3-zoom": "1"
+      },
+      "dependencies": {
+        "d3-array": {
+          "version": "1.2.4",
+          "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+          "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        }
+      }
+    },
     "d3-array": {
       "version": "2.2.0",
       "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.2.0.tgz",
       "integrity": "sha512-eE0QmSh6xToqM3sxHiJYg/QFdNn52ZEgmFE8A8abU8GsHvsIOolqH8B70/8+VGAKm5MlwaExhqR3DLIjOJMLPA=="
     },
+    "d3-axis": {
+      "version": "1.0.12",
+      "resolved": "https://registry.npmjs.org/d3-axis/-/d3-axis-1.0.12.tgz",
+      "integrity": "sha512-ejINPfPSNdGFKEOAtnBtdkpr24c4d4jsei6Lg98mxf424ivoDP2956/5HDpIAtmHo85lqT4pruy+zEgvRUBqaQ=="
+    },
+    "d3-brush": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.6.tgz",
+      "integrity": "sha512-lGSiF5SoSqO5/mYGD5FAeGKKS62JdA1EV7HPrU2b5rTX4qEJJtpjaGLJngjnkewQy7UnGstnFd3168wpf5z76w==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-transition": "1"
+      }
+    },
+    "d3-chord": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-chord/-/d3-chord-1.0.6.tgz",
+      "integrity": "sha512-JXA2Dro1Fxw9rJe33Uv+Ckr5IrAa74TlfDEhE/jfLOaXegMQFQTAgAw9WnZL8+HxVBRXaRGCkrNU7pJeylRIuA==",
+      "requires": {
+        "d3-array": "1",
+        "d3-path": "1"
+      },
+      "dependencies": {
+        "d3-array": {
+          "version": "1.2.4",
+          "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+          "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        }
+      }
+    },
+    "d3-collection": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.7.tgz",
+      "integrity": "sha512-ii0/r5f4sjKNTfh84Di+DpztYwqKhEyUlKoPrzUFfeSkWxjW49xU2QzO9qrPrNkpdI0XJkfzvmTu8V2Zylln6A=="
+    },
+    "d3-color": {
+      "version": "1.2.8",
+      "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.2.8.tgz",
+      "integrity": "sha512-yeANXzP37PHk0DbSTMNPhnJD+Nn4G//O5E825bR6fAfHH43hobSBpgB9G9oWVl9+XgUaQ4yCnsX1H+l8DoaL9A=="
+    },
+    "d3-contour": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-contour/-/d3-contour-1.3.2.tgz",
+      "integrity": "sha512-hoPp4K/rJCu0ladiH6zmJUEz6+u3lgR+GSm/QdM2BBvDraU39Vr7YdDCicJcxP1z8i9B/2dJLgDC1NcvlF8WCg==",
+      "requires": {
+        "d3-array": "^1.1.1"
+      },
+      "dependencies": {
+        "d3-array": {
+          "version": "1.2.4",
+          "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+          "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        }
+      }
+    },
+    "d3-dispatch": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.5.tgz",
+      "integrity": "sha512-vwKx+lAqB1UuCeklr6Jh1bvC4SZgbSqbkGBLClItFBIYH4vqDJCA7qfoy14lXmJdnBOdxndAMxjCbImJYW7e6g=="
+    },
+    "d3-drag": {
+      "version": "1.2.3",
+      "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.3.tgz",
+      "integrity": "sha512-8S3HWCAg+ilzjJsNtWW1Mutl74Nmzhb9yU6igspilaJzeZVFktmY6oO9xOh5TDk+BM2KrNFjttZNoJJmDnkjkg==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-selection": "1"
+      }
+    },
+    "d3-dsv": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmjs.org/d3-dsv/-/d3-dsv-1.1.1.tgz",
+      "integrity": "sha512-1EH1oRGSkeDUlDRbhsFytAXU6cAmXFzc52YUe6MRlPClmWb85MP1J5x+YJRzya4ynZWnbELdSAvATFW/MbxaXw==",
+      "requires": {
+        "commander": "2",
+        "iconv-lite": "0.4",
+        "rw": "1"
+      }
+    },
+    "d3-ease": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.5.tgz",
+      "integrity": "sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ=="
+    },
+    "d3-fetch": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/d3-fetch/-/d3-fetch-1.1.2.tgz",
+      "integrity": "sha512-S2loaQCV/ZeyTyIF2oP8D1K9Z4QizUzW7cWeAOAS4U88qOt3Ucf6GsmgthuYSdyB2HyEm4CeGvkQxWsmInsIVA==",
+      "requires": {
+        "d3-dsv": "1"
+      }
+    },
+    "d3-force": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.2.1.tgz",
+      "integrity": "sha512-HHvehyaiUlVo5CxBJ0yF/xny4xoaxFxDnBXNvNcfW9adORGZfyNF1dj6DGLKyk4Yh3brP/1h3rnDzdIAwL08zg==",
+      "requires": {
+        "d3-collection": "1",
+        "d3-dispatch": "1",
+        "d3-quadtree": "1",
+        "d3-timer": "1"
+      }
+    },
+    "d3-format": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.3.2.tgz",
+      "integrity": "sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ=="
+    },
+    "d3-geo": {
+      "version": "1.11.6",
+      "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-1.11.6.tgz",
+      "integrity": "sha512-z0J8InXR9e9wcgNtmVnPTj0TU8nhYT6lD/ak9may2PdKqXIeHUr8UbFLoCtrPYNsjv6YaLvSDQVl578k6nm7GA==",
+      "requires": {
+        "d3-array": "1"
+      },
+      "dependencies": {
+        "d3-array": {
+          "version": "1.2.4",
+          "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+          "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        }
+      }
+    },
+    "d3-hierarchy": {
+      "version": "1.1.8",
+      "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.8.tgz",
+      "integrity": "sha512-L+GHMSZNwTpiq4rt9GEsNcpLa4M96lXMR8M/nMG9p5hBE0jy6C+3hWtyZMenPQdwla249iJy7Nx0uKt3n+u9+w=="
+    },
+    "d3-interpolate": {
+      "version": "1.3.2",
+      "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.3.2.tgz",
+      "integrity": "sha512-NlNKGopqaz9qM1PXh9gBF1KSCVh+jSFErrSlD/4hybwoNX/gt1d8CDbDW+3i+5UOHhjC6s6nMvRxcuoMVNgL2w==",
+      "requires": {
+        "d3-color": "1"
+      }
+    },
+    "d3-path": {
+      "version": "1.0.7",
+      "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.7.tgz",
+      "integrity": "sha512-q0cW1RpvA5c5ma2rch62mX8AYaiLX0+bdaSM2wxSU9tXjU4DNvkx9qiUvjkuWCj3p22UO/hlPivujqMiR9PDzA=="
+    },
+    "d3-polygon": {
+      "version": "1.0.5",
+      "resolved": "https://registry.npmjs.org/d3-polygon/-/d3-polygon-1.0.5.tgz",
+      "integrity": "sha512-RHhh1ZUJZfhgoqzWWuRhzQJvO7LavchhitSTHGu9oj6uuLFzYZVeBzaWTQ2qSO6bz2w55RMoOCf0MsLCDB6e0w=="
+    },
+    "d3-quadtree": {
+      "version": "1.0.6",
+      "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.6.tgz",
+      "integrity": "sha512-NUgeo9G+ENQCQ1LsRr2qJg3MQ4DJvxcDNCiohdJGHt5gRhBW6orIB5m5FJ9kK3HNL8g9F4ERVoBzcEwQBfXWVA=="
+    },
+    "d3-random": {
+      "version": "1.1.2",
+      "resolved": "https://registry.npmjs.org/d3-random/-/d3-random-1.1.2.tgz",
+      "integrity": "sha512-6AK5BNpIFqP+cx/sreKzNjWbwZQCSUatxq+pPRmFIQaWuoD+NrbVWw7YWpHiXpCQ/NanKdtGDuB+VQcZDaEmYQ=="
+    },
+    "d3-scale": {
+      "version": "2.2.2",
+      "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-2.2.2.tgz",
+      "integrity": "sha512-LbeEvGgIb8UMcAa0EATLNX0lelKWGYDQiPdHj+gLblGVhGLyNbaCn3EvrJf0A3Y/uOOU5aD6MTh5ZFCdEwGiCw==",
+      "requires": {
+        "d3-array": "^1.2.0",
+        "d3-collection": "1",
+        "d3-format": "1",
+        "d3-interpolate": "1",
+        "d3-time": "1",
+        "d3-time-format": "2"
+      },
+      "dependencies": {
+        "d3-array": {
+          "version": "1.2.4",
+          "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.4.tgz",
+          "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw=="
+        }
+      }
+    },
+    "d3-scale-chromatic": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/d3-scale-chromatic/-/d3-scale-chromatic-1.3.3.tgz",
+      "integrity": "sha512-BWTipif1CimXcYfT02LKjAyItX5gKiwxuPRgr4xM58JwlLocWbjPLI7aMEjkcoOQXMkYsmNsvv3d2yl/OKuHHw==",
+      "requires": {
+        "d3-color": "1",
+        "d3-interpolate": "1"
+      }
+    },
+    "d3-selection": {
+      "version": "1.4.0",
+      "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.4.0.tgz",
+      "integrity": "sha512-EYVwBxQGEjLCKF2pJ4+yrErskDnz5v403qvAid96cNdCMr8rmCYfY5RGzWz24mdIbxmDf6/4EAH+K9xperD5jg=="
+    },
+    "d3-shape": {
+      "version": "1.3.5",
+      "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.5.tgz",
+      "integrity": "sha512-VKazVR3phgD+MUCldapHD7P9kcrvPcexeX/PkMJmkUov4JM8IxsSg1DvbYoYich9AtdTsa5nNk2++ImPiDiSxg==",
+      "requires": {
+        "d3-path": "1"
+      }
+    },
+    "d3-time": {
+      "version": "1.0.11",
+      "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.11.tgz",
+      "integrity": "sha512-Z3wpvhPLW4vEScGeIMUckDW7+3hWKOQfAWg/U7PlWBnQmeKQ00gCUsTtWSYulrKNA7ta8hJ+xXc6MHrMuITwEw=="
+    },
+    "d3-time-format": {
+      "version": "2.1.3",
+      "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.3.tgz",
+      "integrity": "sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==",
+      "requires": {
+        "d3-time": "1"
+      }
+    },
+    "d3-timer": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.9.tgz",
+      "integrity": "sha512-rT34J5HnQUHhcLvhSB9GjCkN0Ddd5Y8nCwDBG2u6wQEeYxT/Lf51fTFFkldeib/sE/J0clIe0pnCfs6g/lRbyg=="
+    },
+    "d3-transition": {
+      "version": "1.2.0",
+      "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.2.0.tgz",
+      "integrity": "sha512-VJ7cmX/FPIPJYuaL2r1o1EMHLttvoIuZhhuAlRoOxDzogV8iQS6jYulDm3xEU3TqL80IZIhI551/ebmCMrkvhw==",
+      "requires": {
+        "d3-color": "1",
+        "d3-dispatch": "1",
+        "d3-ease": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "^1.1.0",
+        "d3-timer": "1"
+      }
+    },
+    "d3-voronoi": {
+      "version": "1.1.4",
+      "resolved": "https://registry.npmjs.org/d3-voronoi/-/d3-voronoi-1.1.4.tgz",
+      "integrity": "sha512-dArJ32hchFsrQ8uMiTBLq256MpnZjeuBtdHpaDlYuQyjU0CVzCJl/BVW+SkszaAeH95D/8gxqAhgx0ouAWAfRg=="
+    },
+    "d3-zoom": {
+      "version": "1.7.3",
+      "resolved": "https://registry.npmjs.org/d3-zoom/-/d3-zoom-1.7.3.tgz",
+      "integrity": "sha512-xEBSwFx5Z9T3/VrwDkMt+mr0HCzv7XjpGURJ8lWmIC8wxe32L39eWHIasEe/e7Ox8MPU4p1hvH8PKN2olLzIBg==",
+      "requires": {
+        "d3-dispatch": "1",
+        "d3-drag": "1",
+        "d3-interpolate": "1",
+        "d3-selection": "1",
+        "d3-transition": "1"
+      }
+    },
     "dashdash": {
       "version": "1.14.1",
       "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
@@ -5182,25 +5743,29 @@
       "dependencies": {
         "abbrev": {
           "version": "1.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
+          "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==",
           "dev": true,
           "optional": true
         },
         "ansi-regex": {
           "version": "2.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+          "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
           "dev": true,
           "optional": true
         },
         "aproba": {
           "version": "1.2.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
+          "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==",
           "dev": true,
           "optional": true
         },
         "are-we-there-yet": {
           "version": "1.1.5",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
+          "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5210,13 +5775,15 @@
         },
         "balanced-match": {
           "version": "1.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
+          "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
           "dev": true,
           "optional": true
         },
         "brace-expansion": {
           "version": "1.1.11",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+          "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5226,37 +5793,43 @@
         },
         "chownr": {
           "version": "1.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz",
+          "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==",
           "dev": true,
           "optional": true
         },
         "code-point-at": {
           "version": "1.1.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
+          "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
           "dev": true,
           "optional": true
         },
         "concat-map": {
           "version": "0.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+          "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
           "dev": true,
           "optional": true
         },
         "console-control-strings": {
           "version": "1.1.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
+          "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=",
           "dev": true,
           "optional": true
         },
         "core-util-is": {
           "version": "1.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+          "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
           "dev": true,
           "optional": true
         },
         "debug": {
           "version": "4.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz",
+          "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5265,25 +5838,29 @@
         },
         "deep-extend": {
           "version": "0.6.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
+          "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==",
           "dev": true,
           "optional": true
         },
         "delegates": {
           "version": "1.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
+          "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=",
           "dev": true,
           "optional": true
         },
         "detect-libc": {
           "version": "1.0.3",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
+          "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=",
           "dev": true,
           "optional": true
         },
         "fs-minipass": {
           "version": "1.2.5",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz",
+          "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5292,13 +5869,15 @@
         },
         "fs.realpath": {
           "version": "1.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+          "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
           "dev": true,
           "optional": true
         },
         "gauge": {
           "version": "2.7.4",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
+          "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5314,7 +5893,8 @@
         },
         "glob": {
           "version": "7.1.3",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
+          "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5328,13 +5908,15 @@
         },
         "has-unicode": {
           "version": "2.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
+          "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=",
           "dev": true,
           "optional": true
         },
         "iconv-lite": {
           "version": "0.4.24",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
+          "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5343,7 +5925,8 @@
         },
         "ignore-walk": {
           "version": "3.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz",
+          "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5352,7 +5935,8 @@
         },
         "inflight": {
           "version": "1.0.6",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+          "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5362,19 +5946,22 @@
         },
         "inherits": {
           "version": "2.0.3",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
+          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
           "dev": true,
           "optional": true
         },
         "ini": {
           "version": "1.3.5",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
+          "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==",
           "dev": true,
           "optional": true
         },
         "is-fullwidth-code-point": {
           "version": "1.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
+          "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5383,13 +5970,15 @@
         },
         "isarray": {
           "version": "1.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+          "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
           "dev": true,
           "optional": true
         },
         "minimatch": {
           "version": "3.0.4",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
+          "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5398,13 +5987,15 @@
         },
         "minimist": {
           "version": "0.0.8",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
+          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
           "dev": true,
           "optional": true
         },
         "minipass": {
           "version": "2.3.5",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz",
+          "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5414,7 +6005,8 @@
         },
         "minizlib": {
           "version": "1.2.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz",
+          "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5423,7 +6015,8 @@
         },
         "mkdirp": {
           "version": "0.5.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
+          "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5432,13 +6025,15 @@
         },
         "ms": {
           "version": "2.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
+          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
           "dev": true,
           "optional": true
         },
         "needle": {
           "version": "2.3.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/needle/-/needle-2.3.0.tgz",
+          "integrity": "sha512-QBZu7aAFR0522EyaXZM0FZ9GLpq6lvQ3uq8gteiDUp7wKdy0lSd2hPlgFwVuW1CBkfEs9PfDQsQzZghLs/psdg==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5449,7 +6044,8 @@
         },
         "node-pre-gyp": {
           "version": "0.12.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz",
+          "integrity": "sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5467,7 +6063,8 @@
         },
         "nopt": {
           "version": "4.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz",
+          "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5477,13 +6074,15 @@
         },
         "npm-bundled": {
           "version": "1.0.6",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.6.tgz",
+          "integrity": "sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==",
           "dev": true,
           "optional": true
         },
         "npm-packlist": {
           "version": "1.4.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.1.tgz",
+          "integrity": "sha512-+TcdO7HJJ8peiiYhvPxsEDhF3PJFGUGRcFsGve3vxvxdcpO2Z4Z7rkosRM0kWj6LfbK/P0gu3dzk5RU1ffvFcw==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5493,7 +6092,8 @@
         },
         "npmlog": {
           "version": "4.1.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
+          "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5505,19 +6105,22 @@
         },
         "number-is-nan": {
           "version": "1.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
+          "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
           "dev": true,
           "optional": true
         },
         "object-assign": {
           "version": "4.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
+          "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
           "dev": true,
           "optional": true
         },
         "once": {
           "version": "1.4.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+          "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5526,19 +6129,22 @@
         },
         "os-homedir": {
           "version": "1.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
+          "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
           "dev": true,
           "optional": true
         },
         "os-tmpdir": {
           "version": "1.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
+          "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=",
           "dev": true,
           "optional": true
         },
         "osenv": {
           "version": "0.1.5",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
+          "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5548,19 +6154,22 @@
         },
         "path-is-absolute": {
           "version": "1.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+          "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
           "dev": true,
           "optional": true
         },
         "process-nextick-args": {
           "version": "2.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz",
+          "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==",
           "dev": true,
           "optional": true
         },
         "rc": {
           "version": "1.2.8",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
+          "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5572,7 +6181,8 @@
           "dependencies": {
             "minimist": {
               "version": "1.2.0",
-              "bundled": true,
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
+              "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=",
               "dev": true,
               "optional": true
             }
@@ -5580,7 +6190,8 @@
         },
         "readable-stream": {
           "version": "2.3.6",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
+          "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5595,7 +6206,8 @@
         },
         "rimraf": {
           "version": "2.6.3",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
+          "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5604,43 +6216,50 @@
         },
         "safe-buffer": {
           "version": "5.1.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+          "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
           "dev": true,
           "optional": true
         },
         "safer-buffer": {
           "version": "2.1.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+          "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==",
           "dev": true,
           "optional": true
         },
         "sax": {
           "version": "1.2.4",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
+          "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
           "dev": true,
           "optional": true
         },
         "semver": {
           "version": "5.7.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
+          "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
           "dev": true,
           "optional": true
         },
         "set-blocking": {
           "version": "2.0.0",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
+          "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
           "dev": true,
           "optional": true
         },
         "signal-exit": {
           "version": "3.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
+          "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=",
           "dev": true,
           "optional": true
         },
         "string-width": {
           "version": "1.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
+          "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5651,7 +6270,8 @@
         },
         "string_decoder": {
           "version": "1.1.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+          "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5660,7 +6280,8 @@
         },
         "strip-ansi": {
           "version": "3.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+          "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5669,13 +6290,15 @@
         },
         "strip-json-comments": {
           "version": "2.0.1",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
+          "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
           "dev": true,
           "optional": true
         },
         "tar": {
           "version": "4.4.8",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz",
+          "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5690,13 +6313,15 @@
         },
         "util-deprecate": {
           "version": "1.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+          "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
           "dev": true,
           "optional": true
         },
         "wide-align": {
           "version": "1.1.3",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
+          "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
           "dev": true,
           "optional": true,
           "requires": {
@@ -5705,13 +6330,15 @@
         },
         "wrappy": {
           "version": "1.0.2",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+          "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
           "dev": true,
           "optional": true
         },
         "yallist": {
           "version": "3.0.3",
-          "bundled": true,
+          "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz",
+          "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==",
           "dev": true,
           "optional": true
         }
@@ -11063,6 +11690,11 @@
         "aproba": "^1.1.1"
       }
     },
+    "rw": {
+      "version": "1.3.3",
+      "resolved": "https://registry.npmjs.org/rw/-/rw-1.3.3.tgz",
+      "integrity": "sha1-P4Yt+pGrdmsUiF700BEkv9oHT7Q="
+    },
     "safe-buffer": {
       "version": "5.1.2",
       "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
diff --git a/web-console/package.json b/web-console/package.json
index ea100bc..4f62c4d 100644
--- a/web-console/package.json
+++ b/web-console/package.json
@@ -58,6 +58,7 @@
     "classnames": "^2.2.6",
     "copy-to-clipboard": "^3.2.0",
     "core-js": "^3.1.4",
+    "d3": "^5.9.7",
     "d3-array": "^2.2.0",
     "druid-console": "^0.0.2",
     "file-saver": "^2.0.2",
@@ -82,6 +83,7 @@
     "@babel/preset-env": "^7.5.5",
     "@testing-library/react": "^8.0.7",
     "@types/classnames": "^2.2.9",
+    "@types/d3": "^5.7.2",
     "@types/d3-array": "^2.0.0",
     "@types/enzyme": "^3.10.3",
     "@types/enzyme-adapter-react-16": "^1.0.5",
diff --git a/web-console/src/components/index.ts b/web-console/src/components/index.ts
index fb9475d..3280dd8 100644
--- a/web-console/src/components/index.ts
+++ b/web-console/src/components/index.ts
@@ -35,3 +35,4 @@ export * from './view-control-bar/view-control-bar';
 export * from './clearable-input/clearable-input';
 export * from './refresh-button/refresh-button';
 export * from './timed-button/timed-button';
+export * from './segment-timeline/segment-timeline';
diff --git a/web-console/src/views/datasource-view/datasource-view.scss b/web-console/src/components/segment-timeline/segment-timeline.scss
similarity index 60%
copy from web-console/src/views/datasource-view/datasource-view.scss
copy to web-console/src/components/segment-timeline/segment-timeline.scss
index 7c483ce..7c8682c 100644
--- a/web-console/src/views/datasource-view/datasource-view.scss
+++ b/web-console/src/components/segment-timeline/segment-timeline.scss
@@ -16,20 +16,43 @@
  * limitations under the License.
  */
 
-@import '../../variables';
-
-.data-sources-view {
+.segment-timeline {
+  display: grid;
+  grid-template-columns: 85% 15%;
   height: 100%;
-  width: 100%;
+  margin-top: 10px;
+
+  .loader {
+    width: 85%;
+  }
+
+  .loading-error {
+    position: fixed;
+    top: 50%;
+    left: 50%;
+    -webkit-transform: translate(-50%, -50%);
+    transform: translate(-50%, -50%);
+  }
+
+  .bar-chart-tooltip {
+    margin-top: 15px;
+    text-align: center;
 
-  .clickable-cell {
-    cursor: pointer;
+    div {
+      display: inline-block;
+      width: 200px;
+    }
   }
 
-  .ReactTable {
+  .no-data-text {
     position: absolute;
-    top: $view-control-bar-height + $standard-padding;
-    bottom: 0;
-    width: 100%;
+    left: 30vw;
+    top: 15vh;
+    font-size: 20px;
+  }
+
+  .side-control {
+    padding-left: 1vw;
+    padding-top: 5vh;
   }
 }
diff --git a/web-console/src/components/segment-timeline/segment-timeline.tsx b/web-console/src/components/segment-timeline/segment-timeline.tsx
new file mode 100644
index 0000000..34d3a88
--- /dev/null
+++ b/web-console/src/components/segment-timeline/segment-timeline.tsx
@@ -0,0 +1,496 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { FormGroup, HTMLSelect, Radio, RadioGroup } from '@blueprintjs/core';
+import * as d3 from 'd3';
+import { AxisScale } from 'd3';
+import React from 'react';
+
+import { formatBytes, queryDruidSql, QueryManager } from '../../utils/index';
+import { StackedBarChart } from '../../visualization/stacked-bar-chart';
+import { Loader } from '../loader/loader';
+
+import './segment-timeline.scss';
+
+interface SegmentTimelineProps extends React.Props<any> {
+  chartHeight: number;
+  chartWidth: number;
+}
+
+interface SegmentTimelineState {
+  data?: Record<string, any>;
+  datasources: string[];
+  stackedData?: Record<string, BarUnitData[]>;
+  singleDatasourceData?: Record<string, Record<string, BarUnitData[]>>;
+  activeDatasource: string | null;
+  activeDataType: string; // "countData" || "sizeData"
+  dataToRender: BarUnitData[];
+  timeSpan: number; // by months
+  loading: boolean;
+  error?: string;
+  xScale: AxisScale<Date> | null;
+  yScale: AxisScale<number> | null;
+  dStart: Date;
+  dEnd: Date;
+}
+
+interface BarChartScales {
+  xScale: AxisScale<Date>;
+  yScale: AxisScale<number>;
+}
+
+export interface BarUnitData {
+  x: number;
+  y: number;
+  y0?: number;
+  width: number;
+  datasource: string;
+  color: string;
+}
+
+export interface BarChartMargin {
+  top: number;
+  right: number;
+  bottom: number;
+  left: number;
+}
+
+export class SegmentTimeline extends React.Component<SegmentTimelineProps, SegmentTimelineState> {
+  private dataQueryManager: QueryManager<null, any>;
+  private datasourceQueryManager: QueryManager<null, any>;
+  private colors = [
+    '#b33040',
+    '#d25c4d',
+    '#f2b447',
+    '#d9d574',
+    '#4FAA7E',
+    '#57ceff',
+    '#789113',
+    '#098777',
+    '#b33040',
+    '#d2757b',
+    '#f29063',
+    '#d9a241',
+    '#80aa61',
+    '#c4ff9e',
+    '#915412',
+    '#87606c',
+  ];
+  private chartMargin = { top: 20, right: 10, bottom: 20, left: 10 };
+
+  constructor(props: SegmentTimelineProps) {
+    super(props);
+    const dStart = new Date();
+    const dEnd = new Date();
+    dStart.setMonth(dStart.getMonth() - 3);
+    this.state = {
+      data: {},
+      datasources: [],
+      stackedData: {},
+      singleDatasourceData: {},
+      dataToRender: [],
+      activeDatasource: null,
+      activeDataType: 'countData',
+      timeSpan: 3,
+      loading: true,
+      xScale: null,
+      yScale: null,
+      dEnd: dEnd,
+      dStart: dStart,
+    };
+
+    this.dataQueryManager = new QueryManager({
+      processQuery: async () => {
+        const { timeSpan } = this.state;
+        const query = `SELECT "start", "end", "datasource", COUNT(*) AS "count", sum(size) as "total_size"
+              FROM sys.segments
+              WHERE "start" > time_format(TIMESTAMPADD(MONTH, -${timeSpan}, current_timestamp), 'yyyy-MM-dd''T''hh:mm:ss.SSS')
+              GROUP BY 1, 2, 3
+              ORDER BY "start" DESC`;
+        const resp: any[] = await queryDruidSql({ query });
+        const data = this.processRawData(resp);
+        const stackedData = this.calculateStackedData(data);
+        const singleDatasourceData = this.calculateSingleDatasourceData(data);
+        return { data, stackedData, singleDatasourceData };
+      },
+      onStateChange: ({ result, loading, error }) => {
+        this.setState({
+          data: result ? result.data : undefined,
+          stackedData: result ? result.stackedData : undefined,
+          singleDatasourceData: result ? result.singleDatasourceData : undefined,
+          loading,
+          error,
+        });
+      },
+    });
+
+    this.datasourceQueryManager = new QueryManager({
+      processQuery: async () => {
+        const query = `SELECT DISTINCT "datasource" FROM sys.segments`;
+        const resp: any[] = await queryDruidSql({ query });
+        const data = resp.map((r: any) => r.datasource);
+        return data;
+      },
+      onStateChange: ({ result }) => {
+        if (result == null) result = [];
+        this.setState({
+          datasources: result,
+        });
+      },
+    });
+  }
+
+  componentDidMount(): void {
+    this.dataQueryManager.runQuery(null);
+    this.datasourceQueryManager.runQuery(null);
+  }
+
+  componentWillUnmount(): void {
+    this.dataQueryManager.terminate();
+    this.datasourceQueryManager.terminate();
+  }
+
+  componentDidUpdate(prevProps: SegmentTimelineProps, prevState: SegmentTimelineState): void {
+    const { activeDatasource, activeDataType, singleDatasourceData, stackedData } = this.state;
+    if (
+      prevState.data !== this.state.data ||
+      prevState.activeDataType !== this.state.activeDataType ||
+      prevState.activeDatasource !== this.state.activeDatasource ||
+      prevProps.chartWidth !== this.props.chartWidth ||
+      prevProps.chartHeight !== this.props.chartHeight
+    ) {
+      const scales: BarChartScales | undefined = this.calculateScales();
+      let dataToRender: BarUnitData[] | undefined;
+      dataToRender = activeDatasource
+        ? singleDatasourceData
+          ? singleDatasourceData[activeDataType][activeDatasource]
+          : undefined
+        : stackedData
+        ? stackedData[activeDataType]
+        : undefined;
+
+      if (scales && dataToRender) {
+        this.setState({
+          dataToRender,
+          xScale: scales.xScale,
+          yScale: scales.yScale,
+        });
+      }
+    }
+  }
+
+  private processRawData(data: any) {
+    if (data === null) return [];
+    const countData: Record<string, any> = {};
+    const sizeData: Record<string, any> = {};
+    data.forEach((entry: any) => {
+      const start = entry.start;
+      const day = start.split('T')[0];
+      const datasource = entry.datasource;
+      const count = entry.count;
+      const segmentSize = entry['total_size'];
+      if (countData[day] === undefined) {
+        countData[day] = {
+          day,
+          [datasource]: count,
+          total: count,
+        };
+        sizeData[day] = {
+          day,
+          [datasource]: segmentSize,
+          total: segmentSize,
+        };
+      } else {
+        const countDataEntry = countData[day][datasource];
+        countData[day][datasource] = count + (countDataEntry === undefined ? 0 : countDataEntry);
+        const sizeDataEntry = sizeData[day][datasource];
+        sizeData[day][datasource] = segmentSize + (sizeDataEntry === undefined ? 0 : sizeDataEntry);
+        countData[day].total += count;
+        sizeData[day].total += segmentSize;
+      }
+    });
+    const countDataArray = Object.keys(countData)
+      .reverse()
+      .map((time: any) => {
+        return countData[time];
+      });
+    const sizeDataArray = Object.keys(sizeData)
+      .reverse()
+      .map((time: any) => {
+        return sizeData[time];
+      });
+    return { countData: countDataArray, sizeData: sizeDataArray };
+  }
+
+  private calculateStackedData(data: Record<string, any>): Record<string, BarUnitData[]> {
+    const { datasources } = this.state;
+    const newStackedData: Record<string, BarUnitData[]> = {};
+    Object.keys(data).forEach((type: any) => {
+      const stackedData: any = data[type].map((d: any) => {
+        let y0 = 0;
+        return datasources.map((datasource: string, i) => {
+          const barUnitData = {
+            x: d.day,
+            y: d[datasource] === undefined ? 0 : d[datasource],
+            y0,
+            datasource,
+            color: this.colors[i],
+          };
+          y0 += d[datasource] === undefined ? 0 : d[datasource];
+          return barUnitData;
+        });
+      });
+      newStackedData[type] = stackedData.flat();
+    });
+    return newStackedData;
+  }
+
+  private calculateSingleDatasourceData(
+    data: Record<string, any>,
+  ): Record<string, Record<string, BarUnitData[]>> {
+    const { datasources } = this.state;
+    const singleDatasourceData: Record<string, Record<string, BarUnitData[]>> = {};
+    Object.keys(data).forEach(dataType => {
+      singleDatasourceData[dataType] = {};
+      datasources.forEach((datasource, i) => {
+        const currentData = data[dataType];
+        if (currentData.length === 0) return;
+        const dataResult = currentData.map((d: any) => {
+          let y = 0;
+          if (d[datasource] !== undefined) {
+            y = d[datasource];
+          }
+          return {
+            x: d.day,
+            y,
+            datasource,
+            color: this.colors[i],
+          };
+        });
+        if (!dataResult.every((d: any) => d.y === 0)) {
+          singleDatasourceData[dataType][datasource] = dataResult;
+        }
+      });
+    });
+    return singleDatasourceData;
+  }
+
+  private calculateScales(): BarChartScales | undefined {
+    const { chartWidth, chartHeight } = this.props;
+    const {
+      data,
+      activeDataType,
+      activeDatasource,
+      singleDatasourceData,
+      dStart,
+      dEnd,
+    } = this.state;
+    if (!data || !Object.keys(data).length) return;
+    const activeData = data[activeDataType];
+    const xDomain: Date[] = [dStart, dEnd];
+    let yDomain: number[] = [
+      0,
+      activeData.length === 0
+        ? 0
+        : activeData.reduce((max: any, d: any) => (max.total > d.total ? max : d)).total,
+    ];
+
+    if (
+      activeDatasource !== null &&
+      singleDatasourceData![activeDataType][activeDatasource] !== undefined
+    ) {
+      yDomain = [
+        0,
+        singleDatasourceData![activeDataType][activeDatasource].reduce((max: any, d: any) =>
+          max.y > d.y ? max : d,
+        ).y,
+      ];
+    }
+
+    const xScale: AxisScale<Date> = d3
+      .scaleTime()
+      .domain(xDomain)
+      .range([0, chartWidth - this.chartMargin.left - this.chartMargin.right]);
+
+    const yScale: AxisScale<number> = d3
+      .scaleLinear()
+      .rangeRound([chartHeight - this.chartMargin.top - this.chartMargin.bottom, 0])
+      .domain(yDomain);
+
+    return {
+      xScale,
+      yScale,
+    };
+  }
+
+  onTimeSpanChange = (e: any) => {
+    const dStart = new Date();
+    const dEnd = new Date();
+    dStart.setMonth(dStart.getMonth() - e);
+    this.setState({
+      timeSpan: e,
+      loading: true,
+      dStart,
+      dEnd,
+    });
+    this.dataQueryManager.rerunLastQuery();
+  };
+
+  formatTick = (n: number) => {
+    const { activeDataType } = this.state;
+    if (activeDataType === 'countData') {
+      return n.toString();
+    } else {
+      return formatBytes(n);
+    }
+  };
+
+  renderStackedBarChart() {
+    const { chartWidth, chartHeight } = this.props;
+    const {
+      loading,
+      dataToRender,
+      activeDataType,
+      error,
+      xScale,
+      yScale,
+      data,
+      activeDatasource,
+      dStart,
+      dEnd,
+    } = this.state;
+    if (loading) {
+      return (
+        <div>
+          <Loader loading={loading} />
+        </div>
+      );
+    }
+
+    if (error) {
+      return (
+        <div>
+          <span className={'no-data-text'}>Error when loading data: {error}</span>
+        </div>
+      );
+    }
+
+    if (xScale === null || yScale === null) {
+      return (
+        <div>
+          <span className={'no-data-text'}>Error when calculating scales</span>
+        </div>
+      );
+    }
+
+    if (data![activeDataType].length === 0) {
+      return (
+        <div>
+          <span className={'no-data-text'}>No data available for the time span selected</span>
+        </div>
+      );
+    }
+
+    if (
+      activeDatasource !== null &&
+      data![activeDataType].every((d: any) => d[activeDatasource] === undefined)
+    ) {
+      return (
+        <div>
+          <span className={'no-data-text'}>
+            No data available for <i>{activeDatasource}</i>
+          </span>
+        </div>
+      );
+    }
+
+    const millisecondsPerDay = 24 * 60 * 60 * 1000;
+    const barCounts = (dEnd.getTime() - dStart.getTime()) / millisecondsPerDay;
+    const barWidth = (chartWidth - this.chartMargin.left - this.chartMargin.right) / barCounts;
+    return (
+      <StackedBarChart
+        dataToRender={dataToRender}
+        svgHeight={chartHeight}
+        svgWidth={chartWidth}
+        margin={this.chartMargin}
+        changeActiveDatasource={(e: string) => this.setState({ activeDatasource: e })}
+        activeDataType={activeDataType}
+        formatTick={(n: number) => this.formatTick(n)}
+        xScale={xScale}
+        yScale={yScale}
+        barWidth={barWidth}
+      />
+    );
+  }
+
+  render(): JSX.Element {
+    const { datasources, activeDataType, activeDatasource, timeSpan } = this.state;
+
+    return (
+      <div className={'segment-timeline app-view'}>
+        {this.renderStackedBarChart()}
+        <div className={'side-control'}>
+          <FormGroup>
+            <RadioGroup
+              onChange={(e: any) => this.setState({ activeDataType: e.target.value })}
+              selectedValue={activeDataType}
+            >
+              <Radio label={'Segment count'} value={'countData'} />
+              <Radio label={'Total size'} value={'sizeData'} />
+            </RadioGroup>
+          </FormGroup>
+
+          <FormGroup label={'Datasource:'}>
+            <HTMLSelect
+              onChange={(e: any) =>
+                this.setState({
+                  activeDatasource: e.target.value === 'all' ? null : e.target.value,
+                })
+              }
+              value={activeDatasource == null ? 'all' : activeDatasource}
+              fill
+            >
+              <option value={'all'}>Show all</option>
+              {datasources.map(d => {
+                return (
+                  <option key={d} value={d}>
+                    {d}
+                  </option>
+                );
+              })}
+            </HTMLSelect>
+          </FormGroup>
+
+          <FormGroup label={'Period:'}>
+            <HTMLSelect
+              onChange={(e: any) => this.onTimeSpanChange(e.target.value)}
+              value={timeSpan}
+              fill
+            >
+              <option value={1}> 1 months</option>
+              <option value={3}> 3 months</option>
+              <option value={6}> 6 months</option>
+              <option value={9}> 9 months</option>
+              <option value={12}> 1 year</option>
+            </HTMLSelect>
+          </FormGroup>
+        </div>
+      </div>
+    );
+  }
+}
diff --git a/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap b/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
index b619181..9162516 100755
--- a/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
+++ b/web-console/src/views/datasource-view/__snapshots__/datasource-view.spec.tsx.snap
@@ -18,6 +18,11 @@ exports[`data source view matches snapshot 1`] = `
     />
     <Blueprint3.Switch
       checked={false}
+      label="Show segment timeline"
+      onChange={[Function]}
+    />
+    <Blueprint3.Switch
+      checked={false}
       label="Show disabled"
       onChange={[Function]}
     />
@@ -58,7 +63,7 @@ exports[`data source view matches snapshot 1`] = `
     TrComponent={[Function]}
     TrGroupComponent={[Function]}
     aggregatedKey="_aggregated"
-    className=""
+    className="-striped -highlight full-height"
     collapseOnDataChange={true}
     collapseOnPageChange={true}
     collapseOnSortingChange={true}
diff --git a/web-console/src/views/datasource-view/datasource-view.scss b/web-console/src/views/datasource-view/datasource-view.scss
index 7c483ce..6891a82 100644
--- a/web-console/src/views/datasource-view/datasource-view.scss
+++ b/web-console/src/views/datasource-view/datasource-view.scss
@@ -21,15 +21,25 @@
 .data-sources-view {
   height: 100%;
   width: 100%;
+  overflow: auto;
 
   .clickable-cell {
     cursor: pointer;
   }
 
+  .chart-container {
+    height: 40vh;
+    margin-bottom: 10px;
+  }
+
   .ReactTable {
     position: absolute;
-    top: $view-control-bar-height + $standard-padding;
+    top: 50%; //$view-control-bar-height + $standard-padding;
     bottom: 0;
     width: 100%;
+
+    &.full-height {
+      top: 50px;
+    }
   }
 }
diff --git a/web-console/src/views/datasource-view/datasource-view.tsx b/web-console/src/views/datasource-view/datasource-view.tsx
index 6580af6..9390984 100644
--- a/web-console/src/views/datasource-view/datasource-view.tsx
+++ b/web-console/src/views/datasource-view/datasource-view.tsx
@@ -19,6 +19,7 @@
 import { Button, FormGroup, InputGroup, Intent, Switch } from '@blueprintjs/core';
 import { IconNames } from '@blueprintjs/icons';
 import axios from 'axios';
+import classNames from 'classnames';
 import React from 'react';
 import ReactTable, { Filter } from 'react-table';
 
@@ -30,6 +31,7 @@ import {
   ViewControlBar,
 } from '../../components';
 import { ActionIcon } from '../../components/action-icon/action-icon';
+import { SegmentTimeline } from '../../components/segment-timeline/segment-timeline';
 import { AsyncActionDialog, CompactionDialog, RetentionDialog } from '../../dialogs';
 import { AppToaster } from '../../singletons/toaster';
 import {
@@ -123,6 +125,9 @@ export interface DatasourcesViewState {
   dropReloadAction: 'drop' | 'reload';
   dropReloadInterval: string;
   hiddenColumns: LocalStorageBackedArray<string>;
+  showChart: boolean;
+  chartWidth: number;
+  chartHeight: number;
 }
 
 export class DatasourcesView extends React.PureComponent<
@@ -175,6 +180,9 @@ GROUP BY 1`;
       hiddenColumns: new LocalStorageBackedArray<string>(
         LocalStorageKeys.DATASOURCE_TABLE_COLUMN_SELECTION,
       ),
+      showChart: false,
+      chartWidth: window.innerWidth * 0.85,
+      chartHeight: window.innerHeight * 0.4,
     };
 
     this.datasourceQueryManager = new QueryManager({
@@ -252,9 +260,31 @@ GROUP BY 1`;
     });
   }
 
+  private handleResize = () => {
+    this.setState({
+      chartWidth: window.innerWidth * 0.85,
+      chartHeight: window.innerHeight * 0.4,
+    });
+  };
+
+  private refresh = (auto: any): void => {
+    this.datasourceQueryManager.rerunLastQuery(auto);
+    // this looks ugly, but it forces the chart to re-render when refresh is clicked
+    this.setState(
+      {
+        showChart: !this.state.showChart,
+      },
+      () =>
+        this.setState({
+          showChart: !this.state.showChart,
+        }),
+    );
+  };
+
   componentDidMount(): void {
     const { noSqlMode } = this.props;
     this.datasourceQueryManager.runQuery(noSqlMode);
+    window.addEventListener('resize', this.handleResize);
   }
 
   componentWillUnmount(): void {
@@ -572,6 +602,7 @@ GROUP BY 1`;
       datasourcesFilter,
       showDisabled,
       hiddenColumns,
+      showChart,
     } = this.state;
     let data = datasources || [];
     if (!showDisabled) {
@@ -790,6 +821,7 @@ GROUP BY 1`;
             },
           ]}
           defaultPageSize={50}
+          className={classNames(`-striped -highlight`, showChart ? '' : 'full-height')}
         />
         {this.renderDropDataAction()}
         {this.renderEnableAction()}
@@ -803,13 +835,15 @@ GROUP BY 1`;
 
   render(): JSX.Element {
     const { goToQuery, noSqlMode } = this.props;
-    const { showDisabled, hiddenColumns } = this.state;
+    const { showDisabled, hiddenColumns, showChart, chartHeight, chartWidth } = this.state;
 
     return (
       <div className="data-sources-view app-view">
         <ViewControlBar label="Datasources">
           <RefreshButton
-            onRefresh={auto => this.datasourceQueryManager.rerunLastQuery(auto)}
+            onRefresh={auto => {
+              this.refresh(auto);
+            }}
             localStorageKey={LocalStorageKeys.DATASOURCES_REFRESH_RATE}
           />
           {!noSqlMode && (
@@ -820,6 +854,11 @@ GROUP BY 1`;
             />
           )}
           <Switch
+            checked={showChart}
+            label="Show segment timeline"
+            onChange={() => this.setState({ showChart: !showChart })}
+          />
+          <Switch
             checked={showDisabled}
             label="Show disabled"
             onChange={() => this.toggleDisabled(showDisabled)}
@@ -830,6 +869,11 @@ GROUP BY 1`;
             tableColumnsHidden={hiddenColumns.storedArray}
           />
         </ViewControlBar>
+        {showChart && (
+          <div className={'chart-container'}>
+            <SegmentTimeline chartHeight={chartHeight} chartWidth={chartWidth} />
+          </div>
+        )}
         {this.renderDatasourceTable()}
       </div>
     );
diff --git a/web-console/src/visualization/bar-group.tsx b/web-console/src/visualization/bar-group.tsx
new file mode 100644
index 0000000..0856905
--- /dev/null
+++ b/web-console/src/visualization/bar-group.tsx
@@ -0,0 +1,90 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { AxisScale } from 'd3-axis';
+import React from 'react';
+
+import { BarUnitData } from '../components/segment-timeline/segment-timeline';
+
+import { BarUnit } from './bar-unit';
+import { HoveredBarInfo } from './stacked-bar-chart';
+
+interface BarGroupProps extends React.Props<any> {
+  dataToRender: BarUnitData[];
+  changeActiveDatasource: (e: string) => void;
+  formatTick: (e: number) => string;
+  xScale: AxisScale<Date>;
+  yScale: AxisScale<number>;
+  barWidth: number;
+  onHoverBar?: (e: any) => void;
+  offHoverBar?: () => void;
+  hoverOn?: HoveredBarInfo | null;
+}
+
+interface BarGroupState {}
+
+export class BarGroup extends React.Component<BarGroupProps, BarGroupState> {
+  constructor(props: BarGroupProps) {
+    super(props);
+    this.state = {};
+  }
+
+  shouldComponentUpdate(nextProps: BarGroupProps, nextState: BarGroupState): boolean {
+    if (nextState === null) console.log(nextState);
+    return nextProps.hoverOn === this.props.hoverOn;
+  }
+
+  render(): JSX.Element[] | null {
+    const {
+      dataToRender,
+      changeActiveDatasource,
+      xScale,
+      yScale,
+      onHoverBar,
+      barWidth,
+    } = this.props;
+    if (dataToRender === undefined) return null;
+
+    return dataToRender.map((entry: BarUnitData, i: number) => {
+      const y0 = yScale(entry.y0 || 0) || 0;
+      const x = xScale(new Date(entry.x));
+      const y = yScale((entry.y0 || 0) + entry.y) || 0;
+      const height = y0 - y;
+      const barInfo: HoveredBarInfo = {
+        xCoordinate: x,
+        yCoordinate: y,
+        height,
+        datasource: entry.datasource,
+        xValue: entry.x,
+        yValue: entry.y,
+      };
+      return (
+        <BarUnit
+          key={i}
+          x={x}
+          y={y}
+          width={barWidth}
+          height={height}
+          style={{ fill: entry.color }}
+          onClick={() => changeActiveDatasource(entry.datasource)}
+          onHover={() => onHoverBar && onHoverBar(barInfo)}
+        />
+      );
+    });
+  }
+}
diff --git a/web-console/src/views/datasource-view/datasource-view.scss b/web-console/src/visualization/bar-unit.scss
similarity index 75%
copy from web-console/src/views/datasource-view/datasource-view.scss
copy to web-console/src/visualization/bar-unit.scss
index 7c483ce..5767d68 100644
--- a/web-console/src/views/datasource-view/datasource-view.scss
+++ b/web-console/src/visualization/bar-unit.scss
@@ -16,20 +16,6 @@
  * limitations under the License.
  */
 
-@import '../../variables';
-
-.data-sources-view {
-  height: 100%;
-  width: 100%;
-
-  .clickable-cell {
-    cursor: pointer;
-  }
-
-  .ReactTable {
-    position: absolute;
-    top: $view-control-bar-height + $standard-padding;
-    bottom: 0;
-    width: 100%;
-  }
+.bar-chart-unit {
+  transform: translateX(65px);
 }
diff --git a/web-console/src/visualization/bar-unit.tsx b/web-console/src/visualization/bar-unit.tsx
new file mode 100644
index 0000000..6c43b1c
--- /dev/null
+++ b/web-console/src/visualization/bar-unit.tsx
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import React from 'react';
+
+import './bar-unit.scss';
+
+interface BarChartUnitProps extends React.Props<any> {
+  x: number | undefined;
+  y: number;
+  width: number;
+  height: number;
+  style?: any;
+  onClick?: () => void;
+  onHover?: () => void;
+  offHover?: () => void;
+}
+
+interface BarChartUnitState {}
+
+export class BarUnit extends React.Component<BarChartUnitProps, BarChartUnitState> {
+  constructor(props: BarChartUnitProps) {
+    super(props);
+    this.state = {};
+  }
+
+  render(): JSX.Element {
+    const { x, y, width, height, style, onClick, onHover, offHover } = this.props;
+    return (
+      <g
+        className={`bar-chart-unit`}
+        onClick={onClick}
+        onMouseOver={onHover}
+        onMouseLeave={offHover}
+      >
+        <rect x={x} y={y} width={width} height={height} style={style} />
+      </g>
+    );
+  }
+}
diff --git a/web-console/src/views/datasource-view/datasource-view.scss b/web-console/src/visualization/chart-axis.tsx
similarity index 58%
copy from web-console/src/views/datasource-view/datasource-view.scss
copy to web-console/src/visualization/chart-axis.tsx
index 7c483ce..294a64b 100644
--- a/web-console/src/views/datasource-view/datasource-view.scss
+++ b/web-console/src/visualization/chart-axis.tsx
@@ -16,20 +16,31 @@
  * limitations under the License.
  */
 
-@import '../../variables';
+import * as d3 from 'd3';
+import React from 'react';
 
-.data-sources-view {
-  height: 100%;
-  width: 100%;
+interface ChartAxisProps extends React.Props<any> {
+  transform: string;
+  scale: any;
+  className?: string;
+}
+
+interface ChartAxisState {}
 
-  .clickable-cell {
-    cursor: pointer;
+export class ChartAxis extends React.Component<ChartAxisProps, ChartAxisState> {
+  constructor(props: ChartAxisProps) {
+    super(props);
+    this.state = {};
   }
 
-  .ReactTable {
-    position: absolute;
-    top: $view-control-bar-height + $standard-padding;
-    bottom: 0;
-    width: 100%;
+  render(): JSX.Element {
+    const { transform, scale, className } = this.props;
+    return (
+      <g
+        className={`axis ${className}`}
+        transform={transform}
+        ref={node => d3.select(node).call(scale)}
+      />
+    );
   }
 }
diff --git a/web-console/src/views/datasource-view/datasource-view.scss b/web-console/src/visualization/stacked-bar-chart.scss
similarity index 76%
copy from web-console/src/views/datasource-view/datasource-view.scss
copy to web-console/src/visualization/stacked-bar-chart.scss
index 7c483ce..fed00ae 100644
--- a/web-console/src/views/datasource-view/datasource-view.scss
+++ b/web-console/src/visualization/stacked-bar-chart.scss
@@ -16,20 +16,18 @@
  * limitations under the License.
  */
 
-@import '../../variables';
-
-.data-sources-view {
-  height: 100%;
-  width: 100%;
-
-  .clickable-cell {
-    cursor: pointer;
+.bar-chart {
+  .hovered-bar {
+    fill: transparent;
+    stroke: #ffffff;
+    stroke-width: 1.5px;
+    transform: translateX(65px);
   }
 
-  .ReactTable {
-    position: absolute;
-    top: $view-control-bar-height + $standard-padding;
-    bottom: 0;
-    width: 100%;
+  .gridline-x {
+    line {
+      stroke-dasharray: 5, 5;
+      opacity: 0.5;
+    }
   }
 }
diff --git a/web-console/src/visualization/stacked-bar-chart.tsx b/web-console/src/visualization/stacked-bar-chart.tsx
new file mode 100644
index 0000000..9fdab75
--- /dev/null
+++ b/web-console/src/visualization/stacked-bar-chart.tsx
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import * as d3 from 'd3';
+import { AxisScale } from 'd3';
+import React from 'react';
+
+import { BarChartMargin, BarUnitData } from '../components/segment-timeline/segment-timeline';
+
+import { BarGroup } from './bar-group';
+import { ChartAxis } from './chart-axis';
+
+import './stacked-bar-chart.scss';
+
+interface StackedBarChartProps extends React.Props<any> {
+  svgWidth: number;
+  svgHeight: number;
+  margin: BarChartMargin;
+  activeDataType?: string;
+  dataToRender: BarUnitData[];
+  changeActiveDatasource: (e: string) => void;
+  formatTick: (e: number) => string;
+  xScale: AxisScale<Date>;
+  yScale: AxisScale<number>;
+  barWidth: number;
+}
+
+interface StackedBarChartState {
+  width: number;
+  height: number;
+  hoverOn?: HoveredBarInfo | null;
+}
+
+export interface HoveredBarInfo {
+  xCoordinate?: number;
+  yCoordinate?: number;
+  height?: number;
+  width?: number;
+  datasource?: string;
+  xValue?: number;
+  yValue?: number;
+}
+
+export class StackedBarChart extends React.Component<StackedBarChartProps, StackedBarChartState> {
+  constructor(props: StackedBarChartProps) {
+    super(props);
+    this.state = {
+      width: this.props.svgWidth - this.props.margin.left - this.props.margin.right,
+      height: this.props.svgHeight - this.props.margin.bottom - this.props.margin.top,
+    };
+  }
+
+  componentWillReceiveProps(nextProps: StackedBarChartProps): void {
+    if (nextProps !== this.props) {
+      this.setState({
+        width: nextProps.svgWidth - this.props.margin.left - this.props.margin.right,
+        height: nextProps.svgHeight - this.props.margin.bottom - this.props.margin.top,
+      });
+    }
+  }
+
+  renderBarChart() {
+    const {
+      svgWidth,
+      svgHeight,
+      formatTick,
+      xScale,
+      yScale,
+      dataToRender,
+      changeActiveDatasource,
+      barWidth,
+    } = this.props;
+    const { width, height, hoverOn } = this.state;
+    return (
+      <div className={'bar-chart-container'}>
+        <svg
+          width={width}
+          height={height}
+          viewBox={`0 0 ${svgWidth} ${svgHeight}`}
+          preserveAspectRatio={'xMinYMin meet'}
+          style={{ marginTop: '20px' }}
+        >
+          <ChartAxis
+            className={'gridline-x'}
+            transform={'translate(60, 0)'}
+            scale={d3
+              .axisLeft(yScale)
+              .ticks(5)
+              .tickSize(-width)
+              .tickFormat(() => '')
+              .tickSizeOuter(0)}
+          />
+          <ChartAxis
+            className={'axis--x'}
+            transform={`translate(65, ${height})`}
+            scale={d3.axisBottom(xScale)}
+          />
+          <ChartAxis
+            className={'axis--y'}
+            transform={'translate(60, 0)'}
+            scale={d3
+              .axisLeft(yScale)
+              .ticks(5)
+              .tickFormat((e: number) => formatTick(e))}
+          />
+          <g className="bars-group" onMouseLeave={() => this.setState({ hoverOn: null })}>
+            <BarGroup
+              dataToRender={dataToRender}
+              changeActiveDatasource={changeActiveDatasource}
+              formatTick={formatTick}
+              xScale={xScale}
+              yScale={yScale}
+              onHoverBar={(e: HoveredBarInfo) => this.setState({ hoverOn: e })}
+              hoverOn={hoverOn}
+              barWidth={barWidth}
+            />
+            {hoverOn && (
+              <g
+                className={'hovered-bar'}
+                onClick={() => {
+                  this.setState({ hoverOn: null });
+                  changeActiveDatasource(hoverOn.datasource as string);
+                }}
+              >
+                <rect
+                  x={hoverOn.xCoordinate}
+                  y={hoverOn.yCoordinate}
+                  width={barWidth}
+                  height={hoverOn.height}
+                />
+              </g>
+            )}
+          </g>
+        </svg>
+      </div>
+    );
+  }
+
+  render(): JSX.Element {
+    const { activeDataType, formatTick } = this.props;
+    const { hoverOn } = this.state;
+    return (
+      <div className={'bar-chart'}>
+        <div className={'bar-chart-tooltip'}>
+          <div>Datasource: {hoverOn ? hoverOn.datasource : ''}</div>
+          <div>Time: {hoverOn ? hoverOn.xValue : ''}</div>
+          <div>
+            {`${activeDataType === 'countData' ? 'Count:' : 'Size:'} ${
+              hoverOn ? formatTick(hoverOn.yValue as number) : ''
+            }`}
+          </div>
+        </div>
+        {this.renderBarChart()}
+      </div>
+    );
+  }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@druid.apache.org
For additional commands, e-mail: commits-help@druid.apache.org