function flowDiagram(data, {
bind = null,
margin = { top: 0, right: 0, bottom: 0, left: 0 },
width = 410,
height = 410,
edgeStroke = 4,
centerSquare = 115,
squareConnector = centerSquare * 0.15,
targetDirection = 'above',
centerSquareFill = bgdCol2,
domainRange = [0, 50]
} = {}) {
const w = width + margin.left + margin.right;
const h = height + margin.top + margin.bottom;
bind.selectAll('div').remove();
const divContainer = bind.append('div')
.attr('class', 'bars-wrap clearfix');
const svgContainer = divContainer.append('div')
.attr('class', 'svg-container');
const svg = svgContainer.append('svg')
.attr('width', w)
.attr('height', h)
.append('g')
.attr('transform', `translate(${margin.left},${margin.top})`);
const centerH = (w / 2) - (centerSquare / 2);
const centerV = (h / 2) - (centerSquare / 2);
const squareSize = 60;
// left and right node
svg.append('rect')
.attr('width', centerSquare + squareConnector)
.attr('height', squareConnector)
.attr('x', centerH -(squareConnector/2))
.attr('y', centerV + (centerSquare / 2) - (squareConnector/2))
.attr('fill', centerSquareFill);
// top and bottom node
svg.append('rect')
.attr('width', squareConnector)
.attr('height', centerSquare + squareConnector)
.attr('y', centerV -(squareConnector/2))
.attr('x', centerH + (centerSquare / 2) - (squareConnector/2))
.attr('fill', centerSquareFill);
// edge/connector lines
// horizontal edges
svg.append('rect')
.attr('width', centerSquare + squareConnector + 50)
.attr('height', edgeStroke)
.attr('x', centerH -(squareConnector/2) - 25)
.attr('y', centerV + (centerSquare / 2) - (edgeStroke/2))
.attr('fill', centerSquareFill)
.style('stroke-linecap', 'round');
// vertical edges
svg.append('rect')
.attr('width', edgeStroke)
.attr('height', centerSquare + squareConnector + 50)
.attr('x', centerH + (centerSquare / 2) - (edgeStroke/2))
.attr('y', centerV - (squareConnector/2) - 25)
.attr('fill', centerSquareFill)
.style('rx', '2');
// background/center shape
svg.append('rect')
.attr('width', centerSquare)
.attr('height', centerSquare)
.attr('x', centerH)
.attr('y', centerV)
.attr('rx', 5)
.attr('fill', centerSquareFill);
// some helpers for each of the data square locations
const middleSquare = svg.append('g')
.attr('transform', `translate(${w/2 - (squareSize / 2)}, ${h/2 - 25})`);
const topSquare = svg.append('g')
.attr('transform', `translate(${w/2 - (squareSize / 2)}, ${h/2 - 100 - 60})`);
const botSquare = svg.append('g')
.attr('transform', `translate(${w/2 - (squareSize / 2)}, ${h/2 + 100})`);
const leftSquare = svg.append('g')
.attr('transform', `translate(${w/2 - ((squareSize * 2) + 40)}, ${h/2 - 25})`);
const rightSquare = svg.append('g')
.attr('transform', `translate(${w/2 + (squareSize + 40)}, ${h/2 - 25})`);
// render the squares with data
squareBar([data[0]], {
bind: middleSquare, // pass in the selection
barWidth: squareSize,
titleFill: '#555',
titlePadding: 9,
xAxis: domainRange
});
squareBar([data[1]], {
bind: topSquare, // pass in the selection
barWidth: squareSize,
xAxis: domainRange
});
squareBar([data[2]], {
bind: botSquare, // pass in the selection
barWidth: squareSize,
titlePadding: 25,
titleTop: false,
xAxis: domainRange
});
squareBar([data[3]], {
bind: leftSquare, // pass in the selection
markerRight: false, // display marker on the left
barWidth: squareSize,
xAxis: domainRange
});
squareBar([data[4]], {
bind: rightSquare, // pass in the selection
barWidth: squareSize,
xAxis: domainRange
});
}