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/30 21:43:42 UTC

[GitHub] williaster closed pull request #5721: [SIP-5] Repair and refactor CountryMap

williaster closed pull request #5721: [SIP-5] Repair and refactor CountryMap
URL: https://github.com/apache/incubator-superset/pull/5721
 
 
   

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/src/visualizations/country_map.css b/superset/assets/src/visualizations/country_map.css
index 8a16105aaa..7bde0c8c69 100644
--- a/superset/assets/src/visualizations/country_map.css
+++ b/superset/assets/src/visualizations/country_map.css
@@ -1,5 +1,5 @@
 .country_map svg {
-    background-color: #feffff;
+  background-color: #feffff;
 }
 
 .country_map {
@@ -7,30 +7,36 @@
 }
 
 .country_map .background {
-    fill: rgba(255,255,255,0);
-    pointer-events: all;
+  fill: rgba(255,255,255,0);
+  pointer-events: all;
 }
 
 .country_map .map-layer {
-    fill: #fff;
-    stroke: #aaa;
+  fill: #fff;
+  stroke: #aaa;
 }
 
 .country_map .effect-layer {
-    pointer-events: none;
+  pointer-events: none;
 }
 
-.country_map text {
-    font-weight: 300;
-    color: #333333;
+.country_map .text-layer {
+  color: #333333;
+  text-anchor: middle;
+  pointer-events: none;
+}
+
+.country_map text.result-text {
+  font-weight: 300;
+  font-size: 24px;
 }
 
 .country_map text.big-text {
-    font-size: 30px;
-    font-weight: 400;
-    color: #333333;
+  font-weight: 700;
+  font-size: 16px;
 }
 
 .country_map path.region {
-    cursor: pointer;
+  cursor: pointer;
+  stroke: #eee;
 }
diff --git a/superset/assets/src/visualizations/country_map.js b/superset/assets/src/visualizations/country_map.js
index 09d325de67..92c799bff3 100644
--- a/superset/assets/src/visualizations/country_map.js
+++ b/superset/assets/src/visualizations/country_map.js
@@ -1,83 +1,112 @@
 import d3 from 'd3';
-import './country_map.css';
+import PropTypes from 'prop-types';
 import { colorScalerFactory } from '../modules/colors';
+import './country_map.css';
 
-
-function countryMapChart(slice, payload) {
-  // CONSTANTS
-  const fd = payload.form_data;
-  let path;
-  let g;
-  let bigText;
-  let resultText;
-  const container = slice.container;
-  const data = payload.data;
-  const format = d3.format(fd.number_format);
-
-  const colorScaler = colorScalerFactory(fd.linear_color_scheme, data, v => v.metric);
+const propTypes = {
+  data: PropTypes.arrayOf(PropTypes.shape({
+    country_id: PropTypes.string,
+    metric: PropTypes.number,
+  })),
+  width: PropTypes.number,
+  height: PropTypes.number,
+  country: PropTypes.string,
+  linearColorScheme: PropTypes.string,
+  mapBaseUrl: PropTypes.string,
+  numberFormat: PropTypes.string,
+};
+
+const maps = {};
+
+function CountryMap(element, props) {
+  PropTypes.checkPropTypes(propTypes, props, 'prop', 'CountryMap');
+
+  const {
+    data,
+    width,
+    height,
+    country,
+    linearColorScheme,
+    mapBaseUrl = '/static/assets/src/visualizations/countries',
+    numberFormat,
+  } = props;
+
+  const container = element;
+  const format = d3.format(numberFormat);
+  const colorScaler = colorScalerFactory(linearColorScheme, data, v => v.metric);
   const colorMap = {};
   data.forEach((d) => {
     colorMap[d.country_id] = colorScaler(d.metric);
   });
   const colorFn = d => colorMap[d.properties.ISO] || 'none';
 
-  let centered;
-  path = d3.geo.path();
-  d3.select(slice.selector).selectAll('*').remove();
-  const div = d3.select(slice.selector)
-    .append('svg:svg')
-    .attr('width', slice.width())
-    .attr('height', slice.height())
+  const path = d3.geo.path();
+  const div = d3.select(container);
+  div.selectAll('*').remove();
+  container.style.height = `${height}px`;
+  container.style.width = `${width}px`;
+  const svg = div.append('svg:svg')
+    .attr('width', width)
+    .attr('height', height)
     .attr('preserveAspectRatio', 'xMidYMid meet');
+  const backgroundRect = svg.append('rect')
+    .attr('class', 'background')
+    .attr('width', width)
+    .attr('height', height);
+  const g = svg.append('g');
+  const mapLayer = g.append('g')
+    .classed('map-layer', true);
+  const textLayer = g.append('g')
+    .classed('text-layer', true)
+    .attr('transform', `translate(${width / 2}, 45)`);
+  const bigText = textLayer.append('text')
+    .classed('big-text', true);
+  const resultText = textLayer.append('text')
+    .classed('result-text', true)
+    .attr('dy', '1em');
 
-  container.css('height', slice.height());
-  container.css('width', slice.width());
+  let centered;
 
   const clicked = function (d) {
+    const hasCenter = d && centered !== d;
     let x;
     let y;
     let k;
-    let bigTextX;
-    let bigTextY;
-    let bigTextSize;
-    let resultTextX;
-    let resultTextY;
+    const halfWidth = width / 2;
+    const halfHeight = height / 2;
 
-    if (d && centered !== d) {
+    if (hasCenter) {
       const centroid = path.centroid(d);
       x = centroid[0];
       y = centroid[1];
-      bigTextX = centroid[0];
-      bigTextY = centroid[1] - 40;
-      resultTextX = centroid[0];
-      resultTextY = centroid[1] - 40;
-      bigTextSize = '6px';
       k = 4;
       centered = d;
     } else {
-      x = slice.width() / 2;
-      y = slice.height() / 2;
-      bigTextX = 0;
-      bigTextY = 0;
-      resultTextX = 0;
-      resultTextY = 0;
-      bigTextSize = '30px';
+      x = halfWidth;
+      y = halfHeight;
       k = 1;
       centered = null;
     }
 
     g.transition()
       .duration(750)
-      .attr('transform', 'translate(' + slice.width() / 2 + ',' + slice.height() / 2 + ')scale(' + k + ')translate(' + -x + ',' + -y + ')');
+      .attr('transform', `translate(${halfWidth},${halfHeight})scale(${k})translate(${-x},${-y})`);
+    textLayer
+        .style('opacity', 0)
+        .attr('transform', `translate(0,0)translate(${x},${hasCenter ? (y - 5) : 45})`)
+      .transition()
+        .duration(750)
+        .style('opacity', 1);
     bigText.transition()
       .duration(750)
-      .attr('transform', 'translate(0,0)translate(' + bigTextX + ',' + bigTextY + ')')
-      .style('font-size', bigTextSize);
+      .style('font-size', hasCenter ? 6 : 16);
     resultText.transition()
       .duration(750)
-      .attr('transform', 'translate(0,0)translate(' + resultTextX + ',' + resultTextY + ')');
+      .style('font-size', hasCenter ? 16 : 24);
   };
 
+  backgroundRect.on('click', clicked);
+
   const selectAndDisplayNameOfRegion = function (feature) {
     let name = '';
     if (feature && feature.properties) {
@@ -114,44 +143,29 @@ function countryMapChart(slice, payload) {
     resultText.text('');
   };
 
-  div.append('rect')
-    .attr('class', 'background')
-    .attr('width', slice.width())
-    .attr('height', slice.height())
-    .on('click', clicked);
-
-  g = div.append('g');
-  const mapLayer = g.append('g')
-    .classed('map-layer', true);
-  bigText = g.append('text')
-    .classed('big-text', true)
-    .attr('x', 20)
-    .attr('y', 45);
-  resultText = g.append('text')
-    .classed('result-text', true)
-    .attr('x', 20)
-    .attr('y', 60);
-
-  const url = `/static/assets/src/visualizations/countries/${fd.select_country.toLowerCase()}.geojson`;
-  d3.json(url, function (error, mapData) {
+  function drawMap(mapData) {
     const features = mapData.features;
     const center = d3.geo.centroid(mapData);
-    let scale = 150;
-    let offset = [slice.width() / 2, slice.height() / 2];
-    let projection = d3.geo.mercator().scale(scale).center(center)
-      .translate(offset);
-
-    path = path.projection(projection);
-
+    const scale = 100;
+    const projection = d3.geo.mercator()
+      .scale(scale)
+      .center(center)
+      .translate([width / 2, height / 2]);
+    path.projection(projection);
+
+    // Compute scale that fits container.
     const bounds = path.bounds(mapData);
-    const hscale = scale * slice.width() / (bounds[1][0] - bounds[0][0]);
-    const vscale = scale * slice.height() / (bounds[1][1] - bounds[0][1]);
-    scale = (hscale < vscale) ? hscale : vscale;
-    const offsetWidth = slice.width() - (bounds[0][0] + bounds[1][0]) / 2;
-    const offsetHeigth = slice.height() - (bounds[0][1] + bounds[1][1]) / 2;
-    offset = [offsetWidth, offsetHeigth];
-    projection = d3.geo.mercator().center(center).scale(scale).translate(offset);
-    path = path.projection(projection);
+    const hscale = scale * width / (bounds[1][0] - bounds[0][0]);
+    const vscale = scale * height / (bounds[1][1] - bounds[0][1]);
+    const newScale = (hscale < vscale) ? hscale : vscale;
+
+    // Compute bounds and offset using the updated scale.
+    projection.scale(newScale);
+    const newBounds = path.bounds(mapData);
+    projection.translate([
+      width - (newBounds[0][0] + newBounds[1][0]) / 2,
+      height - (newBounds[0][1] + newBounds[1][1]) / 2,
+    ]);
 
     // Draw each province as a path
     mapLayer.selectAll('path')
@@ -164,8 +178,43 @@ function countryMapChart(slice, payload) {
       .on('mouseenter', mouseenter)
       .on('mouseout', mouseout)
       .on('click', clicked);
+  }
+
+  const countryKey = country.toLowerCase();
+  const map = maps[countryKey];
+  if (map) {
+    drawMap(map);
+  } else {
+    const url = `${mapBaseUrl}/${countryKey}.geojson`;
+    d3.json(url, function (error, mapData) {
+      if (!error) {
+        maps[countryKey] = mapData;
+        drawMap(mapData);
+      }
+    });
+  }
+
+}
+
+CountryMap.propTypes = propTypes;
+
+function adaptor(slice, payload) {
+  const { selector, formData } = slice;
+  const {
+    linear_color_scheme: linearColorScheme,
+    number_format: numberFormat,
+    select_country: country,
+  } = formData;
+  const element = document.querySelector(selector);
+
+  return CountryMap(element, {
+    data: payload.data,
+    width: slice.width(),
+    height: slice.height(),
+    country,
+    linearColorScheme,
+    numberFormat,
   });
-  container.show();
 }
 
-module.exports = countryMapChart;
+export default adaptor;


 

----------------------------------------------------------------
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