com.mycollab.ui.chart.JFreeChartWrapper.java Source code

Java tutorial

Introduction

Here is the source code for com.mycollab.ui.chart.JFreeChartWrapper.java

Source

/**
 * This file is part of mycollab-web.
 *
 * mycollab-web is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * mycollab-web is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with mycollab-web.  If not, see <http://www.gnu.org/licenses/>.
 */
package com.mycollab.ui.chart;

import com.vaadin.server.*;
import com.vaadin.server.StreamResource.StreamSource;
import com.vaadin.ui.Embedded;
import org.jfree.chart.ChartUtilities;
import org.jfree.chart.JFreeChart;
import org.jfree.graphics2d.svg.SVGGraphics2D;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;

/**
 * @author MyCollab Ltd
 * @since 5.1.1
 */
public class JFreeChartWrapper extends Embedded {

    public enum RenderingMode {
        SVG, PNG, AUTO
    }

    private static final Logger log = LoggerFactory.getLogger(JFreeChartWrapper.class);

    // 809x 500 ~g olden ratio
    private static final int DEFAULT_WIDTH = 809;
    private static final int DEFAULT_HEIGHT = 500;

    private final JFreeChart chart;
    private Resource res;
    private RenderingMode mode = RenderingMode.AUTO;
    private boolean gzipEnabled = false;
    private int graphWidthInPixels = -1;
    private int graphHeightInPixels = -1;
    private String aspectRatio = "none"; // stretch to fill whole space

    public JFreeChartWrapper(JFreeChart chartToBeWrapped) {
        chart = chartToBeWrapped;
        setWidth(DEFAULT_WIDTH, Unit.PIXELS);
        setHeight(DEFAULT_HEIGHT, Unit.PIXELS);
    }

    /**
     * Compress SVG charts in wrapper. It makes sense to put this on if the
     * server does not automatically compress responses.
     *
     * @param compress true to enable component level compression, default false
     */
    public void setGzipCompression(boolean compress) {
        this.gzipEnabled = compress;
    }

    private void setRenderingMode(RenderingMode newMode) {
        if (newMode == RenderingMode.PNG) {
            setType(TYPE_IMAGE);
        } else {
            setType(TYPE_OBJECT);
            setMimeType("image/svg+xml");
        }
        mode = newMode;
    }

    @Override
    public void attach() {
        super.attach();
        if (mode == RenderingMode.AUTO) {
            WebBrowser browser = Page.getCurrent().getWebBrowser();
            if (browser.isIE() && browser.getBrowserMajorVersion() < 9) {
                setRenderingMode(RenderingMode.PNG);
            } else {
                // all decent browsers support SVG
                setRenderingMode(RenderingMode.SVG);
            }
        }
        setResource("src", getSource());
    }

    @Override
    public void detach() {
        super.detach();
    }

    /**
     * This method may be used to tune rendering of the chart when using
     * relative sizes. Most commonly you should use just use common methods
     * inherited from {@link Sizeable} interface.
     * <p/>
     * Sets the pixel size of the area where the graph is rendered. Most commonly developer may need to fine tune the value when the {@link JFreeChartWrapper} has a relative size.
     *
     * @param width
     * @see JFreeChartWrapper#getGraphWidth()
     * @see #setSvgAspectRatio(String)
     */
    public void setGraphWidth(int width) {
        graphWidthInPixels = width;
    }

    /**
     * This method may be used to tune rendering of the chart when using
     * relative sizes. Most commonly you should use just use common methods
     * inherited from {@link Sizeable} interface.
     * <p/>
     * Sets the pixel size of the area where the graph is rendered. Most commonly developer may need to fine tune the value when the {@link JFreeChartWrapper} has a relative size.
     *
     * @param height
     * @see JFreeChartWrapper#getGraphHeigt()
     * @see #setSvgAspectRatio(String)
     */
    public void setGraphHeight(int height) {
        graphHeightInPixels = height;
    }

    /**
     * Gets the pixel width into which the graph is rendered. Unless explicitly
     * set, the value is derived from the components size, except when the
     * component has relative size.
     */
    public int getGraphWidth() {
        if (graphWidthInPixels > 0) {
            return graphWidthInPixels;
        }
        int width;
        float w = getWidth();
        if (w < 0) {
            return DEFAULT_WIDTH;
        }
        switch (getWidthUnits()) {
        case CM:
            width = (int) (w * 96 / 2.54);
            break;
        case INCH:
            width = (int) (w * 96);
            break;
        case PERCENTAGE:
            width = DEFAULT_WIDTH;
            break;
        default:
            width = (int) w;
            break;
        }
        return width;
    }

    /**
     * Gets the pixel height into which the graph is rendered. Unless explicitly
     * set, the value is derived from the components size, except when the
     * component has relative size.
     */
    public int getGraphHeight() {
        if (graphHeightInPixels > 0) {
            return graphHeightInPixels;
        }
        int height;
        float w = getHeight();
        if (w < 0) {
            return DEFAULT_HEIGHT;
        }
        switch (getWidthUnits()) {
        case CM:
            height = (int) (w * 96 / 2.54);
            break;
        case INCH:
            height = (int) (w * 96);
            break;
        case PERCENTAGE:
            height = DEFAULT_HEIGHT;
            break;
        default:
            height = (int) w;
            break;
        }
        return height;
    }

    public String getSvgAspectRatio() {
        return aspectRatio;
    }

    /**
     * See SVG spec from W3 for more information.
     * Default is "none" (stretch), another common value is "xMidYMid" (stretch
     * proportionally, align middle of the area).
     *
     * @param svgAspectRatioSetting
     */
    public void setSvgAspectRatio(String svgAspectRatioSetting) {
        aspectRatio = svgAspectRatioSetting;
    }

    @Override
    public Resource getSource() {
        if (res == null) {
            StreamSource streamSource = new StreamResource.StreamSource() {
                private ByteArrayInputStream bytestream = null;

                ByteArrayInputStream getByteStream() {
                    if (chart != null && bytestream == null) {
                        int width = getGraphWidth();
                        int height = getGraphHeight();

                        if (mode == RenderingMode.SVG) {
                            // Create an instance of the SVG Generator
                            SVGGraphics2D svgGenerator = new SVGGraphics2D(width, height);

                            // draw the chart in the SVG generator
                            chart.draw(svgGenerator, new Rectangle(width, height));
                            // create an xml string in svg format from the drawing
                            String drawingSVG = svgGenerator.getSVGElement();
                            return new ByteArrayInputStream(drawingSVG.getBytes(StandardCharsets.UTF_8));
                        } else {
                            // Draw png to bytestream
                            try {
                                byte[] bytes = ChartUtilities.encodeAsPNG(chart.createBufferedImage(width, height));
                                bytestream = new ByteArrayInputStream(bytes);
                            } catch (Exception e) {
                                log.error("Error while generating PNG chart", e);
                            }

                        }

                    } else {
                        bytestream.reset();
                    }
                    return bytestream;
                }

                @Override
                public InputStream getStream() {
                    return getByteStream();
                }
            };

            res = new StreamResource(streamSource, String.format("graph%d", System.currentTimeMillis())) {

                @Override
                public int getBufferSize() {
                    if (getStreamSource().getStream() != null) {
                        try {
                            return getStreamSource().getStream().available();
                        } catch (IOException e) {
                            log.warn("Error while get stream info", e);
                            return 0;
                        }
                    } else {
                        return 0;
                    }
                }

                @Override
                public long getCacheTime() {
                    return 0;
                }

                @Override
                public String getFilename() {
                    if (mode == RenderingMode.PNG) {
                        return super.getFilename() + ".png";
                    } else {
                        return super.getFilename() + (gzipEnabled ? ".svgz" : ".svg");
                    }
                }

                @Override
                public DownloadStream getStream() {
                    DownloadStream downloadStream = new DownloadStream(getStreamSource().getStream(), getMIMEType(),
                            getFilename());
                    if (gzipEnabled && mode == RenderingMode.SVG) {
                        downloadStream.setParameter("Content-Encoding", "gzip");
                    }
                    return downloadStream;
                }

                @Override
                public String getMIMEType() {
                    if (mode == RenderingMode.PNG) {
                        return "image/png";
                    } else {
                        return "image/svg+xml";
                    }
                }
            };
        }
        return res;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void markAsDirty() {
        super.markAsDirty();
        res = null;
    }
}