Java tutorial
/* * OpenFaces - JSF Component Library 3.0 * Copyright (C) 2007-2012, TeamDev Ltd. * licensing@openfaces.org * Unless agreed in writing the contents of this file are subject to * the GNU Lesser General Public License Version 2.1 (the "LGPL" License). * This library 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. * Please visit http://openfaces.org/licensing/ for more details. */ package org.openfaces.component.chart.impl.renderers; import org.jfree.chart.LegendItem; import org.jfree.chart.axis.CategoryAxis; import org.jfree.chart.axis.ValueAxis; import org.jfree.chart.entity.EntityCollection; import org.jfree.chart.labels.XYSeriesLabelGenerator; import org.jfree.chart.plot.CategoryPlot; import org.jfree.chart.plot.CrosshairState; import org.jfree.chart.plot.PlotOrientation; import org.jfree.chart.plot.PlotRenderingInfo; import org.jfree.chart.plot.XYPlot; import org.jfree.chart.renderer.category.CategoryItemRendererState; import org.jfree.chart.renderer.xy.AbstractXYItemRenderer; import org.jfree.chart.renderer.xy.XYItemRenderer; import org.jfree.chart.renderer.xy.XYItemRendererState; import org.jfree.data.category.CategoryDataset; import org.jfree.data.xy.XYDataset; import org.jfree.util.BooleanUtilities; import org.jfree.util.ShapeUtilities; import org.openfaces.component.chart.ChartView; import org.openfaces.component.chart.GradientLineAreaFill; import org.openfaces.component.chart.LineAreaFill; import org.openfaces.component.chart.SolidLineAreaFill; import org.openfaces.component.chart.impl.configuration.ConfigurableRenderer; import org.openfaces.component.chart.impl.configuration.RendererConfigurator; import org.openfaces.component.chart.impl.renderers.states.XYLineFillItemRendererState; import java.awt.*; import java.awt.geom.Line2D; import java.awt.geom.Rectangle2D; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Map; public class XYLineFillRenderer extends AbstractXYItemRenderer implements XYItemRenderer, XYRendererAdapter, AreaFillRenderer, CustomizedRenderer, ConfigurableRenderer { private ItemsRenderer delegate = new ItemsRenderer(); private ConfigurableRendererBase configurationDelegate = new ConfigurableRendererBase(); private Map<Integer, Boolean> seriesLinesVisible = new HashMap<Integer, Boolean>(); private Map<Integer, Boolean> seriesShapesVisible = new HashMap<Integer, Boolean>(); private Map<Integer, Boolean> seriesShapesFilled = new HashMap<Integer, Boolean>(); private boolean baseShapesVisible = true; private boolean baseLinesVisible = true; private boolean baseShapesFilled = true; private boolean useFillPaint = false; private boolean useOutlinePaint = false; private boolean drawFilledArea = true; private boolean drawOutlines = false; private Paint backgroundPaint; private LineAreaFill lineAreaFill; public int getPassCount() { return 2; } public XYItemRendererState initialise(Graphics2D g2, Rectangle2D dataArea, XYPlot plot, XYDataset data, PlotRenderingInfo info) { XYLineFillItemRendererState itemRendererState = new XYLineFillItemRendererState(info); itemRendererState.setProcessVisibleItemsOnly(false); return itemRendererState; } public LegendItem getLegendItem(int dataSetIndex, int series) { XYPlot plot = getPlot(); if (plot == null) { return null; } LegendItem legendItem = null; XYDataset dataSet = plot.getDataset(dataSetIndex); if (dataSet != null) { if (getItemVisible(series, 0)) { legendItem = createLegendItem(dataSetIndex, series, dataSet); } } return legendItem; } public void drawItem(Graphics2D g2, XYItemRendererState state, Rectangle2D dataArea, PlotRenderingInfo info, XYPlot plot, ValueAxis domainAxis, ValueAxis rangeAxis, XYDataset dataSet, int series, int item, CrosshairState crosshairState, int pass) { if (!getItemVisible(series, item)) { return; } double itemXValue = dataSet.getXValue(series, item); double itemYValue = dataSet.getYValue(series, item); if (Double.isNaN(itemYValue) || Double.isNaN(itemXValue)) { return; } double currentItemX = calculateItemXPoint(series, item, dataArea, domainAxis, dataSet, plot); double currentItemY = calculateItemYPoint(series, item, dataArea, rangeAxis, dataSet, plot); int previousItemIndex = item > 0 ? item - 1 : 0; double previousItemX = calculateItemXPoint(series, previousItemIndex, dataArea, domainAxis, dataSet, plot); double previousItemY = calculateItemYPoint(series, previousItemIndex, dataArea, rangeAxis, dataSet, plot); final int lastItemIndex = dataSet.getItemCount(series) - 1; int nextItemIndex = item < lastItemIndex ? item + 1 : lastItemIndex; double nextItemX = calculateItemXPoint(series, nextItemIndex, dataArea, domainAxis, dataSet, plot); double nextItemY = calculateItemYPoint(series, nextItemIndex, dataArea, rangeAxis, dataSet, plot); double zeroRangePoint = rangeAxis.valueToJava2D(0.0, dataArea, plot.getRangeAxisEdge()); if (isAreaAndLinePass(pass)) { XYLineFillItemRendererState rendererState = (XYLineFillItemRendererState) state; renderLineArea(g2, info, plot, series, item, rendererState, dataSet, currentItemX, currentItemY, previousItemX, previousItemY, zeroRangePoint); } else if (isShapesAndLabelsPass(pass)) { Shape entityArea = renderShapeAndLabel(g2, dataArea, plot, dataSet, series, item, itemYValue, currentItemX, currentItemY, previousItemX, previousItemY, nextItemX, nextItemY, zeroRangePoint); int domainAxisIndex = plot.getDomainAxisIndex(domainAxis); int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis); updateCrosshairValues(crosshairState, itemXValue, itemYValue, domainAxisIndex, rangeAxisIndex, currentItemX, currentItemY, plot.getOrientation()); EntityCollection entityCollection = state.getEntityCollection(); if (entityCollection != null) { addEntity(entityCollection, entityArea, dataSet, series, item, 0.0, 0.0); } } else { throw new IllegalStateException("Unknown pass: " + pass); } } private void renderLineArea(Graphics2D g2, PlotRenderingInfo info, XYPlot plot, int series, int item, XYLineFillItemRendererState rendererState, XYDataset dataSet, double currentItemX, double currentItemY, double previousItemX, double previousItemY, double zeroRangePoint) { boolean isFirstItem = item == 0; boolean isLastItem = item == (dataSet.getItemCount(series) - 1); boolean areaPolygonCanBeFilled = !isFirstItem && isLastItem; if (isFirstItem) { initializeRendererState(rendererState, plot, currentItemX, zeroRangePoint); } addPointToAreaPolygon(rendererState.getAreaPolygon(), plot, currentItemX, currentItemY); if (isDrawFilledArea() && areaPolygonCanBeFilled) { final Polygon polygon = rendererState.getAreaPolygon(); addPointToAreaPolygon(polygon, plot, currentItemX, zeroRangePoint); final Paint itemPaint = getItemPaint(series, item); configureAreaFill(g2, plot, info, itemPaint); g2.fill(polygon); } if (getItemLineVisible(series, item) && !isFirstItem) { final Collection<Line2D> lines = rendererState.getLines(); addItemLine(plot, lines, previousItemX, previousItemY, currentItemX, currentItemY); if (isLastItem) { drawSeriesLines(g2, lines, series, item); } } } private void configureAreaFill(Graphics2D g2, XYPlot plot, PlotRenderingInfo info, Paint itemPaint) { LineAreaFill areaFill = getLineAreaFill(); if (areaFill instanceof SolidLineAreaFill) { configureSolidAreaFill(g2, itemPaint, (SolidLineAreaFill) areaFill); } else if (areaFill instanceof GradientLineAreaFill) { configureGradientAreaFill(g2, plot, info, itemPaint, (GradientLineAreaFill) areaFill); } } private void configureGradientAreaFill(Graphics2D g2, XYPlot plot, PlotRenderingInfo info, Paint itemPaint, GradientLineAreaFill gradientLineAreaFill) { final Rectangle2D plotArea = info.getPlotArea(); double plotWidth = plotArea.getWidth(); double plotHeight = plotArea.getHeight(); Double mainColorTransparency = gradientLineAreaFill.getMaxValueTransparency(); Double bgColorTransparency = gradientLineAreaFill.getMinValueTransparency(); if (itemPaint instanceof Color) { Color itemColor = (Color) itemPaint; int red = itemColor.getRed(); int green = itemColor.getGreen(); int blue = itemColor.getBlue(); int mainColorAlpha = (mainColorTransparency >= 0.0 && mainColorTransparency <= 1.0) ? Math.round(255 * mainColorTransparency.floatValue()) : 150; int bgColorAlpha = (bgColorTransparency >= 0.0 && bgColorTransparency <= 1.0) ? Math.round(255 * bgColorTransparency.floatValue()) : 128; Color mainColor = new Color(red, green, blue, mainColorAlpha); Paint bgColor = getBackgroundPaint(); if (bgColor == null) { bgColor = plot.getBackgroundPaint(); } Color secondaryColor = getSecondaryColor(bgColorAlpha, bgColor); Paint areaPaint = getAreaFillPaint(plot, plotWidth, plotHeight, mainColor, secondaryColor); g2.setPaint(areaPaint); } else { g2.setPaint(itemPaint); } } private Color getSecondaryColor(int bgColorAlpha, Paint bgColor) { return (bgColor != null && bgColor instanceof Color) ? new Color(((Color) bgColor).getRed(), ((Color) bgColor).getGreen(), ((Color) bgColor).getBlue(), bgColorAlpha) : new Color(0, 0, 0, bgColorAlpha); } private Paint getAreaFillPaint(XYPlot plot, Double plotWidth, Double plotHeight, Color mainColor, Color secondaryColor) { return (plot.getOrientation() == PlotOrientation.VERTICAL) ? new GradientPaint(0.0f, 0.0f, mainColor, 0.0f, plotHeight.floatValue(), secondaryColor, true) : new GradientPaint(plotWidth.floatValue(), 0.0f, mainColor, 0.0f, 0.0f, secondaryColor, true); } private void configureSolidAreaFill(Graphics2D g2, Paint itemPaint, SolidLineAreaFill solidLineAreaFill) { double transparency = solidLineAreaFill.getTransparency(); if (itemPaint instanceof Color) { Color itemColor = (Color) itemPaint; int alpha = transparency >= 0.0 && transparency <= 1.0 ? Math.round(255 * (float) transparency) : 255; g2.setPaint(new Color(itemColor.getRed(), itemColor.getGreen(), itemColor.getBlue(), alpha)); } else { g2.setPaint(itemPaint); } } private void addPointToAreaPolygon(Polygon polygon, XYPlot plot, double currentItemX, double currentItemY) { if (plot.getOrientation() == PlotOrientation.VERTICAL) { polygon.addPoint((int) currentItemX, (int) currentItemY); } else { polygon.addPoint((int) currentItemY, (int) currentItemX); } } private void initializeRendererState(XYLineFillItemRendererState rendererState, XYPlot plot, double currentItemX, double zeroRangePoint) { rendererState.setLines(new ArrayList<Line2D>()); final Polygon polygon = new Polygon(); rendererState.setAreaPolygon(polygon); addPointToAreaPolygon(polygon, plot, currentItemX, zeroRangePoint); } public void completePass(Graphics2D g2, CategoryItemRendererState state, Rectangle2D dataArea, CategoryPlot plot, CategoryAxis domainAxis, ValueAxis rangeAxis, CategoryDataset dataSet, int row, int pass) { // This renderer does not require any additional processing during complete pass phase } private void drawSeriesLines(Graphics2D g2, Collection<Line2D> lines, int series, int item) { g2.setPaint(getItemPaint(series, item)); g2.setStroke(getItemStroke(series, item)); for (Line2D line : lines) { g2.draw(line); } } private void addItemLine(XYPlot plot, Collection<Line2D> lines, double previousItemX, double previousItemY, double currentItemX, double currentItemY) { if (plot.getOrientation() == PlotOrientation.VERTICAL) { lines.add(new Line2D.Double(previousItemX, previousItemY, currentItemX, currentItemY)); } else if (plot.getOrientation() == PlotOrientation.HORIZONTAL) { lines.add(new Line2D.Double(previousItemY, previousItemX, currentItemY, currentItemX)); } } private Shape renderShapeAndLabel(Graphics2D g2, Rectangle2D dataArea, XYPlot plot, XYDataset dataSet, int series, int item, double yValue, double currentItemX, double currentItemY, double previousItemX, double previousItemY, double nextItemX, double nextItemY, double zeroRangePoint) { boolean isVerticallyOrientedPlot = plot.getOrientation() == PlotOrientation.VERTICAL; Shape entityShape; if (getItemShapeVisible(series, item)) { entityShape = getItemShape(series, item); if (isVerticallyOrientedPlot) { entityShape = ShapeUtilities.createTranslatedShape(entityShape, currentItemX, currentItemY); } else { entityShape = ShapeUtilities.createTranslatedShape(entityShape, currentItemY, currentItemX); } if (entityShape.intersects(dataArea)) { drawItemShape(g2, series, item, entityShape); } } else { entityShape = createEntityArea(plot, previousItemX, previousItemY, currentItemX, currentItemY, nextItemX, nextItemY, zeroRangePoint); } if (isItemLabelVisible(series, item)) { drawLabel(g2, dataSet, series, item, currentItemX, currentItemY, yValue < 0, plot.getOrientation()); } return entityShape; } private void drawItemShape(Graphics2D g2, int series, int item, Shape entityShape) { if (getItemShapeFilled(series, item)) { g2.setPaint(getUseFillPaint() ? getItemFillPaint(series, item) : getItemPaint(series, item)); g2.fill(entityShape); } if (getDrawOutlines()) { g2.setPaint(getUseOutlinePaint() ? getItemOutlinePaint(series, item) : getItemPaint(series, item)); g2.setStroke(getItemOutlineStroke(series, item)); } g2.draw(entityShape); } private void drawLabel(Graphics2D g2, XYDataset dataSet, int series, int item, double currentItemX, double currentItemY, boolean negative, PlotOrientation orientation) { double labelX = (orientation == PlotOrientation.HORIZONTAL) ? currentItemY : currentItemX; double labelY = (orientation == PlotOrientation.HORIZONTAL) ? currentItemX : currentItemY; drawItemLabel(g2, orientation, dataSet, series, item, labelX, labelY, negative); } private Polygon createEntityArea(XYPlot plot, double previousItemX, double previousItemY, double currentItemX, double currentItemY, double nextItemX, double nextItemY, double zeroPoint) { Polygon entityAreaPolygon = new Polygon(); final int halfwayPrevX = (int) ((previousItemX + currentItemX) / 2.0); final int halfwayPrevY = (int) ((previousItemY + currentItemY) / 2.0); final int halfwayNextY = (int) ((currentItemY + nextItemY) / 2.0); final int halfwayNextX = (int) ((currentItemX + nextItemX) / 2.0); if (plot.getOrientation() == PlotOrientation.HORIZONTAL) { entityAreaPolygon.addPoint((int) zeroPoint, halfwayPrevX); entityAreaPolygon.addPoint(halfwayPrevY, halfwayPrevX); entityAreaPolygon.addPoint((int) currentItemY, (int) currentItemX); entityAreaPolygon.addPoint(halfwayNextY, halfwayNextX); entityAreaPolygon.addPoint((int) zeroPoint, halfwayNextX); } else { entityAreaPolygon.addPoint(halfwayPrevX, (int) zeroPoint); entityAreaPolygon.addPoint(halfwayPrevX, halfwayPrevY); entityAreaPolygon.addPoint((int) currentItemX, (int) currentItemY); entityAreaPolygon.addPoint(halfwayNextX, halfwayNextY); entityAreaPolygon.addPoint(halfwayNextX, (int) zeroPoint); } return entityAreaPolygon; } private double calculateItemXPoint(int series, int item, Rectangle2D dataArea, ValueAxis domainAxis, XYDataset dataSet, XYPlot plot) { double xValue = dataSet.getXValue(series, item); return domainAxis.valueToJava2D(xValue, dataArea, plot.getDomainAxisEdge()); } private double calculateItemYPoint(int series, int item, Rectangle2D dataArea, ValueAxis rangeAxis, XYDataset dataSet, XYPlot plot) { double yValue = dataSet.getYValue(series, item); return rangeAxis.valueToJava2D(yValue, dataArea, plot.getRangeAxisEdge()); } private LegendItem createLegendItem(int dataSetIndex, int series, XYDataset dataSet) { Shape shape = lookupLegendShape(series); Paint fillPaint = (getUseFillPaint() ? lookupSeriesFillPaint(series) : lookupSeriesPaint(series)); Paint outlinePaint = (getUseOutlinePaint() ? lookupSeriesOutlinePaint(series) : lookupSeriesPaint(series)); Stroke outlineStroke = lookupSeriesOutlineStroke(series); Stroke lineStroke = lookupSeriesStroke(series); Paint linePaint = lookupSeriesPaint(series); Paint labelPaint = lookupLegendTextPaint(series); Font labelFont = lookupLegendTextFont(series); String itemLegendLabel = getLegendItemLabelGenerator().generateLabel(dataSet, series); final XYSeriesLabelGenerator toolTipGenerator = getLegendItemToolTipGenerator(); String toolTipText = (toolTipGenerator != null) ? toolTipGenerator.generateLabel(dataSet, series) : null; final XYSeriesLabelGenerator urlGenerator = getLegendItemURLGenerator(); String urlText = urlGenerator != null ? urlGenerator.generateLabel(dataSet, series) : null; boolean isItemShapeVisible = getItemShapeVisible(series, 0); boolean isItemShapeFilled = getItemShapeFilled(series, 0); boolean isItemShapeOutlineVisible = getDrawOutlines(); boolean isItemLineVisible = getItemLineVisible(series, 0); LegendItem legendItem = new LegendItem(itemLegendLabel, itemLegendLabel, toolTipText, urlText, isItemShapeVisible, shape, isItemShapeFilled, fillPaint, isItemShapeOutlineVisible, outlinePaint, outlineStroke, isItemLineVisible, new Line2D.Double(-7.0, 0.0, 7.0, 0.0), lineStroke, linePaint); legendItem.setLabelFont(labelFont); legendItem.setLabelPaint(labelPaint); legendItem.setSeriesKey(dataSet.getSeriesKey(series)); legendItem.setSeriesIndex(series); legendItem.setDataset(dataSet); legendItem.setDatasetIndex(dataSetIndex); return legendItem; } protected boolean isAreaAndLinePass(int pass) { return pass == 0; } protected boolean isShapesAndLabelsPass(int pass) { return pass == 1; } public Paint getBackgroundPaint() { return backgroundPaint; } public void setBackgroundPaint(Paint backgroundPaint) { this.backgroundPaint = backgroundPaint; } public LineAreaFill getLineAreaFill() { return lineAreaFill; } public void setLineAreaFill(LineAreaFill lineAreaFill) { this.lineAreaFill = lineAreaFill; } public boolean getUseFillPaint() { return useFillPaint; } public void setUseFillPaint(boolean flag) { this.useFillPaint = flag; } public boolean getDrawOutlines() { return drawOutlines; } public void setDrawOutlines(boolean show) { this.drawOutlines = show; } public boolean getUseOutlinePaint() { return useOutlinePaint; } public void setUseOutlinePaint(boolean flag) { this.useOutlinePaint = flag; } public boolean isDrawFilledArea() { return drawFilledArea; } public void setDrawFilledArea(boolean drawFilledArea) { this.drawFilledArea = drawFilledArea; } public Boolean getSeriesLinesVisible(int series) { return seriesLinesVisible.get(series); } public void setSeriesLinesVisible(int series, Boolean flag) { seriesLinesVisible.put(series, flag); } public void setSeriesLinesVisible(int series, boolean visible) { setSeriesLinesVisible(series, BooleanUtilities.valueOf(visible)); } public Boolean getSeriesShapesVisible(int series) { return seriesShapesVisible.get(series); } public void setSeriesShapesVisible(int series, boolean visible) { setSeriesShapesVisible(series, BooleanUtilities.valueOf(visible)); } public void setSeriesShapesVisible(int series, Boolean flag) { seriesShapesVisible.put(series, flag); } public Boolean getSeriesShapesFilled(int series) { return seriesShapesFilled.get(series); } public void setSeriesShapesFilled(int series, boolean filled) { seriesShapesFilled.put(series, filled); } public void setSeriesShapesFilled(int series, Boolean filled) { seriesShapesFilled.put(series, filled); } public boolean getBaseLinesVisible() { return baseLinesVisible; } public void setBaseLinesVisible(boolean flag) { this.baseLinesVisible = flag; } public boolean getBaseShapesVisible() { return baseShapesVisible; } public void setBaseShapesVisible(boolean flag) { this.baseShapesVisible = flag; } public boolean getBaseShapesFilled() { return baseShapesFilled; } public void setBaseShapesFilled(boolean flag) { this.baseShapesFilled = flag; } public boolean getItemShapeFilled(int series, int item) { final Boolean shapesFilled = getSeriesShapesFilled(series); return shapesFilled != null ? shapesFilled : getBaseShapesFilled(); } public boolean getItemLineVisible(int series, int item) { final Boolean linesVisible = getSeriesLinesVisible(series); return linesVisible != null ? linesVisible : getBaseLinesVisible(); } public boolean getItemShapeVisible(int series, int item) { final Boolean shapesVisible = getSeriesShapesVisible(series); return shapesVisible != null ? shapesVisible : getBaseShapesVisible(); } @Override public Paint getItemOutlinePaint(int row, int column) { final Paint itemOutlinePaint = delegate.getItemOutlinePaint(row, column); if (itemOutlinePaint != null) { return itemOutlinePaint; } return super.getItemOutlinePaint(row, column); } @Override public Stroke getItemOutlineStroke(int row, int column) { final Stroke outlineStroke = delegate.getItemOutlineStroke(row, column); if (outlineStroke != null) { return outlineStroke; } return super.getItemOutlineStroke(row, column); } @Override public Paint getItemPaint(int row, int column) { final Paint itemPaint = delegate.getItemPaint(row, column); if (itemPaint != null) { return itemPaint; } return super.getItemPaint(row, column); } public void setItemOutlinePaint(int row, int column, Paint paint) { delegate.setItemOutlinePaint(row, column, paint); } public void setItemOutlineStroke(int row, int column, Stroke stroke) { delegate.setItemOutlineStroke(row, column, stroke); } public void setItemPaint(int row, int column, Paint paint) { delegate.setItemPaint(row, column, paint); } public void addConfigurator(RendererConfigurator configurator) { configurationDelegate.addConfigurator(configurator); } public Collection<RendererConfigurator> getConfigurators() { return configurationDelegate.getConfigurators(); } public void configure(ChartView chartView) { configurationDelegate.configure(chartView, this); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; XYLineFillRenderer that = (XYLineFillRenderer) o; if (baseLinesVisible != that.baseLinesVisible) return false; if (baseShapesFilled != that.baseShapesFilled) return false; if (baseShapesVisible != that.baseShapesVisible) return false; if (drawFilledArea != that.drawFilledArea) return false; if (drawOutlines != that.drawOutlines) return false; if (useFillPaint != that.useFillPaint) return false; if (useOutlinePaint != that.useOutlinePaint) return false; if (backgroundPaint != null ? !backgroundPaint.equals(that.backgroundPaint) : that.backgroundPaint != null) return false; if (delegate != null ? !delegate.equals(that.delegate) : that.delegate != null) return false; if (lineAreaFill != null ? !lineAreaFill.equals(that.lineAreaFill) : that.lineAreaFill != null) return false; if (seriesLinesVisible != null ? !seriesLinesVisible.equals(that.seriesLinesVisible) : that.seriesLinesVisible != null) return false; if (seriesShapesFilled != null ? !seriesShapesFilled.equals(that.seriesShapesFilled) : that.seriesShapesFilled != null) return false; if (seriesShapesVisible != null ? !seriesShapesVisible.equals(that.seriesShapesVisible) : that.seriesShapesVisible != null) return false; return true; } @Override public int hashCode() { int result = super.hashCode(); result = 31 * result + (delegate != null ? delegate.hashCode() : 0); result = 31 * result + (seriesShapesVisible != null ? seriesShapesVisible.hashCode() : 0); result = 31 * result + (seriesLinesVisible != null ? seriesLinesVisible.hashCode() : 0); result = 31 * result + (seriesShapesFilled != null ? seriesShapesFilled.hashCode() : 0); result = 31 * result + (baseShapesVisible ? 1 : 0); result = 31 * result + (baseLinesVisible ? 1 : 0); result = 31 * result + (baseShapesFilled ? 1 : 0); result = 31 * result + (useFillPaint ? 1 : 0); result = 31 * result + (useOutlinePaint ? 1 : 0); result = 31 * result + (drawFilledArea ? 1 : 0); result = 31 * result + (drawOutlines ? 1 : 0); result = 31 * result + (backgroundPaint != null ? backgroundPaint.hashCode() : 0); result = 31 * result + (lineAreaFill != null ? lineAreaFill.hashCode() : 0); return result; } }