1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105 |
- /*
- * ====================================================================
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * ====================================================================
- */
-
- package org.apache.poi.xddf.usermodel.chart;
-
- import static org.apache.poi.ooxml.POIXMLTypeLoader.DEFAULT_XML_OPTIONS;
-
- import java.io.IOException;
- import java.io.OutputStream;
- import java.util.ArrayList;
- import java.util.Collections;
- import java.util.HashMap;
- import java.util.LinkedList;
- import java.util.List;
- import java.util.Map;
- import java.util.Optional;
- import java.util.function.Function;
- import java.util.function.Predicate;
-
- import javax.xml.namespace.QName;
-
- import org.apache.poi.ooxml.POIXMLDocument;
- import org.apache.poi.ooxml.POIXMLDocumentPart;
- import org.apache.poi.ooxml.POIXMLException;
- import org.apache.poi.ooxml.POIXMLFactory;
- import org.apache.poi.ooxml.POIXMLRelation;
- import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
- import org.apache.poi.openxml4j.exceptions.NotOfficeXmlFileException;
- import org.apache.poi.openxml4j.opc.PackagePart;
- import org.apache.poi.openxml4j.opc.PackageRelationship;
- import org.apache.poi.ss.util.CellRangeAddress;
- import org.apache.poi.ss.util.CellReference;
- import org.apache.poi.util.Beta;
- import org.apache.poi.util.Internal;
- import org.apache.poi.xddf.usermodel.XDDFShapeProperties;
- import org.apache.poi.xddf.usermodel.text.TextContainer;
- import org.apache.poi.xddf.usermodel.text.XDDFTextBody;
- import org.apache.poi.xssf.usermodel.XSSFCell;
- import org.apache.poi.xssf.usermodel.XSSFRow;
- import org.apache.poi.xssf.usermodel.XSSFSheet;
- import org.apache.poi.xssf.usermodel.XSSFWorkbook;
- import org.apache.xmlbeans.XmlException;
- import org.apache.xmlbeans.XmlOptions;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTArea3DChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTAreaChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTBar3DChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTBarChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTBoolean;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTCatAx;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTChartSpace;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTDateAx;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTDoughnutChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTExternalData;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTLine3DChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTLineChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTPie3DChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTPieChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTPlotArea;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTRadarChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTScatterChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTSerAx;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTSurface;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTSurface3DChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTSurfaceChart;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTTitle;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTValAx;
- import org.openxmlformats.schemas.drawingml.x2006.chart.CTView3D;
- import org.openxmlformats.schemas.drawingml.x2006.chart.ChartSpaceDocument;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTShapeProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTTextCharacterProperties;
- import org.openxmlformats.schemas.drawingml.x2006.main.CTTextParagraphProperties;
-
- @Beta
- public abstract class XDDFChart extends POIXMLDocumentPart implements TextContainer {
-
- /**
- * default width of chart in emu
- */
- public static final int DEFAULT_WIDTH = 500000;
-
- /**
- * default height of chart in emu
- */
- public static final int DEFAULT_HEIGHT = 500000;
-
- /**
- * default x-coordinate of chart in emu
- */
- public static final int DEFAULT_X = 10;
-
- /**
- * default y-coordinate value of chart in emu
- */
- public static final int DEFAULT_Y = 10;
-
- /**
- * Underlying workbook
- */
- private XSSFWorkbook workbook;
-
- private int chartIndex = 0;
-
- protected List<XDDFChartAxis> axes = new ArrayList<>();
-
- /**
- * Root element of the Chart part
- */
- protected final CTChartSpace chartSpace;
-
-
- /**
- * Construct a chart.
- */
- protected XDDFChart() {
- super();
-
- chartSpace = CTChartSpace.Factory.newInstance();
- chartSpace.addNewChart().addNewPlotArea();
- }
-
- /**
- * Construct a DrawingML chart from a package part.
- *
- * @param part
- * the package part holding the chart data, the content type must
- * be
- * {@code application/vnd.openxmlformats-officedocument.drawingml.chart+xml}
- * @since POI 3.14-Beta1
- */
- protected XDDFChart(PackagePart part) throws IOException, XmlException {
- super(part);
-
- chartSpace = ChartSpaceDocument.Factory.parse(part.getInputStream(), DEFAULT_XML_OPTIONS).getChartSpace();
- }
-
- /**
- * Return the underlying CTChartSpace bean, the root element of the Chart
- * part.
- *
- * @return the underlying CTChartSpace bean
- */
- @Internal
- public CTChartSpace getCTChartSpace() {
- return chartSpace;
- }
-
- /**
- * Return the underlying CTChart bean, within the Chart Space
- *
- * @return the underlying CTChart bean
- */
- @Internal
- public CTChart getCTChart() {
- return chartSpace.getChart();
- }
-
- /**
- * Return the underlying CTPlotArea bean, within the Chart
- *
- * @return the underlying CTPlotArea bean
- */
- @Internal
- protected CTPlotArea getCTPlotArea() {
- return getCTChart().getPlotArea();
- }
-
- /**
- * Clear all properties, as if a new instance had just been created.
- * @since POI 4.1.2
- */
- public void clear() {
- axes.clear();
- seriesCount = 0;
- if (workbook != null) {
- workbook.removeSheetAt(0);
- workbook.createSheet();
- }
- getCTChart().set(CTChart.Factory.newInstance());
- getCTChart().addNewPlotArea();
- }
-
- /**
- * @return true if only visible cells will be present on the chart, false
- * otherwise
- */
- public boolean isPlotOnlyVisibleCells() {
- if (getCTChart().isSetPlotVisOnly()) {
- return getCTChart().getPlotVisOnly().getVal();
- } else {
- return false;
- }
- }
-
- /**
- * @param only
- * a flag specifying if only visible cells should be present on
- * the chart
- */
- public void setPlotOnlyVisibleCells(boolean only) {
- if (!getCTChart().isSetPlotVisOnly()) {
- getCTChart().setPlotVisOnly(CTBoolean.Factory.newInstance());
- }
- getCTChart().getPlotVisOnly().setVal(only);
- }
-
- public void setFloor(int thickness) {
- if (!getCTChart().isSetFloor()) {
- getCTChart().setFloor(CTSurface.Factory.newInstance());
- }
- getCTChart().getFloor().getThickness().setVal(thickness);
- }
-
- public void setBackWall(int thickness) {
- if (!getCTChart().isSetBackWall()) {
- getCTChart().setBackWall(CTSurface.Factory.newInstance());
- }
- getCTChart().getBackWall().getThickness().setVal(thickness);
- }
-
- public void setSideWall(int thickness) {
- if (!getCTChart().isSetSideWall()) {
- getCTChart().setSideWall(CTSurface.Factory.newInstance());
- }
- getCTChart().getSideWall().getThickness().setVal(thickness);
- }
-
- public void setAutoTitleDeleted(boolean deleted) {
- if (!getCTChart().isSetAutoTitleDeleted()) {
- getCTChart().setAutoTitleDeleted(CTBoolean.Factory.newInstance());
- }
- getCTChart().getAutoTitleDeleted().setVal(deleted);
- if (deleted && getCTChart().isSetTitle()) {
- getCTChart().unsetTitle();
- }
- }
-
- /**
- * @since 4.0.1
- *
- */
- public void displayBlanksAs(DisplayBlanks as) {
- if (as == null){
- if (getCTChart().isSetDispBlanksAs()) {
- getCTChart().unsetDispBlanksAs();
- }
- } else {
- if (getCTChart().isSetDispBlanksAs()) {
- getCTChart().getDispBlanksAs().setVal(as.underlying);
- } else {
- getCTChart().addNewDispBlanksAs().setVal(as.underlying);
- }
- }
- }
-
- /**
- * @since 4.0.1
- */
- public Boolean getTitleOverlay() {
- if (getCTChart().isSetTitle()) {
- CTTitle title = getCTChart().getTitle();
- if (title.isSetOverlay()) {
- return title.getOverlay().getVal();
- }
- }
- return null;
- }
-
- /**
- * @since 4.0.1
- */
- public void setTitleOverlay(boolean overlay) {
- if (!getCTChart().isSetTitle()) {
- getCTChart().addNewTitle();
- }
- new XDDFTitle(this, getCTChart().getTitle()).setOverlay(overlay);
- }
-
- /**
- * Sets the title text as a static string.
- *
- * @param text
- * to use as new title
- * @since 4.0.1
- */
- public void setTitleText(String text) {
- if (!getCTChart().isSetTitle()) {
- getCTChart().addNewTitle();
- }
- new XDDFTitle(this, getCTChart().getTitle()).setText(text);
- }
-
- /**
- * @since 4.0.1
- */
- public XDDFTitle getTitle() {
- if (getCTChart().isSetTitle()) {
- return new XDDFTitle(this, getCTChart().getTitle());
- } else {
- return null;
- }
- }
-
- /**
- * Remove the chart title.
- * @since POI 5.0.0
- */
- public void removeTitle() {
- setAutoTitleDeleted(true);
- }
-
- /**
- * Get or Add chart 3D view into chart
- *
- * @return this method will add 3D view
- */
- public XDDFView3D getOrAddView3D() {
- CTView3D view3D;
- if (getCTChart().isSetView3D()) {
- view3D = getCTChart().getView3D();
- } else {
- view3D = getCTChart().addNewView3D();
- }
- return new XDDFView3D(view3D);
- }
-
- /**
- * Get the chart title body if there is one, i.e. title is set and is not a
- * formula.
- *
- * @return text body or null, if title is a formula or no title is set.
- */
- @Beta
- public XDDFTextBody getFormattedTitle() {
- if (!getCTChart().isSetTitle()) {
- return null;
- }
- return new XDDFTitle(this, getCTChart().getTitle()).getBody();
- }
-
- @Override
- public <R> Optional<R> findDefinedParagraphProperty(Predicate<CTTextParagraphProperties> isSet,
- Function<CTTextParagraphProperties, R> getter) {
- // TODO Auto-generated method stub
- return Optional.empty();
- }
-
- @Override
- public <R> Optional<R> findDefinedRunProperty(Predicate<CTTextCharacterProperties> isSet,
- Function<CTTextCharacterProperties, R> getter) {
- // TODO Auto-generated method stub
- return Optional.empty();
- }
-
- public XDDFShapeProperties getOrAddShapeProperties() {
- CTPlotArea plotArea = getCTPlotArea();
- CTShapeProperties properties;
- if (plotArea.isSetSpPr()) {
- properties = plotArea.getSpPr();
- } else {
- properties = plotArea.addNewSpPr();
- }
- return new XDDFShapeProperties(properties);
- }
-
- public void deleteShapeProperties() {
- if (getCTPlotArea().isSetSpPr()) {
- getCTPlotArea().unsetSpPr();
- }
- }
-
- public XDDFChartLegend getOrAddLegend() {
- return new XDDFChartLegend(getCTChart());
- }
-
- public void deleteLegend() {
- if (getCTChart().isSetLegend()) {
- getCTChart().unsetLegend();
- }
- }
-
- public XDDFManualLayout getOrAddManualLayout() {
- return new XDDFManualLayout(getCTPlotArea());
- }
-
- private long seriesCount = 0;
- protected long incrementSeriesCount() {
- return seriesCount++;
- }
-
- public void plot(XDDFChartData data) {
- XSSFSheet sheet = getSheet();
- for (int idx = 0; idx < data.getSeriesCount(); idx++) {
- XDDFChartData.Series series = data.getSeries(idx);
- series.plot();
- XDDFDataSource<?> categoryDS = series.getCategoryData();
- XDDFNumericalDataSource<? extends Number> valuesDS = series.getValuesData();
- if (categoryDS != null && !categoryDS.isCellRange() && !categoryDS.isLiteral() &&
- valuesDS != null && !valuesDS.isCellRange() && !valuesDS.isLiteral()) {
- fillSheet(sheet, categoryDS, valuesDS);
- }
- // otherwise let's assume the data is already in the sheet
- }
- }
-
- public List<XDDFChartData> getChartSeries() {
- List<XDDFChartData> series = new LinkedList<>();
- CTPlotArea plotArea = getCTPlotArea();
- Map<Long, XDDFChartAxis> categories = getCategoryAxes();
- Map<Long, XDDFValueAxis> values = getValueAxes();
-
- for (int i = 0; i < plotArea.sizeOfAreaChartArray(); i++) {
- CTAreaChart areaChart = plotArea.getAreaChartArray(i);
- series.add(new XDDFAreaChartData(this, areaChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfArea3DChartArray(); i++) {
- CTArea3DChart areaChart = plotArea.getArea3DChartArray(i);
- series.add(new XDDFArea3DChartData(this, areaChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfBarChartArray(); i++) {
- CTBarChart barChart = plotArea.getBarChartArray(i);
- series.add(new XDDFBarChartData(this, barChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfBar3DChartArray(); i++) {
- CTBar3DChart barChart = plotArea.getBar3DChartArray(i);
- series.add(new XDDFBar3DChartData(this, barChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfDoughnutChartArray(); i++) {
- CTDoughnutChart doughnutChart = plotArea.getDoughnutChartArray(i);
- series.add(new XDDFDoughnutChartData(this, doughnutChart));
- }
-
- for (int i = 0; i < plotArea.sizeOfLineChartArray(); i++) {
- CTLineChart lineChart = plotArea.getLineChartArray(i);
- series.add(new XDDFLineChartData(this, lineChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfLine3DChartArray(); i++) {
- CTLine3DChart lineChart = plotArea.getLine3DChartArray(i);
- series.add(new XDDFLine3DChartData(this, lineChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfPieChartArray(); i++) {
- CTPieChart pieChart = plotArea.getPieChartArray(i);
- series.add(new XDDFPieChartData(this, pieChart));
- }
-
- for (int i = 0; i < plotArea.sizeOfPie3DChartArray(); i++) {
- CTPie3DChart pieChart = plotArea.getPie3DChartArray(i);
- series.add(new XDDFPie3DChartData(this, pieChart));
- }
-
- for (int i = 0; i < plotArea.sizeOfRadarChartArray(); i++) {
- CTRadarChart radarChart = plotArea.getRadarChartArray(i);
- series.add(new XDDFRadarChartData(this, radarChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfScatterChartArray(); i++) {
- CTScatterChart scatterChart = plotArea.getScatterChartArray(i);
- series.add(new XDDFScatterChartData(this, scatterChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfSurfaceChartArray(); i++) {
- CTSurfaceChart surfaceChart = plotArea.getSurfaceChartArray(i);
- series.add(new XDDFSurfaceChartData(this, surfaceChart, categories, values));
- }
-
- for (int i = 0; i < plotArea.sizeOfSurface3DChartArray(); i++) {
- CTSurface3DChart surfaceChart = plotArea.getSurface3DChartArray(i);
- series.add(new XDDFSurface3DChartData(this, surfaceChart, categories, values));
- }
- // TODO repeat above code for missing charts: Bubble, OfPie and Stock
-
- seriesCount = series.size();
- return series;
- }
-
- /**
- * Clear all chart series, as if a new instance had just been created.
- * @since POI 4.1.2
- */
- public void clearChartSeries() {
- CTPlotArea plotArea = getCTPlotArea();
-
- for (int i = plotArea.sizeOfAreaChartArray(); i > 0; i--) {
- plotArea.removeAreaChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfArea3DChartArray(); i > 0; i--) {
- plotArea.removeArea3DChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfBarChartArray(); i > 0; i--) {
- plotArea.removeBarChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfBar3DChartArray(); i > 0; i--) {
- plotArea.removeBar3DChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfBubbleChartArray(); i > 0; i--) {
- plotArea.removeBubbleChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfDoughnutChartArray(); i > 0; i--) {
- plotArea.removeDoughnutChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfLineChartArray(); i > 0; i--) {
- plotArea.removeLineChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfLine3DChartArray(); i > 0; i--) {
- plotArea.removeLine3DChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfOfPieChartArray(); i > 0; i--) {
- plotArea.removeOfPieChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfPieChartArray(); i > 0; i--) {
- plotArea.removePieChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfPie3DChartArray(); i > 0; i--) {
- plotArea.removePie3DChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfRadarChartArray(); i > 0; i--) {
- plotArea.removeRadarChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfScatterChartArray(); i > 0; i--) {
- plotArea.removeScatterChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfStockChartArray(); i > 0; i--) {
- plotArea.removeStockChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfSurfaceChartArray(); i > 0; i--) {
- plotArea.removeSurfaceChart(i - 1);
- }
-
- for (int i = plotArea.sizeOfSurface3DChartArray(); i > 0; i--) {
- plotArea.removeSurface3DChart(i - 1);
- }
- }
-
- private Map<Long, XDDFChartAxis> getCategoryAxes() {
- CTPlotArea plotArea = getCTPlotArea();
- int sizeOfArray = plotArea.sizeOfCatAxArray();
- Map<Long, XDDFChartAxis> axesMap = new HashMap<>(sizeOfArray);
- for (int i = 0; i < sizeOfArray; i++) {
- CTCatAx category = plotArea.getCatAxArray(i);
- axesMap.put(category.getAxId().getVal(), new XDDFCategoryAxis(category));
- }
- return axesMap;
- }
-
- private Map<Long, XDDFValueAxis> getValueAxes() {
- CTPlotArea plotArea = getCTPlotArea();
- int sizeOfArray = plotArea.sizeOfValAxArray();
- Map<Long, XDDFValueAxis> axesMap = new HashMap<>(sizeOfArray);
- for (int i = 0; i < sizeOfArray; i++) {
- CTValAx values = plotArea.getValAxArray(i);
- axesMap.put(values.getAxId().getVal(), new XDDFValueAxis(values));
- }
- return axesMap;
- }
-
- public XDDFValueAxis createValueAxis(AxisPosition pos) {
- XDDFValueAxis valueAxis = new XDDFValueAxis(getCTPlotArea(), pos);
- addAxis(valueAxis);
- return valueAxis;
- }
-
- /**
- * this method will return series axis with specified position
- *
- * @param pos axis position Left, Right, Top, Bottom
- * @return series axis with specified position
- */
- public XDDFSeriesAxis createSeriesAxis(AxisPosition pos) {
- XDDFSeriesAxis seriesAxis = new XDDFSeriesAxis(getCTPlotArea(), pos);
- addAxis(seriesAxis);
- return seriesAxis;
- }
-
- public XDDFCategoryAxis createCategoryAxis(AxisPosition pos) {
- XDDFCategoryAxis categoryAxis = new XDDFCategoryAxis(getCTPlotArea(), pos);
- addAxis(categoryAxis);
- return categoryAxis;
- }
-
- public XDDFDateAxis createDateAxis(AxisPosition pos) {
- XDDFDateAxis dateAxis = new XDDFDateAxis(getCTPlotArea(), pos);
- addAxis(dateAxis);
- return dateAxis;
- }
-
- private void addAxis(XDDFChartAxis newAxis) {
- if (axes.size() == 1) {
- XDDFChartAxis axis = axes.get(0);
- axis.crossAxis(newAxis);
- newAxis.crossAxis(axis);
- axis.setCrosses(AxisCrosses.AUTO_ZERO);
- newAxis.setCrosses(AxisCrosses.AUTO_ZERO);
- }
- axes.add(newAxis);
- }
-
- /**
- * this method will return specified chart data with category and series values
- *
- * @param type chart type
- * @param category category values of chart
- * @param values series values of chart
- * @return specified chart data.
- */
- public XDDFChartData createData(ChartTypes type, XDDFChartAxis category, XDDFValueAxis values) {
- Map<Long, XDDFChartAxis> categories = null;
- Map<Long, XDDFValueAxis> mapValues = null;
-
- if (ChartTypes.PIE != type && ChartTypes.PIE3D != type && ChartTypes.DOUGHNUT != type) {
- categories = Collections.singletonMap(category.getId(), category);
- mapValues = Collections.singletonMap(values.getId(), values);
- }
-
- final CTPlotArea plotArea = getCTPlotArea();
- switch (type) {
- case AREA:
- return new XDDFAreaChartData(this, plotArea.addNewAreaChart(), categories, mapValues);
- case AREA3D:
- return new XDDFArea3DChartData(this, plotArea.addNewArea3DChart(), categories, mapValues);
- case BAR:
- return new XDDFBarChartData(this, plotArea.addNewBarChart(), categories, mapValues);
- case BAR3D:
- return new XDDFBar3DChartData(this, plotArea.addNewBar3DChart(), categories, mapValues);
- case DOUGHNUT:
- return new XDDFDoughnutChartData(this, plotArea.addNewDoughnutChart());
- case LINE:
- return new XDDFLineChartData(this, plotArea.addNewLineChart(), categories, mapValues);
- case LINE3D:
- return new XDDFLine3DChartData(this, plotArea.addNewLine3DChart(), categories, mapValues);
- case PIE:
- return new XDDFPieChartData(this, plotArea.addNewPieChart());
- case PIE3D:
- return new XDDFPie3DChartData(this, plotArea.addNewPie3DChart());
- case RADAR:
- return new XDDFRadarChartData(this, plotArea.addNewRadarChart(), categories, mapValues);
- case SCATTER:
- return new XDDFScatterChartData(this, plotArea.addNewScatterChart(), categories, mapValues);
- case SURFACE:
- return new XDDFSurfaceChartData(this, plotArea.addNewSurfaceChart(), categories, mapValues);
- case SURFACE3D:
- return new XDDFSurface3DChartData(this, plotArea.addNewSurface3DChart(), categories, mapValues);
- // TODO repeat above code for missing charts: Bubble, OfPie and Stock
- default:
- return null;
- }
- }
-
- public List<? extends XDDFChartAxis> getAxes() {
- if (axes.isEmpty() && hasAxes()) {
- parseAxes();
- }
- return axes;
- }
-
- private boolean hasAxes() {
- CTPlotArea ctPlotArea = getCTPlotArea();
- int totalAxisCount = ctPlotArea.sizeOfValAxArray() + ctPlotArea.sizeOfCatAxArray() + ctPlotArea
- .sizeOfDateAxArray() + ctPlotArea.sizeOfSerAxArray();
- return totalAxisCount > 0;
- }
-
- private void parseAxes() {
- for (CTCatAx catAx : getCTPlotArea().getCatAxArray()) {
- axes.add(new XDDFCategoryAxis(catAx));
- }
- for (CTDateAx dateAx : getCTPlotArea().getDateAxArray()) {
- axes.add(new XDDFDateAxis(dateAx));
- }
- for (CTSerAx serAx : getCTPlotArea().getSerAxArray()) {
- axes.add(new XDDFSeriesAxis(serAx));
- }
- for (CTValAx valAx : getCTPlotArea().getValAxArray()) {
- axes.add(new XDDFValueAxis(valAx));
- }
- }
-
- /**
- * Set value range (basic Axis Options)
- *
- * @param axisIndex
- * 0 - primary axis, 1 - secondary axis
- * @param minimum
- * minimum value; Double.NaN - automatic; null - no change
- * @param maximum
- * maximum value; Double.NaN - automatic; null - no change
- * @param majorUnit
- * major unit value; Double.NaN - automatic; null - no change
- * @param minorUnit
- * minor unit value; Double.NaN - automatic; null - no change
- */
- public void setValueRange(int axisIndex, Double minimum, Double maximum, Double majorUnit, Double minorUnit) {
- XDDFChartAxis axis = getAxes().get(axisIndex);
- if (axis == null) {
- return;
- }
- if (minimum != null) {
- axis.setMinimum(minimum);
- }
- if (maximum != null) {
- axis.setMaximum(maximum);
- }
- if (majorUnit != null) {
- axis.setMajorUnit(majorUnit);
- }
- if (minorUnit != null) {
- axis.setMinorUnit(minorUnit);
- }
- }
-
- /**
- * method to create relationship with embedded part for example writing xlsx
- * file stream into output stream
- *
- * @param chartRelation
- * relationship object
- * @param chartFactory
- * ChartFactory object
- * @param chartIndex
- * index used to suffix on file
- * @return return relation part which used to write relation in .rels file
- * and get relation id
- * @since POI 4.0.0
- */
- public PackageRelationship createRelationshipInChart(POIXMLRelation chartRelation, POIXMLFactory chartFactory,
- int chartIndex) {
- POIXMLDocumentPart documentPart =
- createRelationship(chartRelation, chartFactory, chartIndex, true).getDocumentPart();
- return addRelation(null, chartRelation, documentPart).getRelationship();
- }
-
- /**
- * if embedded part was null then create new part
- *
- * @param chartWorkbookRelation
- * chart workbook relation object
- * @param chartFactory
- * factory object of POIXMLFactory (XWPFFactory/XSLFFactory)
- * @return return the new package part
- * @since POI 4.0.0
- */
- private PackagePart createWorksheetPart(POIXMLRelation chartWorkbookRelation, POIXMLFactory chartFactory)
- throws InvalidFormatException {
- PackageRelationship xlsx = createRelationshipInChart(chartWorkbookRelation, chartFactory, chartIndex);
- setExternalId(xlsx.getId());
- return getTargetPart(xlsx);
- }
-
- /**
- * this method write the XSSFWorkbook object data into embedded excel file
- *
- * @param workbook XSSFworkbook object
- * @since POI 4.0.0
- */
- public void saveWorkbook(XSSFWorkbook workbook) throws IOException, InvalidFormatException {
- PackagePart worksheetPart = getWorksheetPart();
- if (worksheetPart == null) {
- POIXMLRelation chartWorkbookRelation = getChartWorkbookRelation();
- POIXMLFactory chartFactory = getChartFactory();
- if (chartWorkbookRelation != null && chartFactory != null) {
- worksheetPart = createWorksheetPart(chartWorkbookRelation, chartFactory);
- } else {
- throw new InvalidFormatException("unable to determine chart relations");
- }
- }
- try (OutputStream xlsOut = worksheetPart.getOutputStream()) {
- setWorksheetPartCommitted();
- workbook.write(xlsOut);
- }
- }
-
- /**
- *
- * @return the chart relation in the implementing subclass.
- * @since POI 4.0.0
- */
- protected abstract POIXMLRelation getChartRelation();
-
- /**
- *
- * @return the chart workbook relation in the implementing subclass.
- * @since POI 4.0.0
- */
- protected abstract POIXMLRelation getChartWorkbookRelation();
-
- /**
- *
- * @return the chart factory in the implementing subclass.
- * @since POI 4.0.0
- */
- protected abstract POIXMLFactory getChartFactory();
-
- /**
- * this method writes the data into sheet
- *
- * @param sheet
- * sheet of embedded excel
- * @param categoryData
- * category values
- * @param valuesData
- * data values
- * @since POI 4.0.0
- */
- protected void fillSheet(XSSFSheet sheet, XDDFDataSource<?> categoryData, XDDFNumericalDataSource<?> valuesData) {
- int numOfPoints = categoryData.getPointCount();
- for (int i = 0; i < numOfPoints; i++) {
- XSSFRow row = getRow(sheet, i + 1); // first row is for title
- Object category = categoryData.getPointAt(i);
- if (category != null) {
- getCell(row, categoryData.getColIndex()).setCellValue(category.toString());
- }
- Number value = valuesData.getPointAt(i);
- if (value != null) {
- getCell(row, valuesData.getColIndex()).setCellValue(value.doubleValue());
- }
- }
- }
-
- /**
- * this method return row on given index if row is null then create new row
- *
- * @param sheet
- * current sheet object
- * @param index
- * index of current row
- * @return this method return sheet row on given index
- * @since POI 4.0.0
- */
- private XSSFRow getRow(XSSFSheet sheet, int index) {
- XSSFRow row = sheet.getRow(index);
- if (row == null) {
- return sheet.createRow(index);
- } else {
- return row;
- }
- }
-
- /**
- * this method return cell on given index if cell is null then create new
- * cell
- *
- * @param row
- * current row object
- * @param index
- * index of current cell
- * @return this method return sheet cell on given index
- * @since POI 4.0.0
- */
- private XSSFCell getCell(XSSFRow row, int index) {
- XSSFCell cell = row.getCell(index);
- if (cell == null) {
- return row.createCell(index);
- } else {
- return cell;
- }
- }
-
- /**
- * import content from other chart to created chart
- *
- * @param other
- * chart object
- * @since POI 4.0.0
- */
- public void importContent(XDDFChart other) {
- getCTChartSpace().set(other.getCTChartSpace());
- }
-
- /**
- * save chart xml
- */
- @Override
- protected void commit() throws IOException {
- XmlOptions xmlOptions = new XmlOptions(DEFAULT_XML_OPTIONS);
- xmlOptions.setSaveSyntheticDocumentElement(
- new QName(CTChartSpace.type.getName().getNamespaceURI(), "chartSpace", "c"));
-
- if (workbook != null) {
- try {
- saveWorkbook(workbook);
- } catch (InvalidFormatException e) {
- throw new POIXMLException(e);
- }
- }
-
- PackagePart part = getPackagePart();
- try (OutputStream out = part.getOutputStream()) {
- chartSpace.save(out, xmlOptions);
- }
- }
-
- /**
- * set sheet title in excel file
- *
- * @param title
- * title of sheet
- * @param column
- * column index
- * @return return cell reference
- * @since POI 4.0.0
- */
- public CellReference setSheetTitle(String title, int column) {
- XSSFSheet sheet = getSheet();
- if (sheet == null) {
- return null;
- }
- XSSFRow row = getRow(sheet, 0);
- XSSFCell cell = getCell(row, column);
- cell.setCellValue(title);
-
- return new CellReference(sheet.getSheetName(), 0, column, true, true);
- }
-
- /**
- * @since POI 4.0.0
- */
- public String formatRange(CellRangeAddress range) {
- final XSSFSheet sheet = getSheet();
- return (sheet == null) ? null : range.formatAsString(sheet.getSheetName(), true);
- }
-
- /**
- * get sheet object of embedded excel file
- *
- * @return excel sheet object
- * @since POI 4.0.0
- */
- private XSSFSheet getSheet() {
- try {
- return getWorkbook().getSheetAt(0);
- } catch (InvalidFormatException | IOException ignored) {
- return null;
- }
- }
-
- /**
- * this method is used to get worksheet part if call is from saveworkbook
- * method then check isCommitted isCommitted variable shows that we are
- * writing xssfworkbook object into output stream of embedded part
- *
- * @return returns the packagepart of embedded file
- * @since POI 4.0.0
- */
- private PackagePart getWorksheetPart() throws InvalidFormatException {
- for (RelationPart part : getRelationParts()) {
- if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) {
- return getTargetPart(part.getRelationship());
- }
- }
- return null;
- }
-
- private void setWorksheetPartCommitted() {
- for (RelationPart part : getRelationParts()) {
- if (POIXMLDocument.PACK_OBJECT_REL_TYPE.equals(part.getRelationship().getRelationshipType())) {
- part.getDocumentPart().setCommitted(true);
- break;
- }
- }
- }
-
- /**
- * @return returns the workbook object of embedded excel file
- * @since POI 4.0.0
- */
- public XSSFWorkbook getWorkbook() throws IOException, InvalidFormatException {
- if (workbook == null) {
- try {
- PackagePart worksheetPart = getWorksheetPart();
- if (worksheetPart == null) {
- workbook = new XSSFWorkbook();
- workbook.createSheet();
- } else {
- workbook = new XSSFWorkbook(worksheetPart.getInputStream());
- }
- } catch (NotOfficeXmlFileException e) {
- workbook = new XSSFWorkbook();
- workbook.createSheet();
- }
- }
- return workbook;
- }
-
- /**
- * while reading chart from template file then we need to parse and store
- * embedded excel file in chart object show that we can modify value
- * according to use
- *
- * @param workbook
- * workbook object which we read from chart embedded part
- * @since POI 4.0.0
- */
- public void setWorkbook(XSSFWorkbook workbook) {
- this.workbook = workbook;
- }
-
- /**
- * set the relation id of embedded excel relation id into external data
- * relation tag
- *
- * @param id
- * relation id of embedded excel relation id into external data
- * relation tag
- * @since POI 4.0.0
- */
- public void setExternalId(String id) {
- CTChartSpace ctChartSpace = getCTChartSpace();
- CTExternalData externalData = ctChartSpace.isSetExternalData()
- ? ctChartSpace.getExternalData()
- : ctChartSpace.addNewExternalData();
- externalData.setId(id);
- }
-
- /**
- * @return method return chart index
- * @since POI 4.0.0
- */
- protected int getChartIndex() {
- return chartIndex;
- }
-
- /**
- * Set chart index which can be used for relation part.
- *
- * @param chartIndex
- * chart index which can be used for relation part.
- */
- public void setChartIndex(int chartIndex) {
- this.chartIndex = chartIndex;
- }
-
- /**
- * Replace references to the sheet name in the data supporting the chart.
- *
- * @param newSheet
- * sheet to be used in the data references.
- *
- * @since POI 5.1.0
- */
- public void replaceReferences(XSSFSheet newSheet) {
- for (XDDFChartData data : getChartSeries()) {
- for (XDDFChartData.Series series : data.series) {
- XDDFDataSource<?> newCategory = series.categoryData;
- XDDFNumericalDataSource<? extends Number> newValues = series.valuesData;
- try {
- if (series.categoryData != null && series.categoryData.isReference()) {
- String ref = series.categoryData.getDataRangeReference();
- CellRangeAddress rangeAddress = CellRangeAddress.valueOf(ref.substring(ref.indexOf('!') + 1));
- newCategory = series.categoryData.isNumeric()
- ? XDDFDataSourcesFactory.fromNumericCellRange(newSheet, rangeAddress)
- : XDDFDataSourcesFactory.fromStringCellRange(newSheet, rangeAddress);
- if (newCategory.isNumeric()) {
- ((XDDFNumericalDataSource<? extends Number>) newCategory).setFormatCode(series.categoryData.getFormatCode());
- }
- }
- if (series.valuesData!= null && series.valuesData.isReference()) {
- String ref = series.valuesData.getDataRangeReference();
- CellRangeAddress rangeAddress = CellRangeAddress.valueOf(ref.substring(ref.indexOf('!') + 1));
- newValues = XDDFDataSourcesFactory.fromNumericCellRange(newSheet, rangeAddress);
- newValues.setFormatCode(series.valuesData.getFormatCode());
- }
- } catch (IllegalArgumentException iae) {
- // keep old values when cell range cannot be parsed
- }
- series.replaceData(newCategory, newValues);
- series.plot();
- }
- }
- }
- }
|