From 7cd830f3256bd4980a1b6a13dcc0ba8acfeb1749 Mon Sep 17 00:00:00 2001 From: Quincy Morgan Date: Thu, 4 Jun 2020 17:15:24 -0400 Subject: [PATCH] Update statistics --- docs/statistics.html | 1686 ++++++++++++------------------------------ 1 file changed, 489 insertions(+), 1197 deletions(-) diff --git a/docs/statistics.html b/docs/statistics.html index 18c637c5b..9ffb2dede 100644 --- a/docs/statistics.html +++ b/docs/statistics.html @@ -7,9 +7,9 @@ RollUp Visualizer @@ -103,881 +115,18 @@ main { var drawChart = (function () { 'use strict'; - var xhtml = "http://www.w3.org/1999/xhtml"; + var n,u,i,t,o,r,f,e={},c=[],s=/acit|ex(?:s|g|n|p|$)|rph|grid|ows|mnc|ntw|ine[ch]|zoo|^ord/i;function a(n,l){for(var u in l)n[u]=l[u];return n}function v(n){var l=n.parentNode;l&&l.removeChild(n);}function h(n,l,u){var i,t=arguments,o={};for(i in l)"key"!==i&&"ref"!==i&&(o[i]=l[i]);if(arguments.length>3)for(u=[u],i=3;i=u.__.length&&u.__.push({}),u.__[t]}function v$1(n){return m$1(x$1,n)}function m$1(n,u,i){var o=a$1(t$1++);return o.__c||(o.__c=r$1,o.__=[i?i(u):x$1(void 0,u),function(t){var r=n(o.__[0],t);o.__[0]!==r&&(o.__[0]=r,o.__c.setState({}));}]),o.__}function p$1(n,u){var i=a$1(t$1++);q(i.__H,u)&&(i.__=n,i.__H=u,r$1.__H.__h.push(i));}function y(n){return s$1(function(){return {current:n}},[])}function s$1(n,r){var u=a$1(t$1++);return q(u.__H,r)?(u.__H=r,u.__h=n,u.__=n()):u.__}function F(){i$1.some(function(t){if(t.__P)try{t.__H.__h.forEach(_$1),t.__H.__h.forEach(g$1),t.__H.__h=[];}catch(r){return n.__e(r,t.__v),!0}}),i$1=[];}function _$1(n){n.t&&n.t();}function g$1(n){var t=n.__();"function"==typeof t&&(n.t=t);}function q(n,t){return !n||t.some(function(t,r){return t!==n[r]})}function x$1(n,t){return "function"==typeof t?t(n):t}n.__r=function(n){o$1&&o$1(n),t$1=0,(r$1=n.__c).__H&&(r$1.__H.__h.forEach(_$1),r$1.__H.__h.forEach(g$1),r$1.__H.__h=[]);},n.diffed=function(t){f$1&&f$1(t);var r=t.__c;if(r){var o=r.__H;o&&o.__h.length&&(1!==i$1.push(r)&&u$1===n.requestAnimationFrame||((u$1=n.requestAnimationFrame)||function(n){var t,r=function(){clearTimeout(u),cancelAnimationFrame(t),setTimeout(n);},u=setTimeout(r,100);"undefined"!=typeof window&&(t=requestAnimationFrame(r));})(F));}},n.__c=function(t,r){r.some(function(t){try{t.__h.forEach(_$1),t.__h=t.__h.filter(function(n){return !n.__||g$1(n)});}catch(u){r.some(function(n){n.__h&&(n.__h=[]);}),r=[],n.__e(u,t.__v);}}),c$1&&c$1(t,r);},n.unmount=function(t){e$1&&e$1(t);var r=t.__c;if(r){var u=r.__H;if(u)try{u.__.forEach(function(n){return n.t&&n.t()});}catch(t){n.__e(t,r.__v);}}}; - function namespace(name) { - var prefix = name += "", i = prefix.indexOf(":"); - if (i >= 0 && (prefix = name.slice(0, i)) !== "xmlns") name = name.slice(i + 1); - return namespaces.hasOwnProperty(prefix) ? {space: namespaces[prefix], local: name} : name; // eslint-disable-line no-prototype-builtins - } + var n$1=function(t,s,r,e){var u;s[0]=0;for(var h=1;h=5&&((e||!n&&5===r)&&(h.push(r,0,e,s),r=6),n&&(h.push(r,n,0,s),r=6)),e="";},a=0;a"===t?(r=1,e=""):e=t+e[0]:u?t===u?u="":e+=t:'"'===t||"'"===t?u=t:">"===t?(p(),r=1):r&&("="===t?(r=5,s=e,e=""):"/"===t&&(r<5||">"===n[a][l+1])?(p(),3===r&&(h=h[0]),r=h,(h=h[0]).push(2,0,r),r=0):" "===t||"\t"===t||"\n"===t||"\r"===t?(p(),r=2):e+=t),3===r&&"!--"===e&&(r=4,h=h[0]);}return p(),h}(s)),r),arguments,[])).length>1?r:r[0]} - function creatorInherit(name) { - return function() { - var document = this.ownerDocument, - uri = this.namespaceURI; - return uri === xhtml && document.documentElement.namespaceURI === xhtml - ? document.createElement(name) - : document.createElementNS(uri, name); - }; - } - - function creatorFixed(fullname) { - return function() { - return this.ownerDocument.createElementNS(fullname.space, fullname.local); - }; - } - - function creator(name) { - var fullname = namespace(name); - return (fullname.local - ? creatorFixed - : creatorInherit)(fullname); - } - - function none() {} - - function selector(selector) { - return selector == null ? none : function() { - return this.querySelector(selector); - }; - } - - function selection_select(select) { - if (typeof select !== "function") select = selector(select); - - for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { - for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i) { - if ((node = group[i]) && (subnode = select.call(node, node.__data__, i, group))) { - if ("__data__" in node) subnode.__data__ = node.__data__; - subgroup[i] = subnode; - } - } - } - - return new Selection(subgroups, this._parents); - } - - function array(x) { - return typeof x === "object" && "length" in x - ? x // Array, TypedArray, NodeList, array-like - : Array.from(x); // Map, Set, iterable, string, or anything else - } - - function empty() { - return []; - } - - function selectorAll(selector) { - return selector == null ? empty : function() { - return this.querySelectorAll(selector); - }; - } - - function arrayAll(select) { - return function() { - var group = select.apply(this, arguments); - return group == null ? [] : array(group); - }; - } - - function selection_selectAll(select) { - if (typeof select === "function") select = arrayAll(select); - else select = selectorAll(select); - - for (var groups = this._groups, m = groups.length, subgroups = [], parents = [], j = 0; j < m; ++j) { - for (var group = groups[j], n = group.length, node, i = 0; i < n; ++i) { - if (node = group[i]) { - subgroups.push(select.call(node, node.__data__, i, group)); - parents.push(node); - } - } - } - - return new Selection(subgroups, parents); - } - - function matcher(selector) { - return function() { - return this.matches(selector); - }; - } - - function selection_filter(match) { - if (typeof match !== "function") match = matcher(match); - - for (var groups = this._groups, m = groups.length, subgroups = new Array(m), j = 0; j < m; ++j) { - for (var group = groups[j], n = group.length, subgroup = subgroups[j] = [], node, i = 0; i < n; ++i) { - if ((node = group[i]) && match.call(node, node.__data__, i, group)) { - subgroup.push(node); - } - } - } - - return new Selection(subgroups, this._parents); - } - - function sparse(update) { - return new Array(update.length); - } - - function selection_enter() { - return new Selection(this._enter || this._groups.map(sparse), this._parents); - } - - function EnterNode(parent, datum) { - this.ownerDocument = parent.ownerDocument; - this.namespaceURI = parent.namespaceURI; - this._next = null; - this._parent = parent; - this.__data__ = datum; - } - - EnterNode.prototype = { - constructor: EnterNode, - appendChild: function(child) { return this._parent.insertBefore(child, this._next); }, - insertBefore: function(child, next) { return this._parent.insertBefore(child, next); }, - querySelector: function(selector) { return this._parent.querySelector(selector); }, - querySelectorAll: function(selector) { return this._parent.querySelectorAll(selector); } - }; - - function constant(x) { - return function() { - return x; - }; - } - - function bindIndex(parent, group, enter, update, exit, data) { - var i = 0, - node, - groupLength = group.length, - dataLength = data.length; - - // Put any non-null nodes that fit into update. - // Put any null nodes into enter. - // Put any remaining data into enter. - for (; i < dataLength; ++i) { - if (node = group[i]) { - node.__data__ = data[i]; - update[i] = node; - } else { - enter[i] = new EnterNode(parent, data[i]); - } - } - - // Put any non-null nodes that don’t fit into exit. - for (; i < groupLength; ++i) { - if (node = group[i]) { - exit[i] = node; - } - } - } - - function bindKey(parent, group, enter, update, exit, data, key) { - var i, - node, - nodeByKeyValue = new Map, - groupLength = group.length, - dataLength = data.length, - keyValues = new Array(groupLength), - keyValue; - - // Compute the key for each node. - // If multiple nodes have the same key, the duplicates are added to exit. - for (i = 0; i < groupLength; ++i) { - if (node = group[i]) { - keyValues[i] = keyValue = key.call(node, node.__data__, i, group) + ""; - if (nodeByKeyValue.has(keyValue)) { - exit[i] = node; - } else { - nodeByKeyValue.set(keyValue, node); - } - } - } - - // Compute the key for each datum. - // If there a node associated with this key, join and add it to update. - // If there is not (or the key is a duplicate), add it to enter. - for (i = 0; i < dataLength; ++i) { - keyValue = key.call(parent, data[i], i, data) + ""; - if (node = nodeByKeyValue.get(keyValue)) { - update[i] = node; - node.__data__ = data[i]; - nodeByKeyValue.delete(keyValue); - } else { - enter[i] = new EnterNode(parent, data[i]); - } - } - - // Add any remaining nodes that were not bound to data to exit. - for (i = 0; i < groupLength; ++i) { - if ((node = group[i]) && (nodeByKeyValue.get(keyValues[i]) === node)) { - exit[i] = node; - } - } - } - - function datum(node) { - return node.__data__; - } - - function selection_data(value, key) { - if (!arguments.length) return Array.from(this, datum); - - var bind = key ? bindKey : bindIndex, - parents = this._parents, - groups = this._groups; - - if (typeof value !== "function") value = constant(value); - - for (var m = groups.length, update = new Array(m), enter = new Array(m), exit = new Array(m), j = 0; j < m; ++j) { - var parent = parents[j], - group = groups[j], - groupLength = group.length, - data = array(value.call(parent, parent && parent.__data__, j, parents)), - dataLength = data.length, - enterGroup = enter[j] = new Array(dataLength), - updateGroup = update[j] = new Array(dataLength), - exitGroup = exit[j] = new Array(groupLength); - - bind(parent, group, enterGroup, updateGroup, exitGroup, data, key); - - // Now connect the enter nodes to their following update node, such that - // appendChild can insert the materialized enter node before this node, - // rather than at the end of the parent node. - for (var i0 = 0, i1 = 0, previous, next; i0 < dataLength; ++i0) { - if (previous = enterGroup[i0]) { - if (i0 >= i1) i1 = i0 + 1; - while (!(next = updateGroup[i1]) && ++i1 < dataLength); - previous._next = next || null; - } - } - } - - update = new Selection(update, parents); - update._enter = enter; - update._exit = exit; - return update; - } - - function selection_exit() { - return new Selection(this._exit || this._groups.map(sparse), this._parents); - } - - function selection_join(onenter, onupdate, onexit) { - var enter = this.enter(), update = this, exit = this.exit(); - enter = typeof onenter === "function" ? onenter(enter) : enter.append(onenter + ""); - if (onupdate != null) update = onupdate(update); - if (onexit == null) exit.remove(); else onexit(exit); - return enter && update ? enter.merge(update).order() : update; - } - - function selection_merge(selection) { - if (!(selection instanceof Selection)) throw new Error("invalid merge"); - - for (var groups0 = this._groups, groups1 = selection._groups, m0 = groups0.length, m1 = groups1.length, m = Math.min(m0, m1), merges = new Array(m0), j = 0; j < m; ++j) { - for (var group0 = groups0[j], group1 = groups1[j], n = group0.length, merge = merges[j] = new Array(n), node, i = 0; i < n; ++i) { - if (node = group0[i] || group1[i]) { - merge[i] = node; - } - } - } - - for (; j < m0; ++j) { - merges[j] = groups0[j]; - } - - return new Selection(merges, this._parents); - } - - function selection_order() { - - for (var groups = this._groups, j = -1, m = groups.length; ++j < m;) { - for (var group = groups[j], i = group.length - 1, next = group[i], node; --i >= 0;) { - if (node = group[i]) { - if (next && node.compareDocumentPosition(next) ^ 4) next.parentNode.insertBefore(node, next); - next = node; - } - } - } - - return this; - } - - function selection_sort(compare) { - if (!compare) compare = ascending; - - function compareNode(a, b) { - return a && b ? compare(a.__data__, b.__data__) : !a - !b; - } - - for (var groups = this._groups, m = groups.length, sortgroups = new Array(m), j = 0; j < m; ++j) { - for (var group = groups[j], n = group.length, sortgroup = sortgroups[j] = new Array(n), node, i = 0; i < n; ++i) { - if (node = group[i]) { - sortgroup[i] = node; - } - } - sortgroup.sort(compareNode); - } - - return new Selection(sortgroups, this._parents).order(); - } + var m$2=e$2.bind(h); function ascending(a, b) { return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; } - function selection_call() { - var callback = arguments[0]; - arguments[0] = this; - callback.apply(null, arguments); - return this; - } - - function selection_nodes() { - return Array.from(this); - } - - function selection_node() { - - for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { - for (var group = groups[j], i = 0, n = group.length; i < n; ++i) { - var node = group[i]; - if (node) return node; - } - } - - return null; - } - - function selection_size() { - let size = 0; - for (const node of this) ++size; // eslint-disable-line no-unused-vars - return size; - } - - function selection_empty() { - return !this.node(); - } - - function selection_each(callback) { - - for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { - for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { - if (node = group[i]) callback.call(node, node.__data__, i, group); - } - } - - return this; - } - - function attrRemove(name) { - return function() { - this.removeAttribute(name); - }; - } - - function attrRemoveNS(fullname) { - return function() { - this.removeAttributeNS(fullname.space, fullname.local); - }; - } - - function attrConstant(name, value) { - return function() { - this.setAttribute(name, value); - }; - } - - function attrConstantNS(fullname, value) { - return function() { - this.setAttributeNS(fullname.space, fullname.local, value); - }; - } - - function attrFunction(name, value) { - return function() { - var v = value.apply(this, arguments); - if (v == null) this.removeAttribute(name); - else this.setAttribute(name, v); - }; - } - - function attrFunctionNS(fullname, value) { - return function() { - var v = value.apply(this, arguments); - if (v == null) this.removeAttributeNS(fullname.space, fullname.local); - else this.setAttributeNS(fullname.space, fullname.local, v); - }; - } - - function selection_attr(name, value) { - var fullname = namespace(name); - - if (arguments.length < 2) { - var node = this.node(); - return fullname.local - ? node.getAttributeNS(fullname.space, fullname.local) - : node.getAttribute(fullname); - } - - return this.each((value == null - ? (fullname.local ? attrRemoveNS : attrRemove) : (typeof value === "function" - ? (fullname.local ? attrFunctionNS : attrFunction) - : (fullname.local ? attrConstantNS : attrConstant)))(fullname, value)); - } - - function defaultView(node) { - return (node.ownerDocument && node.ownerDocument.defaultView) // node is a Node - || (node.document && node) // node is a Window - || node.defaultView; // node is a Document - } - - function styleRemove(name) { - return function() { - this.style.removeProperty(name); - }; - } - - function styleConstant(name, value, priority) { - return function() { - this.style.setProperty(name, value, priority); - }; - } - - function styleFunction(name, value, priority) { - return function() { - var v = value.apply(this, arguments); - if (v == null) this.style.removeProperty(name); - else this.style.setProperty(name, v, priority); - }; - } - - function selection_style(name, value, priority) { - return arguments.length > 1 - ? this.each((value == null - ? styleRemove : typeof value === "function" - ? styleFunction - : styleConstant)(name, value, priority == null ? "" : priority)) - : styleValue(this.node(), name); - } - - function styleValue(node, name) { - return node.style.getPropertyValue(name) - || defaultView(node).getComputedStyle(node, null).getPropertyValue(name); - } - - function propertyRemove(name) { - return function() { - delete this[name]; - }; - } - - function propertyConstant(name, value) { - return function() { - this[name] = value; - }; - } - - function propertyFunction(name, value) { - return function() { - var v = value.apply(this, arguments); - if (v == null) delete this[name]; - else this[name] = v; - }; - } - - function selection_property(name, value) { - return arguments.length > 1 - ? this.each((value == null - ? propertyRemove : typeof value === "function" - ? propertyFunction - : propertyConstant)(name, value)) - : this.node()[name]; - } - - function classArray(string) { - return string.trim().split(/^|\s+/); - } - - function classList(node) { - return node.classList || new ClassList(node); - } - - function ClassList(node) { - this._node = node; - this._names = classArray(node.getAttribute("class") || ""); - } - - ClassList.prototype = { - add: function(name) { - var i = this._names.indexOf(name); - if (i < 0) { - this._names.push(name); - this._node.setAttribute("class", this._names.join(" ")); - } - }, - remove: function(name) { - var i = this._names.indexOf(name); - if (i >= 0) { - this._names.splice(i, 1); - this._node.setAttribute("class", this._names.join(" ")); - } - }, - contains: function(name) { - return this._names.indexOf(name) >= 0; - } - }; - - function classedAdd(node, names) { - var list = classList(node), i = -1, n = names.length; - while (++i < n) list.add(names[i]); - } - - function classedRemove(node, names) { - var list = classList(node), i = -1, n = names.length; - while (++i < n) list.remove(names[i]); - } - - function classedTrue(names) { - return function() { - classedAdd(this, names); - }; - } - - function classedFalse(names) { - return function() { - classedRemove(this, names); - }; - } - - function classedFunction(names, value) { - return function() { - (value.apply(this, arguments) ? classedAdd : classedRemove)(this, names); - }; - } - - function selection_classed(name, value) { - var names = classArray(name + ""); - - if (arguments.length < 2) { - var list = classList(this.node()), i = -1, n = names.length; - while (++i < n) if (!list.contains(names[i])) return false; - return true; - } - - return this.each((typeof value === "function" - ? classedFunction : value - ? classedTrue - : classedFalse)(names, value)); - } - - function textRemove() { - this.textContent = ""; - } - - function textConstant(value) { - return function() { - this.textContent = value; - }; - } - - function textFunction(value) { - return function() { - var v = value.apply(this, arguments); - this.textContent = v == null ? "" : v; - }; - } - - function selection_text(value) { - return arguments.length - ? this.each(value == null - ? textRemove : (typeof value === "function" - ? textFunction - : textConstant)(value)) - : this.node().textContent; - } - - function htmlRemove() { - this.innerHTML = ""; - } - - function htmlConstant(value) { - return function() { - this.innerHTML = value; - }; - } - - function htmlFunction(value) { - return function() { - var v = value.apply(this, arguments); - this.innerHTML = v == null ? "" : v; - }; - } - - function selection_html(value) { - return arguments.length - ? this.each(value == null - ? htmlRemove : (typeof value === "function" - ? htmlFunction - : htmlConstant)(value)) - : this.node().innerHTML; - } - - function raise() { - if (this.nextSibling) this.parentNode.appendChild(this); - } - - function selection_raise() { - return this.each(raise); - } - - function lower() { - if (this.previousSibling) this.parentNode.insertBefore(this, this.parentNode.firstChild); - } - - function selection_lower() { - return this.each(lower); - } - - function selection_append(name) { - var create = typeof name === "function" ? name : creator(name); - return this.select(function() { - return this.appendChild(create.apply(this, arguments)); - }); - } - - function constantNull() { - return null; - } - - function selection_insert(name, before) { - var create = typeof name === "function" ? name : creator(name), - select = before == null ? constantNull : typeof before === "function" ? before : selector(before); - return this.select(function() { - return this.insertBefore(create.apply(this, arguments), select.apply(this, arguments) || null); - }); - } - - function remove() { - var parent = this.parentNode; - if (parent) parent.removeChild(this); - } - - function selection_remove() { - return this.each(remove); - } - - function selection_cloneShallow() { - var clone = this.cloneNode(false), parent = this.parentNode; - return parent ? parent.insertBefore(clone, this.nextSibling) : clone; - } - - function selection_cloneDeep() { - var clone = this.cloneNode(true), parent = this.parentNode; - return parent ? parent.insertBefore(clone, this.nextSibling) : clone; - } - - function selection_clone(deep) { - return this.select(deep ? selection_cloneDeep : selection_cloneShallow); - } - - function selection_datum(value) { - return arguments.length - ? this.property("__data__", value) - : this.node().__data__; - } - - function contextListener(listener) { - return function(event) { - listener.call(this, event, this.__data__); - }; - } - - function parseTypenames(typenames) { - return typenames.trim().split(/^|\s+/).map(function(t) { - var name = "", i = t.indexOf("."); - if (i >= 0) name = t.slice(i + 1), t = t.slice(0, i); - return {type: t, name: name}; - }); - } - - function onRemove(typename) { - return function() { - var on = this.__on; - if (!on) return; - for (var j = 0, i = -1, m = on.length, o; j < m; ++j) { - if (o = on[j], (!typename.type || o.type === typename.type) && o.name === typename.name) { - this.removeEventListener(o.type, o.listener, o.options); - } else { - on[++i] = o; - } - } - if (++i) on.length = i; - else delete this.__on; - }; - } - - function onAdd(typename, value, options) { - return function() { - var on = this.__on, o, listener = contextListener(value); - if (on) for (var j = 0, m = on.length; j < m; ++j) { - if ((o = on[j]).type === typename.type && o.name === typename.name) { - this.removeEventListener(o.type, o.listener, o.options); - this.addEventListener(o.type, o.listener = listener, o.options = options); - o.value = value; - return; - } - } - this.addEventListener(typename.type, listener, options); - o = {type: typename.type, name: typename.name, value: value, listener: listener, options: options}; - if (!on) this.__on = [o]; - else on.push(o); - }; - } - - function selection_on(typename, value, options) { - var typenames = parseTypenames(typename + ""), i, n = typenames.length, t; - - if (arguments.length < 2) { - var on = this.node().__on; - if (on) for (var j = 0, m = on.length, o; j < m; ++j) { - for (i = 0, o = on[j]; i < n; ++i) { - if ((t = typenames[i]).type === o.type && t.name === o.name) { - return o.value; - } - } - } - return; - } - - on = value ? onAdd : onRemove; - for (i = 0; i < n; ++i) this.each(on(typenames[i], value, options)); - return this; - } - - function dispatchEvent(node, type, params) { - var window = defaultView(node), - event = window.CustomEvent; - - if (typeof event === "function") { - event = new event(type, params); - } else { - event = window.document.createEvent("Event"); - if (params) event.initEvent(type, params.bubbles, params.cancelable), event.detail = params.detail; - else event.initEvent(type, false, false); - } - - node.dispatchEvent(event); - } - - function dispatchConstant(type, params) { - return function() { - return dispatchEvent(this, type, params); - }; - } - - function dispatchFunction(type, params) { - return function() { - return dispatchEvent(this, type, params.apply(this, arguments)); - }; - } - - function selection_dispatch(type, params) { - return this.each((typeof params === "function" - ? dispatchFunction - : dispatchConstant)(type, params)); - } - - function* selection_iterator() { - for (var groups = this._groups, j = 0, m = groups.length; j < m; ++j) { - for (var group = groups[j], i = 0, n = group.length, node; i < n; ++i) { - if (node = group[i]) yield node; - } - } - } - - var root = [null]; - - function Selection(groups, parents) { - this._groups = groups; - this._parents = parents; - } - - function selection() { - return new Selection([[document.documentElement]], root); - } - - Selection.prototype = selection.prototype = { - constructor: Selection, - select: selection_select, - selectAll: selection_selectAll, - filter: selection_filter, - data: selection_data, - enter: selection_enter, - exit: selection_exit, - join: selection_join, - merge: selection_merge, - order: selection_order, - sort: selection_sort, - call: selection_call, - nodes: selection_nodes, - node: selection_node, - size: selection_size, - empty: selection_empty, - each: selection_each, - attr: selection_attr, - style: selection_style, - property: selection_property, - classed: selection_classed, - text: selection_text, - html: selection_html, - raise: selection_raise, - lower: selection_lower, - append: selection_append, - insert: selection_insert, - remove: selection_remove, - clone: selection_clone, - datum: selection_datum, - on: selection_on, - dispatch: selection_dispatch, - [Symbol.iterator]: selection_iterator - }; - - function select(selector) { - return typeof selector === "string" - ? new Selection([[document.querySelector(selector)]], [document.documentElement]) - : new Selection([[selector]], root); - } - - function pointer(event, node = event.currentTarget) { - if (node) { - var svg = node.ownerSVGElement || node; - if (svg.createSVGPoint) { - var point = svg.createSVGPoint(); - point.x = event.clientX, point.y = event.clientY; - point = point.matrixTransform(node.getScreenCTM().inverse()); - return [point.x, point.y]; - } - if (node.getBoundingClientRect) { - var rect = node.getBoundingClientRect(); - return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop]; - } - } - return [event.pageX, event.pageY]; - } - - function ascending$1(a, b) { - return a < b ? -1 : a > b ? 1 : a >= b ? 0 : NaN; - } - function bisector(compare) { if (compare.length === 1) compare = ascendingComparator(compare); return { @@ -1006,11 +155,11 @@ main { function ascendingComparator(f) { return function(d, x) { - return ascending$1(f(d), x); + return ascending(f(d), x); }; } - var ascendingBisect = bisector(ascending$1); + var ascendingBisect = bisector(ascending); var bisectRight = ascendingBisect.right; function identity(x) { @@ -1306,7 +455,7 @@ main { return 0; } - function constant$1(x) { + function constant(x) { return function() { return x; }; @@ -1473,7 +622,7 @@ main { }; treemap.paddingInner = function(x) { - return arguments.length ? (paddingInner = typeof x === "function" ? x : constant$1(+x), treemap) : paddingInner; + return arguments.length ? (paddingInner = typeof x === "function" ? x : constant(+x), treemap) : paddingInner; }; treemap.paddingOuter = function(x) { @@ -1481,19 +630,19 @@ main { }; treemap.paddingTop = function(x) { - return arguments.length ? (paddingTop = typeof x === "function" ? x : constant$1(+x), treemap) : paddingTop; + return arguments.length ? (paddingTop = typeof x === "function" ? x : constant(+x), treemap) : paddingTop; }; treemap.paddingRight = function(x) { - return arguments.length ? (paddingRight = typeof x === "function" ? x : constant$1(+x), treemap) : paddingRight; + return arguments.length ? (paddingRight = typeof x === "function" ? x : constant(+x), treemap) : paddingRight; }; treemap.paddingBottom = function(x) { - return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant$1(+x), treemap) : paddingBottom; + return arguments.length ? (paddingBottom = typeof x === "function" ? x : constant(+x), treemap) : paddingBottom; }; treemap.paddingLeft = function(x) { - return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant$1(+x), treemap) : paddingLeft; + return arguments.length ? (paddingLeft = typeof x === "function" ? x : constant(+x), treemap) : paddingLeft; }; return treemap; @@ -1639,7 +788,7 @@ main { } } - function uid(name) { + function uid (name) { count$1 += 1; const id = ["O", name, count$1].filter(Boolean).join("-"); return new Id(id); @@ -2078,7 +1227,7 @@ main { }; } - function constant$2(x) { + function constant$1(x) { return function() { return x; }; @@ -2098,13 +1247,13 @@ main { function gamma(y) { return (y = +y) === 1 ? nogamma : function(a, b) { - return b - a ? exponential(a, b, y) : constant$2(isNaN(a) ? b : a); + return b - a ? exponential(a, b, y) : constant$1(isNaN(a) ? b : a); }; } function nogamma(a, b) { var d = b - a; - return d ? linear(a, d) : constant$2(isNaN(a) ? b : a); + return d ? linear(a, d) : constant$1(isNaN(a) ? b : a); } var rgb$1 = (function rgbGamma(y) { @@ -2288,7 +1437,7 @@ main { function interpolate(a, b) { var t = typeof b, c; - return b == null || t === "boolean" ? constant$2(b) + return b == null || t === "boolean" ? constant$1(b) : (t === "number" ? interpolateNumber : t === "string" ? ((c = color(b)) ? (b = c, rgb$1) : string) : b instanceof color ? rgb$1 @@ -2305,7 +1454,7 @@ main { }; } - function constant$3(x) { + function constant$2(x) { return function() { return x; }; @@ -2324,7 +1473,7 @@ main { function normalize(a, b) { return (b -= (a = +a)) ? function(x) { return (x - a) / b; } - : constant$3(isNaN(b) ? NaN : 0.5); + : constant$2(isNaN(b) ? NaN : 0.5); } function clamper(a, b) { @@ -2536,7 +1685,7 @@ main { switch (s[i]) { case ".": i0 = i1 = i; break; case "0": if (i0 === 0) i0 = i; i1 = i; break; - default: if (i0 > 0) { if (!+s[i]) break out; i0 = 0; } break; + default: if (!+s[i]) break out; if (i0 > 0) i0 = 0; break; } } return i0 > 0 ? s.slice(0, i0) + s.slice(i1 + 1) : s; @@ -2968,7 +2117,7 @@ main { return r * rc + g * gc + b * bc; } - const createRainbowColor = root => { + const createRainbowColor = (root) => { const colorParentMap = new Map(); colorParentMap.set(root, COLOR_BASE); @@ -2984,11 +2133,9 @@ main { const colorMap = new Map(); - const lightScale = linear$1() - .domain([0, root.height]) - .range([0.8, 0.1]); + const lightScale = linear$1().domain([0, root.height]).range([0.8, 0.1]); - const getBackgroundColor = node => { + const getBackgroundColor = (node) => { const parents = node.ancestors(); const colorStr = parents.length === 1 @@ -3001,7 +2148,7 @@ main { return hslColor; }; - return node => { + return (node) => { if (!colorMap.has(node)) { const backgroundColor = getBackgroundColor(node); const l = relativeLuminance(backgroundColor.rgb()); @@ -3013,148 +2160,391 @@ main { }; }; - const getNodePathTree = d => - d - .ancestors() - .reverse() - .map(d => d.data.name) - .join("/"); + const LABELS = { + renderedLength: "Rendered", + gzipLength: "Gzip", + brotliLength: "Brotli", + }; - const getNodeSizeTree = d => d.value; - - const getNodeUidTree = d => d.data.uid; - - class Tooltip { - constructor(container) { - this.tooltip = container - .append("div") - .style("opacity", 0) - .attr("class", "tooltip"); - - this.container = container; - - this.onMouseLeave = this.onMouseLeave.bind(this); - this.onMouseOver = this.onMouseOver.bind(this); - this.onMouseMove = this.onMouseMove.bind(this); + const getAvailableSizeOptions = (options = {}) => { + const availableSizeProperties = ["renderedLength"]; + if (options.gzip) { + availableSizeProperties.push("gzipLength"); + } + if (options.brotli) { + availableSizeProperties.push("brotliLength"); } - onMouseOver() { - this.tooltip.style("opacity", 1); - } + return availableSizeProperties; + }; - onMouseMove(event, data) { - const { html } = this.tooltipContentCache.get(data); + const Tooltip = ({ + node, + visible, + root, + sizeProperty, + availableSizeProperties, + importedByCache, + }) => { + const ref = y(); + const [style, setStyle] = v$1({}); + const content = s$1(() => { + if (!node) return null; - this.tooltip.html(html); + const mainSize = node.originalValue[sizeProperty]; - const [x, y] = pointer(event, this.container.node()); + const percentageNum = (100 * mainSize) / root.originalValue[sizeProperty]; + const percentage = percentageNum.toFixed(2); + const percentageString = percentage + "%"; - const tooltipBox = this.tooltip.node().getBoundingClientRect(); - const containerBox = this.container.node().getBoundingClientRect(); + const uid = node.data.uid; - const availableWidthRight = containerBox.width - x; - const availableHeightBottom = containerBox.height - y; + const path = node + .ancestors() + .reverse() + .map((d) => d.data.name) + .join("/"); - const positionStyles = []; - const offsetX = 10; - const offsetY = 10; - if (availableHeightBottom >= tooltipBox.height + offsetY) { - positionStyles.push(["top", y + offsetY], ["bottom", null]); - } else { - positionStyles.push( - ["top", null], - ["bottom", availableHeightBottom + offsetY] - ); - } - if (availableWidthRight >= tooltipBox.width + offsetX) { - positionStyles.push(["left", x + offsetX], ["right", null]); - } else { - positionStyles.push( - ["left", null], - ["right", availableWidthRight + offsetX] - ); + return m$2` +
${path}
+ ${availableSizeProperties.map((sizeProp) => { + if (sizeProp === sizeProperty) { + return m$2` +
+ ${LABELS[sizeProp]}:${" "}${format_1(mainSize)}${" "}(${percentageString}) +
+ `; + } else { + return m$2` +
+ ${LABELS[sizeProp]}:${" "} + ${format_1(node.originalValue[sizeProp])} +
+ `; + } + })} + ${uid && + importedByCache.has(uid) && + m$2` +
+
Imported By:
+ ${[...new Set(importedByCache.get(uid).map(({ id }) => id))].map( + (id) => m$2`
${id}
` + )} +
+ `} + `; + }, [node]); + + const updatePosition = (mouseCoords) => { + const pos = { + left: mouseCoords.x + Tooltip.marginX, + top: mouseCoords.y + Tooltip.marginY, + }; + + const boundingRect = ref.current.getBoundingClientRect(); + + if (pos.left + boundingRect.width > window.innerWidth) { + // Shifting horizontally + pos.left = window.innerWidth - boundingRect.width; } - for (const [pos, offset] of positionStyles) { - this.tooltip.style( - pos, - typeof offset === "number" ? offset + "px" : offset - ); - } - } - - onMouseLeave() { - this.tooltip.style("opacity", 0); - } - - buildCache( - contentNodes, - { - totalSize, - getNodeSize = getNodeSizeTree, - getNodePath = getNodePathTree, - getNodeUid = getNodeUidTree, - nodes, - links - } - ) { - this.tooltipContentCache = new Map(); - - const importedByCache = new Map(); - const importedCache = new Map(); - - for (const { source, target } of links || []) { - if (!importedByCache.has(target)) { - importedByCache.set(target, []); - } - if (!importedCache.has(source)) { - importedCache.set(source, []); - } - - importedByCache.get(target).push({ uid: source, ...nodes[source] }); - importedCache.get(source).push({ uid: target, ...nodes[target] }); + if (pos.top + boundingRect.height > window.innerHeight) { + // Flipping vertically + pos.top = mouseCoords.y - Tooltip.marginY - boundingRect.height; } - contentNodes.each(data => { - const contentCache = {}; + setStyle(pos); + }; - const str = []; - if (getNodePath != null) { - str.push(getNodePath(data)); - } - - const value = getNodeSize(data); - if (value !== 0) { - let sizeStr = `Size: ${format_1(value)}`; - - if (totalSize != null) { - const percentageNum = (100 * value) / totalSize; - const percentage = percentageNum.toFixed(2); - const percentageString = percentage + "%"; - - sizeStr += ` (${percentageString})`; - } - str.push(sizeStr); - } - - const uid = getNodeUid(data); - if (uid && importedByCache.has(uid)) { - const importedBy = importedByCache.get(uid); - str.push( - `Imported By:
${[ - ...new Set(importedBy.map(({ id }) => id)) - ].join("
")}` - ); - } - - contentCache.html = str.join("
"); - - this.tooltipContentCache.set(data, contentCache); + const handleMouseMove = (event) => { + updatePosition({ + x: event.pageX, + y: event.pageY, }); - } - } + }; + + p$1(() => { + document.addEventListener("mousemove", handleMouseMove, true); + return () => { + document.removeEventListener("mousemove", handleMouseMove, true); + }; + }, []); + + return m$2` +
+ ${content} +
+ `; + }; + + Tooltip.marginX = 10; + Tooltip.marginY = 30; + + const Node$1 = ({ + node, + backgroundColor, + fontColor, + onClick, + isSelected, + onNodeHover, + sizeProperty, + }) => { + const { + nodeUid, + x0, + x1, + y1, + y0, + clipUid, + data, + originalValue, + children = null, + } = node; + + const tspan1Props = {}; + const tspan2Props = {}; + if (children != null) { + tspan1Props.dx = 3; + tspan2Props.dx = 3; + tspan1Props.y = 13; + tspan2Props.y = 13; + } else { + tspan1Props.x = 3; + tspan2Props.x = 3; + tspan1Props.y = "1.1em"; + tspan2Props.y = "2.3em"; + } + + const handleClickSelection = (event) => { + if (window.getSelection().toString() !== "") { + event.stopPropagation(); + } + }; + + return m$2` + { + evt.stopPropagation(); + onNodeHover(node); + }} + > + + + + + + + ${data.name} + ${format_1(originalValue[sizeProperty])} + + + `; + }; + + const TreeMap = ({ + root, + layout, + color, + width, + height, + onNodeHover, + sizeProperty, + }) => { + const [selectedNode, setSelectedNode] = v$1(null); + + const desiredValue = root.originalValue[sizeProperty] * 0.2; + + //handle zoom of selected node + const selectedNodeMultiplier = + selectedNode != null + ? desiredValue > selectedNode.originalValue[sizeProperty] + ? desiredValue / selectedNode.originalValue[sizeProperty] + : 3 + : 1; + + // i only need to increase value of leaf nodes + // as folders will sum they up + const nodesToIncrease = + selectedNode != null + ? selectedNode.children != null + ? selectedNode.leaves() + : [selectedNode] + : []; + + const nodesToIncreaseSet = new Set(nodesToIncrease); + + // update value for nodes + root = root.eachAfter((node) => { + let sum = 0; + const children = node.children; + if (children != null) { + let i = children.length; + while (--i >= 0) sum += children[i].value; + } else { + sum = nodesToIncreaseSet.has(node) + ? node.originalValue[sizeProperty] * selectedNodeMultiplier + : node.originalValue[sizeProperty]; + } + + node.value = sum; + }); + + layout(root); + + // this will make groups by height + const nestedDataMap = group(root.descendants(), (d) => d.height); + const nestedData = Array.from(nestedDataMap, ([key, values]) => ({ + key, + values, + })); + nestedData.sort((a, b) => b.key - a.key); + + return m$2` + + ${nestedData.map(({ key, values }) => { + return m$2` + + ${values.map((node) => { + const { backgroundColor, fontColor } = color(node); + return m$2` + <${Node$1} + node=${node} + backgroundColor=${backgroundColor} + fontColor=${fontColor} + onClick=${() => + setSelectedNode(selectedNode === node ? null : node)} + isSelected=${selectedNode === node} + onNodeHover=${onNodeHover} + sizeProperty=${sizeProperty} + /> + `; + })} + + `; + })} + + `; + }; + + const Chart = ({ + layout, + root, + color, + width, + height, + sizeProperty, + availableSizeProperties, + importedCache, + importedByCache, + }) => { + const [showTooltip, setShowTooltip] = v$1(false); + const [tooltipNode, setTooltipNode] = v$1(null); + + const handleMouseOut = () => { + setShowTooltip(false); + }; + + p$1(() => { + document.addEventListener("mouseover", handleMouseOut); + return () => { + document.removeEventListener("mouseover", handleMouseOut); + }; + }, []); + + return m$2` + <${TreeMap} + layout=${layout} + root=${root} + color=${color} + width=${width} + height=${height} + sizeProperty=${sizeProperty} + availableSizeProperties=${availableSizeProperties} + onNodeHover=${(node) => { + setTooltipNode(node); + setShowTooltip(true); + }} + /> + <${Tooltip} + visible=${showTooltip} + node=${tooltipNode} + root=${root} + sizeProperty=${sizeProperty} + availableSizeProperties=${availableSizeProperties} + importedByCache=${importedByCache} + importedCache=${importedCache} + /> + `; + }; + + const SideBar = ({ + availableSizeProperties, + sizeProperty, + setSizeProperty, + }) => { + const handleChange = (sizeProp) => () => { + if (sizeProp !== sizeProperty) { + setSizeProperty(sizeProp); + } + }; + return m$2` + + `; + }; + + const Main = ({ + width, + height, + data: { tree, nodes, links, options = {} }, + }) => { + const availableSizeProperties = getAvailableSizeOptions(options); + + const [sizeProperty, setSizeProperty] = v$1(availableSizeProperties[0]); - const drawChart = (parentNode, { tree, nodes, links }, width, height) => { const layout = d3treemap() .size([width, height]) .paddingOuter(8) @@ -3163,180 +2553,82 @@ main { .round(true) .tile(treemapResquarify); - const charNode = select(parentNode); + const root = hierarchy(tree) + .eachAfter((node) => { + const value = {}; + for (const prop of availableSizeProperties) { + value[prop] = 0; + } - const svg = charNode.append("svg").attr("viewBox", [0, 0, width, height]); - - const tooltip = new Tooltip(charNode); - - let root = hierarchy(tree) - .eachAfter(node => { - let sum = 0; - const children = node.children; - if (children != null) { - let i = children.length; - while (--i >= 0) sum += children[i].value; + // use node.data.children because if it is empty d3 will skip this node + // and it will look like it is actually a leaf - which technically it is but not exactly + // it is just a chunk without deps - usually just with imports + if (node.data.children != null) { + const children = node.children; + let i = node.data.children.length; + while (--i >= 0) { + for (const prop of availableSizeProperties) { + value[prop] += children[i].originalValue[prop]; + } + } } else { - sum = nodes[node.data.uid].renderedLength; + for (const prop of availableSizeProperties) { + value[prop] = nodes[node.data.uid][prop]; + } } node.clipUid = uid("clip"); node.nodeUid = uid("node"); - node.originalValue = sum; - node.value = sum; + node.originalValue = value; + node.value = value[sizeProperty]; }) - .sort((a, b) => b.originalValue - a.originalValue); + .sort( + (a, b) => b.originalValue[sizeProperty] - a.originalValue[sizeProperty] + ); const color = createRainbowColor(root); - const desiredValue = root.originalValue * 0.2; + const importedByCache = new Map(); + const importedCache = new Map(); - const updateChart = selectedNode => { - //handle zoom of selected node - const selectedNodeMultiplier = - selectedNode != null - ? desiredValue > selectedNode.originalValue - ? desiredValue / selectedNode.originalValue - : 3 - : 1; - - // i only need to increase value of leaf nodes - // as folders will sum they up - const nodesToIncrease = - selectedNode != null - ? selectedNode.children != null - ? selectedNode.leaves() - : [selectedNode] - : []; - - const nodesToIncreaseSet = new Set(nodesToIncrease); - - // update value for nodes - root = root.eachAfter(node => { - let sum = 0; - const children = node.children; - if (children != null) { - let i = children.length; - while (--i >= 0) sum += children[i].value; - } else { - sum = nodesToIncreaseSet.has(node) - ? node.originalValue * selectedNodeMultiplier - : node.originalValue; - } - - node.value = sum; - }); - - layout(root); - - // this will make groups by height - const nestedDataMap = group(root.descendants(), d => d.height); - const nestedData = Array.from(nestedDataMap, ([key, values]) => ({ - key, - values - })); - nestedData.sort((a, b) => b.key - a.key); - - const layers = svg - .selectAll(".layer") - .data(nestedData, d => d.key) - .join("g") - .attr("class", "layer"); - - const nodeGroups = layers - .selectAll(".node") - .data( - d => d.values, - d => d - ) - .join("g") - .attr("class", "node") - .attr("transform", d => `translate(${d.x0},${d.y0})`) - .on("mouseover", tooltip.onMouseOver) - .on("mousemove", tooltip.onMouseMove) - .on("mouseleave", tooltip.onMouseLeave) - .on("click", (event, d) => { - if (d === selectedNode) { - updateChart(); - } else { - updateChart(d); - } - }); - //fill node groups - const rect = nodeGroups - .selectAll("rect") - .data(d => [d]) - .join("rect") - .attr("id", d => d.nodeUid.id) - .attr("fill", d => color(d).backgroundColor) - .attr("rx", 2) - .attr("ry", 2) - .attr("width", d => d.x1 - d.x0) - .attr("height", d => d.y1 - d.y0) - .style("stroke", null) - .attr("stroke-width", null); - - if (selectedNode != null) { - rect - .filter(d => d === selectedNode) - .style("stroke", "#fff") - .attr("stroke-width", 2); + for (const { source, target } of links || []) { + if (!importedByCache.has(target)) { + importedByCache.set(target, []); + } + if (!importedCache.has(source)) { + importedCache.set(source, []); } - // add clipPath so text do not go out of node - nodeGroups - .selectAll("clipPath") - .data(d => [d]) - .join("clipPath") - .attr("id", d => d.clipUid.id) - .selectAll("use") - .data(d => [d]) - .join("use") - .attr("xlink:href", d => d.nodeUid.href); + importedByCache.get(target).push({ uid: source, ...nodes[source] }); + importedCache.get(source).push({ uid: target, ...nodes[target] }); + } - // add text with clipping - const text = nodeGroups - .selectAll("text") - .data(d => [d]) - .join("text") - .attr("clip-path", d => d.clipUid) - .style("fill", d => color(d).fontColor); + return m$2` + <${SideBar} + sizeProperty=${sizeProperty} + availableSizeProperties=${availableSizeProperties} + setSizeProperty=${setSizeProperty} + /> + <${Chart} + layout=${layout} + root=${root} + color=${color} + width=${width} + height=${height} + sizeProperty=${sizeProperty} + availableSizeProperties=${availableSizeProperties} + importedByCache=${importedByCache} + importedCache=${importedCache} + /> + `; + }; - text - .selectAll("tspan") - .data(d => [d.data.name, format_1(d.originalValue)]) - .join("tspan") - .attr("fill-opacity", (d, i, nodes) => - i === nodes.length - 1 ? 0.7 : null - ) - .style("font-size", "0.7em") - .text(d => d); - - nodeGroups - .filter(d => d.children) - .selectAll("tspan") - .attr("dx", 3) - .attr("y", 13); - - nodeGroups - .filter(d => !d.children) - .selectAll("tspan") - .attr("x", 3) - .attr( - "y", - (d, i, nodes) => `${(i === nodes.length - 1) * 0.3 + 1.1 + i * 0.9}em` - ); - - tooltip.buildCache(nodeGroups, { - getNodeSize: d => d.originalValue, - totalSize: root.originalValue, - nodes, - links - }); - }; - - updateChart(); + const drawChart = (parentNode, data, width, height) => { + H( + m$2` <${Main} data=${data} width=${width} height=${height} /> `, + parentNode + ); }; return drawChart; @@ -3346,7 +2638,7 @@ main {