@x-nivo/sankey
Version:
[](https://www.npmjs.com/package/@nivo/sankey)
1,157 lines (1,088 loc) • 42.9 kB
JavaScript
;
Object.defineProperty(exports, '__esModule', { value: true });
function _interopDefault (ex) { return (ex && (typeof ex === 'object') && 'default' in ex) ? ex['default'] : ex; }
var _uniq = _interopDefault(require('lodash/uniq'));
var React = require('react');
var React__default = _interopDefault(React);
var core = require('@nivo/core');
var legends = require('@nivo/legends');
var PropTypes = _interopDefault(require('prop-types'));
var d3Sankey = require('d3-sankey');
var pure = _interopDefault(require('recompose/pure'));
var _withPropsOnChange = _interopDefault(require('recompose/withPropsOnChange'));
var _withState = _interopDefault(require('recompose/withState'));
var _defaultProps = _interopDefault(require('recompose/defaultProps'));
var _compose = _interopDefault(require('recompose/compose'));
var _cloneDeep = _interopDefault(require('lodash/cloneDeep'));
var reactMotion = require('react-motion');
var withHandlers = _interopDefault(require('recompose/withHandlers'));
var d3Shape = require('d3-shape');
var sankeyAlignmentPropMapping = {
center: d3Sankey.sankeyCenter,
justify: d3Sankey.sankeyJustify,
start: d3Sankey.sankeyLeft,
end: d3Sankey.sankeyRight
};
var sankeyAlignmentPropKeys = Object.keys(sankeyAlignmentPropMapping);
var sankeyAlignmentPropType = PropTypes.oneOf(sankeyAlignmentPropKeys);
var sankeyAlignmentFromProp = function sankeyAlignmentFromProp(prop) {
return sankeyAlignmentPropMapping[prop];
};
var SankeyPropTypes = {
data: PropTypes.shape({
nodes: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
})).isRequired,
links: PropTypes.arrayOf(PropTypes.shape({
source: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
target: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
})).isRequired
}).isRequired,
layout: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
align: sankeyAlignmentPropType.isRequired,
sort: PropTypes.oneOfType([PropTypes.oneOf(['auto', 'input', 'ascending', 'descending']), PropTypes.func]).isRequired,
nodeOpacity: PropTypes.number.isRequired,
nodeHoverOpacity: PropTypes.number.isRequired,
nodeHoverOthersOpacity: PropTypes.number.isRequired,
nodeThickness: PropTypes.number.isRequired,
nodeSpacing: PropTypes.number.isRequired,
nodeInnerPadding: PropTypes.number.isRequired,
nodeBorderWidth: PropTypes.number.isRequired,
nodeBorderColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
linkOpacity: PropTypes.number.isRequired,
linkHoverOpacity: PropTypes.number.isRequired,
linkHoverOthersOpacity: PropTypes.number.isRequired,
linkContract: PropTypes.number.isRequired,
linkBlendMode: core.blendModePropType.isRequired,
enableLinkGradient: PropTypes.bool.isRequired,
enableLabels: PropTypes.bool.isRequired,
labelPosition: PropTypes.oneOf(['inside', 'outside']).isRequired,
labelPadding: PropTypes.number.isRequired,
labelOrientation: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
labelTextColor: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
getLabelTextColor: PropTypes.func.isRequired,
// computed
label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
labelFormat: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
getLabel: PropTypes.func.isRequired,
// computed
nodeTooltip: PropTypes.func,
linkTooltip: PropTypes.func,
isInteractive: PropTypes.bool.isRequired,
onClick: PropTypes.func.isRequired,
tooltipFormat: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
legends: PropTypes.arrayOf(PropTypes.shape(legends.LegendPropShape)).isRequired
};
var SankeyDefaultProps = {
layout: 'horizontal',
align: 'center',
sort: 'auto',
nodeOpacity: 0.75,
nodeHoverOpacity: 1,
nodeHoverOthersOpacity: 0.15,
nodeThickness: 12,
nodeSpacing: 12,
nodeInnerPadding: 0,
nodeBorderWidth: 1,
nodeBorderColor: 'inherit:darker(0.5)',
linkOpacity: 0.25,
linkHoverOpacity: 0.6,
linkHoverOthersOpacity: 0.15,
linkContract: 0,
linkBlendMode: 'multiply',
enableLinkGradient: false,
enableLabels: true,
label: 'id',
labelPosition: 'inside',
labelPadding: 9,
labelOrientation: 'horizontal',
labelTextColor: 'inherit:darker(0.8)',
isInteractive: true,
onClick: core.noop,
legends: []
};
var getId = function getId(d) {
return d.id;
};
var enhance = (function (Component) {
return _compose(_defaultProps(SankeyDefaultProps), _withState('currentNode', 'setCurrentNode', null), _withState('currentLink', 'setCurrentLink', null), core.withColors(), core.withColors({
colorByKey: 'linkColorBy',
destKey: 'getLinkColor',
defaultColorBy: 'source.id'
}), core.withTheme(), core.withDimensions(), core.withMotion(), _withPropsOnChange(['nodeBorderColor'], function (_ref) {
var nodeBorderColor = _ref.nodeBorderColor;
return {
getNodeBorderColor: core.getInheritedColorGenerator(nodeBorderColor)
};
}), _withPropsOnChange(['labelTextColor'], function (_ref2) {
var labelTextColor = _ref2.labelTextColor;
return {
getLabelTextColor: core.getInheritedColorGenerator(labelTextColor)
};
}), _withPropsOnChange(['label', 'labelFormat'], function (_ref3) {
var label = _ref3.label,
labelFormat = _ref3.labelFormat;
return {
getLabel: core.getLabelGenerator(label, labelFormat)
};
}), _withPropsOnChange(['sort'], function (_ref4) {
var sort = _ref4.sort;
var sortFunction;
if (sort === 'input') {
sortFunction = null;
} else if (sort === 'ascending') {
sortFunction = function sortFunction(a, b) {
return a.value - b.value;
};
} else if (sort === 'descending') {
sortFunction = function sortFunction(a, b) {
return b.value - a.value;
};
}
return {
sortFunction: sortFunction
};
}), _withPropsOnChange(['align'], function (_ref5) {
var align = _ref5.align;
return {
alignFunction: sankeyAlignmentFromProp(align)
};
}), _withPropsOnChange(['data', 'layout', 'alignFunction', 'sortFunction', 'nodeThickness', 'nodeSpacing', 'nodeInnerPadding', 'width', 'height', 'getColor', 'getLinkColor', 'getLabel'], function (_ref6) {
var _data = _ref6.data,
layout = _ref6.layout,
alignFunction = _ref6.alignFunction,
sortFunction = _ref6.sortFunction,
nodeThickness = _ref6.nodeThickness,
nodeSpacing = _ref6.nodeSpacing,
nodeInnerPadding = _ref6.nodeInnerPadding,
width = _ref6.width,
height = _ref6.height,
getColor = _ref6.getColor,
getLinkColor = _ref6.getLinkColor,
getLabel = _ref6.getLabel;
var sankey = d3Sankey.sankey().nodeAlign(alignFunction).nodeSort(sortFunction).nodeWidth(nodeThickness).nodePadding(nodeSpacing).size(layout === 'horizontal' ? [width, height] : [height, width]).nodeId(getId); // deep clone is required as the sankey diagram mutates data
// we need a different identity for correct updates
var data = _cloneDeep(_data);
sankey(data);
data.nodes.forEach(function (node) {
node.color = getColor(node);
node.label = getLabel(node);
if (layout === 'horizontal') {
node.x = node.x0 + nodeInnerPadding;
node.y = node.y0;
node.width = Math.max(node.x1 - node.x0 - nodeInnerPadding * 2, 0);
node.height = Math.max(node.y1 - node.y0, 0);
} else {
node.x = node.y0;
node.y = node.x0 + nodeInnerPadding;
node.width = Math.max(node.y1 - node.y0, 0);
node.height = Math.max(node.x1 - node.x0 - nodeInnerPadding * 2, 0);
var oldX0 = node.x0;
var oldX1 = node.x1;
node.x0 = node.y0;
node.x1 = node.y1;
node.y0 = oldX0;
node.y1 = oldX1;
}
});
data.links.forEach(function (link) {
link.color = getLinkColor(link);
link.pos0 = link.y0;
link.pos1 = link.y1;
link.thickness = link.width;
delete link.y0;
delete link.y1;
delete link.width;
});
return data;
}), _withPropsOnChange(['nodes'], function (_ref7) {
var nodes = _ref7.nodes;
return {
legendData: nodes.map(function (node) {
return {
id: node.id,
label: node.label,
color: node.color
};
})
};
}), pure)(Component);
});
var SankeyNodesItem = function SankeyNodesItem(_ref) {
var x = _ref.x,
y = _ref.y,
width = _ref.width,
height = _ref.height,
color = _ref.color,
opacity = _ref.opacity,
borderWidth = _ref.borderWidth,
borderColor = _ref.borderColor,
handleMouseEnter = _ref.handleMouseEnter,
handleMouseMove = _ref.handleMouseMove,
handleMouseLeave = _ref.handleMouseLeave,
onClick = _ref.onClick;
return React__default.createElement("rect", {
x: x,
y: y,
width: width,
height: height,
fill: color,
fillOpacity: opacity,
strokeWidth: borderWidth,
stroke: borderColor,
strokeOpacity: opacity,
onMouseEnter: handleMouseEnter,
onMouseMove: handleMouseMove,
onMouseLeave: handleMouseLeave,
onClick: onClick
});
};
SankeyNodesItem.propTypes = {
node: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
color: PropTypes.string.isRequired
}),
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired,
opacity: PropTypes.number.isRequired,
borderWidth: PropTypes.number.isRequired,
borderColor: PropTypes.string.isRequired,
showTooltip: PropTypes.func.isRequired,
hideTooltip: PropTypes.func.isRequired,
setCurrent: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired,
handleMouseEnter: PropTypes.func.isRequired,
handleMouseMove: PropTypes.func.isRequired,
handleMouseLeave: PropTypes.func.isRequired,
tooltip: PropTypes.element.isRequired,
theme: PropTypes.object.isRequired
};
var enhance$1 = _compose(_withPropsOnChange(['node', 'theme', 'tooltip'], function (_ref2) {
var node = _ref2.node,
theme = _ref2.theme,
tooltip = _ref2.tooltip;
if (tooltip) {
return {
tooltip: React__default.createElement(core.BasicTooltip, {
id: tooltip(node),
enableChip: false,
theme: theme
})
};
}
return {
tooltip: React__default.createElement(core.BasicTooltip, {
id: node.label,
enableChip: true,
color: node.color,
theme: theme
})
};
}), _withPropsOnChange(['onClick', 'node'], function (_ref3) {
var _onClick = _ref3.onClick,
node = _ref3.node;
return {
onClick: function onClick(event) {
return _onClick(node, event);
}
};
}), withHandlers({
handleMouseEnter: function handleMouseEnter(_ref4) {
var showTooltip = _ref4.showTooltip,
setCurrent = _ref4.setCurrent,
node = _ref4.node,
tooltip = _ref4.tooltip;
return function (e) {
setCurrent(node);
showTooltip(tooltip, e);
};
},
handleMouseMove: function handleMouseMove(_ref5) {
var showTooltip = _ref5.showTooltip,
tooltip = _ref5.tooltip;
return function (e) {
showTooltip(tooltip, e);
};
},
handleMouseLeave: function handleMouseLeave(_ref6) {
var hideTooltip = _ref6.hideTooltip,
setCurrent = _ref6.setCurrent;
return function () {
setCurrent(null);
hideTooltip();
};
}
}), pure);
var SankeyNodesItem$1 = enhance$1(SankeyNodesItem);
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty(target, key, source[key]); }); } return target; }
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var SankeyNodes = function SankeyNodes(_ref) {
var nodes = _ref.nodes,
nodeOpacity = _ref.nodeOpacity,
nodeHoverOpacity = _ref.nodeHoverOpacity,
nodeHoverOthersOpacity = _ref.nodeHoverOthersOpacity,
nodeBorderWidth = _ref.nodeBorderWidth,
getNodeBorderColor = _ref.getNodeBorderColor,
animate = _ref.animate,
motionDamping = _ref.motionDamping,
motionStiffness = _ref.motionStiffness,
showTooltip = _ref.showTooltip,
hideTooltip = _ref.hideTooltip,
setCurrentNode = _ref.setCurrentNode,
currentNode = _ref.currentNode,
currentLink = _ref.currentLink,
isCurrentNode = _ref.isCurrentNode,
onClick = _ref.onClick,
tooltip = _ref.tooltip,
theme = _ref.theme;
var getOpacity = function getOpacity(node) {
if (!currentNode && !currentLink) return nodeOpacity;
if (isCurrentNode(node)) return nodeHoverOpacity;
return nodeHoverOthersOpacity;
};
if (!animate) {
return React__default.createElement(React.Fragment, null, nodes.map(function (node) {
return React__default.createElement(SankeyNodesItem$1, {
key: node.id,
node: node,
x: node.x,
y: node.y,
width: node.width,
height: node.height,
color: node.color,
opacity: getOpacity(node),
borderWidth: nodeBorderWidth,
borderColor: getNodeBorderColor(node),
showTooltip: showTooltip,
hideTooltip: hideTooltip,
setCurrent: setCurrentNode,
onClick: onClick,
tooltip: tooltip,
theme: theme
});
}));
}
var springProps = {
damping: motionDamping,
stiffness: motionStiffness
};
return React__default.createElement(reactMotion.TransitionMotion, {
styles: nodes.map(function (node) {
return {
key: node.id,
data: node,
style: _objectSpread({
x: reactMotion.spring(node.x, springProps),
y: reactMotion.spring(node.y, springProps),
width: reactMotion.spring(node.width, springProps),
height: reactMotion.spring(node.height, springProps),
opacity: reactMotion.spring(getOpacity(node), springProps)
}, core.colorMotionSpring(node.color, springProps))
};
})
}, function (interpolatedStyles) {
return React__default.createElement(React.Fragment, null, interpolatedStyles.map(function (_ref2) {
var key = _ref2.key,
style = _ref2.style,
node = _ref2.data;
var color = core.getInterpolatedColor(style);
return React__default.createElement(SankeyNodesItem$1, {
key: key,
node: node,
x: style.x,
y: style.y,
width: Math.max(style.width, 0),
height: Math.max(style.height, 0),
color: color,
opacity: style.opacity,
borderWidth: nodeBorderWidth,
borderColor: getNodeBorderColor(_objectSpread({}, node, {
color: color
})),
showTooltip: showTooltip,
hideTooltip: hideTooltip,
setCurrent: setCurrentNode,
onClick: onClick,
tooltip: tooltip,
theme: theme
});
}));
});
};
SankeyNodes.propTypes = _objectSpread({
nodes: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
})).isRequired,
nodeOpacity: PropTypes.number.isRequired,
nodeHoverOpacity: PropTypes.number.isRequired,
nodeHoverOthersOpacity: PropTypes.number.isRequired,
nodeBorderWidth: PropTypes.number.isRequired,
getNodeBorderColor: PropTypes.func.isRequired,
theme: PropTypes.object.isRequired,
tooltip: PropTypes.func
}, core.motionPropTypes, {
showTooltip: PropTypes.func.isRequired,
hideTooltip: PropTypes.func.isRequired,
setCurrentNode: PropTypes.func.isRequired,
currentNode: PropTypes.object,
currentLink: PropTypes.object,
isCurrentNode: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired
});
var SankeyNodes$1 = pure(SankeyNodes);
function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
var SankeyLinkGradient = React.memo(function (_ref) {
var id = _ref.id,
layout = _ref.layout,
startColor = _ref.startColor,
endColor = _ref.endColor;
var gradientProps = {};
if (layout === 'horizontal') {
gradientProps.x1 = '0%';
gradientProps.x2 = '100%';
gradientProps.y1 = '0%';
gradientProps.y2 = '0%';
} else {
gradientProps.x1 = '0%';
gradientProps.x2 = '0%';
gradientProps.y1 = '0%';
gradientProps.y2 = '100%';
}
return React__default.createElement("linearGradient", _extends({
id: id,
spreadMethod: "pad"
}, gradientProps), React__default.createElement("stop", {
offset: "0%",
stopColor: startColor
}), React__default.createElement("stop", {
offset: "100%",
stopColor: endColor
}));
});
SankeyLinkGradient.propTypes = {
id: PropTypes.string.isRequired,
layout: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
startColor: PropTypes.string.isRequired,
endColor: PropTypes.string.isRequired
};
SankeyLinkGradient.displayName = 'SankeyLinkGradient';
var tooltipStyles = {
container: {
display: 'flex',
alignItems: 'center'
},
sourceChip: {
marginRight: 7
},
targetChip: {
marginLeft: 7,
marginRight: 7
}
};
var TooltipContent = function TooltipContent(_ref) {
var link = _ref.link,
format = _ref.format;
return React__default.createElement("span", {
style: tooltipStyles.container
}, React__default.createElement(core.Chip, {
color: link.source.color,
style: tooltipStyles.sourceChip
}), React__default.createElement("strong", null, link.source.label), ' > ', React__default.createElement("strong", null, link.target.label), React__default.createElement(core.Chip, {
color: link.target.color,
style: tooltipStyles.targetChip
}), React__default.createElement("strong", null, format ? format(link.value) : link.value));
};
TooltipContent.propTypes = {
link: PropTypes.shape({
source: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
}).isRequired,
target: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
}).isRequired,
color: PropTypes.string.isRequired,
value: PropTypes.number.isRequired
}).isRequired,
format: PropTypes.func
};
var SankeyLinksItem = function SankeyLinksItem(_ref2) {
var link = _ref2.link,
layout = _ref2.layout,
path = _ref2.path,
color = _ref2.color,
opacity = _ref2.opacity,
blendMode = _ref2.blendMode,
enableGradient = _ref2.enableGradient,
handleMouseEnter = _ref2.handleMouseEnter,
handleMouseMove = _ref2.handleMouseMove,
handleMouseLeave = _ref2.handleMouseLeave,
onClick = _ref2.onClick;
var linkId = "".concat(link.source.id, ".").concat(link.target.id);
return React__default.createElement(React.Fragment, null, enableGradient && React__default.createElement(SankeyLinkGradient, {
id: linkId,
layout: layout,
startColor: link.startColor || link.source.color,
endColor: link.endColor || link.target.color
}), React__default.createElement("path", {
fill: enableGradient ? "url(#".concat(linkId, ")") : color,
d: path,
fillOpacity: opacity,
onMouseEnter: handleMouseEnter,
onMouseMove: handleMouseMove,
onMouseLeave: handleMouseLeave,
onClick: onClick,
style: {
mixBlendMode: blendMode
}
}));
};
SankeyLinksItem.propTypes = {
link: PropTypes.shape({
source: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
color: PropTypes.string.isRequired
}).isRequired,
target: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
color: PropTypes.string.isRequired
}).isRequired,
color: PropTypes.string.isRequired,
value: PropTypes.number.isRequired
}).isRequired,
layout: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
path: PropTypes.string.isRequired,
color: PropTypes.string.isRequired,
opacity: PropTypes.number.isRequired,
blendMode: core.blendModePropType.isRequired,
enableGradient: PropTypes.bool.isRequired,
theme: PropTypes.object.isRequired,
showTooltip: PropTypes.func.isRequired,
hideTooltip: PropTypes.func.isRequired,
setCurrent: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired,
handleMouseEnter: PropTypes.func.isRequired,
handleMouseMove: PropTypes.func.isRequired,
handleMouseLeave: PropTypes.func.isRequired
};
var enhance$2 = _compose(_withPropsOnChange(['link', 'theme', 'tooltip', 'tooltipFormat'], function (_ref3) {
var link = _ref3.link,
theme = _ref3.theme,
tooltip = _ref3.tooltip,
tooltipFormat = _ref3.tooltipFormat;
if (tooltip) {
return {
tooltip: React__default.createElement(core.BasicTooltip, {
id: tooltip(link),
enableChip: false,
theme: theme
})
};
}
return {
tooltip: React__default.createElement(core.BasicTooltip, {
id: React__default.createElement(TooltipContent, {
format: tooltipFormat,
link: link
}),
theme: theme
})
};
}), _withPropsOnChange(['onClick', 'link'], function (_ref4) {
var _onClick = _ref4.onClick,
link = _ref4.link;
return {
onClick: function onClick(event) {
return _onClick(link, event);
}
};
}), withHandlers({
handleMouseEnter: function handleMouseEnter(_ref5) {
var showTooltip = _ref5.showTooltip,
setCurrent = _ref5.setCurrent,
link = _ref5.link,
tooltip = _ref5.tooltip;
return function (e) {
setCurrent(link);
showTooltip(tooltip, e);
};
},
handleMouseMove: function handleMouseMove(_ref6) {
var showTooltip = _ref6.showTooltip,
tooltip = _ref6.tooltip;
return function (e) {
showTooltip(tooltip, e);
};
},
handleMouseLeave: function handleMouseLeave(_ref7) {
var hideTooltip = _ref7.hideTooltip,
setCurrent = _ref7.setCurrent;
return function () {
setCurrent(null);
hideTooltip();
};
}
}), pure);
var SankeyLinksItem$1 = enhance$2(SankeyLinksItem);
var sankeyLinkHorizontal = function sankeyLinkHorizontal() {
var lineGenerator = d3Shape.line().curve(d3Shape.curveMonotoneX);
return function (n, contract) {
var thickness = Math.max(1, n.thickness - contract * 2);
var halfThickness = thickness / 2;
var linkLength = n.target.x0 - n.source.x1;
var padLength = linkLength * 0.12;
var dots = [[n.source.x1, n.pos0 - halfThickness], [n.source.x1 + padLength, n.pos0 - halfThickness], [n.target.x0 - padLength, n.pos1 - halfThickness], [n.target.x0, n.pos1 - halfThickness], [n.target.x0, n.pos1 + halfThickness], [n.target.x0 - padLength, n.pos1 + halfThickness], [n.source.x1 + padLength, n.pos0 + halfThickness], [n.source.x1, n.pos0 + halfThickness], [n.source.x1, n.pos0 - halfThickness]];
return lineGenerator(dots) + 'Z';
};
};
var sankeyLinkVertical = function sankeyLinkVertical() {
var lineGenerator = d3Shape.line().curve(d3Shape.curveMonotoneY);
return function (n, contract) {
var thickness = Math.max(1, n.thickness - contract * 2);
var halfThickness = thickness / 2;
var linkLength = n.target.y0 - n.source.y1;
var padLength = linkLength * 0.12;
var dots = [[n.pos0 + halfThickness, n.source.y1], [n.pos0 + halfThickness, n.source.y1 + padLength], [n.pos1 + halfThickness, n.target.y0 - padLength], [n.pos1 + halfThickness, n.target.y0], [n.pos1 - halfThickness, n.target.y0], [n.pos1 - halfThickness, n.target.y0 - padLength], [n.pos0 - halfThickness, n.source.y1 + padLength], [n.pos0 - halfThickness, n.source.y1], [n.pos0 + halfThickness, n.source.y1]];
return lineGenerator(dots) + 'Z';
};
};
function _objectSpread$1(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty$1(target, key, source[key]); }); } return target; }
function _defineProperty$1(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _extends$1() { _extends$1 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
var SankeyLinks = function SankeyLinks(_ref) {
var links = _ref.links,
layout = _ref.layout,
linkOpacity = _ref.linkOpacity,
linkHoverOpacity = _ref.linkHoverOpacity,
linkHoverOthersOpacity = _ref.linkHoverOthersOpacity,
linkContract = _ref.linkContract,
linkBlendMode = _ref.linkBlendMode,
enableLinkGradient = _ref.enableLinkGradient,
animate = _ref.animate,
motionDamping = _ref.motionDamping,
motionStiffness = _ref.motionStiffness,
showTooltip = _ref.showTooltip,
hideTooltip = _ref.hideTooltip,
setCurrentLink = _ref.setCurrentLink,
currentNode = _ref.currentNode,
currentLink = _ref.currentLink,
isCurrentLink = _ref.isCurrentLink,
onClick = _ref.onClick,
tooltipFormat = _ref.tooltipFormat,
tooltip = _ref.tooltip,
theme = _ref.theme;
var getOpacity = function getOpacity(link) {
if (!currentNode && !currentLink) return linkOpacity;
if (isCurrentLink(link)) return linkHoverOpacity;
return linkHoverOthersOpacity;
};
var getLinkPath = layout === 'horizontal' ? sankeyLinkHorizontal() : sankeyLinkVertical();
if (animate !== true) {
return React__default.createElement("g", null, links.map(function (link) {
return React__default.createElement(SankeyLinksItem$1, {
key: "".concat(link.source.id, ".").concat(link.target.id),
link: link,
layout: layout,
path: getLinkPath(link, linkContract),
color: link.color,
opacity: getOpacity(link),
blendMode: linkBlendMode,
enableGradient: enableLinkGradient,
showTooltip: showTooltip,
hideTooltip: hideTooltip,
setCurrent: setCurrentLink,
onClick: onClick,
tooltip: tooltip,
theme: theme,
tooltipFormat: tooltipFormat
});
}));
}
var springConfig = {
stiffness: motionStiffness,
damping: motionDamping
};
return React__default.createElement(React.Fragment, null, links.map(function (link) {
return React__default.createElement(core.SmartMotion, {
key: "".concat(link.source.id, ".").concat(link.target.id),
style: function style(spring) {
return {
path: spring(getLinkPath(link, linkContract), springConfig),
color: spring(link.color, springConfig),
opacity: spring(getOpacity(link), springConfig)
};
}
}, function (style) {
return React__default.createElement(SankeyLinksItem$1, _extends$1({
link: link,
layout: layout
}, style, {
blendMode: linkBlendMode,
enableGradient: enableLinkGradient,
showTooltip: showTooltip,
hideTooltip: hideTooltip,
setCurrent: setCurrentLink,
onClick: onClick,
tooltip: tooltip,
theme: theme,
tooltipFormat: tooltipFormat
}));
});
}));
};
SankeyLinks.propTypes = _objectSpread$1({
layout: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
links: PropTypes.arrayOf(PropTypes.shape({
source: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
}).isRequired,
target: PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired
}).isRequired,
thickness: PropTypes.number.isRequired,
color: PropTypes.string.isRequired
})).isRequired,
linkOpacity: PropTypes.number.isRequired,
linkHoverOpacity: PropTypes.number.isRequired,
linkHoverOthersOpacity: PropTypes.number.isRequired,
linkContract: PropTypes.number.isRequired,
linkBlendMode: core.blendModePropType.isRequired,
enableLinkGradient: PropTypes.bool.isRequired,
theme: PropTypes.object.isRequired,
tooltip: PropTypes.func
}, core.motionPropTypes, {
showTooltip: PropTypes.func.isRequired,
hideTooltip: PropTypes.func.isRequired,
setCurrentLink: PropTypes.func.isRequired,
currentLink: PropTypes.object,
isCurrentLink: PropTypes.func.isRequired,
onClick: PropTypes.func.isRequired
});
var SankeyLinks$1 = pure(SankeyLinks);
function _objectSpread$2(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; var ownKeys = Object.keys(source); if (typeof Object.getOwnPropertySymbols === 'function') { ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { return Object.getOwnPropertyDescriptor(source, sym).enumerable; })); } ownKeys.forEach(function (key) { _defineProperty$2(target, key, source[key]); }); } return target; }
function _defineProperty$2(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
var SankeyLabels = function SankeyLabels(_ref) {
var nodes = _ref.nodes,
layout = _ref.layout,
width = _ref.width,
height = _ref.height,
labelPosition = _ref.labelPosition,
labelPadding = _ref.labelPadding,
labelOrientation = _ref.labelOrientation,
getLabelTextColor = _ref.getLabelTextColor,
theme = _ref.theme,
animate = _ref.animate,
motionDamping = _ref.motionDamping,
motionStiffness = _ref.motionStiffness;
var labelRotation = labelOrientation === 'vertical' ? -90 : 0;
var labels = nodes.map(function (node) {
var x;
var y;
var textAnchor;
if (layout === 'horizontal') {
y = node.y + node.height / 2;
if (node.x < width / 2) {
if (labelPosition === 'inside') {
x = node.x1 + labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'middle' : 'start';
} else {
x = node.x - labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'middle' : 'end';
}
} else {
if (labelPosition === 'inside') {
x = node.x - labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'middle' : 'end';
} else {
x = node.x1 + labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'middle' : 'start';
}
}
} else if (layout === 'vertical') {
x = node.x + node.width / 2;
if (node.y < height / 2) {
if (labelPosition === 'inside') {
y = node.y1 + labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'end' : 'middle';
} else {
y = node.y - labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'start' : 'middle';
}
} else {
if (labelPosition === 'inside') {
y = node.y - labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'start' : 'middle';
} else {
y = node.y1 + labelPadding;
textAnchor = labelOrientation === 'vertical' ? 'end' : 'middle';
}
}
}
return {
id: node.id,
label: node.label,
x: x,
y: y,
textAnchor: textAnchor,
color: getLabelTextColor(node)
};
});
if (!animate) {
return React__default.createElement("g", null, labels.map(function (label) {
return React__default.createElement("text", {
key: label.id,
alignmentBaseline: "central",
textAnchor: label.textAnchor,
transform: "translate(".concat(label.x, ", ").concat(label.y, ") rotate(").concat(labelRotation, ")"),
style: _objectSpread$2({}, theme.labels.text, {
fill: label.color
})
}, label.label);
}));
}
var springProps = {
damping: motionDamping,
stiffness: motionStiffness
};
return React__default.createElement(reactMotion.TransitionMotion, {
styles: labels.map(function (label) {
return {
key: label.id,
data: label,
style: _objectSpread$2({
x: reactMotion.spring(label.x, springProps),
y: reactMotion.spring(label.y, springProps),
rotation: reactMotion.spring(labelRotation, springProps)
}, core.colorMotionSpring(label.color, springProps))
};
})
}, function (interpolatedStyles) {
return React__default.createElement(React.Fragment, null, interpolatedStyles.map(function (_ref2) {
var key = _ref2.key,
style = _ref2.style,
data = _ref2.data;
var color = core.getInterpolatedColor(style);
return React__default.createElement("text", {
key: key,
transform: "translate(".concat(style.x, ", ").concat(style.y, ") rotate(").concat(style.rotation, ")"),
alignmentBaseline: "central",
textAnchor: data.textAnchor,
style: _objectSpread$2({}, theme.labels.text, {
fill: color,
pointerEvents: 'none'
})
}, data.label);
}));
});
};
SankeyLabels.propTypes = _objectSpread$2({
nodes: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
x1: PropTypes.number.isRequired,
x: PropTypes.number.isRequired,
y: PropTypes.number.isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired
})).isRequired,
layout: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
labelPosition: PropTypes.oneOf(['inside', 'outside']).isRequired,
labelPadding: PropTypes.number.isRequired,
labelOrientation: PropTypes.oneOf(['horizontal', 'vertical']).isRequired,
getLabelTextColor: PropTypes.func.isRequired,
theme: PropTypes.object.isRequired
}, core.motionPropTypes);
var SankeyLabels$1 = pure(SankeyLabels);
function _extends$2() { _extends$2 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); }
var Sankey = function Sankey(_ref) {
var nodes = _ref.nodes,
links = _ref.links,
layout = _ref.layout,
margin = _ref.margin,
width = _ref.width,
height = _ref.height,
outerWidth = _ref.outerWidth,
outerHeight = _ref.outerHeight,
nodeOpacity = _ref.nodeOpacity,
nodeHoverOpacity = _ref.nodeHoverOpacity,
nodeHoverOthersOpacity = _ref.nodeHoverOthersOpacity,
nodeBorderWidth = _ref.nodeBorderWidth,
getNodeBorderColor = _ref.getNodeBorderColor,
setCurrentNode = _ref.setCurrentNode,
currentNode = _ref.currentNode,
linkOpacity = _ref.linkOpacity,
linkHoverOpacity = _ref.linkHoverOpacity,
linkHoverOthersOpacity = _ref.linkHoverOthersOpacity,
linkContract = _ref.linkContract,
linkBlendMode = _ref.linkBlendMode,
enableLinkGradient = _ref.enableLinkGradient,
setCurrentLink = _ref.setCurrentLink,
currentLink = _ref.currentLink,
enableLabels = _ref.enableLabels,
labelPosition = _ref.labelPosition,
labelPadding = _ref.labelPadding,
labelOrientation = _ref.labelOrientation,
getLabelTextColor = _ref.getLabelTextColor,
theme = _ref.theme,
nodeTooltip = _ref.nodeTooltip,
linkTooltip = _ref.linkTooltip,
animate = _ref.animate,
motionDamping = _ref.motionDamping,
motionStiffness = _ref.motionStiffness,
isInteractive = _ref.isInteractive,
onClick = _ref.onClick,
tooltipFormat = _ref.tooltipFormat,
legends$1 = _ref.legends,
legendData = _ref.legendData;
var motionProps = {
animate: animate,
motionDamping: motionDamping,
motionStiffness: motionStiffness
};
var isCurrentNode = function isCurrentNode() {
return false;
};
var isCurrentLink = function isCurrentLink() {
return false;
};
if (currentLink) {
isCurrentNode = function isCurrentNode(_ref2) {
var id = _ref2.id;
return id === currentLink.source.id || id === currentLink.target.id;
};
isCurrentLink = function isCurrentLink(_ref3) {
var source = _ref3.source,
target = _ref3.target;
return source.id === currentLink.source.id && target.id === currentLink.target.id;
};
}
if (currentNode) {
var currentNodeIds = [currentNode.id];
links.filter(function (_ref4) {
var source = _ref4.source,
target = _ref4.target;
return source.id === currentNode.id || target.id === currentNode.id;
}).forEach(function (_ref5) {
var source = _ref5.source,
target = _ref5.target;
currentNodeIds.push(source.id);
currentNodeIds.push(target.id);
});
currentNodeIds = _uniq(currentNodeIds);
isCurrentNode = function isCurrentNode(_ref6) {
var id = _ref6.id;
return currentNodeIds.includes(id);
};
isCurrentLink = function isCurrentLink(_ref7) {
var source = _ref7.source,
target = _ref7.target;
return source.id === currentNode.id || target.id === currentNode.id;
};
}
return React__default.createElement(core.Container, {
isInteractive: isInteractive,
theme: theme
}, function (_ref8) {
var showTooltip = _ref8.showTooltip,
hideTooltip = _ref8.hideTooltip;
return React__default.createElement(core.SvgWrapper, {
width: outerWidth,
height: outerHeight,
margin: margin,
theme: theme
}, React__default.createElement(SankeyLinks$1, _extends$2({
links: links,
layout: layout,
linkContract: linkContract,
linkOpacity: linkOpacity,
linkHoverOpacity: linkHoverOpacity,
linkHoverOthersOpacity: linkHoverOthersOpacity,
linkBlendMode: linkBlendMode,
enableLinkGradient: enableLinkGradient,
showTooltip: showTooltip,
hideTooltip: hideTooltip,
setCurrentLink: setCurrentLink,
currentNode: currentNode,
currentLink: currentLink,
isCurrentLink: isCurrentLink,
onClick: onClick,
tooltip: linkTooltip,
theme: theme,
tooltipFormat: tooltipFormat
}, motionProps)), React__default.createElement(SankeyNodes$1, _extends$2({
nodes: nodes,
nodeOpacity: nodeOpacity,
nodeHoverOpacity: nodeHoverOpacity,
nodeHoverOthersOpacity: nodeHoverOthersOpacity,
nodeBorderWidth: nodeBorderWidth,
getNodeBorderColor: getNodeBorderColor,
showTooltip: showTooltip,
hideTooltip: hideTooltip,
setCurrentNode: setCurrentNode,
currentNode: currentNode,
currentLink: currentLink,
isCurrentNode: isCurrentNode,
onClick: onClick,
tooltip: nodeTooltip,
theme: theme,
tooltipFormat: tooltipFormat
}, motionProps)), enableLabels && React__default.createElement(SankeyLabels$1, _extends$2({
nodes: nodes,
layout: layout,
width: width,
height: height,
labelPosition: labelPosition,
labelPadding: labelPadding,
labelOrientation: labelOrientation,
getLabelTextColor: getLabelTextColor,
theme: theme
}, motionProps)), legends$1.map(function (legend, i) {
return React__default.createElement(legends.BoxLegendSvg, _extends$2({
key: i
}, legend, {
containerWidth: width,
containerHeight: height,
data: legendData,
theme: theme
}));
}));
});
};
Sankey.propTypes = SankeyPropTypes;
var enhancedSankey = enhance(Sankey);
enhancedSankey.displayName = 'Sankey';
function _extends$3() { _extends$3 = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$3.apply(this, arguments); }
var ResponsiveSankey = function ResponsiveSankey(props) {
return React__default.createElement(core.ResponsiveWrapper, null, function (_ref) {
var width = _ref.width,
height = _ref.height;
return React__default.createElement(enhancedSankey, _extends$3({
width: width,
height: height
}, props));
});
};
exports.ResponsiveSankey = ResponsiveSankey;
exports.Sankey = enhancedSankey;
exports.SankeyDefaultProps = SankeyDefaultProps;
exports.SankeyPropTypes = SankeyPropTypes;
exports.sankeyAlignmentFromProp = sankeyAlignmentFromProp;
exports.sankeyAlignmentPropKeys = sankeyAlignmentPropKeys;
exports.sankeyAlignmentPropMapping = sankeyAlignmentPropMapping;
exports.sankeyAlignmentPropType = sankeyAlignmentPropType;