diff --git a/src/SankeyDiagram.js b/src/SankeyDiagram.js
index c68f73f2..9d50bf0f 100644
--- a/src/SankeyDiagram.js
+++ b/src/SankeyDiagram.js
@@ -88,45 +88,81 @@ const SankeyNodeLabel = props => {
const getLabelText = _.isFunction(nodeLabelText) ? nodeLabelText : nodeId;
const placement = getWithNode(props.nodeLabelPlacement);
const distance = getWithNode(props.nodeLabelDistance) || 0;
+ const labelContent = getWithNode(getLabelText);
+ // don't render empty labels
+ if(_.isNull(labelContent) || _.isUndefined(labelContent) || labelContent === false || labelContent === "") {
+ return null;
+ }
- const className = `sankey-node-label ${getWithNode(props.nodeLabelClassName)}`;
- let style = {...getWithNode(props.nodeLabelStyle)};
- let textPosition;
+ const baseClassName = `sankey-node-label ${getWithNode(props.nodeLabelClassName)}`;
+ const baseStyle = getWithNode(props.nodeLabelStyle);
+ let position;
+ let textStyle;
+ let translate;
// use placement prop to determine x, y, alignmentBaseline and
if (placement === "above") {
- style = {alignmentBaseline: "baseline", textAnchor: "middle", ...style};
- textPosition = {
+ // render label above node, centered horizontally
+ textStyle = {alignmentBaseline: "baseline", textAnchor: "middle", ...baseStyle};
+ translate = '-50%, -100%';
+ position = {
x: node.x0 + Math.abs(node.x1 - node.x0) / 2,
y: node.y0 - distance
};
} else if (placement === "below") {
- style = {alignmentBaseline: "hanging", textAnchor: "middle", ...style};
- textPosition = {
+ // render label above node, centered horizontally
+ textStyle = {alignmentBaseline: "hanging", textAnchor: "middle", ...baseStyle};
+ translate = '-50%, 0';
+ position = {
x: node.x0 + Math.abs(node.x1 - node.x0) / 2,
y: node.y1 + distance
};
} else if (placement === "before") {
- style = {alignmentBaseline: "middle", textAnchor: "end", ...style};
- textPosition = {
+ // render label before (to left of) node, centered vertically
+ textStyle = {alignmentBaseline: "middle", textAnchor: "end", ...baseStyle};
+ translate = '-100%, -50%';
+ position = {
x: node.x0 - distance,
y: node.y0 + Math.abs(node.y1 - node.y0) / 2
};
} else {
if (!_.isUndefined(placement) && placement !== "after")
console.warn(`${placement} is not a valid value for nodeLabelPlacement - defaulting to "after"`);
- style = {alignmentBaseline: "middle", textAnchor: "start", ...style};
- textPosition = {
+ // render label after (to right of) node, centered vertically
+ textStyle = {alignmentBaseline: "middle", textAnchor: "start", ...baseStyle};
+ translate = '0, -50%';
+ position = {
x: node.x1 + distance,
y: node.y0 + Math.abs(node.y1 - node.y0) / 2
};
}
- return (
-
- {getLabelText(node, graph)}
-
- );
+ // if `labelContent` is a string or number, it is rendered as text within a SVG element
+ // otherwise, it is rendered as arbitrary HTML content inside of a
+ // allows users to render arbitrary components inside a node label (eg. to add an icon or link)
+ const isTextLabel = _.isString(labelContent) || _.isNumber(labelContent);
+
+ if(isTextLabel) {
+ const className = `${baseClassName} sankey-node-label-text`;
+ return (
+
+ {labelContent}
+
+ );
+
+ } else {
+ const className = `${baseClassName} sankey-node-label-html`;
+ // wrap HTML labels in a div with "inline-block" so that translation (%) is relative to width of its content
+ const style = {...baseStyle, display: "inline-block", transform: `translate(${translate})`};
+ // give foreignObject container a large width/height to prevent unintentional line breaks/cut off content
+ return (
+
+
+ {labelContent}
+
+
+ );
+ }
};
const SankeyLinkLabel = props => {
@@ -146,10 +182,9 @@ const SankeyLinkLabel = props => {
);
};
-
const SVGContainer = props => {
- const otherProps = _.omit(props, ['standalone']);
- if(props.standalone) {
+ const otherProps = _.omit(props, ["standalone"]);
+ if (props.standalone) {
return ;
}
return ;
@@ -232,6 +267,28 @@ export default class SankeyDiagram extends React.Component {
* Inline style object to be applied to the SVG element.
*/
style: PropTypes.object,
+ /**
+ * Boolean which determines whether the chart should be rendered as a standalone `