From 8de47515287364aaed3e82e1ef737574e6f210d8 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 8 Jan 2020 14:22:16 +0000 Subject: [PATCH 01/30] Remove horizontal-only assumption from filenames, exports --- src/index.js | 2 +- src/{sankeyLinkHorizontal.js => sankeyLink.js} | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) rename src/{sankeyLinkHorizontal.js => sankeyLink.js} (86%) diff --git a/src/index.js b/src/index.js index 8ee1bdd..3a993d2 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,3 @@ export {default as sankey} from "./sankey.js"; export {center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify} from "./align.js"; -export {default as sankeyLinkHorizontal} from "./sankeyLinkHorizontal.js"; +export {sankeyLinkHorizontal} from "./sankeyLink.js"; diff --git a/src/sankeyLinkHorizontal.js b/src/sankeyLink.js similarity index 86% rename from src/sankeyLinkHorizontal.js rename to src/sankeyLink.js index 785bb7b..441b519 100644 --- a/src/sankeyLinkHorizontal.js +++ b/src/sankeyLink.js @@ -8,7 +8,7 @@ function horizontalTarget(d) { return [d.target.x0, d.y1]; } -export default function() { +export function sankeyLinkHorizontal() { return linkHorizontal() .source(horizontalSource) .target(horizontalTarget); From cc7805a9113a84531506431bca88915a20b56233 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 8 Jan 2020 14:51:46 +0000 Subject: [PATCH 02/30] Add no-op library-internal 'horizontal' orientation --- src/orientation.js | 3 +++ src/sankey.js | 10 ++++++++++ 2 files changed, 13 insertions(+) create mode 100644 src/orientation.js diff --git a/src/orientation.js b/src/orientation.js new file mode 100644 index 0000000..d05a1c2 --- /dev/null +++ b/src/orientation.js @@ -0,0 +1,3 @@ +export function horizontal(x, y) { + return [x, y]; +} diff --git a/src/sankey.js b/src/sankey.js index 56ad642..a1ba57a 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,5 +1,6 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; +import {horizontal} from "./orientation.js"; import constant from "./constant.js"; function ascendingSourceBreadth(a, b) { @@ -51,12 +52,20 @@ function computeLinkBreadths({nodes}) { } } +function orientNodes({nodes}, orientation) { + for (const node of nodes) { + [node.x0, node.y0] = orientation(node.x0, node.y0); + [node.x1, node.y1] = orientation(node.x1, node.y1); + } +} + export default function Sankey() { let x0 = 0, y0 = 0, x1 = 1, y1 = 1; // extent let dx = 24; // nodeWidth let dy = 8, py; // nodePadding let id = defaultId; let align = justify; + let orientation = horizontal; let sort; let linkSort; let nodes = defaultNodes; @@ -71,6 +80,7 @@ export default function Sankey() { computeNodeHeights(graph); computeNodeBreadths(graph); computeLinkBreadths(graph); + orientNodes(graph, orientation); return graph; } From ee1f37bcb7674a70e82c658da5fd3c87d28260f2 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 8 Jan 2020 15:53:16 +0000 Subject: [PATCH 03/30] Add and export 'vertical' orientation --- src/index.js | 3 ++- src/orientation.js | 4 ++++ src/sankey.js | 6 +++++- src/sankeyLink.js | 16 +++++++++++++++- 4 files changed, 26 insertions(+), 3 deletions(-) diff --git a/src/index.js b/src/index.js index 3a993d2..826900b 100644 --- a/src/index.js +++ b/src/index.js @@ -1,3 +1,4 @@ export {default as sankey} from "./sankey.js"; export {center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify} from "./align.js"; -export {sankeyLinkHorizontal} from "./sankeyLink.js"; +export {horizontal, vertical} from "./orientation.js"; +export {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; diff --git a/src/orientation.js b/src/orientation.js index d05a1c2..7b14262 100644 --- a/src/orientation.js +++ b/src/orientation.js @@ -1,3 +1,7 @@ export function horizontal(x, y) { return [x, y]; } + +export function vertical(x, y) { + return [y, x]; +} diff --git a/src/sankey.js b/src/sankey.js index a1ba57a..af35f0f 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,6 +1,6 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; -import {horizontal} from "./orientation.js"; +import {horizontal, vertical} from "./orientation.js"; import constant from "./constant.js"; function ascendingSourceBreadth(a, b) { @@ -97,6 +97,10 @@ export default function Sankey() { return arguments.length ? (align = typeof _ === "function" ? _ : constant(_), sankey) : align; }; + sankey.nodeOrientation = function(_) { + return arguments.length ? (orientation = _, sankey) : orientation; + }; + sankey.nodeSort = function(_) { return arguments.length ? (sort = _, sankey) : sort; }; diff --git a/src/sankeyLink.js b/src/sankeyLink.js index 441b519..11a25ef 100644 --- a/src/sankeyLink.js +++ b/src/sankeyLink.js @@ -1,4 +1,4 @@ -import {linkHorizontal} from "d3-shape"; +import {linkHorizontal, linkVertical} from "d3-shape"; function horizontalSource(d) { return [d.source.x1, d.y0]; @@ -13,3 +13,17 @@ export function sankeyLinkHorizontal() { .source(horizontalSource) .target(horizontalTarget); } + +function verticalSource(d) { + return [d.y0, d.source.y1]; +} + +function verticalTarget(d) { + return [d.y1, d.target.y0]; +} + +export function sankeyLinkVertical() { + return linkVertical() + .source(verticalSource) + .target(verticalTarget); +} From a26355ef6d1e3332d268613c1d9199b8dcc8fa61 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 8 Jan 2020 16:30:35 +0000 Subject: [PATCH 04/30] Add linkShape utility function --- src/sankey.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/sankey.js b/src/sankey.js index af35f0f..2509359 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,6 +1,7 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; import {horizontal, vertical} from "./orientation.js"; +import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; function ascendingSourceBreadth(a, b) { @@ -121,6 +122,10 @@ export default function Sankey() { return arguments.length ? (links = typeof _ === "function" ? _ : constant(_), sankey) : links; }; + sankey.linkShape = function() { + return orientation === vertical ? sankeyLinkVertical() : sankeyLinkHorizontal(); + }; + sankey.linkSort = function(_) { return arguments.length ? (linkSort = _, sankey) : linkSort; }; From 3f63c257de07727876a25d116f44cf90f1bc69f2 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 8 Jan 2020 17:09:33 +0000 Subject: [PATCH 05/30] Orient extents before calculating node positions --- src/sankey.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/sankey.js b/src/sankey.js index 2509359..959cdd7 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -75,6 +75,7 @@ export default function Sankey() { function sankey() { const graph = {nodes: nodes.apply(null, arguments), links: links.apply(null, arguments)}; + orientExtents(); computeNodeLinks(graph); computeNodeValues(graph); computeNodeDepths(graph); @@ -85,6 +86,11 @@ export default function Sankey() { return graph; } + function orientExtents() { + [x0, y0] = orientation(x0, y0); + [x1, y1] = orientation(x1, y1); + } + sankey.update = function(graph) { computeLinkBreadths(graph); return graph; From 584ca50ae7e9b0d2e0d22ec91f1405ba65c795f7 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 9 Jan 2020 09:13:12 +0000 Subject: [PATCH 06/30] Update README. --- README.md | 24 +++++++++--------------- 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 6f2f08a..047d7b9 100644 --- a/README.md +++ b/README.md @@ -100,6 +100,10 @@ For convenience, a link’s source and target may be initialized using numeric o * *link*.width - the link’s width (proportional to *link*.value) * *link*.index - the zero-based index of *link* within the array of links +# sankey.linkShape() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") + +Returns a [link shape](https://github.com/d3/d3-shape#links) suitable for rendering paths between the nodes of this Sankey diagram. This will return either a [horizontal](#sankeyLinkHorizontal) or [vertical](#sankeyLinkVertical) link shape. + # sankey.linkSort([sort]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") If *sort* is specified, sets the link sort method and returns this Sankey generator. If *sort* is not specified, returns the current link sort method, which defaults to *undefined*, indicating that vertical order of links within each node will be determined automatically by the layout. If *sort* is null, the order is fixed by the input. Otherwise, the specified *sort* function determines the order; the function is passed two links, and must return a value less than 0 if the first link should be above the second, and a value greater than 0 if the second link should be above the first, or 0 if the order is not specified. @@ -216,23 +220,13 @@ Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any outgoing links ### Links -# d3.sankeyLinkHorizontal() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankeyLinkHorizontal.js "Source") +# d3.sankeyLinkHorizontal() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankeyLink.js "Source") -Returns a [horizontal link shape](https://github.com/d3/d3-shape/blob/master/README.md#linkHorizontal) suitable for a Sankey diagram. The [source accessor](https://github.com/d3/d3-shape/blob/master/README.md#link_source) is defined as: +Returns a [horizontal link shape](https://github.com/d3/d3-shape/blob/master/README.md#linkHorizontal) suitable for a Sankey diagram rendered in a horizontal orientation. -```js -function source(d) { - return [d.source.x1, d.y0]; -} -``` +# d3.sankeyLinkVertical() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankeyLink.js "Source") -The [target accessor](https://github.com/d3/d3-shape/blob/master/README.md#link_target) is defined as: - -```js -function target(d) { - return [d.target.x0, d.y1]; -} -``` +Returns a [vertical link shape](https://github.com/d3/d3-shape/blob/master/README.md#linkVertical) suitable for a Sankey diagram rendered in a vertical orientation. For example, to render the links of a Sankey diagram in SVG, you might say: @@ -244,6 +238,6 @@ svg.append("g") .selectAll("path") .data(graph.links) .join("path") - .attr("d", d3.sankeyLinkHorizontal()) + .attr("d", graph.linkShape()) .attr("stroke-width", function(d) { return d.width; }); ``` From d94e35c98fe40c5d3c05d93c85846768f7b40dca Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 15 Jan 2020 12:23:41 +0000 Subject: [PATCH 07/30] Remove ES6 destructuring assignments --- src/sankey.js | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 959cdd7..e974d4e 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -55,8 +55,10 @@ function computeLinkBreadths({nodes}) { function orientNodes({nodes}, orientation) { for (const node of nodes) { - [node.x0, node.y0] = orientation(node.x0, node.y0); - [node.x1, node.y1] = orientation(node.x1, node.y1); + const topLeft = orientation(node.x0, node.y0); + const bottomRight = orientation(node.x1, node.y1); + node.x0 = topLeft[0], node.y0 = topLeft[1]; + node.x1 = bottomRight[0], node.y1 = bottomRight[1]; } } @@ -87,8 +89,10 @@ export default function Sankey() { } function orientExtents() { - [x0, y0] = orientation(x0, y0); - [x1, y1] = orientation(x1, y1); + const topLeft = orientation(x0, y0); + const bottomRight = orientation(x1, y1); + x0 = topLeft[0], y0 = topLeft[1]; + x1 = bottomRight[0], y1 = bottomRight[1]; } sankey.update = function(graph) { From 9cfd3373d3ea37280dcd7b93c68b2ca0cf51c005 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 15 Jan 2020 12:35:25 +0000 Subject: [PATCH 08/30] Rename {horizontal, vertical} -> {sankeyHorizontal, sankeyVertical} --- src/index.js | 2 +- src/orientation.js | 4 ++-- src/sankey.js | 6 +++--- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/index.js b/src/index.js index 826900b..ff9b76c 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ export {default as sankey} from "./sankey.js"; export {center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify} from "./align.js"; -export {horizontal, vertical} from "./orientation.js"; +export {sankeyHorizontal, sankeyVertical} from "./orientation.js"; export {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; diff --git a/src/orientation.js b/src/orientation.js index 7b14262..9419aba 100644 --- a/src/orientation.js +++ b/src/orientation.js @@ -1,7 +1,7 @@ -export function horizontal(x, y) { +export function sankeyHorizontal(x, y) { return [x, y]; } -export function vertical(x, y) { +export function sankeyVertical(x, y) { return [y, x]; } diff --git a/src/sankey.js b/src/sankey.js index e974d4e..5bd804c 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,6 +1,6 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; -import {horizontal, vertical} from "./orientation.js"; +import {sankeyHorizontal, sankeyVertical} from "./orientation.js"; import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; @@ -68,7 +68,7 @@ export default function Sankey() { let dy = 8, py; // nodePadding let id = defaultId; let align = justify; - let orientation = horizontal; + let orientation = sankeyHorizontal; let sort; let linkSort; let nodes = defaultNodes; @@ -133,7 +133,7 @@ export default function Sankey() { }; sankey.linkShape = function() { - return orientation === vertical ? sankeyLinkVertical() : sankeyLinkHorizontal(); + return orientation === sankeyVertical ? sankeyLinkVertical() : sankeyLinkHorizontal(); }; sankey.linkSort = function(_) { From bcdabc2c5efbc8a93268f8c2d926fe960b5c3c82 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 15 Jan 2020 12:45:27 +0000 Subject: [PATCH 09/30] Add nodeOrientation function docs, rendered examples --- README.md | 20 ++++++++++++++++++++ img/orientation-horizontal.png | Bin 0 -> 31831 bytes img/orientation-vertical.png | Bin 0 -> 34139 bytes 3 files changed, 20 insertions(+) create mode 100644 img/orientation-horizontal.png create mode 100644 img/orientation-vertical.png diff --git a/README.md b/README.md index 047d7b9..e7ce60d 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,10 @@ This is particularly useful when representing graphs in JSON, as JSON does not a If *align* is specified, sets the node [alignment method](#alignments) to the specified function and returns this Sankey generator. If *align* is not specified, returns the current node alignment method, which defaults to [d3.sankeyJustify](#sankeyJustify). The specified function is evaluated for each input *node* in order, being passed the current *node* and the total depth *n* of the graph (one plus the maximum *node*.depth), and must return an integer between 0 and *n* - 1 that indicates the desired horizontal position of the node in the generated Sankey diagram. +# sankey.nodeOrientation([orientation]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") + +If *orientation* is specified, sets the node [orientation method](#orientations) to the specified function and returns this Sankey generator. If *orientation* is not specified, returns the current node orientation method, which defaults to [d3.sankeyHorizontal](#sankeyHorizontal). + # sankey.nodeSort([sort]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") If *sort* is specified, sets the node sort method and returns this Sankey generator. If *sort* is not specified, returns the current node sort method, which defaults to *undefined*, indicating that vertical order of nodes within each column will be determined automatically by the layout. If *sort* is null, the order is fixed by the input. Otherwise, the specified *sort* function determines the order; the function is passed two nodes, and must return a value less than 0 if the first node should be above the second, and a value greater than 0 if the second node should be above the first, or 0 if the order is not specified. @@ -218,6 +222,22 @@ Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any incoming links Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any outgoing links are moved to the far right. +### Orientations + +See [*sankey*.nodeOrientation](#sankey_nodeOrientation). + +# d3.sankeyHorizontal(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") + +horizontal + +Returns horizontally oriented x, y. + +# d3.sankeyVertical(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") + +vertical + +Returns vertically oriented x, y. + ### Links # d3.sankeyLinkHorizontal() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankeyLink.js "Source") diff --git a/img/orientation-horizontal.png b/img/orientation-horizontal.png new file mode 100644 index 0000000000000000000000000000000000000000..4af7cd8bcfa4184ffe9579bdb21fec29a631d330 GIT binary patch literal 31831 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 Date: Wed, 15 Jan 2020 12:47:46 +0000 Subject: [PATCH 10/30] Re-arrange README to improve diff clarity --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index e7ce60d..698a56c 100644 --- a/README.md +++ b/README.md @@ -222,22 +222,6 @@ Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any incoming links Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any outgoing links are moved to the far right. -### Orientations - -See [*sankey*.nodeOrientation](#sankey_nodeOrientation). - -# d3.sankeyHorizontal(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") - -horizontal - -Returns horizontally oriented x, y. - -# d3.sankeyVertical(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") - -vertical - -Returns vertically oriented x, y. - ### Links # d3.sankeyLinkHorizontal() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankeyLink.js "Source") @@ -261,3 +245,19 @@ svg.append("g") .attr("d", graph.linkShape()) .attr("stroke-width", function(d) { return d.width; }); ``` + +### Orientations + +See [*sankey*.nodeOrientation](#sankey_nodeOrientation). + +# d3.sankeyHorizontal(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") + +horizontal + +Returns horizontally oriented x, y. + +# d3.sankeyVertical(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") + +vertical + +Returns vertically oriented x, y. From d49ea0683044e6770fdd0bb62cbd08b8def68a6c Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 11:29:01 +0100 Subject: [PATCH 11/30] Enable node re-orientation for individual axis values instead of co-ordinate pairs --- src/orientation.js | 8 ++++---- src/sankey.js | 18 ++++++++++-------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/src/orientation.js b/src/orientation.js index 9419aba..8aa675f 100644 --- a/src/orientation.js +++ b/src/orientation.js @@ -1,7 +1,7 @@ -export function sankeyHorizontal(x, y) { - return [x, y]; +export function sankeyHorizontal(x0, y0, x1, y1) { + return {x0: x0, y0: y0, x1: x1, y1: y1}; } -export function sankeyVertical(x, y) { - return [y, x]; +export function sankeyVertical(x0, y0, x1, y1) { + return {x0: y0, y0: x0, x1: y1, y1: x1}; } diff --git a/src/sankey.js b/src/sankey.js index 5bd804c..f0961e2 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -55,10 +55,11 @@ function computeLinkBreadths({nodes}) { function orientNodes({nodes}, orientation) { for (const node of nodes) { - const topLeft = orientation(node.x0, node.y0); - const bottomRight = orientation(node.x1, node.y1); - node.x0 = topLeft[0], node.y0 = topLeft[1]; - node.x1 = bottomRight[0], node.y1 = bottomRight[1]; + const nodeOrientation = orientation(node.x0, node.y0, node.x1, node.y1); + node.x0 = nodeOrientation.x0; + node.y0 = nodeOrientation.y0; + node.x1 = nodeOrientation.x1; + node.y1 = nodeOrientation.y1; } } @@ -89,10 +90,11 @@ export default function Sankey() { } function orientExtents() { - const topLeft = orientation(x0, y0); - const bottomRight = orientation(x1, y1); - x0 = topLeft[0], y0 = topLeft[1]; - x1 = bottomRight[0], y1 = bottomRight[1]; + const extentOrientation = orientation(x0, y0, x1, y1); + x0 = extentOrientation.x0; + y0 = extentOrientation.y0; + x1 = extentOrientation.x1; + y1 = extentOrientation.y1; } sankey.update = function(graph) { From 58b77c639806fed956289834c4bc6185c1fd13be Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 11:45:41 +0100 Subject: [PATCH 12/30] Refactor: include concept of direction for orientation --- src/index.js | 2 +- src/orientation.js | 8 ++++---- src/sankey.js | 7 ++++--- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/index.js b/src/index.js index ff9b76c..78b0cea 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ export {default as sankey} from "./sankey.js"; export {center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify} from "./align.js"; -export {sankeyHorizontal, sankeyVertical} from "./orientation.js"; +export {orientRight, orientDown} from "./orientation.js"; export {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; diff --git a/src/orientation.js b/src/orientation.js index 8aa675f..cf00559 100644 --- a/src/orientation.js +++ b/src/orientation.js @@ -1,7 +1,7 @@ -export function sankeyHorizontal(x0, y0, x1, y1) { - return {x0: x0, y0: y0, x1: x1, y1: y1}; +export function orientDown(x0, y0, x1, y1) { + return {x0: y0, y0: x0, x1: y1, y1: x1}; } -export function sankeyVertical(x0, y0, x1, y1) { - return {x0: y0, y0: x0, x1: y1, y1: x1}; +export function orientRight(x0, y0, x1, y1) { + return {x0: x0, y0: y0, x1: x1, y1: y1}; } diff --git a/src/sankey.js b/src/sankey.js index f0961e2..7dfcb08 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,6 +1,6 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; -import {sankeyHorizontal, sankeyVertical} from "./orientation.js"; +import {orientRight} from "./orientation.js"; import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; @@ -69,7 +69,7 @@ export default function Sankey() { let dy = 8, py; // nodePadding let id = defaultId; let align = justify; - let orientation = sankeyHorizontal; + let orientation = orientRight; let sort; let linkSort; let nodes = defaultNodes; @@ -135,7 +135,8 @@ export default function Sankey() { }; sankey.linkShape = function() { - return orientation === sankeyVertical ? sankeyLinkVertical() : sankeyLinkHorizontal(); + const node = orientation(0, 0, 0, 1); + return node.x0 || node.x1 ? sankeyLinkVertical() : sankeyLinkHorizontal(); }; sankey.linkSort = function(_) { From bd170ab3d8a916bc0af8489149f7335378fbffbc Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 14:12:07 +0100 Subject: [PATCH 13/30] Add left & up orientations --- src/index.js | 2 +- src/orientation.js | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/index.js b/src/index.js index 78b0cea..744f7a3 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,4 @@ export {default as sankey} from "./sankey.js"; export {center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify} from "./align.js"; -export {orientRight, orientDown} from "./orientation.js"; +export {orientUp, orientDown, orientLeft, orientRight} from "./orientation.js"; export {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; diff --git a/src/orientation.js b/src/orientation.js index cf00559..7b626af 100644 --- a/src/orientation.js +++ b/src/orientation.js @@ -1,7 +1,15 @@ +export function orientUp(x0, y0, x1, y1) { + return {x0: y0, y0: x1, x1: y1, y1: x0}; +} + export function orientDown(x0, y0, x1, y1) { return {x0: y0, y0: x0, x1: y1, y1: x1}; } +export function orientLeft(x0, y0, x1, y1) { + return {x0: x1, y0: y0, x1: x0, y1: y1}; +} + export function orientRight(x0, y0, x1, y1) { return {x0: x0, y0: y0, x1: x1, y1: y1}; } From 4aec1934d98050bd7c582c04f0f24e19c42b82d0 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 14:12:23 +0100 Subject: [PATCH 14/30] Ensure link width is positive --- src/sankey.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sankey.js b/src/sankey.js index 7dfcb08..1ebece2 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -249,7 +249,7 @@ export default function Sankey() { node.y1 = y + node.value * ky; y = node.y1 + py; for (const link of node.sourceLinks) { - link.width = link.value * ky; + link.width = link.value * Math.abs(ky); } } y = (y1 - y + py) / (nodes.length + 1); From b8a5222425f14bb7724b7d2b9d8b8a39187a3efa Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 17:39:06 +0100 Subject: [PATCH 15/30] Implement orientation-specific rendering without collision detection --- src/sankey.js | 27 +++++++++++++++++---------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 1ebece2..87dd535 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,6 +1,6 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; -import {orientRight} from "./orientation.js"; +import {orientUp, orientRight, orientDown, orientLeft} from "./orientation.js"; import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; @@ -135,8 +135,8 @@ export default function Sankey() { }; sankey.linkShape = function() { - const node = orientation(0, 0, 0, 1); - return node.x0 || node.x1 ? sankeyLinkVertical() : sankeyLinkHorizontal(); + const horizontal = [orientLeft, orientRight]; + return horizontal.includes(orientation) ? sankeyLinkHorizontal() : sankeyLinkVertical(); }; sankey.linkSort = function(_) { @@ -224,13 +224,15 @@ export default function Sankey() { function computeNodeLayers({nodes}) { const x = max(nodes, d => d.depth) + 1; - const kx = (x1 - x0 - dx) / (x - 1); + const kx = (Math.abs(x1 - x0) - dx) / (x - 1); + const origin = orientation === orientUp ? x1 : x0; + const dir = orientation === orientLeft || orientation === orientUp ? -1 : 1; const columns = new Array(x); for (const node of nodes) { const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x)))); node.layer = i; - node.x0 = x0 + i * kx; - node.x1 = node.x0 + dx; + node.x0 = origin + i * kx * dir; + node.x1 = node.x0 + dx * dir; if (columns[i]) columns[i].push(node); else columns[i] = [node]; } @@ -241,9 +243,9 @@ export default function Sankey() { } function initializeNodeBreadths(columns) { - const ky = min(columns, c => (y1 - y0 - (c.length - 1) * py) / sum(c, value)); + const ky = min(columns, c => (Math.abs(y1 - y0) - (c.length - 1) * py) / sum(c, value)); for (const nodes of columns) { - let y = y0; + let y = orientation === orientUp ? y1 : y0; for (const node of nodes) { node.y0 = y; node.y1 = y + node.value * ky; @@ -252,7 +254,8 @@ export default function Sankey() { link.width = link.value * Math.abs(ky); } } - y = (y1 - y + py) / (nodes.length + 1); + let z = orientation === orientUp ? y0 : y1; + y = (z - y + py) / (nodes.length + 1); for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; node.y0 += y * (i + 1); @@ -264,13 +267,17 @@ export default function Sankey() { function computeNodeBreadths(graph) { const columns = computeNodeLayers(graph); - py = Math.min(dy, (y1 - y0) / (max(columns, c => c.length) - 1)); + const horizontal = [orientLeft, orientRight]; + const breadth = horizontal.includes(orientation) ? x1 - x0 : y1 - y0; + py = Math.min(dy, Math.abs(breadth) / (max(columns, c => c.length) - 1)); initializeNodeBreadths(columns); for (let i = 0; i < iterations; ++i) { const alpha = Math.pow(0.99, i); const beta = Math.max(1 - alpha, (i + 1) / iterations); + /* relaxRightToLeft(columns, alpha, beta); relaxLeftToRight(columns, alpha, beta); + */ } } From 0cf48c2546d31c48bd01f7789b765924d9e4c56b Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 21:03:36 +0100 Subject: [PATCH 16/30] Enable orientation-specific collision detection --- src/sankey.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 87dd535..f29f503 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,6 +1,6 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; -import {orientUp, orientRight, orientDown, orientLeft} from "./orientation.js"; +import {orientUp, orientDown, orientLeft, orientRight} from "./orientation.js"; import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; @@ -274,10 +274,8 @@ export default function Sankey() { for (let i = 0; i < iterations; ++i) { const alpha = Math.pow(0.99, i); const beta = Math.max(1 - alpha, (i + 1) / iterations); - /* relaxRightToLeft(columns, alpha, beta); relaxLeftToRight(columns, alpha, beta); - */ } } @@ -329,11 +327,14 @@ export default function Sankey() { function resolveCollisions(nodes, alpha) { const i = nodes.length >> 1; - const subject = nodes[i]; - resolveCollisionsBottomToTop(nodes, subject.y0 - py, i - 1, alpha); - resolveCollisionsTopToBottom(nodes, subject.y1 + py, i + 1, alpha); - resolveCollisionsBottomToTop(nodes, y1, nodes.length - 1, alpha); - resolveCollisionsTopToBottom(nodes, y0, 0, alpha); + const node = nodes[i]; + const inverted = {y0: node.y1, y1: node.y0}; + const subject = orientation === orientUp ? inverted : node; + const dir = orientation === orientUp ? -1 : 1; + resolveCollisionsBottomToTop(nodes, subject.y0 - py * dir, i - dir, alpha); + resolveCollisionsTopToBottom(nodes, subject.y1 + py * dir, i + dir, alpha); + resolveCollisionsBottomToTop(nodes, orientation === orientUp ? y0 : y1, nodes.length - 1, alpha); + resolveCollisionsTopToBottom(nodes, orientation === orientUp ? y1 : y0, 0, alpha); } // Push any overlapping nodes down. From 331af05cc5c47d844811c508e99657783ea0b3d9 Mon Sep 17 00:00:00 2001 From: James Addison Date: Thu, 10 Sep 2020 21:15:22 +0100 Subject: [PATCH 17/30] Update README orientation documentation --- README.md | 17 ++++++----------- img/orientation-horizontal.png | Bin 31831 -> 0 bytes img/orientation-vertical.png | Bin 34139 -> 0 bytes 3 files changed, 6 insertions(+), 11 deletions(-) delete mode 100644 img/orientation-horizontal.png delete mode 100644 img/orientation-vertical.png diff --git a/README.md b/README.md index 698a56c..6fd1eee 100644 --- a/README.md +++ b/README.md @@ -164,7 +164,7 @@ If *align* is specified, sets the node [alignment method](#alignments) to the sp # sankey.nodeOrientation([orientation]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") -If *orientation* is specified, sets the node [orientation method](#orientations) to the specified function and returns this Sankey generator. If *orientation* is not specified, returns the current node orientation method, which defaults to [d3.sankeyHorizontal](#sankeyHorizontal). +If *orientation* is specified, sets the node [orientation method](#orientations) to the specified function and returns this Sankey generator. If *orientation* is not specified, returns the current node orientation method, which defaults to [d3.orientRight](#orientRight). # sankey.nodeSort([sort]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") @@ -250,14 +250,9 @@ svg.append("g") See [*sankey*.nodeOrientation](#sankey_nodeOrientation). -# d3.sankeyHorizontal(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") +Four Sankey diagram rendering orientations are currently available: -horizontal - -Returns horizontally oriented x, y. - -# d3.sankeyVertical(x, y) [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") - -vertical - -Returns vertically oriented x, y. +* # d3.orientUp [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") +* # d3.orientDown [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") +* # d3.orientLeft [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") +* # d3.orientRight [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") diff --git a/img/orientation-horizontal.png b/img/orientation-horizontal.png deleted file mode 100644 index 4af7cd8bcfa4184ffe9579bdb21fec29a631d330..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 31831 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 Date: Thu, 10 Sep 2020 21:24:02 +0100 Subject: [PATCH 18/30] Revert "Ensure link width is positive" This reverts commit 4aec1934d98050bd7c582c04f0f24e19c42b82d0. --- src/sankey.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sankey.js b/src/sankey.js index f29f503..a02462d 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -251,7 +251,7 @@ export default function Sankey() { node.y1 = y + node.value * ky; y = node.y1 + py; for (const link of node.sourceLinks) { - link.width = link.value * Math.abs(ky); + link.width = link.value * ky; } } let z = orientation === orientUp ? y0 : y1; From d813a6b1d21077a64d1936962500ff6f3e989a0c Mon Sep 17 00:00:00 2001 From: James Addison Date: Fri, 11 Sep 2020 10:07:25 +0100 Subject: [PATCH 19/30] Nit: spacing consistency fixup --- src/sankeyLink.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sankeyLink.js b/src/sankeyLink.js index 11a25ef..8559a84 100644 --- a/src/sankeyLink.js +++ b/src/sankeyLink.js @@ -10,8 +10,8 @@ function horizontalTarget(d) { export function sankeyLinkHorizontal() { return linkHorizontal() - .source(horizontalSource) - .target(horizontalTarget); + .source(horizontalSource) + .target(horizontalTarget); } function verticalSource(d) { @@ -24,6 +24,6 @@ function verticalTarget(d) { export function sankeyLinkVertical() { return linkVertical() - .source(verticalSource) - .target(verticalTarget); + .source(verticalSource) + .target(verticalTarget); } From 863b18598413b3e6bbd3301a3c6fb62ebbaba957 Mon Sep 17 00:00:00 2001 From: James Addison Date: Fri, 11 Sep 2020 13:16:50 +0100 Subject: [PATCH 20/30] Nit: rename variable z -> ymax to remove dimenson-name ambiguity --- src/sankey.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index a02462d..0d1266c 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -254,8 +254,8 @@ export default function Sankey() { link.width = link.value * ky; } } - let z = orientation === orientUp ? y0 : y1; - y = (z - y + py) / (nodes.length + 1); + let ymax = orientation === orientUp ? y0 : y1; + y = (ymax - y + py) / (nodes.length + 1); for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; node.y0 += y * (i + 1); From f603a6ccb8158233a5dca0a90b8d9090ddfeda35 Mon Sep 17 00:00:00 2001 From: James Addison Date: Fri, 11 Sep 2020 18:14:04 +0100 Subject: [PATCH 21/30] Revert "Nit: spacing consistency fixup" This reverts commit d813a6b1d21077a64d1936962500ff6f3e989a0c. --- src/sankeyLink.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/sankeyLink.js b/src/sankeyLink.js index 8559a84..11a25ef 100644 --- a/src/sankeyLink.js +++ b/src/sankeyLink.js @@ -10,8 +10,8 @@ function horizontalTarget(d) { export function sankeyLinkHorizontal() { return linkHorizontal() - .source(horizontalSource) - .target(horizontalTarget); + .source(horizontalSource) + .target(horizontalTarget); } function verticalSource(d) { @@ -24,6 +24,6 @@ function verticalTarget(d) { export function sankeyLinkVertical() { return linkVertical() - .source(verticalSource) - .target(verticalTarget); + .source(verticalSource) + .target(verticalTarget); } From 5fbbf1be47e084303aad66d6ffeecbbcf5e3872b Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 14 Sep 2020 10:41:10 +0100 Subject: [PATCH 22/30] Refactor: - Export per-orientation constructors (sankeyTop, ...) - Rename alignment options (sankeyLeft -> sankeyAlignLeft, ...) - Rename orient* functions and variables to transform* - Move transformNodes function within Sankey class - Remove orientation getter/setter - Remove export of orientations --- src/index.js | 5 +-- src/orientation.js | 15 ------- src/sankey.js | 98 +++++++++++++++++++++++++++++----------------- src/transform.js | 15 +++++++ 4 files changed, 78 insertions(+), 55 deletions(-) delete mode 100644 src/orientation.js create mode 100644 src/transform.js diff --git a/src/index.js b/src/index.js index 744f7a3..9fee22e 100644 --- a/src/index.js +++ b/src/index.js @@ -1,4 +1,3 @@ -export {default as sankey} from "./sankey.js"; -export {center as sankeyCenter, left as sankeyLeft, right as sankeyRight, justify as sankeyJustify} from "./align.js"; -export {orientUp, orientDown, orientLeft, orientRight} from "./orientation.js"; +export {sankeyTop, sankeyRight, sankeyBottom, sankeyLeft} from "./sankey.js"; +export {center as sankeyAlignCenter, left as sankeyAlignLeft, right as sankeyAlignRight, justify as sankeyAlignJustify} from "./align.js"; export {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; diff --git a/src/orientation.js b/src/orientation.js deleted file mode 100644 index 7b626af..0000000 --- a/src/orientation.js +++ /dev/null @@ -1,15 +0,0 @@ -export function orientUp(x0, y0, x1, y1) { - return {x0: y0, y0: x1, x1: y1, y1: x0}; -} - -export function orientDown(x0, y0, x1, y1) { - return {x0: y0, y0: x0, x1: y1, y1: x1}; -} - -export function orientLeft(x0, y0, x1, y1) { - return {x0: x1, y0: y0, x1: x0, y1: y1}; -} - -export function orientRight(x0, y0, x1, y1) { - return {x0: x0, y0: y0, x1: x1, y1: y1}; -} diff --git a/src/sankey.js b/src/sankey.js index 0d1266c..3654d59 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -1,9 +1,21 @@ import {max, min, sum} from "d3-array"; import {justify} from "./align.js"; -import {orientUp, orientDown, orientLeft, orientRight} from "./orientation.js"; +import {transformTop, transformRight, transformBottom, transformLeft} from "./transform.js"; import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; +var top = 1, + right = 2, + bottom = 3, + left = 4; + +var transforms = { + [top]: transformTop, + [right]: transformRight, + [bottom]: transformBottom, + [left]: transformLeft +}; + function ascendingSourceBreadth(a, b) { return ascendingBreadth(a.source, b.source) || a.index - b.index; } @@ -53,23 +65,13 @@ function computeLinkBreadths({nodes}) { } } -function orientNodes({nodes}, orientation) { - for (const node of nodes) { - const nodeOrientation = orientation(node.x0, node.y0, node.x1, node.y1); - node.x0 = nodeOrientation.x0; - node.y0 = nodeOrientation.y0; - node.x1 = nodeOrientation.x1; - node.y1 = nodeOrientation.y1; - } -} - -export default function Sankey() { +function Sankey(orient) { let x0 = 0, y0 = 0, x1 = 1, y1 = 1; // extent let dx = 24; // nodeWidth let dy = 8, py; // nodePadding let id = defaultId; let align = justify; - let orientation = orientRight; + let transform = transforms[orient]; let sort; let linkSort; let nodes = defaultNodes; @@ -78,23 +80,33 @@ export default function Sankey() { function sankey() { const graph = {nodes: nodes.apply(null, arguments), links: links.apply(null, arguments)}; - orientExtents(); + transformExtents(); computeNodeLinks(graph); computeNodeValues(graph); computeNodeDepths(graph); computeNodeHeights(graph); computeNodeBreadths(graph); computeLinkBreadths(graph); - orientNodes(graph, orientation); + transformNodes(graph); return graph; } - function orientExtents() { - const extentOrientation = orientation(x0, y0, x1, y1); - x0 = extentOrientation.x0; - y0 = extentOrientation.y0; - x1 = extentOrientation.x1; - y1 = extentOrientation.y1; + function transformExtents() { + const transformedExtents = transform(x0, y0, x1, y1); + x0 = transformedExtents.x0; + y0 = transformedExtents.y0; + x1 = transformedExtents.x1; + y1 = transformedExtents.y1; + } + + function transformNodes({nodes}) { + for (const node of nodes) { + const transformedNode = transform(node.x0, node.y0, node.x1, node.y1); + node.x0 = transformedNode.x0; + node.y0 = transformedNode.y0; + node.x1 = transformedNode.x1; + node.y1 = transformedNode.y1; + } } sankey.update = function(graph) { @@ -110,10 +122,6 @@ export default function Sankey() { return arguments.length ? (align = typeof _ === "function" ? _ : constant(_), sankey) : align; }; - sankey.nodeOrientation = function(_) { - return arguments.length ? (orientation = _, sankey) : orientation; - }; - sankey.nodeSort = function(_) { return arguments.length ? (sort = _, sankey) : sort; }; @@ -135,8 +143,8 @@ export default function Sankey() { }; sankey.linkShape = function() { - const horizontal = [orientLeft, orientRight]; - return horizontal.includes(orientation) ? sankeyLinkHorizontal() : sankeyLinkVertical(); + const horizontal = [left, right]; + return horizontal.includes(orient) ? sankeyLinkHorizontal() : sankeyLinkVertical(); }; sankey.linkSort = function(_) { @@ -225,8 +233,8 @@ export default function Sankey() { function computeNodeLayers({nodes}) { const x = max(nodes, d => d.depth) + 1; const kx = (Math.abs(x1 - x0) - dx) / (x - 1); - const origin = orientation === orientUp ? x1 : x0; - const dir = orientation === orientLeft || orientation === orientUp ? -1 : 1; + const origin = orient === bottom ? x1 : x0; + const dir = orient === left || orient === bottom ? -1 : 1; const columns = new Array(x); for (const node of nodes) { const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x)))); @@ -245,7 +253,7 @@ export default function Sankey() { function initializeNodeBreadths(columns) { const ky = min(columns, c => (Math.abs(y1 - y0) - (c.length - 1) * py) / sum(c, value)); for (const nodes of columns) { - let y = orientation === orientUp ? y1 : y0; + let y = orient === bottom ? y1 : y0; for (const node of nodes) { node.y0 = y; node.y1 = y + node.value * ky; @@ -254,7 +262,7 @@ export default function Sankey() { link.width = link.value * ky; } } - let ymax = orientation === orientUp ? y0 : y1; + let ymax = orient === bottom ? y0 : y1; y = (ymax - y + py) / (nodes.length + 1); for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; @@ -267,8 +275,8 @@ export default function Sankey() { function computeNodeBreadths(graph) { const columns = computeNodeLayers(graph); - const horizontal = [orientLeft, orientRight]; - const breadth = horizontal.includes(orientation) ? x1 - x0 : y1 - y0; + const horizontal = [left, right]; + const breadth = horizontal.includes(orient) ? x1 - x0 : y1 - y0; py = Math.min(dy, Math.abs(breadth) / (max(columns, c => c.length) - 1)); initializeNodeBreadths(columns); for (let i = 0; i < iterations; ++i) { @@ -329,12 +337,12 @@ export default function Sankey() { const i = nodes.length >> 1; const node = nodes[i]; const inverted = {y0: node.y1, y1: node.y0}; - const subject = orientation === orientUp ? inverted : node; - const dir = orientation === orientUp ? -1 : 1; + const subject = orient === bottom ? inverted : node; + const dir = orient === bottom ? -1 : 1; resolveCollisionsBottomToTop(nodes, subject.y0 - py * dir, i - dir, alpha); resolveCollisionsTopToBottom(nodes, subject.y1 + py * dir, i + dir, alpha); - resolveCollisionsBottomToTop(nodes, orientation === orientUp ? y0 : y1, nodes.length - 1, alpha); - resolveCollisionsTopToBottom(nodes, orientation === orientUp ? y1 : y0, 0, alpha); + resolveCollisionsBottomToTop(nodes, orient === bottom ? y0 : y1, nodes.length - 1, alpha); + resolveCollisionsTopToBottom(nodes, orient === bottom ? y1 : y0, 0, alpha); } // Push any overlapping nodes down. @@ -407,3 +415,19 @@ export default function Sankey() { return sankey; } + +export function sankeyTop() { + return Sankey(top); +} + +export function sankeyRight() { + return Sankey(right); +} + +export function sankeyBottom() { + return Sankey(bottom); +} + +export function sankeyLeft() { + return Sankey(left); +} diff --git a/src/transform.js b/src/transform.js new file mode 100644 index 0000000..210c8cb --- /dev/null +++ b/src/transform.js @@ -0,0 +1,15 @@ +export function transformTop(x0, y0, x1, y1) { + return {x0: y0, y0: x0, x1: y1, y1: x1}; +} + +export function transformRight(x0, y0, x1, y1) { + return {x0: x0, y0: y0, x1: x1, y1: y1}; +} + +export function transformBottom(x0, y0, x1, y1) { + return {x0: y0, y0: x1, x1: y1, y1: x0}; +} + +export function transformLeft(x0, y0, x1, y1) { + return {x0: x1, y0: y0, x1: x0, y1: y1}; +} From e70b7724ecd2c6b8a70e0920f8a482c1244c9754 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 14 Sep 2020 10:45:36 +0100 Subject: [PATCH 23/30] Bounds checking: check both lower and upper bounds during node collision resolution --- src/sankey.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 56ad642..a2a3574 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -299,7 +299,7 @@ export default function Sankey() { // Push any overlapping nodes down. function resolveCollisionsTopToBottom(nodes, y, i, alpha) { - for (; i < nodes.length; ++i) { + for (; i >= 0 && i < nodes.length; ++i) { const node = nodes[i]; const dy = (y - node.y0) * alpha; if (dy > 1e-6) node.y0 += dy, node.y1 += dy; @@ -309,7 +309,7 @@ export default function Sankey() { // Push any overlapping nodes up. function resolveCollisionsBottomToTop(nodes, y, i, alpha) { - for (; i >= 0; --i) { + for (; i >= 0 && i < nodes.length; --i) { const node = nodes[i]; const dy = (node.y1 - y) * alpha; if (dy > 1e-6) node.y0 -= dy, node.y1 -= dy; From 332e27bc0619c3d2750761874f675d601678f6d7 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 14 Sep 2020 10:56:30 +0100 Subject: [PATCH 24/30] Update README --- README.md | 43 ++++++++++++++++++++----------------------- 1 file changed, 20 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 6fd1eee..37e3020 100644 --- a/README.md +++ b/README.md @@ -27,9 +27,21 @@ var sankey = d3.sankey(); ## API Reference -# d3.sankey() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") +# d3.sankeyTop() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") -Constructs a new Sankey generator with the default settings. +Constructs a new top-oriented Sankey generator with the default settings. + +# d3.sankeyRight() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") + +Constructs a new right-oriented Sankey generator with the default settings. + +# d3.sankeyBottom() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") + +Constructs a new bottom-oriented Sankey generator with the default settings. + +# d3.sankeyLeft() [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") + +Constructs a new left-oriented Sankey generator with the default settings. # sankey(arguments…) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") @@ -162,10 +174,6 @@ This is particularly useful when representing graphs in JSON, as JSON does not a If *align* is specified, sets the node [alignment method](#alignments) to the specified function and returns this Sankey generator. If *align* is not specified, returns the current node alignment method, which defaults to [d3.sankeyJustify](#sankeyJustify). The specified function is evaluated for each input *node* in order, being passed the current *node* and the total depth *n* of the graph (one plus the maximum *node*.depth), and must return an integer between 0 and *n* - 1 that indicates the desired horizontal position of the node in the generated Sankey diagram. -# sankey.nodeOrientation([orientation]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") - -If *orientation* is specified, sets the node [orientation method](#orientations) to the specified function and returns this Sankey generator. If *orientation* is not specified, returns the current node orientation method, which defaults to [d3.orientRight](#orientRight). - # sankey.nodeSort([sort]) [<>](https://github.com/d3/d3-sankey/blob/master/src/sankey.js "Source") If *sort* is specified, sets the node sort method and returns this Sankey generator. If *sort* is not specified, returns the current node sort method, which defaults to *undefined*, indicating that vertical order of nodes within each column will be determined automatically by the layout. If *sort* is null, the order is fixed by the input. Otherwise, the specified *sort* function determines the order; the function is passed two nodes, and must return a value less than 0 if the first node should be above the second, and a value greater than 0 if the second node should be above the first, or 0 if the order is not specified. @@ -198,29 +206,29 @@ If *iterations* is specified, sets the number of relaxation iterations when [gen See [*sankey*.nodeAlign](#sankey_nodeAlign). -# d3.sankeyLeft(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") +# d3.sankeyAlignLeft(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") [left](https://observablehq.com/@d3/sankey-diagram?align=left) Returns *node*.depth. -# d3.sankeyRight(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") +# d3.sankeyAlignRight(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") [right](https://observablehq.com/@d3/sankey-diagram?align=right) Returns *n* - 1 - *node*.height. -# d3.sankeyCenter(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") +# d3.sankeyAlignCenter(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") [center](https://observablehq.com/@d3/sankey-diagram?align=center) -Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any incoming links are moved as right as possible. +Like [d3.sankeyAlignLeft](#sankeyAlignLeft), except that nodes without any incoming links are moved as right as possible. -# d3.sankeyJustify(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") +# d3.sankeyAlignJustify(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") [justify](https://observablehq.com/@d3/sankey-diagram) -Like [d3.sankeyLeft](#sankeyLeft), except that nodes without any outgoing links are moved to the far right. +Like [d3.sankeyAlignLeft](#sankeyAlignLeft), except that nodes without any outgoing links are moved to the far right. ### Links @@ -245,14 +253,3 @@ svg.append("g") .attr("d", graph.linkShape()) .attr("stroke-width", function(d) { return d.width; }); ``` - -### Orientations - -See [*sankey*.nodeOrientation](#sankey_nodeOrientation). - -Four Sankey diagram rendering orientations are currently available: - -* # d3.orientUp [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") -* # d3.orientDown [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") -* # d3.orientLeft [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") -* # d3.orientRight [<>](https://github.com/d3/d3-sankey/blob/master/src/orientation.js "Source") From ac05124e8c51175a300e4733c405dfde21d0a2f3 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 14 Sep 2020 11:01:06 +0100 Subject: [PATCH 25/30] Nit: brevity during alignment checks --- src/sankey.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 7d38758..763c548 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -143,8 +143,7 @@ function Sankey(orient) { }; sankey.linkShape = function() { - const horizontal = [left, right]; - return horizontal.includes(orient) ? sankeyLinkHorizontal() : sankeyLinkVertical(); + return [left, right].includes(orient) ? sankeyLinkHorizontal() : sankeyLinkVertical(); }; sankey.linkSort = function(_) { @@ -275,8 +274,7 @@ function Sankey(orient) { function computeNodeBreadths(graph) { const columns = computeNodeLayers(graph); - const horizontal = [left, right]; - const breadth = horizontal.includes(orient) ? x1 - x0 : y1 - y0; + const breadth = [left, right].includes(orient) ? x1 - x0 : y1 - y0; py = Math.min(dy, Math.abs(breadth) / (max(columns, c => c.length) - 1)); initializeNodeBreadths(columns); for (let i = 0; i < iterations; ++i) { From 898a673c9d63688a002603d4a8f9540183089764 Mon Sep 17 00:00:00 2001 From: James Addison Date: Mon, 14 Sep 2020 11:26:06 +0100 Subject: [PATCH 26/30] Nit: attempt to further clarify distinct variable names --- src/sankey.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 763c548..90c40cc 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -252,21 +252,21 @@ function Sankey(orient) { function initializeNodeBreadths(columns) { const ky = min(columns, c => (Math.abs(y1 - y0) - (c.length - 1) * py) / sum(c, value)); for (const nodes of columns) { - let y = orient === bottom ? y1 : y0; + let ystart = orient === bottom ? y1 : y0; for (const node of nodes) { - node.y0 = y; - node.y1 = y + node.value * ky; - y = node.y1 + py; + node.y0 = ystart; + node.y1 = ystart + node.value * ky; + ystart = node.y1 + py; for (const link of node.sourceLinks) { link.width = link.value * ky; } } - let ymax = orient === bottom ? y0 : y1; - y = (ymax - y + py) / (nodes.length + 1); + let yend = orient === bottom ? y0 : y1; + ystart = (yend - ystart + py) / (nodes.length + 1); for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; - node.y0 += y * (i + 1); - node.y1 += y * (i + 1); + node.y0 += ystart * (i + 1); + node.y1 += ystart * (i + 1); } reorderLinks(nodes); } From ebfda163bb7a03f190374c29fd5c7c480b962c4f Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 11 Nov 2020 17:40:54 +0000 Subject: [PATCH 27/30] Rename variable: orient -> orientation --- src/sankey.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 90c40cc..de0dfff 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -65,13 +65,13 @@ function computeLinkBreadths({nodes}) { } } -function Sankey(orient) { +function Sankey(orientation) { let x0 = 0, y0 = 0, x1 = 1, y1 = 1; // extent let dx = 24; // nodeWidth let dy = 8, py; // nodePadding let id = defaultId; let align = justify; - let transform = transforms[orient]; + let transform = transforms[orientation]; let sort; let linkSort; let nodes = defaultNodes; @@ -143,7 +143,7 @@ function Sankey(orient) { }; sankey.linkShape = function() { - return [left, right].includes(orient) ? sankeyLinkHorizontal() : sankeyLinkVertical(); + return [left, right].includes(orientation) ? sankeyLinkHorizontal() : sankeyLinkVertical(); }; sankey.linkSort = function(_) { @@ -232,8 +232,8 @@ function Sankey(orient) { function computeNodeLayers({nodes}) { const x = max(nodes, d => d.depth) + 1; const kx = (Math.abs(x1 - x0) - dx) / (x - 1); - const origin = orient === bottom ? x1 : x0; - const dir = orient === left || orient === bottom ? -1 : 1; + const origin = orientation === bottom ? x1 : x0; + const dir = orientation === left || orientation === bottom ? -1 : 1; const columns = new Array(x); for (const node of nodes) { const i = Math.max(0, Math.min(x - 1, Math.floor(align.call(null, node, x)))); @@ -252,7 +252,7 @@ function Sankey(orient) { function initializeNodeBreadths(columns) { const ky = min(columns, c => (Math.abs(y1 - y0) - (c.length - 1) * py) / sum(c, value)); for (const nodes of columns) { - let ystart = orient === bottom ? y1 : y0; + let ystart = orientation === bottom ? y1 : y0; for (const node of nodes) { node.y0 = ystart; node.y1 = ystart + node.value * ky; @@ -261,7 +261,7 @@ function Sankey(orient) { link.width = link.value * ky; } } - let yend = orient === bottom ? y0 : y1; + let yend = orientation === bottom ? y0 : y1; ystart = (yend - ystart + py) / (nodes.length + 1); for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; @@ -274,7 +274,7 @@ function Sankey(orient) { function computeNodeBreadths(graph) { const columns = computeNodeLayers(graph); - const breadth = [left, right].includes(orient) ? x1 - x0 : y1 - y0; + const breadth = [left, right].includes(orientation) ? x1 - x0 : y1 - y0; py = Math.min(dy, Math.abs(breadth) / (max(columns, c => c.length) - 1)); initializeNodeBreadths(columns); for (let i = 0; i < iterations; ++i) { @@ -335,12 +335,12 @@ function Sankey(orient) { const i = nodes.length >> 1; const node = nodes[i]; const inverted = {y0: node.y1, y1: node.y0}; - const subject = orient === bottom ? inverted : node; - const dir = orient === bottom ? -1 : 1; + const subject = orientation === bottom ? inverted : node; + const dir = orientation === bottom ? -1 : 1; resolveCollisionsBottomToTop(nodes, subject.y0 - py * dir, i - dir, alpha); resolveCollisionsTopToBottom(nodes, subject.y1 + py * dir, i + dir, alpha); - resolveCollisionsBottomToTop(nodes, orient === bottom ? y0 : y1, nodes.length - 1, alpha); - resolveCollisionsTopToBottom(nodes, orient === bottom ? y1 : y0, 0, alpha); + resolveCollisionsBottomToTop(nodes, orientation === bottom ? y0 : y1, nodes.length - 1, alpha); + resolveCollisionsTopToBottom(nodes, orientation === bottom ? y1 : y0, 0, alpha); } // Push any overlapping nodes down. From d674a3451aa20f6482b324d7b6fa9e3a3e49db04 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 11 Nov 2020 17:41:53 +0000 Subject: [PATCH 28/30] Rename variables: ystart, yend -> yStart, yEnd --- src/sankey.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index de0dfff..3370060 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -252,21 +252,21 @@ function Sankey(orientation) { function initializeNodeBreadths(columns) { const ky = min(columns, c => (Math.abs(y1 - y0) - (c.length - 1) * py) / sum(c, value)); for (const nodes of columns) { - let ystart = orientation === bottom ? y1 : y0; + let yStart = orientation === bottom ? y1 : y0; for (const node of nodes) { - node.y0 = ystart; - node.y1 = ystart + node.value * ky; - ystart = node.y1 + py; + node.y0 = yStart; + node.y1 = yStart + node.value * ky; + yStart = node.y1 + py; for (const link of node.sourceLinks) { link.width = link.value * ky; } } - let yend = orientation === bottom ? y0 : y1; - ystart = (yend - ystart + py) / (nodes.length + 1); + let yEnd = orientation === bottom ? y0 : y1; + yStart = (yEnd - yStart + py) / (nodes.length + 1); for (let i = 0; i < nodes.length; ++i) { const node = nodes[i]; - node.y0 += ystart * (i + 1); - node.y1 += ystart * (i + 1); + node.y0 += yStart * (i + 1); + node.y1 += yStart * (i + 1); } reorderLinks(nodes); } From 1968a46618e56e4dcd272c37c993b75626996794 Mon Sep 17 00:00:00 2001 From: James Addison Date: Wed, 11 Nov 2020 17:47:58 +0000 Subject: [PATCH 29/30] Use 'const' declaration for static module-level variables Co-authored-by: Curran Kelleher <68416+curran@users.noreply.github.com> --- src/sankey.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sankey.js b/src/sankey.js index 3370060..34c4ab9 100644 --- a/src/sankey.js +++ b/src/sankey.js @@ -4,12 +4,12 @@ import {transformTop, transformRight, transformBottom, transformLeft} from "./tr import {sankeyLinkHorizontal, sankeyLinkVertical} from "./sankeyLink.js"; import constant from "./constant.js"; -var top = 1, +const top = 1, right = 2, bottom = 3, left = 4; -var transforms = { +const transforms = { [top]: transformTop, [right]: transformRight, [bottom]: transformBottom, From 41d6b5932322f529a0a3a7fe8317c2831f98c49e Mon Sep 17 00:00:00 2001 From: James Addison Date: Sun, 21 Feb 2021 22:48:32 +0000 Subject: [PATCH 30/30] Fixup: documentation hyperlinks --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 37e3020..38309b5 100644 --- a/README.md +++ b/README.md @@ -206,25 +206,25 @@ If *iterations* is specified, sets the number of relaxation iterations when [gen See [*sankey*.nodeAlign](#sankey_nodeAlign). -# d3.sankeyAlignLeft(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") +# d3.sankeyAlignLeft(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") [left](https://observablehq.com/@d3/sankey-diagram?align=left) Returns *node*.depth. -# d3.sankeyAlignRight(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") +# d3.sankeyAlignRight(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") [right](https://observablehq.com/@d3/sankey-diagram?align=right) Returns *n* - 1 - *node*.height. -# d3.sankeyAlignCenter(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") +# d3.sankeyAlignCenter(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") [center](https://observablehq.com/@d3/sankey-diagram?align=center) Like [d3.sankeyAlignLeft](#sankeyAlignLeft), except that nodes without any incoming links are moved as right as possible. -# d3.sankeyAlignJustify(node, n) [<>](https://github.com/d3/d3-sankeyAlign/blob/master/src/align.js "Source") +# d3.sankeyAlignJustify(node, n) [<>](https://github.com/d3/d3-sankey/blob/master/src/align.js "Source") [justify](https://observablehq.com/@d3/sankey-diagram)