Skip to content

Commit 103423b

Browse files
committed
rework projection to make the horizontal -> vertical switch appealing
1 parent df53932 commit 103423b

File tree

3 files changed

+68
-33
lines changed

3 files changed

+68
-33
lines changed

src/traces/sankey/constants.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,5 @@ module.exports = {
1616
forceIterations: 5,
1717
forceTicksPerFrame: 10,
1818
duration: 500,
19-
ease: 'linear'
19+
ease: 'cubic-in-out'
2020
};

src/traces/sankey/render.js

+67-32
Original file line numberDiff line numberDiff line change
@@ -198,15 +198,15 @@ function nodeModel(uniqueKeys, d, n) {
198198
nodeLineWidth: d.nodeLineWidth,
199199
textFont: d.textFont,
200200
size: d.horizontal ? d.height : d.width,
201-
visibleWidth: Math.ceil(d.horizontal ? visibleThickness : visibleLength),
202-
visibleHeight: Math.ceil(d.horizontal ? visibleLength : visibleThickness),
203-
zoneX: d.horizontal ? -zoneThicknessPad : -zoneLengthPad,
204-
zoneY: d.horizontal ? -zoneLengthPad : -zoneThicknessPad,
205-
zoneWidth: d.horizontal ? zoneThickness : zoneLength,
206-
zoneHeight: d.horizontal ? zoneLength : zoneThickness,
201+
visibleWidth: Math.ceil(visibleThickness),
202+
visibleHeight: Math.ceil(visibleLength),
203+
zoneX: -zoneThicknessPad,
204+
zoneY: -zoneLengthPad,
205+
zoneWidth: zoneThickness,
206+
zoneHeight: zoneLength,
207207
labelY: d.horizontal ? n.dy / 2 + 1 : n.dx / 2 + 1,
208208
left: n.originalLayer === 1,
209-
sizeAcross: d.horizontal ? d.width : d.height,
209+
sizeAcross: d.width,
210210
forceLayouts: d.forceLayouts,
211211
horizontal: d.horizontal,
212212
darkBackground: tc.getBrightness() <= 128,
@@ -230,9 +230,7 @@ function crispLinesOnEnd(sankeyNode) {
230230
function updateNodePositions(sankeyNode) {
231231
sankeyNode
232232
.attr('transform', function(d) {
233-
return d.horizontal ?
234-
'translate(' + (d.node.x - 0.5) + ', ' + (d.node.y - d.node.dy / 2 + 0.5) + ')' :
235-
'translate(' + (d.node.y - d.node.dy / 2 - 0.5) + ', ' + (d.node.x + 0.5) + ')';
233+
return 'translate(' + (d.node.x - 0.5) + ', ' + (d.node.y - d.node.dy / 2 + 0.5) + ')';
236234
});
237235
}
238236

@@ -263,14 +261,27 @@ function salientEnough(d) {
263261
return d.link.dy > 1 || d.linkLineWidth > 0;
264262
}
265263

266-
function linksTransform(d) {
264+
function sankeyTransform(d) {
265+
var offset = 'translate(' + d.translateX + ',' + d.translateY + ')';
266+
return offset + (d.horizontal ? 'matrix(1 0 0 1 0 0)' : 'matrix(0 1 1 0 0 0)');
267+
}
268+
269+
function sankeyInverseTransform(d) {
267270
return d.horizontal ? 'matrix(1 0 0 1 0 0)' : 'matrix(0 1 1 0 0 0)';
268271
}
269272

273+
function nodeCentering(d) {
274+
return 'translate(' + (d.horizontal ? 0 : d.labelY) + ' ' + (d.horizontal ? d.labelY : 0) + ')';
275+
}
276+
277+
function textFlip(d) {
278+
return d.horizontal ? 'scale(1 1)' : 'scale(-1 1)';
279+
}
280+
270281
function textGuidePath(d) {
271282
return d3.svg.line()([
272-
[d.horizontal ? (d.left ? -d.sizeAcross : d.visibleWidth + c.nodeTextOffsetHorizontal) : c.nodeTextOffsetHorizontal, d.labelY],
273-
[d.horizontal ? (d.left ? - c.nodeTextOffsetHorizontal : d.sizeAcross) : d.visibleWidth - c.nodeTextOffsetHorizontal, d.labelY]
283+
[d.horizontal ? (d.left ? -d.sizeAcross : d.visibleWidth + c.nodeTextOffsetHorizontal) : c.nodeTextOffsetHorizontal, 0],
284+
[d.horizontal ? (d.left ? - c.nodeTextOffsetHorizontal : d.sizeAcross) : d.visibleHeight - c.nodeTextOffsetHorizontal, 0]
274285
]);}
275286

276287
// event handling
@@ -311,7 +322,7 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
311322

312323
var dragBehavior = d3.behavior.drag()
313324

314-
.origin(function(d) {return d.horizontal ? d.node : {x: d.node.y, y: d.node.x};})
325+
.origin(function(d) {return d.node;})
315326

316327
.on('dragstart', function(d) {
317328
if(d.arrangement === 'fixed') return;
@@ -335,8 +346,8 @@ function attachDragHandler(sankeyNode, sankeyLink, callbacks) {
335346

336347
.on('drag', function(d) {
337348
if(d.arrangement === 'fixed') return;
338-
var x = d.horizontal ? d3.event.x : d3.event.y;
339-
var y = d.horizontal ? d3.event.y : d3.event.x;
349+
var x = d3.event.x;
350+
var y = d3.event.y;
340351
if(d.arrangement === 'snap') {
341352
d.node.x = x;
342353
d.node.y = y;
@@ -432,23 +443,20 @@ module.exports = function(svg, styledData, layout, callbacks) {
432443
.style('left', 0)
433444
.style('shape-rendering', 'geometricPrecision')
434445
.style('pointer-events', 'auto')
435-
.style('box-sizing', 'content-box');
446+
.style('box-sizing', 'content-box')
447+
.attr('transform', sankeyTransform);
436448

437-
sankey
438-
.attr('transform', function(d) {return 'translate(' + d.translateX + ',' + d.translateY + ')';});
449+
sankey.transition()
450+
.ease(c.ease).duration(c.duration)
451+
.attr('transform', sankeyTransform);
439452

440453
var sankeyLinks = sankey.selectAll('.sankeyLinks')
441454
.data(repeat, keyFun);
442455

443456
sankeyLinks.enter()
444457
.append('g')
445458
.classed('sankeyLinks', true)
446-
.style('fill', 'none')
447-
.attr('transform', linksTransform);
448-
449-
sankeyLinks.transition()
450-
.ease(c.ease).duration(c.duration)
451-
.attr('transform', linksTransform);
459+
.style('fill', 'none');
452460

453461
var sankeyLink = sankeyLinks.selectAll('.sankeyLink')
454462
.data(function(d) {
@@ -562,26 +570,42 @@ module.exports = function(svg, styledData, layout, callbacks) {
562570
.attr('width', function(d) {return d.zoneWidth;})
563571
.attr('height', function(d) {return d.zoneHeight;});
564572

565-
var nodeLabelGuide = sankeyNode.selectAll('.nodeLabelGuide')
573+
var nodeCentered = sankeyNode.selectAll('.nodeCentered')
574+
.data(repeat);
575+
576+
nodeCentered.enter()
577+
.append('g')
578+
.classed('nodeCentered', true)
579+
.attr('transform', nodeCentering);
580+
581+
nodeCentered
582+
.transition()
583+
.ease(c.ease).duration(c.duration)
584+
.attr('transform', nodeCentering);
585+
586+
var nodeLabelGuide = nodeCentered.selectAll('.nodeLabelGuide')
566587
.data(repeat);
567588

568589
nodeLabelGuide.enter()
569590
.append('path')
570591
.classed('nodeLabelGuide', true)
571592
.attr('id', function(d) {return d.uniqueNodeLabelPathId;})
572-
.attr('d', textGuidePath);
593+
.attr('d', textGuidePath)
594+
.attr('transform', sankeyInverseTransform);
573595

574596
nodeLabelGuide
575597
.transition()
576598
.ease(c.ease).duration(c.duration)
577-
.attr('d', textGuidePath);
599+
.attr('d', textGuidePath)
600+
.attr('transform', sankeyInverseTransform);
578601

579-
var nodeLabel = sankeyNode.selectAll('.nodeLabel')
602+
var nodeLabel = nodeCentered.selectAll('.nodeLabel')
580603
.data(repeat);
581604

582605
nodeLabel.enter()
583606
.append('text')
584607
.classed('nodeLabel', true)
608+
.attr('transform', textFlip)
585609
.style('user-select', 'none')
586610
.style('cursor', 'default')
587611
.style('fill', 'black');
@@ -592,18 +616,29 @@ module.exports = function(svg, styledData, layout, callbacks) {
592616
})
593617
.each(function(d) {Drawing.font(nodeLabel, d.textFont);});
594618

619+
nodeLabel
620+
.transition()
621+
.ease(c.ease).duration(c.duration)
622+
.attr('transform', textFlip);
623+
595624
var nodeLabelTextPath = nodeLabel.selectAll('.nodeLabelTextPath')
596625
.data(repeat);
597626

598627
nodeLabelTextPath.enter()
599628
.append('textPath')
600629
.classed('nodeLabelTextPath', true)
601630
.attr('alignment-baseline', 'middle')
602-
.attr('xlink:href', function(d) {return '#' + d.uniqueNodeLabelPathId;});
631+
.attr('xlink:href', function(d) {return '#' + d.uniqueNodeLabelPathId;})
632+
.attr('startOffset', function(d) {return d.horizontal && d.left ? '100%' : '0%';})
633+
.style('fill', function(d) {return d.darkBackground && !d.horizontal ? 'rgb(255,255,255)' : 'rgb(0,0,0)';});
603634

604635
nodeLabelTextPath
605636
.text(function(d) {return d.horizontal || d.node.dy > 5 ? d.node.label : '';})
637+
.style('text-anchor', function(d) {return d.horizontal && d.left ? 'end' : 'start';});
638+
639+
nodeLabelTextPath
640+
.transition()
641+
.ease(c.ease).duration(c.duration)
606642
.attr('startOffset', function(d) {return d.horizontal && d.left ? '100%' : '0%';})
607-
.style('text-anchor', function(d) {return d.horizontal && d.left ? 'end' : 'start';})
608-
.style('fill', function(d) {return d.darkBackground && !d.horizontal ? 'white' : 'black';});
643+
.style('fill', function(d) {return d.darkBackground && !d.horizontal ? 'rgb(255,255,255)' : 'rgb(0,0,0)';});
609644
};
3.3 KB
Loading

0 commit comments

Comments
 (0)