You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@superset.apache.org by cc...@apache.org on 2018/11/09 19:43:00 UTC

[incubator-superset] branch master updated: [reviewable] Organize d3 utilities usage (#6287)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new 3ffb48c  [reviewable] Organize d3 utilities usage (#6287)
3ffb48c is described below

commit 3ffb48c4921b989eb8075089da9996d060278b91
Author: Krist Wongsuphasawat <kr...@gmail.com>
AuthorDate: Fri Nov 9 11:42:54 2018 -0800

    [reviewable] Organize d3 utilities usage (#6287)
    
    * update package.json
    
    * extract changes from another PR
    
    * add d3 prefix
    
    * two more places
    
    * update lockfile
---
 superset/assets/package.json                       |  4 ++
 superset/assets/src/modules/geo.js                 | 14 +++++++
 superset/assets/src/modules/utils.js               | 44 ++++++++++++----------
 superset/assets/src/utils/common.js                | 11 ------
 .../src/visualizations/BigNumber/transformProps.js |  4 +-
 .../src/visualizations/Horizon/HorizonChart.jsx    |  4 +-
 .../src/visualizations/Horizon/HorizonRow.jsx      |  7 ++--
 .../MapBox/ScatterPlotGlowOverlay.jsx              | 25 ++++++------
 superset/assets/src/visualizations/Table/Table.js  |  7 ++--
 .../src/visualizations/TimeTable/TimeTable.jsx     |  6 +--
 superset/assets/yarn.lock                          |  8 ++--
 11 files changed, 72 insertions(+), 62 deletions(-)

diff --git a/superset/assets/package.json b/superset/assets/package.json
index 8c15bfa..b5ce7d8 100644
--- a/superset/assets/package.json
+++ b/superset/assets/package.json
@@ -66,9 +66,13 @@
     "d3-array": "^1.2.4",
     "d3-cloud": "^1.2.1",
     "d3-color": "^1.2.0",
+    "d3-format": "^1.3.2",
     "d3-hierarchy": "^1.1.5",
     "d3-sankey": "^0.4.2",
+    "d3-scale": "^2.1.2",
+    "d3-selection": "^1.3.2",
     "d3-svg-legend": "^1.x",
+    "d3-time-format": "^2.1.3",
     "d3-tip": "^0.9.1",
     "datamaps": "^0.5.8",
     "datatables.net-bs": "^1.10.15",
diff --git a/superset/assets/src/modules/geo.js b/superset/assets/src/modules/geo.js
index e689a41..2fc2744 100644
--- a/superset/assets/src/modules/geo.js
+++ b/superset/assets/src/modules/geo.js
@@ -1,3 +1,5 @@
+import { round as d3Round } from 'd3-format';
+
 export const defaultViewport = {
   longitude: 6.85236157047845,
   latitude: 31.222656842808707,
@@ -7,6 +9,7 @@ export const defaultViewport = {
 };
 
 const METER_TO_MILE = 1609.34;
+
 export function unitToRadius(unit, num) {
   if (unit === 'square_m') {
     return Math.sqrt(num / Math.PI);
@@ -23,3 +26,14 @@ export function unitToRadius(unit, num) {
   }
   return null;
 }
+
+export const EARTH_CIRCUMFERENCE_KM = 40075.16;
+export const MILES_PER_KM = 1.60934;
+
+export function kmToPixels(kilometers, latitude, zoomLevel) {
+  // Algorithm from: http://wiki.openstreetmap.org/wiki/Zoom_levels
+  const latitudeRad = latitude * (Math.PI / 180);
+  // Seems like the zoomLevel is off by one
+  const kmPerPixel = (EARTH_CIRCUMFERENCE_KM * Math.cos(latitudeRad)) / Math.pow(2, zoomLevel + 9);
+  return d3Round(kilometers / kmPerPixel, 2);
+}
diff --git a/superset/assets/src/modules/utils.js b/superset/assets/src/modules/utils.js
index bc22c5a..1bd82e2 100644
--- a/superset/assets/src/modules/utils.js
+++ b/superset/assets/src/modules/utils.js
@@ -1,9 +1,11 @@
 /* eslint camelcase: 0 */
 import $ from 'jquery';
-import d3 from 'd3';
+import { format as d3Format } from 'd3-format';
+import { d3Select } from 'd3-selection';
+import { timeFormat as d3TimeFormat } from 'd3-time-format';
 import { formatDate, UTC } from './dates';
 
-const siFormatter = d3.format('.3s');
+const siFormatter = d3Format('.3s');
 
 export function defaultNumberFormatter(n) {
   let si = siFormatter(n);
@@ -15,27 +17,43 @@ export function defaultNumberFormatter(n) {
 }
 
 export function d3FormatPreset(format) {
-  // like d3.format, but with support for presets like 'smart_date'
+  // like d3Format, but with support for presets like 'smart_date'
   if (format === 'smart_date') {
     return formatDate;
   }
   if (format) {
-    return d3.format(format);
+    return d3Format(format);
   }
   return defaultNumberFormatter;
 }
+
 export const d3TimeFormatPreset = function (format) {
   const effFormat = format || 'smart_date';
   if (effFormat === 'smart_date') {
     return formatDate;
   }
-  const f = d3.time.format(effFormat);
+  const f = d3TimeFormat(effFormat);
   return function (dttm) {
     const d = UTC(new Date(dttm));
     return f(d);
   };
 };
 
+const formatters = {};
+
+export function d3format(format, number) {
+  format = format || '.3s';
+  // Formats a number and memoizes formatters to be reused
+  if (!(format in formatters)) {
+    formatters[format] = d3Format(format);
+  }
+  try {
+    return formatters[format](number);
+  } catch (e) {
+    return 'ERR';
+  }
+}
+
 /*
   Utility function that takes a d3 svg:text selection and a max width, and splits the
   text's text across multiple tspan lines such that any given line does not exceed max width
@@ -47,7 +65,7 @@ export function wrapSvgText(text, width, adjustedY) {
   const lineHeight = 1;
   // ems
   text.each(function () {
-    const d3Text = d3.select(this);
+    const d3Text = d3Select(this);
     const words = d3Text.text().split(/\s+/);
     let word;
     let line = [];
@@ -118,20 +136,6 @@ export const fixDataTableBodyHeight = function ($tableDom, height) {
   $tableDom.find('.dataTables_scrollBody').css('max-height', height - headHeight - controlsHeight - paginationHeight);
 };
 
-export function d3format(format, number) {
-  const formatters = {};
-  // Formats a number and memoizes formatters to be reused
-  format = format || '.3s';
-  if (!(format in formatters)) {
-    formatters[format] = d3.format(format);
-  }
-  try {
-    return formatters[format](number);
-  } catch (e) {
-    return 'ERR';
-  }
-}
-
 export function formatSelectOptionsForRange(start, end) {
   // outputs array of arrays
   // formatSelectOptionsForRange(1, 5)
diff --git a/superset/assets/src/utils/common.js b/superset/assets/src/utils/common.js
index 282518f..e044df1 100644
--- a/superset/assets/src/utils/common.js
+++ b/superset/assets/src/utils/common.js
@@ -1,24 +1,13 @@
-import d3 from 'd3';
 import { SupersetClient } from '@superset-ui/connection';
 import getClientErrorObject from './getClientErrorObject';
 
-export const EARTH_CIRCUMFERENCE_KM = 40075.16;
 export const LUMINANCE_RED_WEIGHT = 0.2126;
 export const LUMINANCE_GREEN_WEIGHT = 0.7152;
 export const LUMINANCE_BLUE_WEIGHT = 0.0722;
-export const MILES_PER_KM = 1.60934;
 
 // Regexp for the label added to time shifted series (1 hour offset, 2 days offset, etc.)
 export const TIME_SHIFT_PATTERN = /\d+ \w+ offset/;
 
-export function kmToPixels(kilometers, latitude, zoomLevel) {
-  // Algorithm from: http://wiki.openstreetmap.org/wiki/Zoom_levels
-  const latitudeRad = latitude * (Math.PI / 180);
-  // Seems like the zoomLevel is off by one
-  const kmPerPixel = (EARTH_CIRCUMFERENCE_KM * Math.cos(latitudeRad)) / Math.pow(2, zoomLevel + 9);
-  return d3.round(kilometers / kmPerPixel, 2);
-}
-
 export function rgbLuminance(r, g, b) {
   // Formula: https://en.wikipedia.org/wiki/Relative_luminance
   return LUMINANCE_RED_WEIGHT * r + LUMINANCE_GREEN_WEIGHT * g + LUMINANCE_BLUE_WEIGHT * b;
diff --git a/superset/assets/src/visualizations/BigNumber/transformProps.js b/superset/assets/src/visualizations/BigNumber/transformProps.js
index 41a9df5..a046da3 100644
--- a/superset/assets/src/visualizations/BigNumber/transformProps.js
+++ b/superset/assets/src/visualizations/BigNumber/transformProps.js
@@ -1,5 +1,5 @@
 import * as color from 'd3-color';
-import d3 from 'd3';
+import { format as d3Format } from 'd3-format';
 import { d3FormatPreset } from '../../modules/utils';
 import { renderTooltipFactory } from './BigNumber';
 
@@ -43,7 +43,7 @@ export default function transformProps(chartProps) {
         const compareValue = sortedData[compareIndex][metricName];
         percentChange = compareValue === 0
           ? 0 : (bigNumber - compareValue) / Math.abs(compareValue);
-        const formatPercentChange = d3.format('+.1%');
+        const formatPercentChange = d3Format('+.1%');
         formattedSubheader = `${formatPercentChange(percentChange)} ${compareSuffix}`;
       }
     }
diff --git a/superset/assets/src/visualizations/Horizon/HorizonChart.jsx b/superset/assets/src/visualizations/Horizon/HorizonChart.jsx
index f9bb05a..655e89c 100644
--- a/superset/assets/src/visualizations/Horizon/HorizonChart.jsx
+++ b/superset/assets/src/visualizations/Horizon/HorizonChart.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import d3 from 'd3';
+import { extent as d3Extent } from 'd3-array';
 import HorizonRow, { DEFAULT_COLORS } from './HorizonRow';
 import './HorizonChart.css';
 
@@ -52,7 +52,7 @@ class HorizonChart extends React.PureComponent {
         (acc, current) => acc.concat(current.values),
         [],
       );
-      yDomain = d3.extent(allValues, d => d.y);
+      yDomain = d3Extent(allValues, d => d.y);
     }
 
     return (
diff --git a/superset/assets/src/visualizations/Horizon/HorizonRow.jsx b/superset/assets/src/visualizations/Horizon/HorizonRow.jsx
index fd96ad5..df69657 100644
--- a/superset/assets/src/visualizations/Horizon/HorizonRow.jsx
+++ b/superset/assets/src/visualizations/Horizon/HorizonRow.jsx
@@ -1,6 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import d3 from 'd3';
+import { extent as d3Extent } from 'd3-array';
+import { scaleLinear } from 'd3-scale';
 
 export const DEFAULT_COLORS = [
   '#313695',
@@ -91,8 +92,8 @@ class HorizonRow extends React.PureComponent {
       }
 
       // Create y-scale
-      const [min, max] = yDomain || d3.extent(data, d => d.y);
-      const y = d3.scale.linear()
+      const [min, max] = yDomain || d3Extent(data, d => d.y);
+      const y = scaleLinear()
         .domain([0, Math.max(-min, max)])
         .range([0, height]);
 
diff --git a/superset/assets/src/visualizations/MapBox/ScatterPlotGlowOverlay.jsx b/superset/assets/src/visualizations/MapBox/ScatterPlotGlowOverlay.jsx
index e67302a..5a6ba27 100644
--- a/superset/assets/src/visualizations/MapBox/ScatterPlotGlowOverlay.jsx
+++ b/superset/assets/src/visualizations/MapBox/ScatterPlotGlowOverlay.jsx
@@ -1,13 +1,10 @@
-import d3 from 'd3';
 import Immutable from 'immutable';
 import React from 'react';
 import PropTypes from 'prop-types';
 import ViewportMercator from 'viewport-mercator-project';
-import {
-  kmToPixels,
-  rgbLuminance,
-  MILES_PER_KM,
-} from '../../utils/common';
+import { round as d3Round } from 'd3-format';
+import { kmToPixels, MILES_PER_KM } from '../../modules/geo';
+import { rgbLuminance } from '../../utils/common';
 
 const propTypes = {
   aggregation: PropTypes.string,
@@ -131,7 +128,7 @@ class ScatterPlotGlowOverlay extends React.Component {
     if ((props.renderWhileDragging || !props.isDragging) && props.locations) {
       props.locations.forEach(function _forEach(location, i) {
         const pixel = mercator.project(props.lngLatAccessor(location));
-        const pixelRounded = [d3.round(pixel[0], 1), d3.round(pixel[1], 1)];
+        const pixelRounded = [d3Round(pixel[0], 1), d3Round(pixel[1], 1)];
 
         if (pixelRounded[0] + radius >= 0
               && pixelRounded[0] - radius < props.width
@@ -140,8 +137,8 @@ class ScatterPlotGlowOverlay extends React.Component {
           ctx.beginPath();
           if (location.get('properties').get('cluster')) {
             let clusterLabel = clusterLabelMap[i];
-            const scaledRadius = d3.round(Math.pow(clusterLabel / maxLabel, 0.5) * radius, 1);
-            const fontHeight = d3.round(scaledRadius * 0.5, 1);
+            const scaledRadius = d3Round(Math.pow(clusterLabel / maxLabel, 0.5) * radius, 1);
+            const fontHeight = d3Round(scaledRadius * 0.5, 1);
             const gradient = ctx.createRadialGradient(
               pixelRounded[0], pixelRounded[1], scaledRadius,
               pixelRounded[0], pixelRounded[1], 0,
@@ -177,17 +174,17 @@ class ScatterPlotGlowOverlay extends React.Component {
             if (radiusProperty !== null) {
               const pointLatitude = props.lngLatAccessor(location)[1];
               if (props.pointRadiusUnit === 'Kilometers') {
-                pointLabel = d3.round(pointRadius, 2) + 'km';
+                pointLabel = d3Round(pointRadius, 2) + 'km';
                 pointRadius = kmToPixels(pointRadius, pointLatitude, props.zoom);
               } else if (props.pointRadiusUnit === 'Miles') {
-                pointLabel = d3.round(pointRadius, 2) + 'mi';
+                pointLabel = d3Round(pointRadius, 2) + 'mi';
                 pointRadius = kmToPixels(pointRadius * MILES_PER_KM, pointLatitude, props.zoom);
               }
             }
 
             if (pointMetric !== null) {
               pointLabel = Number.isFinite(parseFloat(pointMetric))
-                ? d3.round(pointMetric, 2)
+                ? d3Round(pointMetric, 2)
                 : pointMetric;
             }
 
@@ -196,13 +193,13 @@ class ScatterPlotGlowOverlay extends React.Component {
               pointRadius = defaultRadius;
             }
 
-            ctx.arc(pixelRounded[0], pixelRounded[1], d3.round(pointRadius, 1), 0, Math.PI * 2);
+            ctx.arc(pixelRounded[0], pixelRounded[1], d3Round(pointRadius, 1), 0, Math.PI * 2);
             ctx.fillStyle = 'rgb(' + rgb[1] + ', ' + rgb[2] + ', ' + rgb[3] + ')';
             ctx.fill();
 
             if (pointLabel !== undefined) {
               this.drawText(ctx, pixelRounded, {
-                fontHeight: d3.round(pointRadius, 1),
+                fontHeight: d3Round(pointRadius, 1),
                 label: pointLabel,
                 radius: pointRadius,
                 rgb,
diff --git a/superset/assets/src/visualizations/Table/Table.js b/superset/assets/src/visualizations/Table/Table.js
index 070a96c..7056235 100644
--- a/superset/assets/src/visualizations/Table/Table.js
+++ b/superset/assets/src/visualizations/Table/Table.js
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
 import dt from 'datatables.net-bs';
 import 'datatables.net-bs/css/dataTables.bootstrap.css';
 import dompurify from 'dompurify';
+import { format as d3Format } from 'd3-format';
 import { fixDataTableBodyHeight, d3TimeFormatPreset } from '../../modules/utils';
 import './Table.css';
 
@@ -45,8 +46,8 @@ const propTypes = {
   ]),
 };
 
-const formatValue = d3.format('0,000');
-const formatPercent = d3.format('.3p');
+const formatValue = d3Format(',.0d');
+const formatPercent = d3Format('.3p');
 function NOOP() {}
 
 function TableVis(element, props) {
@@ -129,7 +130,7 @@ function TableVis(element, props) {
         html = `<span class="like-pre">${dompurify.sanitize(val)}</span>`;
       }
       if (isMetric) {
-        html = d3.format(format || '0.3s')(val);
+        html = d3Format(format || '0.3s')(val);
       }
       if (key[0] === '%') {
         html = formatPercent(val);
diff --git a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
index 0eaafc7..38bf058 100644
--- a/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
+++ b/superset/assets/src/visualizations/TimeTable/TimeTable.jsx
@@ -1,7 +1,7 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import d3 from 'd3';
 import Mustache from 'mustache';
+import { scaleLinear } from 'd3-scale';
 import { Table, Thead, Th, Tr, Td } from 'reactable';
 
 import MetricOption from '../../components/MetricOption';
@@ -19,7 +19,7 @@ function colorFromBounds(value, bounds, colorBounds = ACCESSIBLE_COLOR_BOUNDS) {
     const [min, max] = bounds;
     const [minColor, maxColor] = colorBounds;
     if (min !== null && max !== null) {
-      const colorScale = d3.scale.linear()
+      const colorScale = scaleLinear()
         .domain([min, (max + min) / 2, max])
         .range([minColor, 'grey', maxColor]);
       return colorScale(value);
@@ -131,7 +131,7 @@ class TimeTable extends React.PureComponent {
           showYAxis={column.showYAxis}
           renderTooltip={({ index }) => (
             <div>
-              <strong>{d3format(column.d3Format, sparkData[index])}</strong>
+              <strong>{d3format(column.d3format, sparkData[index])}</strong>
               <div>{formatDate(entries[index].time)}</div>
             </div>
           )}
diff --git a/superset/assets/yarn.lock b/superset/assets/yarn.lock
index b1ab09e..cffbb36 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -3943,7 +3943,7 @@ d3-ease@1:
   resolved "https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb"
   integrity sha512-Ct1O//ly5y5lFM9YTdu+ygq7LleSgSE4oj7vUt9tPLHUi8VCV7QoizGpdWRWAwCO9LdYzIrQDg97+hGVdsSGPQ==
 
-d3-format@1, d3-format@^1.2.0:
+d3-format@1, d3-format@^1.2.0, d3-format@^1.3.2:
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/d3-format/-/d3-format-1.3.2.tgz#6a96b5e31bcb98122a30863f7d92365c00603562"
   integrity sha512-Z18Dprj96ExragQ0DeGi+SYPQ7pPfRMtUXtsg/ChVIKNBCzjO8XYJvRTC1usblx52lqge56V5ect+frYTQc8WQ==
@@ -4009,7 +4009,7 @@ d3-scale@^1.0.5, d3-scale@^1.0.6:
     d3-time "1"
     d3-time-format "2"
 
-d3-scale@^2.0.0:
+d3-scale@^2.0.0, d3-scale@^2.1.2:
   version "2.1.2"
   resolved "https://registry.yarnpkg.com/d3-scale/-/d3-scale-2.1.2.tgz#4e932b7b60182aee9073ede8764c98423e5f9a94"
   integrity sha512-bESpd64ylaKzCDzvULcmHKZTlzA/6DGSVwx7QSDj/EnX9cpSevsdiwdHFYI9ouo9tNBbV3v5xztHS2uFeOzh8Q==
@@ -4021,7 +4021,7 @@ d3-scale@^2.0.0:
     d3-time "1"
     d3-time-format "2"
 
-d3-selection@1, d3-selection@^1.1.0, d3-selection@^1.3.0:
+d3-selection@1, d3-selection@^1.1.0, d3-selection@^1.3.0, d3-selection@^1.3.2:
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/d3-selection/-/d3-selection-1.3.2.tgz#6e70a9df60801c8af28ac24d10072d82cbfdf652"
   integrity sha512-OoXdv1nZ7h2aKMVg3kaUFbLLK5jXUFAMLD/Tu5JA96mjf8f2a9ZUESGY+C36t8R1WFeWk/e55hy54Ml2I62CRQ==
@@ -4038,7 +4038,7 @@ d3-svg-legend@^1.x:
   resolved "https://registry.yarnpkg.com/d3-svg-legend/-/d3-svg-legend-1.13.0.tgz#6217478c9add9d62cb333617e1961311a41a4db3"
   integrity sha1-YhdHjJrdnWLLMzYX4ZYTEaQaTbM=
 
-d3-time-format@2:
+d3-time-format@2, d3-time-format@^2.1.3:
   version "2.1.3"
   resolved "https://registry.yarnpkg.com/d3-time-format/-/d3-time-format-2.1.3.tgz#ae06f8e0126a9d60d6364eac5b1533ae1bac826b"
   integrity sha512-6k0a2rZryzGm5Ihx+aFMuO1GgelgIz+7HhB4PH4OEndD5q2zGn1mDfRdNrulspOfR6JXkb2sThhDK41CSK85QA==