Skip to content

Commit 2e4b5a2

Browse files
committed
sankey arrows: adjustments after review
* rename `arrowwidth` for sankey diagram to `arrowlen` * add test vor vertical orientation * check available space for arrows and apply max 50% of it to arrows
1 parent b2e0190 commit 2e4b5a2

9 files changed

+94
-33
lines changed

src/traces/sankey/attributes.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -168,12 +168,12 @@ var attrs = module.exports = overrideAll({
168168
},
169169

170170
link: {
171-
arrowwidth: {
171+
arrowlen: {
172172
valType: 'number',
173173
min: 0,
174174
dflt: 0,
175175
description: [
176-
'Sets the width (in px) of the links arrow, if 0 no arrow will be drawn.'
176+
'Sets the length (in px) of the links arrow, if 0 no arrow will be drawn.'
177177
].join(' ')
178178
},
179179
label: {

src/traces/sankey/defaults.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ module.exports = function supplyDefaults(traceIn, traceOut, defaultColor, layout
5252
return Lib.coerce(linkIn, linkOut, attributes.link, attr, dflt);
5353
}
5454
coerceLink('label');
55-
coerceLink('arrowwidth');
55+
coerceLink('arrowlen');
5656
coerceLink('source');
5757
coerceLink('target');
5858
coerceLink('value');

src/traces/sankey/render.js

+33-29
Original file line numberDiff line numberDiff line change
@@ -271,7 +271,7 @@ function sankeyModel(layout, d, traceIndex) {
271271
nodeLineWidth: trace.node.line.width,
272272
linkLineColor: trace.link.line.color,
273273
linkLineWidth: trace.link.line.width,
274-
linkArrowWidth: trace.link.arrowwidth,
274+
linkArrowLength: trace.link.arrowlen,
275275
valueFormat: trace.valueformat,
276276
valueSuffix: trace.valuesuffix,
277277
textFont: trace.textfont,
@@ -310,7 +310,7 @@ function linkModel(d, l, i) {
310310
linkPath: linkPath,
311311
linkLineColor: d.linkLineColor,
312312
linkLineWidth: d.linkLineWidth,
313-
linkArrowWidth: d.linkArrowWidth,
313+
linkArrowLength: d.linkArrowLength,
314314
valueFormat: d.valueFormat,
315315
valueSuffix: d.valueSuffix,
316316
sankey: d.sankey,
@@ -320,7 +320,7 @@ function linkModel(d, l, i) {
320320
};
321321
}
322322

323-
function createCircularClosedPathString(link, arrowWidth) {
323+
function createCircularClosedPathString(link, arrowLen) {
324324
// Using coordinates computed by d3-sankey-circular
325325
var pathString = '';
326326
var offset = link.width / 2;
@@ -330,17 +330,17 @@ function createCircularClosedPathString(link, arrowWidth) {
330330
pathString =
331331
// start at the left of the target node
332332
'M ' +
333-
(coords.targetX - arrowWidth) + ' ' + (coords.targetY + offset) + ' ' +
333+
(coords.targetX - arrowLen) + ' ' + (coords.targetY + offset) + ' ' +
334334
'L' +
335-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.targetY + offset) +
335+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY + offset) +
336336
'A' +
337337
(coords.rightLargeArcRadius + offset) + ' ' + (coords.rightSmallArcRadius + offset) + ' 0 0 1 ' +
338-
(coords.rightFullExtent - offset - arrowWidth) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
338+
(coords.rightFullExtent - offset - arrowLen) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
339339
'L' +
340-
(coords.rightFullExtent - offset - arrowWidth) + ' ' + coords.verticalRightInnerExtent +
340+
(coords.rightFullExtent - offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
341341
'A' +
342342
(coords.rightLargeArcRadius + offset) + ' ' + (coords.rightLargeArcRadius + offset) + ' 0 0 1 ' +
343-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.verticalFullExtent - offset) +
343+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent - offset) +
344344
'L' +
345345
coords.leftInnerExtent + ' ' + (coords.verticalFullExtent - offset) +
346346
'A' +
@@ -368,35 +368,35 @@ function createCircularClosedPathString(link, arrowWidth) {
368368
(coords.leftLargeArcRadius - offset) + ' ' + (coords.leftLargeArcRadius - offset) + ' 0 0 0 ' +
369369
coords.leftInnerExtent + ' ' + (coords.verticalFullExtent + offset) +
370370
'L' +
371-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.verticalFullExtent + offset) +
371+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent + offset) +
372372
'A' +
373373
(coords.rightLargeArcRadius - offset) + ' ' + (coords.rightLargeArcRadius - offset) + ' 0 0 0 ' +
374-
(coords.rightFullExtent + offset - arrowWidth) + ' ' + coords.verticalRightInnerExtent +
374+
(coords.rightFullExtent + offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
375375
'L' +
376-
(coords.rightFullExtent + offset - arrowWidth) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
376+
(coords.rightFullExtent + offset - arrowLen) + ' ' + (coords.targetY - coords.rightSmallArcRadius) +
377377
'A' +
378378
(coords.rightLargeArcRadius - offset) + ' ' + (coords.rightSmallArcRadius - offset) + ' 0 0 0 ' +
379-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.targetY - offset) +
379+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY - offset) +
380380
'L' +
381-
(coords.targetX - arrowWidth) + ' ' + (coords.targetY - offset) +
382-
(arrowWidth > 0 ? 'L' + coords.targetX + ' ' + (coords.targetY) : '') +
381+
(coords.targetX - arrowLen) + ' ' + (coords.targetY - offset) +
382+
(arrowLen > 0 ? 'L' + coords.targetX + ' ' + (coords.targetY) : '') +
383383
'Z';
384384
} else {
385385
// Bottom path
386386
pathString =
387387
// start at the left of the target node
388388
'M ' +
389-
(coords.targetX - arrowWidth) + ' ' + (coords.targetY - offset) + ' ' +
389+
(coords.targetX - arrowLen) + ' ' + (coords.targetY - offset) + ' ' +
390390
'L' +
391-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.targetY - offset) +
391+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY - offset) +
392392
'A' +
393393
(coords.rightLargeArcRadius + offset) + ' ' + (coords.rightSmallArcRadius + offset) + ' 0 0 0 ' +
394-
(coords.rightFullExtent - offset - arrowWidth) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
394+
(coords.rightFullExtent - offset - arrowLen) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
395395
'L' +
396-
(coords.rightFullExtent - offset - arrowWidth) + ' ' + coords.verticalRightInnerExtent +
396+
(coords.rightFullExtent - offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
397397
'A' +
398398
(coords.rightLargeArcRadius + offset) + ' ' + (coords.rightLargeArcRadius + offset) + ' 0 0 0 ' +
399-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.verticalFullExtent + offset) +
399+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent + offset) +
400400
'L' +
401401
coords.leftInnerExtent + ' ' + (coords.verticalFullExtent + offset) +
402402
'A' +
@@ -424,18 +424,18 @@ function createCircularClosedPathString(link, arrowWidth) {
424424
(coords.leftLargeArcRadius - offset) + ' ' + (coords.leftLargeArcRadius - offset) + ' 0 0 1 ' +
425425
coords.leftInnerExtent + ' ' + (coords.verticalFullExtent - offset) +
426426
'L' +
427-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.verticalFullExtent - offset) +
427+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.verticalFullExtent - offset) +
428428
'A' +
429429
(coords.rightLargeArcRadius - offset) + ' ' + (coords.rightLargeArcRadius - offset) + ' 0 0 1 ' +
430-
(coords.rightFullExtent + offset - arrowWidth) + ' ' + coords.verticalRightInnerExtent +
430+
(coords.rightFullExtent + offset - arrowLen) + ' ' + coords.verticalRightInnerExtent +
431431
'L' +
432-
(coords.rightFullExtent + offset - arrowWidth) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
432+
(coords.rightFullExtent + offset - arrowLen) + ' ' + (coords.targetY + coords.rightSmallArcRadius) +
433433
'A' +
434434
(coords.rightLargeArcRadius - offset) + ' ' + (coords.rightSmallArcRadius - offset) + ' 0 0 1 ' +
435-
(coords.rightInnerExtent - arrowWidth) + ' ' + (coords.targetY + offset) +
435+
(coords.rightInnerExtent - arrowLen) + ' ' + (coords.targetY + offset) +
436436
'L' +
437-
(coords.targetX - arrowWidth) + ' ' + (coords.targetY + offset) +
438-
(arrowWidth > 0 ? 'L' + coords.targetX + ' ' + (coords.targetY) : '') +
437+
(coords.targetX - arrowLen) + ' ' + (coords.targetY + offset) +
438+
(arrowLen > 0 ? 'L' + coords.targetX + ' ' + (coords.targetY) : '') +
439439
'Z';
440440
}
441441
return pathString;
@@ -444,12 +444,16 @@ function createCircularClosedPathString(link, arrowWidth) {
444444
function linkPath() {
445445
var curvature = 0.5;
446446
function path(d) {
447+
var arrowLen = d.linkArrowLength;
447448
if(d.link.circular) {
448-
return createCircularClosedPathString(d.link, d.linkArrowWidth);
449+
return createCircularClosedPathString(d.link, arrowLen);
449450
} else {
450-
var arrowWidth = d.linkArrowWidth;
451+
var maxArrowLength = Math.abs((d.link.target.x0 - d.link.source.x1) / 2);
452+
if(arrowLen > maxArrowLength) {
453+
arrowLen = maxArrowLength;
454+
}
451455
var x0 = d.link.source.x1;
452-
var x1 = d.link.target.x0 - arrowWidth;
456+
var x1 = d.link.target.x0 - arrowLen;
453457
var xi = interpolateNumber(x0, x1);
454458
var x2 = xi(curvature);
455459
var x3 = xi(1 - curvature);
@@ -465,7 +469,7 @@ function linkPath() {
465469
' ' + x2 + ',' + y0b +
466470
' ' + x0 + ',' + y0b;
467471

468-
var rightEnd = arrowWidth > 0 ? 'L' + (x1 + arrowWidth) + ',' + (y1a + d.link.width / 2) : '';
472+
var rightEnd = arrowLen > 0 ? 'L' + (x1 + arrowLen) + ',' + (y1a + d.link.width / 2) : '';
469473
rightEnd += 'L' + x1 + ',' + y1b;
470474
return start + upperCurve + rightEnd + lowerCurve + 'Z';
471475
}
-210 Bytes
Loading
Loading
13.9 KB
Loading

test/image/mocks/sankey_circular_with_arrows.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"label": ["0", "1", "2", "3", "4", "5", "6"]
88
},
99
"link": {
10-
"arrowwidth": 20,
10+
"arrowlen": 20,
1111
"source": [
1212
0, 0, 1, 2, 5, 4, 3
1313
],
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"data": [
3+
{
4+
"type": "sankey",
5+
"orientation": "v",
6+
"node": {
7+
"pad": 5,
8+
"label": ["0", "1", "2", "3", "4", "5", "6"]
9+
},
10+
"link": {
11+
"arrowlen": 20,
12+
"source": [
13+
0, 0, 1, 2, 5, 4, 3
14+
],
15+
"target": [
16+
5, 3, 4, 3, 0, 2, 2
17+
],
18+
"value": [
19+
1, 2, 1, 1, 1, 1, 1
20+
]
21+
}
22+
}],
23+
"layout": {
24+
"title": {"text": "Sankey with circular data and arrows"},
25+
"width": 800,
26+
"height": 800
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
{
2+
"data": [
3+
{
4+
"type": "sankey",
5+
"arrangement": "freeform",
6+
"node": {
7+
"label": ["0", "1", "2"],
8+
"x": [1, 2, 3],
9+
"y": [0,0,0]
10+
},
11+
"link": {
12+
"arrowlen": 40,
13+
"source": [
14+
0, 1, 2
15+
],
16+
"target": [
17+
1, 2, 0
18+
],
19+
"value": [
20+
10, 9, 1
21+
]
22+
}
23+
}],
24+
"layout": {
25+
"title": {"text": "Sankey with little space"},
26+
"width": 400,
27+
"height": 400
28+
}
29+
}

0 commit comments

Comments
 (0)