UNPKG

@mcdevsl/superset-ui

Version:
128 lines (114 loc) 3.97 kB
/** * 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. */ /* eslint-disable react/sort-prop-types */ import d3 from 'd3'; import PropTypes from 'prop-types'; import { extent as d3Extent } from 'd3-array'; import { getNumberFormatter, getSequentialSchemeRegistry } from '@superset-ui/core'; import Datamap from 'datamaps/dist/datamaps.world.min'; const propTypes = { data: PropTypes.arrayOf( PropTypes.shape({ country: PropTypes.string, latitude: PropTypes.number, longitude: PropTypes.number, name: PropTypes.string, m1: PropTypes.number, m2: PropTypes.number, }), ), height: PropTypes.number, maxBubbleSize: PropTypes.number, showBubbles: PropTypes.bool, linearColorScheme: PropTypes.string, color: PropTypes.string, }; const formatter = getNumberFormatter(); function WorldMap(element, props) { const { data, width, height, maxBubbleSize, showBubbles, linearColorScheme, color } = props; const div = d3.select(element); div.classed('superset-legacy-chart-world-map', true); div.selectAll('*').remove(); // Ignore XXX's to get better normalization const filteredData = data.filter(d => d.country && d.country !== 'XXX'); const extRadius = d3.extent(filteredData, d => Math.sqrt(d.m2)); const radiusScale = d3.scale .linear() .domain([extRadius[0], extRadius[1]]) .range([1, maxBubbleSize]); const colorScale = getSequentialSchemeRegistry() .get(linearColorScheme) .createLinearScale(d3Extent(filteredData, d => d.m1)); const processedData = filteredData.map(d => ({ ...d, radius: radiusScale(Math.sqrt(d.m2)), fillColor: colorScale(d.m1), })); const mapData = {}; processedData.forEach(d => { mapData[d.country] = d; }); const map = new Datamap({ element, width, height, data: processedData, fills: { defaultFill: '#eee', }, geographyConfig: { popupOnHover: true, highlightOnHover: true, borderWidth: 1, borderColor: '#feffff', highlightBorderColor: '#feffff', highlightFillColor: color, highlightBorderWidth: 1, popupTemplate: (geo, d) => `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m1)}</div>`, }, bubblesConfig: { borderWidth: 1, borderOpacity: 1, borderColor: color, popupOnHover: true, radius: null, popupTemplate: (geo, d) => `<div class="hoverinfo"><strong>${d.name}</strong><br>${formatter(d.m2)}</div>`, fillOpacity: 0.5, animate: true, highlightOnHover: true, highlightFillColor: color, highlightBorderColor: 'black', highlightBorderWidth: 2, highlightBorderOpacity: 1, highlightFillOpacity: 0.85, exitDelay: 100, key: JSON.stringify, }, }); map.updateChoropleth(mapData); if (showBubbles) { map.bubbles(processedData); div.selectAll('circle.datamaps-bubble').style('fill', color).style('stroke', color); } } WorldMap.displayName = 'WorldMap'; WorldMap.propTypes = propTypes; export default WorldMap;