use of org.jfree.chart.entity.NodeEntity in project ES-LEI-2Sem-2022-Grupo-1 by tmrbo-iscte.
the class FlowPlot method draw.
/**
* Draws the flow plot within the specified area of the supplied graphics
* target {@code g2}.
*
* @param g2 the graphics target ({@code null} not permitted).
* @param area the plot area ({@code null} not permitted).
* @param anchor the anchor point (ignored).
* @param parentState the parent state (ignored).
* @param info the plot rendering info.
*/
@Override
public void draw(Graphics2D g2, Rectangle2D area, Point2D anchor, PlotState parentState, PlotRenderingInfo info) {
Args.nullNotPermitted(g2, "g2");
Args.nullNotPermitted(area, "area");
EntityCollection entities = null;
if (info != null) {
info.setPlotArea(area);
entities = info.getOwner().getEntityCollection();
}
RectangleInsets insets = getInsets();
insets.trim(area);
if (info != null) {
info.setDataArea(area);
}
// use default JFreeChart background handling
drawBackground(g2, area);
// we need to ensure there is space to show all the inflows and all
// the outflows at each node group, so first we calculate the max
// flow space required - for each node in the group, consider the
// maximum of the inflow and the outflow
double flow2d = Double.POSITIVE_INFINITY;
double nodeMargin2d = this.nodeMargin * area.getHeight();
int stageCount = this.dataset.getStageCount();
for (int stage = 0; stage < this.dataset.getStageCount(); stage++) {
List<Comparable> sources = this.dataset.getSources(stage);
int nodeCount = sources.size();
double flowTotal = 0.0;
for (Comparable source : sources) {
double inflow = FlowDatasetUtils.calculateInflow(this.dataset, source, stage);
double outflow = FlowDatasetUtils.calculateOutflow(this.dataset, source, stage);
flowTotal = flowTotal + Math.max(inflow, outflow);
}
if (flowTotal > 0.0) {
double availableH = area.getHeight() - (nodeCount - 1) * nodeMargin2d;
flow2d = Math.min(availableH / flowTotal, flow2d);
}
if (stage == this.dataset.getStageCount() - 1) {
// check inflows to the final destination nodes...
List<Comparable> destinations = this.dataset.getDestinations(stage);
int destinationCount = destinations.size();
flowTotal = 0.0;
for (Comparable destination : destinations) {
double inflow = FlowDatasetUtils.calculateInflow(this.dataset, destination, stage + 1);
flowTotal = flowTotal + inflow;
}
if (flowTotal > 0.0) {
double availableH = area.getHeight() - (destinationCount - 1) * nodeMargin2d;
flow2d = Math.min(availableH / flowTotal, flow2d);
}
}
}
double stageWidth = (area.getWidth() - ((stageCount + 1) * this.nodeWidth)) / stageCount;
double flowOffset = area.getWidth() * this.flowMargin;
Map<NodeKey, Rectangle2D> nodeRects = new HashMap<>();
boolean hasNodeSelections = FlowDatasetUtils.hasNodeSelections(this.dataset);
boolean hasFlowSelections = FlowDatasetUtils.hasFlowSelections(this.dataset);
// in a final pass add the labels
for (int stage = 0; stage < this.dataset.getStageCount(); stage++) {
double stageLeft = area.getX() + (stage + 1) * this.nodeWidth + (stage * stageWidth);
double stageRight = stageLeft + stageWidth;
// calculate the source node and flow rectangles
Map<FlowKey, Rectangle2D> sourceFlowRects = new HashMap<>();
double nodeY = area.getY();
for (Object s : this.dataset.getSources(stage)) {
Comparable source = (Comparable) s;
double inflow = FlowDatasetUtils.calculateInflow(dataset, source, stage);
double outflow = FlowDatasetUtils.calculateOutflow(dataset, source, stage);
double nodeHeight = (Math.max(inflow, outflow) * flow2d);
Rectangle2D nodeRect = new Rectangle2D.Double(stageLeft - nodeWidth, nodeY, nodeWidth, nodeHeight);
if (entities != null) {
entities.add(new NodeEntity(new NodeKey<>(stage, source), nodeRect, source.toString()));
}
nodeRects.put(new NodeKey<>(stage, source), nodeRect);
double y = nodeY;
for (Object d : this.dataset.getDestinations(stage)) {
Comparable destination = (Comparable) d;
Number flow = this.dataset.getFlow(stage, source, destination);
if (flow != null) {
double height = flow.doubleValue() * flow2d;
Rectangle2D rect = new Rectangle2D.Double(stageLeft - nodeWidth, y, nodeWidth, height);
sourceFlowRects.put(new FlowKey<>(stage, source, destination), rect);
y = y + height;
}
}
nodeY = nodeY + nodeHeight + nodeMargin2d;
}
// calculate the destination rectangles
Map<FlowKey, Rectangle2D> destFlowRects = new HashMap<>();
nodeY = area.getY();
for (Object d : this.dataset.getDestinations(stage)) {
Comparable destination = (Comparable) d;
double inflow = FlowDatasetUtils.calculateInflow(dataset, destination, stage + 1);
double outflow = FlowDatasetUtils.calculateOutflow(dataset, destination, stage + 1);
double nodeHeight = Math.max(inflow, outflow) * flow2d;
nodeRects.put(new NodeKey<>(stage + 1, destination), new Rectangle2D.Double(stageRight, nodeY, nodeWidth, nodeHeight));
double y = nodeY;
for (Object s : this.dataset.getSources(stage)) {
Comparable source = (Comparable) s;
Number flow = this.dataset.getFlow(stage, source, destination);
if (flow != null) {
double height = flow.doubleValue() * flow2d;
Rectangle2D rect = new Rectangle2D.Double(stageRight, y, nodeWidth, height);
y = y + height;
destFlowRects.put(new FlowKey<>(stage, source, destination), rect);
}
}
nodeY = nodeY + nodeHeight + nodeMargin2d;
}
for (Object s : this.dataset.getSources(stage)) {
Comparable source = (Comparable) s;
NodeKey nodeKey = new NodeKey<>(stage, source);
Rectangle2D nodeRect = nodeRects.get(nodeKey);
Color ncol = lookupNodeColor(nodeKey);
if (hasNodeSelections) {
if (!Boolean.TRUE.equals(dataset.getNodeProperty(nodeKey, NodeKey.SELECTED_PROPERTY_KEY))) {
int g = (ncol.getRed() + ncol.getGreen() + ncol.getBlue()) / 3;
ncol = new Color(g, g, g, ncol.getAlpha());
}
}
g2.setPaint(ncol);
g2.fill(nodeRect);
for (Object d : this.dataset.getDestinations(stage)) {
Comparable destination = (Comparable) d;
FlowKey flowKey = new FlowKey<>(stage, source, destination);
Rectangle2D sourceRect = sourceFlowRects.get(flowKey);
if (sourceRect == null) {
continue;
}
Rectangle2D destRect = destFlowRects.get(flowKey);
Path2D connect = new Path2D.Double();
connect.moveTo(sourceRect.getMaxX() + flowOffset, sourceRect.getMinY());
connect.curveTo(stageLeft + stageWidth / 2.0, sourceRect.getMinY(), stageLeft + stageWidth / 2.0, destRect.getMinY(), destRect.getX() - flowOffset, destRect.getMinY());
connect.lineTo(destRect.getX() - flowOffset, destRect.getMaxY());
connect.curveTo(stageLeft + stageWidth / 2.0, destRect.getMaxY(), stageLeft + stageWidth / 2.0, sourceRect.getMaxY(), sourceRect.getMaxX() + flowOffset, sourceRect.getMaxY());
connect.closePath();
Color nc = lookupNodeColor(nodeKey);
if (hasFlowSelections) {
if (!Boolean.TRUE.equals(dataset.getFlowProperty(flowKey, FlowKey.SELECTED_PROPERTY_KEY))) {
int g = (ncol.getRed() + ncol.getGreen() + ncol.getBlue()) / 3;
nc = new Color(g, g, g, ncol.getAlpha());
}
}
GradientPaint gp = new GradientPaint((float) sourceRect.getMaxX(), 0, nc, (float) destRect.getMinX(), 0, new Color(nc.getRed(), nc.getGreen(), nc.getBlue(), 128));
Composite saved = g2.getComposite();
g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.75f));
g2.setPaint(gp);
g2.fill(connect);
if (entities != null) {
String toolTip = null;
if (this.toolTipGenerator != null) {
toolTip = this.toolTipGenerator.generateLabel(this.dataset, flowKey);
}
entities.add(new FlowEntity(flowKey, connect, toolTip, ""));
}
g2.setComposite(saved);
}
}
}
// now draw the destination nodes
int lastStage = this.dataset.getStageCount() - 1;
for (Object d : this.dataset.getDestinations(lastStage)) {
Comparable destination = (Comparable) d;
NodeKey nodeKey = new NodeKey<>(lastStage + 1, destination);
Rectangle2D nodeRect = nodeRects.get(nodeKey);
if (nodeRect != null) {
Color ncol = lookupNodeColor(nodeKey);
if (hasNodeSelections) {
if (!Boolean.TRUE.equals(dataset.getNodeProperty(nodeKey, NodeKey.SELECTED_PROPERTY_KEY))) {
int g = (ncol.getRed() + ncol.getGreen() + ncol.getBlue()) / 3;
ncol = new Color(g, g, g, ncol.getAlpha());
}
}
g2.setPaint(ncol);
g2.fill(nodeRect);
if (entities != null) {
entities.add(new NodeEntity(new NodeKey<>(lastStage + 1, destination), nodeRect, destination.toString()));
}
}
}
// now draw all the labels over top of everything else
g2.setFont(this.defaultNodeLabelFont);
g2.setPaint(this.defaultNodeLabelPaint);
for (NodeKey key : nodeRects.keySet()) {
Rectangle2D r = nodeRects.get(key);
if (key.getStage() < this.dataset.getStageCount()) {
TextUtils.drawAlignedString(key.getNode().toString(), g2, (float) (r.getMaxX() + flowOffset + this.nodeLabelOffsetX), (float) labelY(r), TextAnchor.CENTER_LEFT);
} else {
TextUtils.drawAlignedString(key.getNode().toString(), g2, (float) (r.getX() - flowOffset - this.nodeLabelOffsetX), (float) labelY(r), TextAnchor.CENTER_RIGHT);
}
}
}
Aggregations