org.tiefaces.components.websheet.utility.ChartUtility.java Source code

Java tutorial

Introduction

Here is the source code for org.tiefaces.components.websheet.utility.ChartUtility.java

Source

/*
 * Copyright 2017 TieFaces.
 * Licensed under MIT
 */
package org.tiefaces.components.websheet.utility;

import java.awt.BasicStroke;
import java.util.List;
import java.util.Map;
import org.apache.poi.ss.usermodel.ClientAnchor;
import org.apache.poi.xssf.model.ThemesTable;
import org.apache.poi.xssf.usermodel.XSSFChart;
import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
import org.apache.poi.xssf.usermodel.XSSFDrawing;
import org.apache.poi.xssf.usermodel.XSSFRichTextString;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTDrawing;
import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTTwoCellAnchor;
import org.tiefaces.common.AppUtils;
import org.tiefaces.components.websheet.chart.ChartAxis;
import org.tiefaces.components.websheet.chart.ChartData;
import org.tiefaces.components.websheet.chart.ChartType;
import org.tiefaces.components.websheet.chart.ChartsData;
import org.tiefaces.components.websheet.chart.objects.ChartObject;
import org.tiefaces.exception.IllegalChartException;
import org.w3c.dom.Attr;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * Utility Class for Chart.
 *
 * @author Jason Jiang
 */
public final class ChartUtility {

    /** Line style: line. */
    public static final String STYLE_LINE = "line";
    /** Line style: dashed. */
    public static final String STYLE_DASH = "dash";
    /** Line style: dotted. */
    public static final String STYLE_DOT = "dot";
    /** STROKE_DEFAULT_LINE_WIDTH. */
    public static final float STROKE_DEFAULT_LINE_WIDTH = 0.2f;
    /** STROKE_DEFAULT_DASH_WIDTH. */
    public static final float STROKE_DEFAULT_DASH_WIDTH = 5.0f;
    /** STROKE_MITER_LIMIT_STYLE_DOT. */
    public static final float STROKE_MITER_LIMIT_STYLE_DOT = 2.0f;
    /** STROKE_MITER_LIMIT_STYLE_DASH. */
    public static final float STROKE_MITER_LIMIT_STYLE_DASH = 10.0f;
    /** STROKE_DEFAULT_DASHPHASE. */
    public static final float STROKE_DEFAULT_DASHPHASE = 0.0f;

    /**
     * hide constructor.
     */
    private ChartUtility() {
        super();
    }

    /**
     * return chart type from CTChart object.
     * 
     * @param ctChart
     *            object.
     * @return ChartType.
     */
    public static ChartType getChartType(final CTChart ctChart) {
        CTPlotArea plotArea = ctChart.getPlotArea();

        for (ChartType chartType : ChartType.values()) {
            if (chartType.isThisType(plotArea)) {
                return chartType;
            }
        }
        return null;
    }

    /**
     * Convert style string to stroke object.
     * 
     * @param style
     *            One of STYLE_xxx.
     * @return Stroke for <i>style</i> or null if style not supported.
     */
    public static BasicStroke toStroke(final String style) {
        BasicStroke result = null;

        if (style != null) {
            float lineWidth = STROKE_DEFAULT_LINE_WIDTH;
            float[] dash = { STROKE_DEFAULT_DASH_WIDTH };
            float[] dot = { lineWidth };

            if (style.equalsIgnoreCase(STYLE_LINE)) {
                result = new BasicStroke(lineWidth);
            } else if (style.equalsIgnoreCase(STYLE_DASH)) {
                result = new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                        STROKE_MITER_LIMIT_STYLE_DASH, dash, STROKE_DEFAULT_DASHPHASE);
            } else if (style.equalsIgnoreCase(STYLE_DOT)) {
                result = new BasicStroke(lineWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER,
                        STROKE_MITER_LIMIT_STYLE_DOT, dot, STROKE_DEFAULT_DASHPHASE);
            }
        }

        return result;
    }

    /**
     * init chart data.
     * 
     * @param chartId
     *            chartId.
     * @param chart
     *            chart.
     * @param wb
     *            wb.
     * @return chartdata.
     */
    public static ChartData initChartDataFromXSSFChart(final String chartId, final XSSFChart chart,
            final XSSFWorkbook wb) {

        ThemesTable themeTable = wb.getStylesSource().getTheme();

        ChartData chartData = new ChartData();
        XSSFRichTextString chartTitle = chart.getTitle();
        if (chartTitle != null) {
            chartData.setTitle(chartTitle.toString());
        }
        CTChart ctChart = chart.getCTChart();
        ChartType chartType = ChartUtility.getChartType(ctChart);
        if (chartType == null) {
            throw new IllegalChartException("Unknown chart type");
        }

        chartData.setBgColor(ColorUtility.getBgColor(ctChart.getPlotArea(), themeTable));

        chartData.setId(chartId);
        chartData.setType(chartType);

        List<CTCatAx> ctCatAxList = ctChart.getPlotArea().getCatAxList();
        if ((ctCatAxList != null) && (!ctCatAxList.isEmpty())) {
            chartData.setCatAx(new ChartAxis(ctCatAxList.get(0)));
        }
        List<CTValAx> ctValAxList = ctChart.getPlotArea().getValAxList();
        if ((ctValAxList != null) && (!ctValAxList.isEmpty())) {
            chartData.setValAx(new ChartAxis(ctValAxList.get(0)));
        }

        ChartObject ctObj = chartType.createChartObject();

        if (ctObj == null) {
            throw new IllegalChartException("Cannot create chart object.");
        }

        setUpChartData(chartData, ctChart, themeTable, ctObj);

        return chartData;
    }

    /**
     * build chartData for line chart. chartData include categoryList and
     * seriesList which used for generate jfreechart.
     * 
     * @param chartData
     *            chart data.
     * @param ctChart
     *            ct chart.
     * @param themeTable
     *            themeTable used for get color with theme name.
     * @param ctObj
     *            ct object.
     */

    public static void setUpChartData(final ChartData chartData, final CTChart ctChart,
            final ThemesTable themeTable, final ChartObject ctObj) {

        Object chartObj = null;
        @SuppressWarnings("rawtypes")
        List plotCharts = ctObj.getChartListFromCtChart(ctChart);

        // chart object
        if (plotCharts != null && (!plotCharts.isEmpty())) {
            chartObj = plotCharts.get(0);
        }
        if (chartObj != null) {
            @SuppressWarnings("rawtypes")
            List bsers = ctObj.getSerListFromCtObjChart(chartObj);
            if (!AppUtils.emptyList(bsers)) {
                chartData.buildCategoryList(ctObj.getCtAxDataSourceFromSerList(bsers));
                chartData.buildSeriesList(bsers, themeTable, ctObj);
            }
        }
    }

    /**
     * retrieve anchor information from draw.xml for all the charts in the
     * workbook. then save them to anchors map.
     *
     * @param wb
     *            workbook.
     * @param charsData
     *            the chars data
     */
    public static void initXSSFAnchorsMap(final XSSFWorkbook wb, final ChartsData charsData) {

        Map<String, ClientAnchor> anchortMap = charsData.getChartAnchorsMap();
        Map<String, String> positionMap = charsData.getChartPositionMap();
        anchortMap.clear();
        positionMap.clear();
        for (int i = 0; i < wb.getNumberOfSheets(); i++) {
            initXSSFAnchorsMapForSheet(anchortMap, positionMap, wb.getSheetAt(i));
        }
    }

    /**
     * Inits the XSSF anchors map for sheet.
     *
     * @param anchortMap
     *            the anchort map
     * @param positionMap
     *            the position map
     * @param sheet
     *            the sheet
     */
    private static void initXSSFAnchorsMapForSheet(final Map<String, ClientAnchor> anchortMap,
            final Map<String, String> positionMap, final XSSFSheet sheet) {
        XSSFDrawing drawing = sheet.createDrawingPatriarch();
        CTDrawing ctDrawing = drawing.getCTDrawing();
        if (ctDrawing.sizeOfTwoCellAnchorArray() <= 0) {
            return;
        }
        List<CTTwoCellAnchor> alist = ctDrawing.getTwoCellAnchorList();
        for (int j = 0; j < alist.size(); j++) {
            CTTwoCellAnchor ctanchor = alist.get(j);
            String singleChartId = getAnchorAssociateChartId(ctanchor);
            if (singleChartId != null) {
                String chartId = sheet.getSheetName() + "!" + singleChartId;
                int dx1 = (int) ctanchor.getFrom().getColOff();
                int dy1 = (int) ctanchor.getFrom().getRowOff();
                int dx2 = (int) ctanchor.getTo().getColOff();
                int dy2 = (int) ctanchor.getTo().getRowOff();
                int col1 = ctanchor.getFrom().getCol();
                int row1 = ctanchor.getFrom().getRow();
                int col2 = ctanchor.getTo().getCol();
                int row2 = ctanchor.getTo().getRow();
                anchortMap.put(chartId, new XSSFClientAnchor(dx1, dy1, dx2, dy2, col1, row1, col2, row2));
                positionMap.put(WebSheetUtility.getFullCellRefName(sheet.getSheetName(), row1, col1), chartId);
            }
        }
    }

    /**
    * Gets the anchor associate chart id.
    *
    * @param ctanchor
    *            the ctanchor
    * @return the anchor associate chart id
    */
    private static String getAnchorAssociateChartId(final CTTwoCellAnchor ctanchor) {

        if (ctanchor.getGraphicFrame() == null) {
            return null;
        }

        Node parentNode = ctanchor.getGraphicFrame().getGraphic().getGraphicData().getDomNode();

        NodeList childNodes = parentNode.getChildNodes();
        for (int i = 0; i < childNodes.getLength(); i++) {
            Node childNode = childNodes.item(i);
            if ((childNode != null) && ("c:chart".equalsIgnoreCase(childNode.getNodeName()))
                    && (childNode.hasAttributes())) {
                String rId = getChartIdFromChildNodeAttributes(childNode.getAttributes());
                if (rId != null) {
                    return rId;
                }
            }
        }
        return null;
    }

    /**
     * Gets the chart id from child node attributes.
     *
     * @param attrs
     *            the attrs
     * @return the chart id from child node attributes
     */
    private static String getChartIdFromChildNodeAttributes(final NamedNodeMap attrs) {
        for (int j = 0; j < attrs.getLength(); j++) {
            Attr attribute = (Attr) attrs.item(j);
            if ("r:id".equalsIgnoreCase(attribute.getName())) {
                return attribute.getValue();
            }
        }
        return null;
    }

}