You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@superset.apache.org by GitBox <gi...@apache.org> on 2018/08/02 17:34:38 UTC

[GitHub] williaster closed pull request #5469: Update BigNumber

williaster closed pull request #5469: Update BigNumber 
URL: https://github.com/apache/incubator-superset/pull/5469
 
 
   

This is a PR merged from a forked repository.
As GitHub hides the original diff on merge, it is displayed below for
the sake of provenance:

As this is a foreign pull request (from a fork), the diff is supplied
below (as it won't show otherwise due to GitHub magic):

diff --git a/superset/assets/package.json b/superset/assets/package.json
index c427a6dfc5..7eaa845e4b 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -45,6 +45,7 @@
   "dependencies": {
     "@data-ui/event-flow": "^0.0.54",
     "@data-ui/sparkline": "^0.0.54",
+    "@data-ui/xy-chart": "^0.0.61",
     "@vx/responsive": "0.0.153",
     "babel-register": "^6.24.1",
     "bootstrap": "^3.3.6",
diff --git a/superset/assets/src/modules/visUtils.js b/superset/assets/src/modules/visUtils.js
index 974417966c..62e5725eeb 100644
--- a/superset/assets/src/modules/visUtils.js
+++ b/superset/assets/src/modules/visUtils.js
@@ -1,14 +1,105 @@
-export function getTextWidth(text, fontDetails = '12px Roboto') {
-  const canvas = document.createElement('canvas');
-  const context = canvas.getContext('2d');
-  if (context) {
-    // Won't work outside of a browser context (ie unit tests)
-    context.font = fontDetails;
-    return context.measureText(text).width;
+const SVG_NS = 'http://www.w3.org/2000/svg';
+
+function isDefined(x) {
+  return x !== null && x !== undefined;
+}
+
+export function getTextDimension({
+  text,
+  className,
+  style,
+  container = document.body,
+}) {
+  const textNode = document.createElementNS(SVG_NS, 'text');
+  textNode.textContent = text;
+
+  if (isDefined(className)) {
+    textNode.setAttribute('class', className);
+  }
+
+  if (isDefined(style)) {
+    ['font', 'fontWeight', 'fontStyle', 'fontSize', 'fontFamily']
+      .filter(field => isDefined(style[field]))
+      .forEach((field) => {
+        textNode.style[field] = style[field];
+      });
+  }
+
+  const svg = document.createElementNS(SVG_NS, 'svg');
+  svg.style.position = 'absolute'; // so it won't disrupt page layout
+  svg.style.opacity = 0;           // and not visible
+  svg.appendChild(textNode);
+  container.appendChild(svg);
+  let result;
+  if (textNode.getBBox) {
+    const bbox = textNode.getBBox();
+    // round up
+    result = {
+      width: Math.ceil(bbox.width),
+      height: Math.ceil(bbox.height),
+    };
+  } else {
+    // Handle when called from non-browser and do not support getBBox()
+    result = {
+      width: 100,
+      height: 100,
+    };
   }
-  return 100;
+  container.removeChild(svg);
+  return result;
+}
+
+/**
+ * Shim to support legacy calls
+ */
+export function getTextWidth(text, font = '12px Roboto') {
+  return getTextDimension({ text, style: { font } }).width;
 }
 
-export default {
-  getTextWidth,
-};
+export function computeMaxFontSize({
+  text,
+  idealFontSize,
+  maxWidth,
+  maxHeight,
+  className,
+  style,
+  container,
+}) {
+  let size = idealFontSize;
+  if (!isDefined(idealFontSize)) {
+    if (isDefined(maxHeight)) {
+      size = Math.floor(maxHeight);
+    } else {
+      throw new Error('You must specify at least one of maxHeight or idealFontSize');
+    }
+  }
+
+  function computeDimension(fontSize) {
+    return getTextDimension({
+      text,
+      className,
+      style: { ...style, fontSize },
+      container,
+    });
+  }
+
+  let textDimension = computeDimension(size);
+
+  // Decrease size until textWidth is less than maxWidth
+  if (isDefined(maxWidth)) {
+    while (textDimension.width > maxWidth) {
+      size -= 2;
+      textDimension = computeDimension(size);
+    }
+  }
+
+  // Decrease size until textHeight is less than maxHeight
+  if (isDefined(maxHeight)) {
+    while (textDimension.height > maxHeight) {
+      size -= 2;
+      textDimension = computeDimension(size);
+    }
+  }
+
+  return size;
+}
diff --git a/superset/assets/src/visualizations/BigNumber.jsx b/superset/assets/src/visualizations/BigNumber.jsx
new file mode 100644
index 0000000000..6b3e5b79ce
--- /dev/null
+++ b/superset/assets/src/visualizations/BigNumber.jsx
@@ -0,0 +1,274 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import ReactDOM from 'react-dom';
+import { XYChart, AreaSeries, CrossHair, LinearGradient } from '@data-ui/xy-chart';
+
+import { brandColor } from '../modules/colors';
+import { d3FormatPreset } from '../modules/utils';
+import { formatDateVerbose } from '../modules/dates';
+import { computeMaxFontSize } from '../modules/visUtils';
+
+import './big_number.css';
+
+const CHART_MARGIN = {
+  top: 4,
+  right: 4,
+  bottom: 4,
+  left: 4,
+};
+
+const PROPORTION = {
+  HEADER: 0.4,
+  SUBHEADER: 0.14,
+  HEADER_WITH_TRENDLINE: 0.3,
+  SUBHEADER_WITH_TRENDLINE: 0.125,
+  TRENDLINE: 0.3,
+};
+
+function renderTooltipFactory(formatValue) {
+  return function renderTooltip({ datum }) { // eslint-disable-line
+    const { x: rawDate, y: rawValue } = datum;
+    const formattedDate = formatDateVerbose(rawDate);
+    const value = formatValue(rawValue);
+
+    return (
+      <div style={{ padding: '4px 8px' }}>
+        {formattedDate}
+        <br />
+        <strong>{value}</strong>
+      </div>
+    );
+  };
+}
+
+function identity(x) {
+  return x;
+}
+
+const propTypes = {
+  className: PropTypes.string,
+  width: PropTypes.number.isRequired,
+  height: PropTypes.number.isRequired,
+  bigNumber: PropTypes.number.isRequired,
+  formatBigNumber: PropTypes.func,
+  subheader: PropTypes.string,
+  showTrendline: PropTypes.bool,
+  trendlineData: PropTypes.array,
+  mainColor: PropTypes.string,
+  gradientId: PropTypes.string,
+  renderTooltip: PropTypes.func,
+};
+const defaultProps = {
+  className: '',
+  formatBigNumber: identity,
+  subheader: '',
+  showTrendline: false,
+  trendlineData: null,
+  mainColor: brandColor,
+  gradientId: '',
+  renderTooltip: renderTooltipFactory(identity),
+};
+
+class BigNumberVis extends React.Component {
+  getClassName() {
+    const { className, showTrendline } = this.props;
+    const names = `big_number ${className}`;
+    if (showTrendline) {
+      return names;
+    }
+    return `${names} no_trendline`;
+  }
+
+  createTemporaryContainer() {
+    const container = document.createElement('div');
+    container.className = this.getClassName();
+    container.style.position = 'absolute'; // so it won't disrupt page layout
+    container.style.opacity = 0;           // and not visible
+    return container;
+  }
+
+  renderHeader(maxHeight) {
+    const { bigNumber, formatBigNumber, width } = this.props;
+    const text = formatBigNumber(bigNumber);
+
+    const container = this.createTemporaryContainer();
+    document.body.appendChild(container);
+    const fontSize = computeMaxFontSize({
+      text,
+      maxWidth: width,
+      maxHeight,
+      className: 'header_line',
+      container,
+    });
+    document.body.removeChild(container);
+
+    return (
+      <div
+        className="header_line"
+        style={{
+          fontSize,
+          height: maxHeight,
+        }}
+      >
+        <span>{text}</span>
+      </div>
+    );
+  }
+
+  renderSubheader(maxHeight) {
+    const { subheader, width } = this.props;
+    let fontSize = 0;
+    if (subheader) {
+      const container = this.createTemporaryContainer();
+      document.body.appendChild(container);
+      fontSize = computeMaxFontSize({
+        text: subheader,
+        maxWidth: width,
+        maxHeight,
+        className: 'subheader_line',
+        container,
+      });
+      document.body.removeChild(container);
+    }
+
+    return (
+      <div
+        className="subheader_line"
+        style={{
+          fontSize,
+          height: maxHeight,
+        }}
+      >
+        {subheader}
+      </div>
+    );
+  }
+
+  renderTrendline(maxHeight) {
+    const {
+      width,
+      trendlineData,
+      mainColor,
+      subheader,
+      renderTooltip,
+      gradientId,
+    } = this.props;
+    return (
+      <XYChart
+        ariaLabel={`Big number visualization ${subheader}`}
+        xScale={{ type: 'timeUtc' }}
+        yScale={{ type: 'linear' }}
+        width={width}
+        height={maxHeight}
+        margin={CHART_MARGIN}
+        renderTooltip={renderTooltip}
+        snapTooltipToDataX
+      >
+        <LinearGradient
+          id={gradientId}
+          from={mainColor}
+          to="#fff"
+        />
+        <AreaSeries
+          data={trendlineData}
+          fill={`url(#${gradientId})`}
+          stroke={mainColor}
+        />
+        <CrossHair
+          stroke={mainColor}
+          circleFill={mainColor}
+          circleStroke="#fff"
+          showHorizontalLine={false}
+          fullHeight
+          strokeDasharray="5,2"
+        />
+      </XYChart>
+    );
+  }
+
+  render() {
+    const { showTrendline, height } = this.props;
+    const className = this.getClassName();
+
+    if (showTrendline) {
+      const chartHeight = Math.floor(PROPORTION.TRENDLINE * height);
+      const allTextHeight = height - chartHeight;
+      return (
+        <div className={className}>
+          <div
+            className="text_container"
+            style={{ height: allTextHeight }}
+          >
+            {this.renderHeader(Math.ceil(PROPORTION.HEADER_WITH_TRENDLINE * height))}
+            {this.renderSubheader(Math.ceil(PROPORTION.SUBHEADER_WITH_TRENDLINE * height))}
+          </div>
+          {this.renderTrendline(chartHeight)}
+        </div>
+      );
+    }
+    return (
+      <div
+        className={className}
+        style={{ height }}
+      >
+        {this.renderHeader(Math.ceil(PROPORTION.HEADER * height))}
+        {this.renderSubheader(Math.ceil(PROPORTION.SUBHEADER * height))}
+      </div>
+    );
+  }
+}
+
+BigNumberVis.propTypes = propTypes;
+BigNumberVis.defaultProps = defaultProps;
+
+function adaptor(slice, payload) {
+  const { formData, containerId } = slice;
+  const { data, subheader, compare_suffix: compareSuffix } = payload.data;
+  const compareLag = Number(payload.data.compare_lag);
+  const supportTrendline = formData.viz_type === 'big_number';
+  const showTrendline = supportTrendline && formData.show_trend_line;
+  const formatValue = d3FormatPreset(formData.y_axis_format);
+  const bigNumber = supportTrendline ? data[data.length - 1][1] : data[0][0];
+
+  let percentChange = 0;
+  let formattedSubheader = subheader;
+
+  if (supportTrendline && compareLag > 0) {
+    const compareIndex = data.length - (compareLag + 1);
+    if (compareIndex >= 0) {
+      const compareValue = data[compareIndex][1];
+      percentChange = compareValue === 0
+        ? 0 : (bigNumber - compareValue) / Math.abs(compareValue);
+      const formatPercentChange = d3.format('+.1%');
+      formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`;
+    }
+  }
+
+  const trendlineData = showTrendline ? data.map(([x, y]) => ({ x, y })) : null;
+
+  let className = '';
+  if (percentChange > 0) {
+    className = 'positive';
+  } else if (percentChange < 0) {
+    className = 'negative';
+  }
+
+  ReactDOM.render(
+    <BigNumberVis
+      className={className}
+      width={slice.width()}
+      height={slice.height()}
+      bigNumber={bigNumber}
+      formatBigNumber={formatValue}
+      subheader={formattedSubheader}
+      showTrendline={showTrendline}
+      trendlineData={trendlineData}
+      mainColor={brandColor}
+      gradientId={`big_number_${containerId}`}
+      renderTooltip={renderTooltipFactory(formatValue)}
+    />,
+    document.getElementById(containerId),
+  );
+}
+
+export default adaptor;
diff --git a/superset/assets/src/visualizations/big_number.css b/superset/assets/src/visualizations/big_number.css
index 8fd5345ee7..d748137fd7 100644
--- a/superset/assets/src/visualizations/big_number.css
+++ b/superset/assets/src/visualizations/big_number.css
@@ -1,31 +1,38 @@
-.big_number g.axis text,
-.big_number_total g.axis text {
-  font-size: 10px;
-  font-weight: normal;
-  color: gray;
-  fill: gray;
-  text-anchor: middle;
-  alignment-baseline: middle;
-  font-weight: none;
+.big_number {
+  font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Open Sans,Helvetica Neue,sans-serif;
+  position: relative;
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
 }
 
-.big_number text.big,
-.big_number_total text.big{
-  stroke: black;
-  text-anchor: middle;
-  fill: black;
+.big_number.no_trendline .subheader_line {
+  padding-bottom: 0.3em;
 }
 
-.big_number g.tick line,
-.big_number_total g.tick line{
-  stroke-width: 1px;
-  stroke: grey;
+.big_number .text_container {
+  overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  justify-content: center;
 }
 
-.big_number .domain,
-.big_number_total .domain{
-  fill: none;
-  stroke: black;
-  stroke-width: 1;
+.big_number .header_line {
+  position: relative;
+  line-height: 1em;
+  font-weight: 600;
 }
 
+.big_number .header_line span {
+  position: absolute;
+  bottom: 0;
+  left: 0;
+  right: 0;
+}
+
+.big_number .subheader_line {
+  line-height: 1em;
+  padding-bottom: 0;
+  font-weight: 200;
+}
diff --git a/superset/assets/src/visualizations/big_number.js b/superset/assets/src/visualizations/big_number.js
deleted file mode 100644
index cd02ec915e..0000000000
--- a/superset/assets/src/visualizations/big_number.js
+++ /dev/null
@@ -1,231 +0,0 @@
-import d3 from 'd3';
-import d3tip from 'd3-tip';
-import dompurify from 'dompurify';
-import { d3FormatPreset, d3TimeFormatPreset } from '../modules/utils';
-
-import './big_number.css';
-import '../../stylesheets/d3tip.css';
-
-function bigNumberVis(slice, payload) {
-  const div = d3.select(slice.selector);
-  // Define the percentage bounds that define color from red to green
-  div.html(''); // reset
-  const fd = slice.formData;
-  const json = payload.data;
-
-  const f = d3FormatPreset(fd.y_axis_format);
-  const fp = d3.format('+.1%');
-  const formatDate = d3TimeFormatPreset('smart_date');
-  const width = slice.width();
-  const height = slice.height();
-  const svg = div.append('svg');
-  svg.attr('width', width);
-  svg.attr('height', height);
-  const data = json.data;
-  let vCompare;
-  let v;
-  if (fd.viz_type === 'big_number') {
-    v = data[data.length - 1][1];
-  } else {
-    v = data[0][0];
-  }
-  if (json.compare_lag > 0) {
-    const pos = data.length - (json.compare_lag + 1);
-    if (pos >= 0) {
-      const vAnchor = data[pos][1];
-      if (vAnchor !== 0) {
-        vCompare = (v - vAnchor) / Math.abs(vAnchor);
-      } else {
-        vCompare = 0;
-      }
-    }
-  }
-  const dateExt = d3.extent(data, d => d[0]);
-  const valueExt = d3.extent(data, d => d[1]);
-
-  const vMargin = 20;
-  const hMargin = 10;
-  const scaleX = d3.time.scale.utc().domain(dateExt).range([hMargin, width - hMargin]);
-  const scaleY = d3.scale.linear().domain(valueExt).range([height - (vMargin), vMargin]);
-  const colorRange = [d3.hsl(0, 1, 0.3), d3.hsl(120, 1, 0.3)];
-  const scaleColor = d3.scale
-  .linear().domain([-1, 1])
-  .interpolate(d3.interpolateHsl)
-  .range(colorRange)
-  .clamp(true);
-  const line = d3.svg.line()
-  .x(function (d) {
-    return scaleX(d[0]);
-  })
-  .y(function (d) {
-    return scaleY(d[1]);
-  })
-  .interpolate('cardinal');
-
-  let y = height / 2;
-  let g = svg.append('g');
-  // Printing big number
-  g.append('g').attr('class', 'digits')
-  .attr('opacity', 1)
-  .append('text')
-  .attr('x', width / 2)
-  .attr('y', y)
-  .attr('class', 'big')
-  .attr('alignment-baseline', 'middle')
-  .attr('id', 'bigNumber')
-  .style('font-weight', 'bold')
-  .style('cursor', 'pointer')
-  .text(f(v))
-  .style('font-size', d3.min([height, width]) / 3.5)
-  .style('text-anchor', 'middle')
-  .attr('fill', 'black');
-
-  // Printing big number subheader text
-  if (json.subheader !== null) {
-    g.append('text')
-    .attr('x', width / 2)
-    .attr('y', (height / 16) * 12)
-    .text(json.subheader)
-    .attr('id', 'subheader_text')
-    .style('font-size', d3.min([height, width]) / 8)
-    .style('text-anchor', 'middle');
-  }
-
-  if (fd.viz_type === 'big_number') {
-    // Drawing trend line
-    if (fd.show_trend_line) {
-      g.append('path')
-        .attr('d', function () {
-          return line(data);
-        })
-        .attr('stroke-width', 5)
-        .attr('opacity', 0.5)
-        .attr('fill', 'none')
-        .attr('stroke-linecap', 'round')
-        .attr('stroke', 'grey');
-
-      g = svg.append('g')
-        .attr('class', 'digits')
-        .attr('opacity', 1);
-
-      if (vCompare !== null) {
-        y = (height / 8) * 3;
-      }
-    }
-
-    const c = scaleColor(vCompare);
-
-    // Printing compare %
-    if (vCompare) {
-      g.append('text')
-      .attr('x', width / 2)
-      .attr('y', (height / 16) * 12)
-      .text(fp(vCompare) + json.compare_suffix)
-      .style('font-size', d3.min([height, width]) / 8)
-      .style('text-anchor', 'middle')
-      .attr('fill', c)
-      .attr('stroke', c);
-    }
-
-    const gAxis = svg.append('g').attr('class', 'axis').attr('opacity', 0);
-    g = gAxis.append('g');
-    const xAxis = d3.svg.axis()
-    .scale(scaleX)
-    .orient('bottom')
-    .ticks(Math.round(2 + (width / 150)))
-    .tickFormat(formatDate);
-    g.call(xAxis);
-    g.attr('transform', 'translate(0,' + (height - vMargin) + ')');
-
-    g = gAxis.append('g').attr('transform', 'translate(' + (width - hMargin) + ',0)');
-    const yAxis = d3.svg.axis()
-    .scale(scaleY)
-    .orient('left')
-    .tickFormat(f)
-    .tickValues(valueExt);
-
-    g.call(yAxis);
-    g.selectAll('text')
-    .style('text-anchor', 'end')
-    .attr('y', '-7')
-    .attr('x', '-4');
-
-    g.selectAll('text')
-    .style('font-size', '10px');
-
-    const renderTooltip = (d) => {
-      const date = formatDate(d[0]);
-      const value = dompurify.sanitize(f(d[1]));
-      return `
-        <div>
-          <span style="margin-right: 10px;">${date}: </span>
-          <strong>${value}</strong>
-        </div>
-      `;
-    };
-
-    const tip = d3tip()
-      .attr('class', 'd3-tip')
-      .direction('n')
-      .offset([-5, 0])
-      .html(renderTooltip);
-    svg.call(tip);
-
-    // Add the scatterplot and trigger the mouse events for the tooltips
-    svg
-      .selectAll('dot')
-      .data(data)
-      .enter()
-      .append('circle')
-      .attr('r', 3)
-      .attr('stroke-width', 15)
-      .attr('stroke', 'transparent')
-      .attr('stroke-location', 'outside')
-      .attr('cx', d => scaleX(d[0]))
-      .attr('cy', d => scaleY(d[1]))
-      .attr('fill-opacity', 0)
-      .on('mouseover', function (d) {
-        d3.select(this).attr('fill-opacity', 1);
-        tip.show(d, this);
-      })
-      .on('mouseout', function (d) {
-        d3.select(this).attr('fill-opacity', 0);
-        tip.hide(d, this);
-      });
-
-    div.on('mouseover', function () {
-      const el = d3.select(this);
-      el.selectAll('path')
-      .transition()
-      .duration(500)
-      .attr('opacity', 1)
-      .style('stroke-width', '2px');
-      el.selectAll('g.digits')
-      .transition()
-      .duration(500)
-      .attr('opacity', 0.1);
-      el.selectAll('g.axis')
-      .transition()
-      .duration(500)
-      .attr('opacity', 1);
-    })
-    .on('mouseout', function () {
-      const el = d3.select(this);
-      el.select('path')
-      .transition()
-      .duration(500)
-      .attr('opacity', 0.5)
-      .style('stroke-width', '5px');
-      el.selectAll('g.digits')
-      .transition()
-      .duration(500)
-      .attr('opacity', 1);
-      el.selectAll('g.axis')
-      .transition()
-      .duration(500)
-      .attr('opacity', 0);
-    });
-  }
-}
-
-module.exports = bigNumberVis;
diff --git a/superset/assets/src/visualizations/index.js b/superset/assets/src/visualizations/index.js
index 002db6386f..098079ea50 100644
--- a/superset/assets/src/visualizations/index.js
+++ b/superset/assets/src/visualizations/index.js
@@ -65,9 +65,9 @@ const vizMap = {
   [VIZ_TYPES.area]: loadNvd3,
   [VIZ_TYPES.bar]: loadNvd3,
   [VIZ_TYPES.big_number]: () =>
-    loadVis(import(/* webpackChunkName: 'big_number' */ './big_number.js')),
+    loadVis(import(/* webpackChunkName: 'big_number' */ './BigNumber.jsx')),
   [VIZ_TYPES.big_number_total]: () =>
-    loadVis(import(/* webpackChunkName: "big_number" */ './big_number.js')),
+    loadVis(import(/* webpackChunkName: "big_number" */ './BigNumber.jsx')),
   [VIZ_TYPES.box_plot]: loadNvd3,
   [VIZ_TYPES.bubble]: loadNvd3,
   [VIZ_TYPES.bullet]: loadNvd3,
diff --git a/superset/assets/yarn.lock b/superset/assets/yarn.lock
index 11e645613f..e27a87dd31 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -32,6 +32,13 @@
   dependencies:
     "@babel/types" "7.0.0-beta.44"
 
+"@babel/helper-module-imports@^7.0.0-beta.49":
+  version "7.0.0-beta.54"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0-beta.54.tgz#c2d8e14ff034225bf431356db77ef467b8d35aac"
+  dependencies:
+    "@babel/types" "7.0.0-beta.54"
+    lodash "^4.17.5"
+
 "@babel/helper-split-export-declaration@7.0.0-beta.44":
   version "7.0.0-beta.44"
   resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.0.0-beta.44.tgz#c0b351735e0fbcb3822c8ad8db4e583b05ebd9dc"
@@ -78,6 +85,14 @@
     lodash "^4.2.0"
     to-fast-properties "^2.0.0"
 
+"@babel/types@7.0.0-beta.54", "@babel/types@^7.0.0-beta.49":
+  version "7.0.0-beta.54"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.0.0-beta.54.tgz#025ad68492fed542c13f14c579a44c848e531063"
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.5"
+    to-fast-properties "^2.0.0"
+
 "@data-ui/event-flow@^0.0.54":
   version "0.0.54"
   resolved "https://registry.yarnpkg.com/@data-ui/event-flow/-/event-flow-0.0.54.tgz#bb03e1fd2b5634248655b8df9d3c6c38a747e65e"
@@ -143,6 +158,19 @@
     d3-array "^1.2.1"
     prop-types "^15.5.10"
 
+"@data-ui/shared@^0.0.61":
+  version "0.0.61"
+  resolved "https://registry.yarnpkg.com/@data-ui/shared/-/shared-0.0.61.tgz#717a1a1f7bd606c0f51573e65b6acdda51a1252b"
+  dependencies:
+    "@data-ui/theme" "^0.0.61"
+    "@vx/event" "^0.0.165"
+    "@vx/group" "^0.0.165"
+    "@vx/shape" "^0.0.168"
+    "@vx/tooltip" "0.0.165"
+    babel-runtime "^6.26.0"
+    d3-array "^1.2.1"
+    prop-types "^15.5.10"
+
 "@data-ui/sparkline@^0.0.54":
   version "0.0.54"
   resolved "https://registry.yarnpkg.com/@data-ui/sparkline/-/sparkline-0.0.54.tgz#ce3d166d9e0b239a0ba02f3894cb9e8c84171cef"
@@ -171,6 +199,37 @@
   version "0.0.8"
   resolved "https://registry.yarnpkg.com/@data-ui/theme/-/theme-0.0.8.tgz#3116723d04b99f65c7750f81a500e9608b4837c3"
 
+"@data-ui/theme@^0.0.61":
+  version "0.0.61"
+  resolved "https://registry.yarnpkg.com/@data-ui/theme/-/theme-0.0.61.tgz#2a792da6c384d08553d1794bdb16ce633bc02cbd"
+  dependencies:
+    babel-runtime "^6.26.0"
+
+"@data-ui/xy-chart@^0.0.61":
+  version "0.0.61"
+  resolved "https://registry.yarnpkg.com/@data-ui/xy-chart/-/xy-chart-0.0.61.tgz#ee4e47913116a03a7bc4fc0ff1b0d815f80ee736"
+  dependencies:
+    "@data-ui/shared" "^0.0.61"
+    "@data-ui/theme" "^0.0.61"
+    "@vx/axis" "^0.0.168"
+    "@vx/curve" "^0.0.165"
+    "@vx/event" "^0.0.165"
+    "@vx/glyph" "^0.0.165"
+    "@vx/gradient" "^0.0.165"
+    "@vx/grid" "^0.0.169"
+    "@vx/group" "^0.0.165"
+    "@vx/pattern" "^0.0.165"
+    "@vx/point" "^0.0.165"
+    "@vx/responsive" "^0.0.165"
+    "@vx/scale" "^0.0.165"
+    "@vx/shape" "^0.0.165"
+    "@vx/stats" "^0.0.165"
+    "@vx/tooltip" "^0.0.165"
+    "@vx/voronoi" "^0.0.165"
+    babel-runtime "^6.26.0"
+    d3-array "^1.2.0"
+    prop-types "^15.5.10"
+
 "@deck.gl/core@^5.3.1":
   version "5.3.1"
   resolved "https://registry.yarnpkg.com/@deck.gl/core/-/core-5.3.1.tgz#acfc1e5fefd3b12e9142419b0aeb77c07885626c"
@@ -282,6 +341,17 @@
     classnames "^2.2.5"
     prop-types "15.5.10"
 
+"@vx/axis@^0.0.168":
+  version "0.0.168"
+  resolved "https://registry.yarnpkg.com/@vx/axis/-/axis-0.0.168.tgz#fd8c88a2b584b314aaf1ce2023eaebad05304188"
+  dependencies:
+    "@vx/group" "0.0.165"
+    "@vx/point" "0.0.165"
+    "@vx/shape" "0.0.168"
+    "@vx/text" "0.0.165"
+    classnames "^2.2.5"
+    prop-types "^15.6.0"
+
 "@vx/bounds@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/bounds/-/bounds-0.0.140.tgz#4ede9766aabb41b791a4fbf4c27fcc19ed83f910"
@@ -294,6 +364,12 @@
   dependencies:
     prop-types "^15.5.10"
 
+"@vx/bounds@0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/bounds/-/bounds-0.0.165.tgz#75f107a6deb58223c6878db5053382eff3174567"
+  dependencies:
+    prop-types "^15.5.10"
+
 "@vx/clip-path@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/clip-path/-/clip-path-0.0.140.tgz#b2623d004dd5c3c8a6afe8d060de59df51472d94"
@@ -310,6 +386,12 @@
   dependencies:
     d3-shape "^1.0.6"
 
+"@vx/curve@0.0.165", "@vx/curve@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/curve/-/curve-0.0.165.tgz#330d1512dceae0af43dd3eb4c85523132030a3a0"
+  dependencies:
+    d3-shape "^1.0.6"
+
 "@vx/event@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/event/-/event-0.0.140.tgz#658ec4de92cd61df40b883296168d4e0824015bf"
@@ -322,6 +404,12 @@
   dependencies:
     "@vx/point" "0.0.143"
 
+"@vx/event@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/event/-/event-0.0.165.tgz#675d89fdfdc08d0c99c36ff1a381ea50fccfba2e"
+  dependencies:
+    "@vx/point" "0.0.165"
+
 "@vx/glyph@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/glyph/-/glyph-0.0.140.tgz#f8323f82aee22192b675bef25789bbb7d74691ba"
@@ -330,6 +418,14 @@
     classnames "^2.2.5"
     d3-shape "^1.2.0"
 
+"@vx/glyph@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/glyph/-/glyph-0.0.165.tgz#ba6fe31700dae852c60468e00dd732fa7521d1fc"
+  dependencies:
+    "@vx/group" "0.0.165"
+    classnames "^2.2.5"
+    d3-shape "^1.2.0"
+
 "@vx/gradient@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/gradient/-/gradient-0.0.140.tgz#56b421016cbae0dcb00190cfffb9e860a28febf4"
@@ -337,6 +433,13 @@
     classnames "^2.2.5"
     prop-types "^15.5.7"
 
+"@vx/gradient@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/gradient/-/gradient-0.0.165.tgz#0cc0fe873e6acded4943fa274f68601ad5a50a38"
+  dependencies:
+    classnames "^2.2.5"
+    prop-types "^15.5.7"
+
 "@vx/grid@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/grid/-/grid-0.0.140.tgz#9dfd3071bc5d90d4b457dd55d7f795699233b230"
@@ -346,6 +449,15 @@
     "@vx/shape" "0.0.140"
     classnames "^2.2.5"
 
+"@vx/grid@^0.0.169":
+  version "0.0.169"
+  resolved "https://registry.yarnpkg.com/@vx/grid/-/grid-0.0.169.tgz#241b9edb3894394af2e142a1280a05f6ccfd2163"
+  dependencies:
+    "@vx/group" "0.0.165"
+    "@vx/point" "0.0.165"
+    "@vx/shape" "0.0.168"
+    classnames "^2.2.5"
+
 "@vx/group@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/group/-/group-0.0.140.tgz#cba9b0b3f2f007e5be7346f3c86f73f70e038a23"
@@ -358,6 +470,12 @@
   dependencies:
     classnames "^2.2.5"
 
+"@vx/group@0.0.165", "@vx/group@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/group/-/group-0.0.165.tgz#2342523225de94859b5be49c3072dc6bb6795e78"
+  dependencies:
+    classnames "^2.2.5"
+
 "@vx/legend@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/legend/-/legend-0.0.140.tgz#4062c27d6bc9c4d607309d77eff12b844727ae99"
@@ -373,6 +491,13 @@
     classnames "^2.2.5"
     prop-types "^15.5.10"
 
+"@vx/pattern@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/pattern/-/pattern-0.0.165.tgz#0d317cb9a13205e35691f702442739ff0256711d"
+  dependencies:
+    classnames "^2.2.5"
+    prop-types "^15.5.10"
+
 "@vx/point@0.0.136":
   version "0.0.136"
   resolved "https://registry.yarnpkg.com/@vx/point/-/point-0.0.136.tgz#93b325b4b95c9d5b96df740f4204017f57396559"
@@ -381,6 +506,10 @@
   version "0.0.143"
   resolved "https://registry.yarnpkg.com/@vx/point/-/point-0.0.143.tgz#7b6dfa611175ee1b74e3c392072589a79dadf265"
 
+"@vx/point@0.0.165", "@vx/point@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/point/-/point-0.0.165.tgz#7ebde5da3d86954fe31a56f923f31550f0b4b867"
+
 "@vx/responsive@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/responsive/-/responsive-0.0.140.tgz#c73ec68b9e89a181605f1ac9ecc09f35216779a8"
@@ -394,12 +523,26 @@
     lodash "^4.0.8"
     resize-observer-polyfill "1.5.0"
 
+"@vx/responsive@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/responsive/-/responsive-0.0.165.tgz#04b17a52be102a75fc036a8ed3f5db1efd4e8ee5"
+  dependencies:
+    lodash "^4.17.10"
+    prop-types "^15.6.1"
+    resize-observer-polyfill "1.5.0"
+
 "@vx/scale@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/scale/-/scale-0.0.140.tgz#1eb087d11d0000b250c2cdc4061b9e2212edb10d"
   dependencies:
     d3-scale "^1.0.5"
 
+"@vx/scale@0.0.165", "@vx/scale@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/scale/-/scale-0.0.165.tgz#8575880c48296a80c0e9459057f826e8f903bc07"
+  dependencies:
+    d3-scale "^2.0.0"
+
 "@vx/shape@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/shape/-/shape-0.0.140.tgz#6a282d5fdf3a5752b6e938bb3debe983e89ff6d3"
@@ -422,6 +565,48 @@
     d3-shape "^1.2.0"
     prop-types "^15.5.10"
 
+"@vx/shape@0.0.168", "@vx/shape@^0.0.168":
+  version "0.0.168"
+  resolved "https://registry.yarnpkg.com/@vx/shape/-/shape-0.0.168.tgz#172bc1cf4dade47076018efd559e0ecc4e959aec"
+  dependencies:
+    "@vx/curve" "0.0.165"
+    "@vx/group" "0.0.165"
+    "@vx/point" "0.0.165"
+    classnames "^2.2.5"
+    d3-path "^1.0.5"
+    d3-shape "^1.2.0"
+    prop-types "^15.5.10"
+
+"@vx/shape@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/shape/-/shape-0.0.165.tgz#3424121f45d83dd8e7ba62b6adf8b0aea2fb9cf8"
+  dependencies:
+    "@vx/curve" "0.0.165"
+    "@vx/group" "0.0.165"
+    "@vx/point" "0.0.165"
+    classnames "^2.2.5"
+    d3-path "^1.0.5"
+    d3-shape "^1.2.0"
+    prop-types "^15.5.10"
+
+"@vx/stats@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/stats/-/stats-0.0.165.tgz#32413a144383367e51628bbea61b3b0ce980f1fd"
+  dependencies:
+    "@vx/group" "0.0.165"
+    "@vx/scale" "0.0.165"
+    classnames "^2.2.5"
+    d3-shape "^1.2.0"
+
+"@vx/text@0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/text/-/text-0.0.165.tgz#e7f22979a1e744216be1a535414752c2ceb2f97a"
+  dependencies:
+    babel-plugin-lodash "^3.3.2"
+    classnames "^2.2.5"
+    lodash "^4.17.4"
+    reduce-css-calc "^1.3.0"
+
 "@vx/tooltip@0.0.140":
   version "0.0.140"
   resolved "https://registry.yarnpkg.com/@vx/tooltip/-/tooltip-0.0.140.tgz#c5c8306272877c1bbd4e8b478ea5291f1019ffe3"
@@ -438,6 +623,23 @@
     classnames "^2.2.5"
     prop-types "^15.5.10"
 
+"@vx/tooltip@0.0.165", "@vx/tooltip@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/tooltip/-/tooltip-0.0.165.tgz#0d17a1b445a7bc70d7840e36593b780a6e7b40e2"
+  dependencies:
+    "@vx/bounds" "0.0.165"
+    classnames "^2.2.5"
+    prop-types "^15.5.10"
+
+"@vx/voronoi@^0.0.165":
+  version "0.0.165"
+  resolved "https://registry.yarnpkg.com/@vx/voronoi/-/voronoi-0.0.165.tgz#11ab585199b0dccf403544a6ad378a505bfb913b"
+  dependencies:
+    "@vx/group" "0.0.165"
+    classnames "^2.2.5"
+    d3-voronoi "^1.1.2"
+    prop-types "^15.6.1"
+
 "@webassemblyjs/ast@1.5.13":
   version "1.5.13"
   resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.5.13.tgz#81155a570bd5803a30ec31436bc2c9c0ede38f25"
@@ -1262,6 +1464,16 @@ babel-plugin-dynamic-import-node@^1.2.0:
   dependencies:
     babel-plugin-syntax-dynamic-import "^6.18.0"
 
+babel-plugin-lodash@^3.3.2:
+  version "3.3.4"
+  resolved "https://registry.yarnpkg.com/babel-plugin-lodash/-/babel-plugin-lodash-3.3.4.tgz#4f6844358a1340baed182adbeffa8df9967bc196"
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0-beta.49"
+    "@babel/types" "^7.0.0-beta.49"
+    glob "^7.1.1"
+    lodash "^4.17.10"
+    require-package-name "^2.0.1"
+
 babel-plugin-syntax-async-functions@^6.8.0:
   version "6.13.0"
   resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95"
@@ -2435,7 +2647,7 @@ class-utils@^0.3.5:
     isobject "^3.0.0"
     static-extend "^0.1.1"
 
-classnames@2.x, classnames@^2.1.2, classnames@^2.2.3, classnames@^2.2.4, classnames@^2.2.5:
+classnames@^2.1.2, classnames@^2.2.3, classnames@^2.2.4, classnames@^2.2.5:
   version "2.2.6"
   resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.2.6.tgz#43935bffdd291f326dad0a205309b38d00f650ce"
 
@@ -3080,7 +3292,7 @@ d3-interpolate@1:
   dependencies:
     d3-color "1"
 
-d3-path@1:
+d3-path@1, d3-path@^1.0.5:
   version "1.0.5"
   resolved "https://registry.yarnpkg.com/d3-path/-/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764"
 
@@ -3112,6 +3324,17 @@ d3-scale@^1.0.5:
     d3-time "1"
     d3-time-format "2"
 
+d3-scale@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.1.0.tgz#8d3fd3e2a7c9080782a523c08507c5248289eef8"
+  dependencies:
+    d3-array "^1.2.0"
+    d3-collection "1"
+    d3-format "1"
+    d3-interpolate "1"
+    d3-time "1"
+    d3-time-format "2"
+
 d3-selection@1, d3-selection@^1.1.0, d3-selection@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.3.0.tgz#d53772382d3dc4f7507bfb28bcd2d6aed2a0ad6d"
@@ -3158,6 +3381,10 @@ d3-transition@1:
     d3-selection "^1.1.0"
     d3-timer "1"
 
+d3-voronoi@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/d3-voronoi/-/d3-voronoi-1.1.2.tgz#1687667e8f13a2d158c80c1480c5a29cb0d8973c"
+
 d3-zoom@^1.3.0:
   version "1.7.1"
   resolved "https://registry.yarnpkg.com/d3-zoom/-/d3-zoom-1.7.1.tgz#02f43b3c3e2db54f364582d7e4a236ccc5506b63"
@@ -6400,7 +6627,7 @@ lodash.isarray@^3.0.0:
   version "3.0.4"
   resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55"
 
-lodash.isequal@^4.0.0, lodash.isequal@^4.1.1:
+lodash.isequal@^4.1.1:
   version "4.5.0"
   resolved "https://registry.yarnpkg.com/lodash.isequal/-/lodash.isequal-4.5.0.tgz#415c4478f2bcc30120c22ce10ed3226f7d3e18e0"
 
@@ -8842,7 +9069,7 @@ react-dom@^15.6.2:
     object-assign "^4.1.0"
     prop-types "^15.5.10"
 
-react-draggable@3.x, "react-draggable@^2.2.6 || ^3.0.3":
+"react-draggable@^2.2.6 || ^3.0.3":
   version "3.0.5"
   resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-3.0.5.tgz#c031e0ed4313531f9409d6cd84c8ebcec0ddfe2d"
   dependencies:
@@ -8857,16 +9084,6 @@ react-gravatar@^2.6.1:
     md5 "^2.1.0"
     query-string "^4.2.2"
 
-react-grid-layout@0.16.6:
-  version "0.16.6"
-  resolved "https://registry.yarnpkg.com/react-grid-layout/-/react-grid-layout-0.16.6.tgz#9b2407a2b946c2260ebaf66f13b556e1da4efeb2"
-  dependencies:
-    classnames "2.x"
-    lodash.isequal "^4.0.0"
-    prop-types "15.x"
-    react-draggable "3.x"
-    react-resizable "1.x"
-
 react-input-autosize@^2.1.2:
   version "2.2.1"
   resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-2.2.1.tgz#ec428fa15b1592994fb5f9aa15bb1eb6baf420f8"
@@ -8938,7 +9155,7 @@ react-redux@^5.0.2:
     loose-envify "^1.1.0"
     prop-types "^15.6.0"
 
-react-resizable@1.x, react-resizable@^1.3.3:
+react-resizable@^1.3.3:
   version "1.7.5"
   resolved "https://registry.yarnpkg.com/react-resizable/-/react-resizable-1.7.5.tgz#83eb75bb3684da6989bbbf4f826e1470f0af902e"
   dependencies:
@@ -9304,7 +9521,7 @@ redeyed@~0.4.0:
   dependencies:
     esprima "~1.0.4"
 
-reduce-css-calc@^1.2.6:
+reduce-css-calc@^1.2.6, reduce-css-calc@^1.3.0:
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
   dependencies:
@@ -9581,6 +9798,10 @@ require-main-filename@^1.0.1:
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1"
 
+require-package-name@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/require-package-name/-/require-package-name-2.0.1.tgz#c11e97276b65b8e2923f75dabf5fb2ef0c3841b9"
+
 require-uncached@^1.0.3:
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3"
diff --git a/yarn.lock b/yarn.lock
new file mode 100644
index 0000000000..fb57ccd13a
--- /dev/null
+++ b/yarn.lock
@@ -0,0 +1,4 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+


 

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: notifications-unsubscribe@superset.apache.org
For additional commands, e-mail: notifications-help@superset.apache.org