001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 The ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.treemap;
018
019import java.awt.Color;
020import java.awt.Graphics2D;
021import java.awt.Rectangle;
022import java.awt.geom.Rectangle2D;
023
024import org.conqat.lib.commons.color.MultiColor;
025
026/**
027 * A very simple tree map renderer just drawing "flat" rectangles.
028 */
029public class FlatTreeMapRenderer implements ITreeMapRenderer {
030
031        /** {@inheritDoc} */
032        @Override
033        public <T> void renderTreeMap(ITreeMapNode<T> node, Graphics2D graphics) {
034                if (node.getChildren().isEmpty()) {
035                        Rectangle2D rect = node.getLayoutRectangle();
036                        if (rect == null) {
037                                return;
038                        }
039                        fillRect(graphics, rect, node.getColor());
040
041                        if (node.getDrawingPattern() != null) {
042                                drawPattern(graphics, rect, node);
043                        }
044
045                        graphics.setColor(Color.BLACK);
046                        graphics.draw(rect);
047                } else {
048                        for (ITreeMapNode<T> child : node.getChildren()) {
049                                renderTreeMap(child, graphics);
050                        }
051                }
052        }
053
054        /** Fills the given rect with the given color. */
055        private void fillRect(Graphics2D graphics, Rectangle2D rect, Color color) {
056                if (color instanceof MultiColor) {
057                        fillRectMultiColor(graphics, rect, (MultiColor) color);
058                } else {
059                        graphics.setColor(color);
060                        graphics.fill(rect);
061                }
062        }
063
064        /**
065         * Fills the given rect with the given {@link MultiColor}. The colors are
066         * arranged in a striped pattern, which is arranged horizontally or vertically
067         * depending on the aspect ratio of the rectangle.
068         */
069        private void fillRectMultiColor(Graphics2D graphics, Rectangle2D rect, MultiColor multiColor) {
070                double x = rect.getX();
071                double y = rect.getY();
072                double width = rect.getWidth();
073                double height = rect.getHeight();
074
075                double offset = 0;
076                for (int i = 0; i < multiColor.size(); ++i) {
077                        Rectangle2D subrect;
078                        double relativeFrequency = multiColor.getRelativeFrequency(i);
079                        if (width > height) {
080                                subrect = new Rectangle2D.Double(x + offset * width, y, width * relativeFrequency, height);
081                        } else {
082                                subrect = new Rectangle2D.Double(x, y + offset * height, width, height * relativeFrequency);
083                        }
084
085                        fillRect(graphics, subrect, multiColor.getColor(i));
086                        offset += relativeFrequency;
087                }
088        }
089
090        /** Draws the pattern. */
091        private static <T> void drawPattern(Graphics2D graphics, Rectangle2D rect, ITreeMapNode<T> node) {
092                IDrawingPattern drawingPattern = node.getDrawingPattern();
093                graphics.setColor(node.getPatternColor());
094                for (int x = (int) rect.getMinX(); x <= rect.getMaxX(); ++x) {
095                        for (int y = (int) rect.getMinY(); y <= rect.getMaxY(); ++y) {
096                                if (drawingPattern.isForeground(x, y)) {
097                                        graphics.fill(new Rectangle(x, y, 1, 1));
098                                }
099                        }
100                }
101        }
102
103}