+ const UNIT_DATA = [
+ {
+ "i": 0,
+ "name": "proc-macro2",
+ "version": "1.0.70",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.07,
+ "duration": 0.53,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 24
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 1,
+ "name": "unicode-ident",
+ "version": "1.0.12",
+ "mode": "todo",
+ "target": "",
+ "start": 0.07,
+ "duration": 0.22,
+ "rmeta_time": 0.1,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 2,
+ "name": "serde",
+ "version": "1.0.193",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.07,
+ "duration": 0.48,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 23
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 3,
+ "name": "utf8parse",
+ "version": "0.2.1",
+ "mode": "todo",
+ "target": "",
+ "start": 0.07,
+ "duration": 0.43,
+ "rmeta_time": 0.08,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 10
+ ]
+ },
+ {
+ "i": 4,
+ "name": "thiserror",
+ "version": "1.0.50",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.07,
+ "duration": 0.45,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 21
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 5,
+ "name": "anstyle-query",
+ "version": "1.0.1",
+ "mode": "todo",
+ "target": "",
+ "start": 0.07,
+ "duration": 0.16,
+ "rmeta_time": 0.07,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 6,
+ "name": "anstyle",
+ "version": "1.0.4",
+ "mode": "todo",
+ "target": "",
+ "start": 0.07,
+ "duration": 0.66,
+ "rmeta_time": 0.6,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 27
+ ]
+ },
+ {
+ "i": 7,
+ "name": "camino",
+ "version": "1.1.6",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.07,
+ "duration": 0.54,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 25
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 8,
+ "name": "colorchoice",
+ "version": "1.0.0",
+ "mode": "todo",
+ "target": "",
+ "start": 0.1,
+ "duration": 0.35,
+ "rmeta_time": 0.1,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 9,
+ "name": "semver",
+ "version": "1.0.20",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.13,
+ "duration": 0.42,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 22
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 10,
+ "name": "anstyle-parse",
+ "version": "0.2.3",
+ "mode": "todo",
+ "target": "",
+ "start": 0.16,
+ "duration": 0.51,
+ "rmeta_time": 0.43,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 11,
+ "name": "serde_json",
+ "version": "1.0.108",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.2,
+ "duration": 0.32,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 20
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 12,
+ "name": "strsim",
+ "version": "0.10.0",
+ "mode": "todo",
+ "target": "",
+ "start": 0.24,
+ "duration": 0.77,
+ "rmeta_time": 0.5,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 13,
+ "name": "itoa",
+ "version": "1.0.9",
+ "mode": "todo",
+ "target": "",
+ "start": 0.28,
+ "duration": 0.31,
+ "rmeta_time": 0.19,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 14,
+ "name": "equivalent",
+ "version": "1.0.1",
+ "mode": "todo",
+ "target": "",
+ "start": 0.3,
+ "duration": 0.31,
+ "rmeta_time": 0.04,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 15,
+ "name": "anyhow",
+ "version": "1.0.75",
+ "mode": "todo",
+ "target": " build script",
+ "start": 0.42,
+ "duration": 0.47,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 28
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 16,
+ "name": "ryu",
+ "version": "1.0.15",
+ "mode": "todo",
+ "target": "",
+ "start": 0.45,
+ "duration": 0.55,
+ "rmeta_time": 0.43,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 17,
+ "name": "clap_lex",
+ "version": "0.6.0",
+ "mode": "todo",
+ "target": "",
+ "start": 0.48,
+ "duration": 0.44,
+ "rmeta_time": 0.28,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 18,
+ "name": "hashbrown",
+ "version": "0.14.3",
+ "mode": "todo",
+ "target": "",
+ "start": 0.48,
+ "duration": 0.87,
+ "rmeta_time": 0.81,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 32
+ ]
+ },
+ {
+ "i": 19,
+ "name": "fixedbitset",
+ "version": "0.4.2",
+ "mode": "todo",
+ "target": "",
+ "start": 0.5,
+ "duration": 0.38,
+ "rmeta_time": 0.3,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 20,
+ "name": "serde_json",
+ "version": "1.0.108",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.52,
+ "duration": 0.01,
+ "rmeta_time": null,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 21,
+ "name": "thiserror",
+ "version": "1.0.50",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.52,
+ "duration": 0.14,
+ "rmeta_time": null,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 22,
+ "name": "semver",
+ "version": "1.0.20",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.55,
+ "duration": 0.02,
+ "rmeta_time": null,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 23,
+ "name": "serde",
+ "version": "1.0.193",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.55,
+ "duration": 0.03,
+ "rmeta_time": null,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 24,
+ "name": "proc-macro2",
+ "version": "1.0.70",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.6,
+ "duration": 0.02,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 26
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 25,
+ "name": "camino",
+ "version": "1.1.6",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.61,
+ "duration": 0.02,
+ "rmeta_time": null,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 26,
+ "name": "proc-macro2",
+ "version": "1.0.70",
+ "mode": "todo",
+ "target": "",
+ "start": 0.63,
+ "duration": 0.8,
+ "rmeta_time": 0.56,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 31
+ ]
+ },
+ {
+ "i": 27,
+ "name": "anstream",
+ "version": "0.6.4",
+ "mode": "todo",
+ "target": "",
+ "start": 0.68,
+ "duration": 0.46,
+ "rmeta_time": 0.39,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 29
+ ]
+ },
+ {
+ "i": 28,
+ "name": "anyhow",
+ "version": "1.0.75",
+ "mode": "run-custom-build",
+ "target": " build script (run)",
+ "start": 0.89,
+ "duration": 0.19,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 30
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 29,
+ "name": "clap_builder",
+ "version": "4.4.11",
+ "mode": "todo",
+ "target": "",
+ "start": 1.07,
+ "duration": 3.31,
+ "rmeta_time": 2.41,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 35
+ ]
+ },
+ {
+ "i": 30,
+ "name": "anyhow",
+ "version": "1.0.75",
+ "mode": "todo",
+ "target": "",
+ "start": 1.08,
+ "duration": 0.44,
+ "rmeta_time": 0.31,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 31,
+ "name": "quote",
+ "version": "1.0.33",
+ "mode": "todo",
+ "target": "",
+ "start": 1.2,
+ "duration": 0.42,
+ "rmeta_time": 0.27,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 33
+ ]
+ },
+ {
+ "i": 32,
+ "name": "indexmap",
+ "version": "2.1.0",
+ "mode": "todo",
+ "target": "",
+ "start": 1.3,
+ "duration": 0.76,
+ "rmeta_time": 0.64,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 34
+ ]
+ },
+ {
+ "i": 33,
+ "name": "syn",
+ "version": "2.0.39",
+ "mode": "todo",
+ "target": "",
+ "start": 1.48,
+ "duration": 2.29,
+ "rmeta_time": 1.75,
+ "unlocked_units": [
+ 37,
+ 36
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 34,
+ "name": "petgraph",
+ "version": "0.6.4",
+ "mode": "todo",
+ "target": "",
+ "start": 1.97,
+ "duration": 1.1,
+ "rmeta_time": 1.05,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 35,
+ "name": "clap",
+ "version": "4.4.11",
+ "mode": "todo",
+ "target": "",
+ "start": 3.48,
+ "duration": 0.08,
+ "rmeta_time": 0.07,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 36,
+ "name": "serde_derive",
+ "version": "1.0.193",
+ "mode": "todo",
+ "target": "",
+ "start": 3.77,
+ "duration": 2.21,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 39
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 37,
+ "name": "thiserror-impl",
+ "version": "1.0.50",
+ "mode": "todo",
+ "target": "",
+ "start": 3.77,
+ "duration": 1.11,
+ "rmeta_time": null,
+ "unlocked_units": [
+ 38
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 38,
+ "name": "thiserror",
+ "version": "1.0.50",
+ "mode": "todo",
+ "target": "",
+ "start": 4.88,
+ "duration": 0.04,
+ "rmeta_time": 0.03,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 39,
+ "name": "serde",
+ "version": "1.0.193",
+ "mode": "todo",
+ "target": "",
+ "start": 5.98,
+ "duration": 1.52,
+ "rmeta_time": 1.42,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 42,
+ 41,
+ 40,
+ 43
+ ]
+ },
+ {
+ "i": 40,
+ "name": "semver",
+ "version": "1.0.20",
+ "mode": "todo",
+ "target": "",
+ "start": 7.4,
+ "duration": 0.3,
+ "rmeta_time": 0.24,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 41,
+ "name": "serde_json",
+ "version": "1.0.108",
+ "mode": "todo",
+ "target": "",
+ "start": 7.4,
+ "duration": 0.82,
+ "rmeta_time": 0.66,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": [
+ 44
+ ]
+ },
+ {
+ "i": 42,
+ "name": "camino",
+ "version": "1.1.6",
+ "mode": "todo",
+ "target": "",
+ "start": 7.4,
+ "duration": 0.43,
+ "rmeta_time": 0.33,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 43,
+ "name": "cargo-platform",
+ "version": "0.1.5",
+ "mode": "todo",
+ "target": "",
+ "start": 7.4,
+ "duration": 0.26,
+ "rmeta_time": 0.17,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 44,
+ "name": "cargo_metadata",
+ "version": "0.18.1",
+ "mode": "todo",
+ "target": "",
+ "start": 8.06,
+ "duration": 0.88,
+ "rmeta_time": 0.59,
+ "unlocked_units": [
+ 45
+ ],
+ "unlocked_rmeta_units": []
+ },
+ {
+ "i": 45,
+ "name": "cargo-depgraph",
+ "version": "1.6.0",
+ "mode": "todo",
+ "target": " bin \"cargo-depgraph\"",
+ "start": 8.94,
+ "duration": 0.61,
+ "rmeta_time": null,
+ "unlocked_units": [],
+ "unlocked_rmeta_units": []
+ }
+ ];
+
+ const EDGES = {0: [1, 2, 3, 4], 2: [5, 6, 7, 8, 9, 10], 3: [11], 4: [12, 13], 6: [8], 9: [14, 15, 8], 11: [17, 18], 13: [20, 21]};
+ const NODES = ["cargo-depgraph",
+ "anyhow",
+ "cargo_metadata",
+ "clap",
+ "petgraph",
+ "camino",
+ "cargo-platform",
+ "semver",
+ "serde",
+ "serde_json",
+ "thiserror",
+ "clap_builder",
+ "fixedbitset",
+ "indexmap",
+ "itoa",
+ "ryu",
+ "anstream",
+ "anstyle",
+ "clap_lex",
+ "strsim",
+ "equivalent",
+ "hashbrown",
+ "anstyle-parse",
+ "anstyle-query",
+ "colorchoice",
+ "utf8parse"];
+
+ class Crate {
+ constructor(name) {
+ this.name = name;
+
+ for (const [index, node] of NODES.entries()) {
+ if (node == name) {
+ this.node_index = index;
+ break;
+ }
+ }
+ console.assert(this.node_index !== undefined);
+
+ let unit_indexes = [];
+ for (const [index, element] of UNIT_DATA.entries()) {
+ if (element.name === name) {
+ unit_indexes.push(index);
+ }
+ }
+
+ let dependencies = [];
+ if (EDGES[this.node_index] !== undefined) {
+ for (const dependency of EDGES[this.node_index]) {
+ dependencies.push(new Crate(NODES[dependency]));
+ }
+ }
+
+ let total_unlocked = 0;
+ for (const index of unit_indexes) {
+ total_unlocked += UNIT_DATA[index].unlocked_units.length;
+ total_unlocked += UNIT_DATA[index].unlocked_rmeta_units.length;
+ }
+
+ this.total_unlocked = total_unlocked;
+ this.unit_indexes = unit_indexes;
+ this.dependencies = dependencies;
+ }
+
+ sum_duration() {
+ let total = 0;
+ for (const index of this.unit_indexes) {
+ total += UNIT_DATA[index].duration;
+ }
+
+ return total;
+ }
+
+ total_sum_duration() {
+ let total = this.sum_duration();
+ for (const child of this.dependencies) {
+ total += child.total_sum_duration();
+ }
+
+ return total;
+ }
+ }
+
+ let max_unlocked = 0;
+ for (const node of NODES) {
+ const crate = new Crate(node);
+ max_unlocked = Math.max(max_unlocked, crate.total_unlocked)
+ }
+
+
+ function max_sum(items) {
+ let largest = 0;
+ for (const item of items) {
+ largest = Math.max(largest, item.total_sum_duration());
+ }
+
+ console.assert(largest > 0);
+ return largest;
+ }
+
+ function largest_in(items) {
+ let largest = [undefined, 0];
+ for (const [index, item] of items.entries()) {
+ total_duration = item.total_sum_duration();
+ if (total_duration > largest[1]) {
+ largest = [index, total_duration];
+ }
+ }
+
+ console.assert(largest[0] !== undefined);
+ return largest[0];
+ }
+
+ function running_sum(items) {
+ let sum = 0;
+
+ for (const item of items) {
+ sum += item.total_sum_duration();
+ }
+
+ return sum;
+ }
+
+ // From https://stackoverflow.com/questions/12875486/what-is-the-algorithm-to-create-colors-for-a-heatmap
+ function heatMapColorforValue(value){
+ var h = (1.0 - value) * 60
+ return "hsl(" + h + ", 100%, 50%)";
+ }
+
+ function recurse(list, parent) {
+ for (const item of list) {
+ const child = document.createElement("div");
+ child.classList.add(item.name);
+ child.classList.add("crate");
+
+ const container = document.createElement("div");
+ container.classList.add("container")
+
+ const text = document.createElement("span");
+ text.innerHTML = item.name;
+ child.appendChild(text);
+
+ if (parent.classList.contains("column")) {
+ container.classList.add("row");
+ } else {
+ container.classList.add("column");
+ }
+
+ // container.style.flexGrow = item.total_sum_duration();
+ child.style.backgroundColor = heatMapColorforValue(item.total_unlocked / max_unlocked);
+ child.appendChild(container);
+ parent.appendChild(child);
+
+ if (item.dependencies.length > 0) {
+ split(item.dependencies, container);
+ } else {
+ // not sure yet
+ }
+
+ }
+ }
+
+ // Algorithm from "Treemapping via balanced partitioning" paper (algorithm 2: variance-minimizing solution for balanced partition)
+ function split(list, parent) {
+ let height = running_sum(list) / 2;
+
+ let l_1 = [];
+ let l_2 = list.map((item) => new Crate(item.name));
+ let x = largest_in(l_2);
+
+ while (Math.abs(running_sum(l_1) - height) > Math.abs(running_sum(l_1.concat([l_2[x]])) - height)) {
+ l_1.push(l_2[x]);
+ l_2.splice(x, 1);
+
+
+ x = largest_in(l_2);
+ }
+
+ console.log(l_1, l_2);
+ recurse(l_1, parent);
+ recurse(l_2, parent);
+ }
+
+ const heatmap = document.getElementById("heatmap");
+ // const ctx = heatmap.getContext("2d");
+
+ // for (const item of UNIT_DATA) {
+ // ctx.beginPath();
+ // ctx.arc(item.duration * 100, (item.unlocked_units,length + item.unlocked_rmeta_units.length) * 100, 5, 0, 2 * Math.PI);
+ // ctx.stroke();
+ // }
+
+ const root = new Crate("cargo-depgraph");
+
+ split(root.dependencies, heatmap)