williaster closed pull request #6287: [reviewable] Organize d3 utilities usage
URL: https://github.com/apache/incubator-superset/pull/6287
 
 
   

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 8c15bfaeec..b5ce7d848d 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 e689a41682..2fc2744ae4 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 bc22c5a06b..1bd82e21ec 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 4d8574df8a..d94594cbdd 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 41a9df5a37..a046da35cb 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 f9bb05a7ec..655e89cd4e 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 fd96ad5f80..df696570e1 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 e67302aaa9..5a6ba27314 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 070a96c1ed..7056235e71 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 c414a7cbbc..bfe4685931 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 9785972818..3aaa6fd2fa 100644
--- a/superset/assets/yarn.lock
+++ b/superset/assets/yarn.lock
@@ -3433,7 +3433,7 @@ d3-ease@1:
   version "1.0.5"
   resolved 
"https://registry.yarnpkg.com/d3-ease/-/d3-ease-1.0.5.tgz#8ce59276d81241b1b72042d6af2d40e76d936ffb";
 
-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";
 
@@ -3489,7 +3489,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";
   dependencies:
@@ -3500,7 +3500,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";
 
@@ -3514,7 +3514,7 @@ d3-svg-legend@^1.x:
   version "1.13.0"
   resolved 
"https://registry.yarnpkg.com/d3-svg-legend/-/d3-svg-legend-1.13.0.tgz#6217478c9add9d62cb333617e1961311a41a4db3";
 
-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";
   dependencies:


 

----------------------------------------------------------------
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:
[email protected]


With regards,
Apache Git Services

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to