001/* ===========================================================
002 * Orson Charts : a 3D chart library for the Java(tm) platform
003 * ===========================================================
004 * 
005 * (C)opyright 2013-2016, by Object Refinery Limited.  All rights reserved.
006 * 
007 * http://www.object-refinery.com/orsoncharts/index.html
008 * 
009 * This program is free software: you can redistribute it and/or modify
010 * it under the terms of the GNU General Public License as published by
011 * the Free Software Foundation, either version 3 of the License, or
012 * (at your option) any later version.
013 *
014 * This program is distributed in the hope that it will be useful,
015 * but WITHOUT ANY WARRANTY; without even the implied warranty of
016 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
017 * GNU General Public License for more details.
018 *
019 * You should have received a copy of the GNU General Public License
020 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
021 * 
022 * [Oracle and Java are registered trademarks of Oracle and/or its affiliates. 
023 * Other names may be trademarks of their respective owners.]
024 * 
025 * If you do not wish to be bound by the terms of the GPL, an alternative
026 * commercial license can be purchased.  For details, please see visit the
027 * Orson Charts home page:
028 * 
029 * http://www.object-refinery.com/orsoncharts/index.html
030 * 
031 */
032
033package com.orsoncharts;
034
035import java.awt.Graphics2D;
036import java.awt.geom.Rectangle2D;
037import java.util.HashMap;
038import java.util.Map;
039import com.orsoncharts.graphics3d.RenderedElement;
040import com.orsoncharts.graphics3d.RenderingInfo;
041import com.orsoncharts.interaction.InteractiveElementType;
042import com.orsoncharts.table.TableElement;
043import com.orsoncharts.table.TableElementOnDraw;
044
045/**
046 * An 'onDraw' handler that handles two aspects related to chart interactivity:
047 * (1) it adds a {@link RenderedElement} instance to the {@link RenderingInfo} 
048 * for each element in the chart that requires it, and (2) it adds element 
049 * hinting to the {@code Graphics2D} output (how this is handled by the
050 * {@code Graphics2D} instance is implementation dependent).
051 * 
052 * @since 1.3
053 */
054public class OnDrawHandler implements TableElementOnDraw {
055    
056    /** The rendering info the be populated (if not null). */
057    private RenderingInfo info;
058    
059    /** A flag indicating whether or not element hinting is added. */
060    boolean elementHinting;
061    
062    /**
063     * Creates a new handler.
064     * 
065     * @param info  the rendering info to be populated ({@code null} 
066     *     permitted).
067     * @param elementHinting  a flag that controls whether or not element 
068     *     hinting is performed.
069     */
070    public OnDrawHandler(RenderingInfo info, boolean elementHinting) {
071        this.info = info;
072        this.elementHinting = elementHinting;
073    }
074
075    @Override
076    public void beforeDraw(TableElement element, Graphics2D g2, 
077            Rectangle2D bounds) {
078        
079        InteractiveElementType t = (InteractiveElementType) 
080                element.getProperty(TableElement.CLASS);
081        
082        // handle rendering info
083        if (t != null && info != null) {
084            switch (t) {
085                case TITLE:
086                case SUBTITLE:
087                    RenderedElement re = new RenderedElement(t, bounds);
088                    this.info.addElement(re);
089                    break;
090                    
091                case LEGEND_ITEM:
092                    RenderedElement legendItemRE = new RenderedElement(
093                            InteractiveElementType.LEGEND_ITEM, bounds);
094                    legendItemRE.setProperty(Chart3D.SERIES_KEY, 
095                            element.getProperty(Chart3D.SERIES_KEY));
096                    this.info.addElement(legendItemRE);
097                    break;
098                default: 
099                    throw new RuntimeException();
100            }
101        }
102        
103        // handle hinting
104        if (t != null && this.elementHinting) {
105            Map<String, String> m = new HashMap<String, String>();
106            switch (t) {
107                case TITLE:
108                    m.put("ref", "{\"type\": \"title\"}");
109                    g2.setRenderingHint(Chart3DHints.KEY_BEGIN_ELEMENT, m);
110                    break;
111                case SUBTITLE:
112                    m.put("ref", "{\"type\": \"subtitle\"}");
113                    g2.setRenderingHint(Chart3DHints.KEY_BEGIN_ELEMENT, m);
114                    break;
115                case LEGEND_ITEM:
116                    m.put("ref", generateLegendItemRef(element));
117                    g2.setRenderingHint(Chart3DHints.KEY_BEGIN_ELEMENT, m);
118                    break;
119                default:
120                    throw new RuntimeException();
121            }   
122        }
123    }
124        
125    @Override
126    public void afterDraw(TableElement element, Graphics2D g2, 
127            Rectangle2D bounds) {
128        if (!this.elementHinting) {
129            return;
130        }
131        InteractiveElementType t = (InteractiveElementType) 
132                element.getProperty(TableElement.CLASS);
133        if (t == null) {
134            return;
135        }
136        switch (t) {
137            case TITLE:
138            case SUBTITLE:
139            case LEGEND_ITEM:
140                g2.setRenderingHint(Chart3DHints.KEY_END_ELEMENT, Boolean.TRUE);
141                break;
142            default:
143                throw new RuntimeException("Seeing type " + t);
144        }   
145    }
146
147    private String generateLegendItemRef(TableElement element) {
148        Object key = element.getProperty(Chart3D.SERIES_KEY);
149        return "{\"type\": \"legendItem\", \"seriesKey\": \"" + key.toString() 
150                + "\"}";
151    }
152}