cartogram-chart
Version:
Cartogram web component for visualizing geographical data by distorting a TopoJson topology
123 lines (115 loc) • 4.35 kB
JavaScript
import { select } from 'd3-selection';
import 'd3-transition';
import { geoMercator } from 'd3-geo';
import { cartogram as cartogram$1 } from 'topogram';
import Kapsule from 'kapsule';
import accessorFn from 'accessor-fn';
import Tooltip from 'float-tooltip';
var ANIMATION_DURATION = 1200;
var cartogram = new Kapsule({
props: {
width: {
"default": window.innerWidth
},
height: {
"default": window.innerHeight
},
iterations: {
"default": 20
},
projection: {
"default": geoMercator().scale(Math.min((window.innerWidth - 3) / (2 * Math.PI), (window.innerHeight - 3) / (1.2 * Math.PI))).translate([window.innerWidth / 2, window.innerHeight / 1.5])
},
topoJson: {},
topoObjectName: {},
value: {
"default": 1
},
color: {
"default": 'lightgrey'
},
label: {
triggerUpdate: false
},
valFormatter: {
"default": function _default(n) {
return n;
},
triggerUpdate: false
},
units: {
"default": '',
triggerUpdate: false
},
tooltipContent: {
triggerUpdate: false
},
onClick: {}
},
init: function init(domNode, state) {
state.cartogram = cartogram$1().properties(function (d) {
return d.properties;
});
// Dom
var el = select(domNode).append('div').attr('class', 'cartogram');
state.svg = el.append('svg');
// tooltip
state.tooltip = new Tooltip(el);
},
update: function update(state) {
var valueOf = accessorFn(state.value);
var colorOf = accessorFn(state.color);
state.svg.attr('width', state.width).attr('height', state.height);
if (!state.topoJson) return; // No features to render
var topoObject = state.topoJson.objects[state.topoObjectName] || Object.values(state.topoJson.objects)[0];
if (!topoObject) {
console.warn('Unable to find topology object in TopoJson');
return;
}
state.cartogram.projection(state.projection).value(valueOf);
var features = state.svg.selectAll('path.feature').data(state.cartogram.iterations(1) // Initialize new features non-distorted
(state.topoJson, topoObject.geometries).features);
features.exit().remove();
var newFeatures = features.enter().append('path').attr('class', 'feature').style('fill', 'lightgrey').attr('d', state.cartogram.path).on('mouseover', function (ev, feature) {
var valueOf = accessorFn(state.value);
var labelOf = accessorFn(state.label);
var tooltipContentOf = accessorFn(state.tooltipContent);
var label = labelOf(feature);
var extraContent = tooltipContentOf(feature);
state.tooltip.content(!label && !extraContent ? null : "\n ".concat(label ? "<b>".concat(label, "</b>:") : '', "\n ").concat(state.valFormatter(valueOf(feature)), "\n ").concat(state.units, "\n ").concat(extraContent ? "<br/><br/>".concat(extraContent) : '', "\n "));
}).on('mouseout', function () {
state.tooltip.content(null);
}).on('click', function (ev, d) {
return state.onClick && state.onClick(d);
});
features.merge(newFeatures).data(state.cartogram.iterations(state.iterations) // distort all features
(state.topoJson, topoObject.geometries).features).style('cursor', state.onClick ? 'pointer' : null).transition().duration(ANIMATION_DURATION).style('fill', colorOf).attr('d', state.cartogram.path);
}
});
function styleInject(css, ref) {
if (ref === undefined) ref = {};
var insertAt = ref.insertAt;
if (typeof document === 'undefined') {
return;
}
var head = document.head || document.getElementsByTagName('head')[0];
var style = document.createElement('style');
style.type = 'text/css';
if (insertAt === 'top') {
if (head.firstChild) {
head.insertBefore(style, head.firstChild);
} else {
head.appendChild(style);
}
} else {
head.appendChild(style);
}
if (style.styleSheet) {
style.styleSheet.cssText = css;
} else {
style.appendChild(document.createTextNode(css));
}
}
var css_248z = ".cartogram .feature {\n stroke: darkgrey;\n transition: fill-opacity .7s;\n}\n\n.cartogram .feature:hover {\n fill-opacity: 0.6;\n transition: fill-opacity .1s;\n}\n\n.cartogram {\n position: relative;\n}";
styleInject(css_248z);
export { cartogram as default };