source: node_modules/d3-sankey/dist/d3-sankey.js@ e4c61dd

Last change on this file since e4c61dd was e4c61dd, checked in by istevanoska <ilinastevanoska@…>, 6 months ago

Prototype 1.1

  • Property mode set to 100644
File size: 11.7 KB
Line 
1// https://github.com/d3/d3-sankey v0.12.3 Copyright 2019 Mike Bostock
2(function (global, factory) {
3typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('d3-array'), require('d3-shape')) :
4typeof define === 'function' && define.amd ? define(['exports', 'd3-array', 'd3-shape'], factory) :
5(global = global || self, factory(global.d3 = global.d3 || {}, global.d3, global.d3));
6}(this, function (exports, d3Array, d3Shape) { 'use strict';
7
8function targetDepth(d) {
9 return d.target.depth;
10}
11
12function left(node) {
13 return node.depth;
14}
15
16function right(node, n) {
17 return n - 1 - node.height;
18}
19
20function justify(node, n) {
21 return node.sourceLinks.length ? node.depth : n - 1;
22}
23
24function center(node) {
25 return node.targetLinks.length ? node.depth
26 : node.sourceLinks.length ? d3Array.min(node.sourceLinks, targetDepth) - 1
27 : 0;
28}
29
30function constant(x) {
31 return function() {
32 return x;
33 };
34}
35
36function ascendingSourceBreadth(a, b) {
37 return ascendingBreadth(a.source, b.source) || a.index - b.index;
38}
39
40function ascendingTargetBreadth(a, b) {
41 return ascendingBreadth(a.target, b.target) || a.index - b.index;
42}
43
44function ascendingBreadth(a, b) {
45 return a.y0 - b.y0;
46}
47
48function value(d) {
49 return d.value;
50}
51
52function defaultId(d) {
53 return d.index;
54}
55
56function defaultNodes(graph) {
57 return graph.nodes;
58}
59
60function defaultLinks(graph) {
61 return graph.links;
62}
63
64function find(nodeById, id) {
65 const node = nodeById.get(id);
66 if (!node) throw new Error("missing: " + id);
67 return node;
68}
69
70function computeLinkBreadths({nodes}) {
71 for (const node of nodes) {
72 let y0 = node.y0;
73 let y1 = y0;
74 for (const link of node.sourceLinks) {
75 link.y0 = y0 + link.width / 2;
76 y0 += link.width;
77 }
78 for (const link of node.targetLinks) {
79 link.y1 = y1 + link.width / 2;
80 y1 += link.width;
81 }
82 }
83}
84
85function Sankey() {
86 let x0 = 0, y0 = 0, x1 = 1, y1 = 1; // extent
87 let dx = 24; // nodeWidth
88 let dy = 8, py; // nodePadding
89 let id = defaultId;
90 let align = justify;
91 let sort;
92 let linkSort;
93 let nodes = defaultNodes;
94 let links = defaultLinks;
95 let iterations = 6;
96
97 function sankey() {
98 const graph = {nodes: nodes.apply(null, arguments), links: links.apply(null, arguments)};
99 computeNodeLinks(graph);
100 computeNodeValues(graph);
101 computeNodeDepths(graph);
102 computeNodeHeights(graph);
103 computeNodeBreadths(graph);
104 computeLinkBreadths(graph);
105 return graph;
106 }
107
108 sankey.update = function(graph) {
109 computeLinkBreadths(graph);
110 return graph;
111 };
112
113 sankey.nodeId = function(_) {
114 return arguments.length ? (id = typeof _ === "function" ? _ : constant(_), sankey) : id;
115 };
116
117 sankey.nodeAlign = function(_) {
118 return arguments.length ? (align = typeof _ === "function" ? _ : constant(_), sankey) : align;
119 };
120
121 sankey.nodeSort = function(_) {
122 return arguments.length ? (sort = _, sankey) : sort;
123 };
124
125 sankey.nodeWidth = function(_) {
126 return arguments.length ? (dx = +_, sankey) : dx;
127 };
128
129 sankey.nodePadding = function(_) {
130 return arguments.length ? (dy = py = +_, sankey) : dy;
131 };
132
133 sankey.nodes = function(_) {
134 return arguments.length ? (nodes = typeof _ === "function" ? _ : constant(_), sankey) : nodes;
135 };
136
137 sankey.links = function(_) {
138 return arguments.length ? (links = typeof _ === "function" ? _ : constant(_), sankey) : links;
139 };
140
141 sankey.linkSort = function(_) {
142 return arguments.length ? (linkSort = _, sankey) : linkSort;
143 };
144
145 sankey.size = function(_) {
146 return arguments.length ? (x0 = y0 = 0, x1 = +_[0], y1 = +_[1], sankey) : [x1 - x0, y1 - y0];
147 };
148
149 sankey.extent = function(_) {
150 return arguments.length ? (x0 = +_[0][0], x1 = +_[1][0], y0 = +_[0][1], y1 = +_[1][1], sankey) : [[x0, y0], [x1, y1]];
151 };
152
153 sankey.iterations = function(_) {
154 return arguments.length ? (iterations = +_, sankey) : iterations;
155 };
156
157 function computeNodeLinks({nodes, links}) {
158 for (const [i, node] of nodes.entries()) {
159 node.index = i;
160 node.sourceLinks = [];
161 node.targetLinks = [];
162 }
163 const nodeById = new Map(nodes.map((d, i) => [id(d, i, nodes), d]));
164 for (const [i, link] of links.entries()) {
165 link.index = i;
166 let {source, target} = link;
167 if (typeof source !== "object") source = link.source = find(nodeById, source);
168 if (typeof target !== "object") target = link.target = find(nodeById, target);
169 source.sourceLinks.push(link);
170 target.targetLinks.push(link);
171 }
172 if (linkSort != null) {
173 for (const {sourceLinks, targetLinks} of nodes) {
174 sourceLinks.sort(linkSort);
175 targetLinks.sort(linkSort);
176 }
177 }
178 }
179
180 function computeNodeValues({nodes}) {
181 for (const node of nodes) {
182 node.value = node.fixedValue === undefined
183 ? Math.max(d3Array.sum(node.sourceLinks, value), d3Array.sum(node.targetLinks, value))
184 : node.fixedValue;
185 }
186 }
187
188 function computeNodeDepths({nodes}) {
189 const n = nodes.length;
190 let current = new Set(nodes);
191 let next = new Set;
192 let x = 0;
193 while (current.size) {
194 for (const node of current) {
195 node.depth = x;
196 for (const {target} of node.sourceLinks) {
197 next.add(target);
198 }
199 }
200 if (++x > n) throw new Error("circular link");
201 current = next;
202 next = new Set;
203 }
204 }
205
206 function computeNodeHeights({nodes}) {
207 const n = nodes.length;
208 let current = new Set(nodes);
209 let next = new Set;
210 let x = 0;
211 while (current.size) {
212 for (const node of current) {
213 node.height = x;
214 for (const {source} of node.targetLinks) {
215 next.add(source);
216 }
217 }
218 if (++x > n) throw new Error("circular link");
219 current = next;
220 next = new Set;
221 }
222 }
223
224 function computeNodeLayers({nodes}) {
225 const x = d3Array.max(nodes, d => d.depth) + 1;
226 const kx = (x1 - x0 - dx) / (x - 1);
227 const columns = new Array(x);
228 for (const node of nodes) {
229 const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x))));
230 node.layer = i;
231 node.x0 = x0 + i * kx;
232 node.x1 = node.x0 + dx;
233 if (columns[i]) columns[i].push(node);
234 else columns[i] = [node];
235 }
236 if (sort) for (const column of columns) {
237 column.sort(sort);
238 }
239 return columns;
240 }
241
242 function initializeNodeBreadths(columns) {
243 const ky = d3Array.min(columns, c => (y1 - y0 - (c.length - 1) * py) / d3Array.sum(c, value));
244 for (const nodes of columns) {
245 let y = y0;
246 for (const node of nodes) {
247 node.y0 = y;
248 node.y1 = y + node.value * ky;
249 y = node.y1 + py;
250 for (const link of node.sourceLinks) {
251 link.width = link.value * ky;
252 }
253 }
254 y = (y1 - y + py) / (nodes.length + 1);
255 for (let i = 0; i < nodes.length; ++i) {
256 const node = nodes[i];
257 node.y0 += y * (i + 1);
258 node.y1 += y * (i + 1);
259 }
260 reorderLinks(nodes);
261 }
262 }
263
264 function computeNodeBreadths(graph) {
265 const columns = computeNodeLayers(graph);
266 py = Math.min(dy, (y1 - y0) / (d3Array.max(columns, c => c.length) - 1));
267 initializeNodeBreadths(columns);
268 for (let i = 0; i < iterations; ++i) {
269 const alpha = Math.pow(0.99, i);
270 const beta = Math.max(1 - alpha, (i + 1) / iterations);
271 relaxRightToLeft(columns, alpha, beta);
272 relaxLeftToRight(columns, alpha, beta);
273 }
274 }
275
276 // Reposition each node based on its incoming (target) links.
277 function relaxLeftToRight(columns, alpha, beta) {
278 for (let i = 1, n = columns.length; i < n; ++i) {
279 const column = columns[i];
280 for (const target of column) {
281 let y = 0;
282 let w = 0;
283 for (const {source, value} of target.targetLinks) {
284 let v = value * (target.layer - source.layer);
285 y += targetTop(source, target) * v;
286 w += v;
287 }
288 if (!(w > 0)) continue;
289 let dy = (y / w - target.y0) * alpha;
290 target.y0 += dy;
291 target.y1 += dy;
292 reorderNodeLinks(target);
293 }
294 if (sort === undefined) column.sort(ascendingBreadth);
295 resolveCollisions(column, beta);
296 }
297 }
298
299 // Reposition each node based on its outgoing (source) links.
300 function relaxRightToLeft(columns, alpha, beta) {
301 for (let n = columns.length, i = n - 2; i >= 0; --i) {
302 const column = columns[i];
303 for (const source of column) {
304 let y = 0;
305 let w = 0;
306 for (const {target, value} of source.sourceLinks) {
307 let v = value * (target.layer - source.layer);
308 y += sourceTop(source, target) * v;
309 w += v;
310 }
311 if (!(w > 0)) continue;
312 let dy = (y / w - source.y0) * alpha;
313 source.y0 += dy;
314 source.y1 += dy;
315 reorderNodeLinks(source);
316 }
317 if (sort === undefined) column.sort(ascendingBreadth);
318 resolveCollisions(column, beta);
319 }
320 }
321
322 function resolveCollisions(nodes, alpha) {
323 const i = nodes.length >> 1;
324 const subject = nodes[i];
325 resolveCollisionsBottomToTop(nodes, subject.y0 - py, i - 1, alpha);
326 resolveCollisionsTopToBottom(nodes, subject.y1 + py, i + 1, alpha);
327 resolveCollisionsBottomToTop(nodes, y1, nodes.length - 1, alpha);
328 resolveCollisionsTopToBottom(nodes, y0, 0, alpha);
329 }
330
331 // Push any overlapping nodes down.
332 function resolveCollisionsTopToBottom(nodes, y, i, alpha) {
333 for (; i < nodes.length; ++i) {
334 const node = nodes[i];
335 const dy = (y - node.y0) * alpha;
336 if (dy > 1e-6) node.y0 += dy, node.y1 += dy;
337 y = node.y1 + py;
338 }
339 }
340
341 // Push any overlapping nodes up.
342 function resolveCollisionsBottomToTop(nodes, y, i, alpha) {
343 for (; i >= 0; --i) {
344 const node = nodes[i];
345 const dy = (node.y1 - y) * alpha;
346 if (dy > 1e-6) node.y0 -= dy, node.y1 -= dy;
347 y = node.y0 - py;
348 }
349 }
350
351 function reorderNodeLinks({sourceLinks, targetLinks}) {
352 if (linkSort === undefined) {
353 for (const {source: {sourceLinks}} of targetLinks) {
354 sourceLinks.sort(ascendingTargetBreadth);
355 }
356 for (const {target: {targetLinks}} of sourceLinks) {
357 targetLinks.sort(ascendingSourceBreadth);
358 }
359 }
360 }
361
362 function reorderLinks(nodes) {
363 if (linkSort === undefined) {
364 for (const {sourceLinks, targetLinks} of nodes) {
365 sourceLinks.sort(ascendingTargetBreadth);
366 targetLinks.sort(ascendingSourceBreadth);
367 }
368 }
369 }
370
371 // Returns the target.y0 that would produce an ideal link from source to target.
372 function targetTop(source, target) {
373 let y = source.y0 - (source.sourceLinks.length - 1) * py / 2;
374 for (const {target: node, width} of source.sourceLinks) {
375 if (node === target) break;
376 y += width + py;
377 }
378 for (const {source: node, width} of target.targetLinks) {
379 if (node === source) break;
380 y -= width;
381 }
382 return y;
383 }
384
385 // Returns the source.y0 that would produce an ideal link from source to target.
386 function sourceTop(source, target) {
387 let y = target.y0 - (target.targetLinks.length - 1) * py / 2;
388 for (const {source: node, width} of target.targetLinks) {
389 if (node === source) break;
390 y += width + py;
391 }
392 for (const {target: node, width} of source.sourceLinks) {
393 if (node === target) break;
394 y -= width;
395 }
396 return y;
397 }
398
399 return sankey;
400}
401
402function horizontalSource(d) {
403 return [d.source.x1, d.y0];
404}
405
406function horizontalTarget(d) {
407 return [d.target.x0, d.y1];
408}
409
410function sankeyLinkHorizontal() {
411 return d3Shape.linkHorizontal()
412 .source(horizontalSource)
413 .target(horizontalTarget);
414}
415
416exports.sankey = Sankey;
417exports.sankeyCenter = center;
418exports.sankeyJustify = justify;
419exports.sankeyLeft = left;
420exports.sankeyLinkHorizontal = sankeyLinkHorizontal;
421exports.sankeyRight = right;
422
423Object.defineProperty(exports, '__esModule', { value: true });
424
425}));
Note: See TracBrowser for help on using the repository browser.