UNPKG

@d3fc/d3fc-data-join

Version:

A component that simplifies the D3 data join and supports the d3fc decorate pattern

94 lines (78 loc) 3.09 kB
// "Caution: avoid interpolating to or from the number zero when the interpolator is used to generate // a string (such as with attr). // Very small values, when stringified, may be converted to scientific notation and // cause a temporarily invalid attribute or style property value. // For example, the number 0.0000001 is converted to the string "1e-7". // This is particularly noticeable when interpolating opacity values. // To avoid scientific notation, start or end the transition at 1e-6, // which is the smallest value that is not stringified in exponential notation." // - https://github.com/mbostock/d3/wiki/Transitions#d3_interpolateNumber export const effectivelyZero = 1e-6; export const isTransition = selectionOrTransition => selectionOrTransition.selection() !== selectionOrTransition; // Wrapper around d3's selectAll/data data-join, which allows decoration of the result. // This is achieved by appending the element to the enter selection before exposing it. // A default transition of fade in/out is also implicitly added but can be modified. export default (element, className) => { element = element || 'g'; let key = (_, i) => i; let explicitTransition = null; const dataJoin = function(container, data) { data = data || (d => d); const selection = container.selection(); const implicitTransition = isTransition(container) ? container : null; const selected = selection.selectChildren( className == null ? element : `${element}.${className}` ); let update = selected.data(data, key); const enter = update .enter() .append(element) .attr('class', className); let exit = update.exit(); // automatically merge in the enter selection update = update.merge(enter); // if transitions are enabled apply a default fade in/out transition const transition = implicitTransition || explicitTransition; if (transition) { update = update.transition(transition).style('opacity', 1); enter.style('opacity', effectivelyZero); exit = exit .transition(transition) .style('opacity', effectivelyZero); } exit.remove(); update.enter = () => enter; update.exit = () => exit; return update; }; dataJoin.element = (...args) => { if (!args.length) { return element; } element = args[0]; return dataJoin; }; dataJoin.className = (...args) => { if (!args.length) { return className; } className = args[0]; return dataJoin; }; dataJoin.key = (...args) => { if (!args.length) { return key; } key = args[0]; return dataJoin; }; dataJoin.transition = (...args) => { if (!args.length) { return explicitTransition; } explicitTransition = args[0]; return dataJoin; }; return dataJoin; };