Search in sources :

Example 1 with FlowEntity

use of org.jfree.chart.entity.FlowEntity 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);
        }
    }
}
Also used : HashMap(java.util.HashMap) Path2D(java.awt.geom.Path2D) GradientPaint(java.awt.GradientPaint) FlowEntity(org.jfree.chart.entity.FlowEntity) NodeKey(org.jfree.data.flow.NodeKey) FlowKey(org.jfree.data.flow.FlowKey) AlphaComposite(java.awt.AlphaComposite) Composite(java.awt.Composite) Color(java.awt.Color) Rectangle2D(java.awt.geom.Rectangle2D) Paint(java.awt.Paint) GradientPaint(java.awt.GradientPaint) EntityCollection(org.jfree.chart.entity.EntityCollection) RectangleInsets(org.jfree.chart.api.RectangleInsets) NodeEntity(org.jfree.chart.entity.NodeEntity)

Aggregations

AlphaComposite (java.awt.AlphaComposite)1 Color (java.awt.Color)1 Composite (java.awt.Composite)1 GradientPaint (java.awt.GradientPaint)1 Paint (java.awt.Paint)1 Path2D (java.awt.geom.Path2D)1 Rectangle2D (java.awt.geom.Rectangle2D)1 HashMap (java.util.HashMap)1 RectangleInsets (org.jfree.chart.api.RectangleInsets)1 EntityCollection (org.jfree.chart.entity.EntityCollection)1 FlowEntity (org.jfree.chart.entity.FlowEntity)1 NodeEntity (org.jfree.chart.entity.NodeEntity)1 FlowKey (org.jfree.data.flow.FlowKey)1 NodeKey (org.jfree.data.flow.NodeKey)1