UNPKG

terriajs

Version:

Geospatial data visualization platform.

57 lines (53 loc) 2.04 kB
"use strict"; const childNodesSelector = function () { return this.childNodes; }; /** * Convenience wrapper that manages D3's enter/exit mechanics to synchronise an array of data * with DOM elements. * @param {Element} parent HTML element which will contain the nodes * @param {Object[]} arrayData Data to be synchronised. * @param {String} childElementTagName Name of HTML element to be created for each data point. * @param {Function} updateCallBack Function called with (d3object, isNewElement). If it returns the d3object, * an opacity transition will be applied. * @param {Boolean} transition Parameter passed to d3.transition(). */ function d3Sync( parent, arrayData, childElementTagName, updateCallback, transition = null ) { // move stray elements that are not 'childElementTagName' to the bottom // that way they can be removed with the fade out animation parent .selectAll(childNodesSelector) .filter((d, i, nodes) => nodes[i].tagName !== childElementTagName) .each(function () { this.parentElement.appendChild(this); }); // synchronise intended elements const existing = parent .selectAll(childNodesSelector) .data(arrayData, function (d) { return d ? d.id || d : this.id; }); // id hack for ChartData objects which get re-created each time there are any changes const enter = existing.enter().append(childElementTagName); const exit = existing.exit(); if (transition) { exit.transition(transition).style("opacity", 1e-2).remove(); const entered = updateCallback(enter, true); if (entered) { // We don't want to randomly transition all attributes on new elements, because it looks bad. // Instead, let's just transition opacity. entered.style("opacity", 0).transition(transition).style("opacity", 1); } updateCallback(existing.transition(transition).style("opacity", 1), false); } else { exit.remove(); updateCallback(enter, true); updateCallback(existing, false); } } module.exports = d3Sync;