Mercurial > dive4elements > river
diff artifacts/src/main/java/org/dive4elements/river/jfree/EnhancedLineAndShapeRenderer.java @ 9186:eec4df8165a1
Implemented 'ShowLineLabel' for area themes.
author | gernotbelger |
---|---|
date | Thu, 28 Jun 2018 10:47:04 +0200 |
parents | 5e38e2924c07 |
children |
line wrap: on
line diff
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/EnhancedLineAndShapeRenderer.java Thu Jun 28 10:47:00 2018 +0200 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/EnhancedLineAndShapeRenderer.java Thu Jun 28 10:47:04 2018 +0200 @@ -45,8 +45,7 @@ private static final long serialVersionUID = 1L; /** Own log. */ - private static final Logger log = - Logger.getLogger(EnhancedLineAndShapeRenderer.class); + private static final Logger log = Logger.getLogger(EnhancedLineAndShapeRenderer.class); protected BooleanList isMinimumShapeVisible; protected BooleanList isMaximumShapeVisible; @@ -61,95 +60,85 @@ protected BooleanList showLineLabelBG; protected Map<Integer, Color> lineLabelBGColors; - - public EnhancedLineAndShapeRenderer(boolean lines, boolean shapes) { + public EnhancedLineAndShapeRenderer(final boolean lines, final boolean shapes) { super(lines, shapes); this.isMinimumShapeVisible = new BooleanList(); this.isMaximumShapeVisible = new BooleanList(); - this.showLineLabel = new BooleanList(); - this.showLineLabelBG = new BooleanList(); - this.seriesMinimum = new HashMap<Integer, Double>(); - this.seriesMaximum = new HashMap<Integer, Double>(); - this.seriesMinimumX = new HashMap<Integer, Double>(); - this.lineLabelFonts = new HashMap<Integer, Font>(); - this.lineLabelTextColors = new HashMap<Integer, Color>(); - this.lineLabelBGColors = new HashMap<Integer, Color>(); + this.showLineLabel = new BooleanList(); + this.showLineLabelBG = new BooleanList(); + this.seriesMinimum = new HashMap<>(); + this.seriesMaximum = new HashMap<>(); + this.seriesMinimumX = new HashMap<>(); + this.lineLabelFonts = new HashMap<>(); + this.lineLabelTextColors = new HashMap<>(); + this.lineLabelBGColors = new HashMap<>(); } - /** * Draw a background-box of a text to render. - * @param g2 graphics device to use - * @param text text to draw - * @param textX x-position for text - * @param textY y-position for text - * @param bgColor color to fill box with. + * + * @param g2 + * graphics device to use + * @param text + * text to draw + * @param textX + * x-position for text + * @param textY + * y-position for text + * @param bgColor + * color to fill box with. */ - public static void drawTextBox(Graphics2D g2, - String text, float textX, float textY, Color bgColor - ) { - Rectangle2D hotspotBox = g2.getFontMetrics().getStringBounds(text, g2); - float w = (float)hotspotBox.getWidth(); - float h = (float)hotspotBox.getHeight(); - hotspotBox.setRect(textX, textY-h, w, h); - Color oldColor = g2.getColor(); + public static void drawTextBox(final Graphics2D g2, final String text, final float textX, final float textY, final Color bgColor) { + final Rectangle2D hotspotBox = g2.getFontMetrics().getStringBounds(text, g2); + final float w = (float) hotspotBox.getWidth(); + final float h = (float) hotspotBox.getHeight(); + hotspotBox.setRect(textX, textY - h, w, h); + final Color oldColor = g2.getColor(); g2.setColor(bgColor); g2.fill(hotspotBox); g2.setColor(oldColor); } - /** * Whether or not a specific item in a series (maybe the maxima) should * be rendered with shape. */ - public boolean getItemShapeVisible( - XYDataset dataset, - int series, - int item - ){ + private boolean getItemShapeVisible(final XYDataset dataset, final int series, final int item) { if (super.getItemShapeVisible(series, item)) { return true; } - if (isMinimumShapeVisible(series) - && isMinimum(dataset, series, item) - ) { + if (isMinimumShapeVisible(series) && isMinimum(dataset, series, item)) { return true; } - if (isMaximumShapeVisible(series) - && isMaximum(dataset, series, item) - ) { + if (isMaximumShapeVisible(series) && isMaximum(dataset, series, item)) { return true; } return false; } - /** * Rectangle used to draw maximums shape. */ - public Shape getMaximumShape(int series, int column) { + private Shape getMaximumShape(final int series, final int column) { return new Rectangle2D.Double(-5d, -5d, 10d, 10d); } - /** * Rectangle used to draw minimums shape. */ - public Shape getMinimumShape(int series, int column) { + private Shape getMinimumShape(final int series, final int column) { return new Rectangle2D.Double(-5d, -5d, 10d, 10d); } - /** Get fill paint for the maximum indicators. */ - public Paint getMaximumFillPaint(int series, int column) { - Paint p = getItemPaint(series, column); + private Paint getMaximumFillPaint(final int series, final int column) { + final Paint p = getItemPaint(series, column); if (p instanceof Color) { - Color c = (Color) p; + final Color c = (Color) p; Color b = c; for (int i = 0; i < 2; i++) { @@ -163,13 +152,12 @@ return p; } - /** Get fill paint for the minimum indicators. */ - public Paint getMinimumFillPaint(int series, int column) { - Paint p = getItemPaint(series, column); + private Paint getMinimumFillPaint(final int series, final int column) { + final Paint p = getItemPaint(series, column); if (p instanceof Color) { - Color c = (Color) p; + final Color c = (Color) p; Color b = c; for (int i = 0; i < 2; i++) { @@ -183,82 +171,63 @@ return p; } - /** * Overrides XYLineAndShapeRenderer.drawSecondaryPass() to call an adapted * method getItemShapeVisible() which now takes an XYDataset. So, 99% of * code equal the code in XYLineAndShapeRenderer. */ @Override - protected void drawSecondaryPass( - Graphics2D g2, - XYPlot plot, - XYDataset dataset, - int pass, - int series, - int item, - ValueAxis domainAxis, - Rectangle2D dataArea, - ValueAxis rangeAxis, - CrosshairState crosshairState, - EntityCollection entities - ) { + protected void drawSecondaryPass(final Graphics2D g2, final XYPlot plot, final XYDataset dataset, final int pass, final int series, final int item, + final ValueAxis domainAxis, final Rectangle2D dataArea, final ValueAxis rangeAxis, final CrosshairState crosshairState, + final EntityCollection entities) { Shape entityArea = null; // get the data point... - double x1 = dataset.getXValue(series, item); - double y1 = dataset.getYValue(series, item); + final double x1 = dataset.getXValue(series, item); + final double y1 = dataset.getYValue(series, item); if (Double.isNaN(y1) || Double.isNaN(x1)) { return; } - PlotOrientation orientation = plot.getOrientation(); - RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); - RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); - double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); - double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); + final PlotOrientation orientation = plot.getOrientation(); + final RectangleEdge xAxisLocation = plot.getDomainAxisEdge(); + final RectangleEdge yAxisLocation = plot.getRangeAxisEdge(); + final double transX1 = domainAxis.valueToJava2D(x1, dataArea, xAxisLocation); + final double transY1 = rangeAxis.valueToJava2D(y1, dataArea, yAxisLocation); if (getItemShapeVisible(dataset, series, item)) { Shape shape = null; // OPTIMIZE: instead of calculating minimum and maximum for every - // point, calculate it just once (assume that dataset - // content does not change during rendering). - // NOTE: Above OPTIMIZE might already be fulfilled to - // most extend. - boolean isMinimum = isMinimumShapeVisible(series) - && isMinimum(dataset, series, item); + // point, calculate it just once (assume that dataset + // content does not change during rendering). + // NOTE: Above OPTIMIZE might already be fulfilled to + // most extend. + final boolean isMinimum = isMinimumShapeVisible(series) && isMinimum(dataset, series, item); - boolean isMaximum = isMaximumShapeVisible(series) - && isMaximum(dataset, series, item); + final boolean isMaximum = isMaximumShapeVisible(series) && isMaximum(dataset, series, item); if (isMinimum) { log.debug("Create a Minimum shape."); shape = getMinimumShape(series, item); - } - else if (isMaximum) { + } else if (isMaximum) { log.debug("Create a Maximum shape."); shape = getMaximumShape(series, item); - } - else { + } else { shape = getItemShape(series, item); } if (orientation == PlotOrientation.HORIZONTAL) { - shape = ShapeUtilities.createTranslatedShape(shape, transY1, - transX1); - } - else if (orientation == PlotOrientation.VERTICAL) { - shape = ShapeUtilities.createTranslatedShape(shape, transX1, - transY1); + shape = ShapeUtilities.createTranslatedShape(shape, transY1, transX1); + } else if (orientation == PlotOrientation.VERTICAL) { + shape = ShapeUtilities.createTranslatedShape(shape, transX1, transY1); } entityArea = shape; if (shape.intersects(dataArea)) { if (getItemShapeFilled(series, item)) { if (getUseFillPaint()) { g2.setPaint(getItemFillPaint(series, item)); - } - else { + } else { g2.setPaint(getItemPaint(series, item)); } g2.fill(shape); @@ -266,8 +235,7 @@ if (getDrawOutlines()) { if (getUseOutlinePaint()) { g2.setPaint(getItemOutlinePaint(series, item)); - } - else { + } else { g2.setPaint(getItemPaint(series, item)); } g2.setStroke(getItemOutlineStroke(series, item)); @@ -280,8 +248,7 @@ g2.setPaint(getItemOutlinePaint(series, item)); g2.setStroke(getItemOutlineStroke(series, item)); g2.draw(shape); - } - else if (isMaximum) { + } else if (isMaximum) { g2.setPaint(getMaximumFillPaint(series, item)); g2.fill(shape); g2.setPaint(getItemOutlinePaint(series, item)); @@ -299,78 +266,27 @@ } // Draw the item label if there is one... - if (isItemLabelVisible(series, item)) { - drawItemLabel(g2, orientation, dataset, series, item, xx, yy, - (y1 < 0.0)); - } + if (isItemLabelVisible(series, item)) + drawItemLabel(g2, orientation, dataset, series, item, xx, yy, (y1 < 0.0)); // Draw label of line. - if (dataset instanceof XYSeriesCollection - && isShowLineLabel(series) - && isMinimumX (dataset, series, item) - ) { - XYSeries xYSeries = ((XYSeriesCollection)dataset) - .getSeries(series); - String waterlevelLabel = (xYSeries instanceof HasLabel) - ? ((HasLabel)xYSeries).getLabel() - : xYSeries.getKey().toString(); + if (dataset instanceof XYSeriesCollection && isShowLineLabel(series) && isMinimumX(dataset, series, item)) { + final XYSeries xYSeries = ((XYSeriesCollection) dataset).getSeries(series); + final String waterlevelLabel = (xYSeries instanceof HasLabel) ? ((HasLabel) xYSeries).getLabel() : xYSeries.getKey().toString(); // TODO Force water of some German rivers to flow // direction mountains. - Font oldFont = g2.getFont(); - - Color oldColor = g2.getColor(); - g2.setFont(this.getLineLabelFont(series)); - g2.setColor(this.getLineLabelTextColor(series)); - g2.setBackground(Color.black); - - // Try to always display label if the data is visible. - if (!isPointInRect(dataArea, xx, yy)) { - // Move into the data area. - xx = Math.max(xx, dataArea.getMinX()); - xx = Math.min(xx, dataArea.getMaxX()); - yy = Math.max(yy, dataArea.getMinY()); - yy = Math.min(yy, dataArea.getMaxY()); - } + final Font labelFont = this.getLineLabelFont(series); + final Color labelColor = this.getLineLabelTextColor(series); + final boolean showBG = isShowLineLabelBG(series); + final Color bgColor = getLineLabelBGColor(series); - // Move to right until no collisions exist anymore - Shape hotspot = TextUtilities.calculateRotatedStringBounds( - waterlevelLabel, g2, (float)xx, (float)yy-3f, - TextAnchor.CENTER_LEFT, - 0f, TextAnchor.CENTER_LEFT); - while (JFreeUtil.collides(hotspot, entities, - CollisionFreeLineLabelEntity.class)) { - xx += 5f; - hotspot = TextUtilities.calculateRotatedStringBounds( - waterlevelLabel, - g2, - (float)xx, - (float)yy-3f, - TextAnchor.CENTER_LEFT, - 0f, - TextAnchor.CENTER_LEFT); - } - - // Register to avoid collissions. - entities.add(new CollisionFreeLineLabelEntity(hotspot, - 1, "", "")); - - // Fill background. - if (isShowLineLabelBG(series)) { - drawTextBox(g2, waterlevelLabel, (float)xx, (float)yy-3f, - getLineLabelBGColor(series)); - } - - g2.drawString(waterlevelLabel, (float)xx, (float)yy-3f); - - g2.setFont(oldFont); - g2.setColor(oldColor); + drawLineLabel(g2, dataArea, entities, xx, yy, labelFont, labelColor, showBG, bgColor, waterlevelLabel); } - int domainAxisIndex = plot.getDomainAxisIndex(domainAxis); - int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis); - updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex, - rangeAxisIndex, transX1, transY1, orientation); + final int domainAxisIndex = plot.getDomainAxisIndex(domainAxis); + final int rangeAxisIndex = plot.getRangeAxisIndex(rangeAxis); + updateCrosshairValues(crosshairState, x1, y1, domainAxisIndex, rangeAxisIndex, transX1, transY1, orientation); // Add an entity for the item, but only if it falls within the data // area... @@ -379,77 +295,115 @@ } } + public static void drawLineLabel(final Graphics2D g2, final Rectangle2D dataArea, final EntityCollection entities, final double labelX, final double labelY, + final Font font, + final Color fgColor, + final boolean showBG, final Color bgColor, final String label) { + + final Font oldFont = g2.getFont(); + final Color oldColor = g2.getColor(); + + g2.setFont(font); + g2.setColor(fgColor); + g2.setBackground(Color.black); + + // Try to always display label if the data is visible. + double posX = labelX; + double posY = labelY; + if (!isPointInRect(dataArea, posX, posY)) { + // Move into the data area. + posX = Math.max(posX, dataArea.getMinX()); + posX = Math.min(posX, dataArea.getMaxX()); + posY = Math.max(posY, dataArea.getMinY()); + posY = Math.min(posY, dataArea.getMaxY()); + } + + // Move to right until no collisions exist anymore + Shape hotspot = TextUtilities.calculateRotatedStringBounds(label, g2, (float) posX, (float) posY - 3f, TextAnchor.CENTER_LEFT, 0f, + TextAnchor.CENTER_LEFT); + while (JFreeUtil.collides(hotspot, entities, CollisionFreeLineLabelEntity.class)) { + posX += 5f; + hotspot = TextUtilities.calculateRotatedStringBounds(label, g2, (float) posX, (float) posY - 3f, TextAnchor.CENTER_LEFT, 0f, + TextAnchor.CENTER_LEFT); + } + + // Register to avoid collissions. + entities.add(new CollisionFreeLineLabelEntity(hotspot, 1, "", "")); + + // Fill background. + if (showBG) + drawTextBox(g2, label, (float) posX, (float) posY - 3f, bgColor); + + g2.drawString(label, (float) posX, (float) posY - 3f); + + g2.setFont(oldFont); + g2.setColor(oldColor); + } /** * Sets whether or not the minimum should be rendered with shape. */ - public void setIsMinimumShapeVisisble(int series, boolean isVisible) { + public void setIsMinimumShapeVisisble(final int series, final boolean isVisible) { this.isMinimumShapeVisible.setBoolean(series, isVisible); } - /** * Whether or not the minimum should be rendered with shape. */ - public boolean isMinimumShapeVisible(int series) { + private boolean isMinimumShapeVisible(final int series) { if (this.isMinimumShapeVisible.size() <= series) { return false; } - return isMinimumShapeVisible.getBoolean(series); + return this.isMinimumShapeVisible.getBoolean(series); } - /** * Sets whether or not the maximum should be rendered with shape. */ - public void setIsMaximumShapeVisible(int series, boolean isVisible) { + public void setIsMaximumShapeVisible(final int series, final boolean isVisible) { this.isMaximumShapeVisible.setBoolean(series, isVisible); } - /** * Whether or not the maximum should be rendered with shape. */ - public boolean isMaximumShapeVisible(int series) { + private boolean isMaximumShapeVisible(final int series) { if (this.isMaximumShapeVisible.size() <= series) { return false; } - return isMaximumShapeVisible.getBoolean(series); + return this.isMaximumShapeVisible.getBoolean(series); } /** Whether or not a label should be shown for series. */ - public boolean isShowLineLabel(int series) { + private boolean isShowLineLabel(final int series) { if (this.showLineLabel.size() <= series) { return false; } - return showLineLabel.getBoolean(series); + return this.showLineLabel.getBoolean(series); } - /** Sets whether or not a label should be shown for series. */ - public void setShowLineLabel(boolean showLineLabel, int series) { + public void setShowLineLabel(final boolean showLineLabel, final int series) { this.showLineLabel.setBoolean(series, showLineLabel); } - /** Whether or not a label should be shown for series. */ - public boolean isShowLineLabelBG(int series) { + private boolean isShowLineLabelBG(final int series) { if (this.showLineLabelBG.size() <= series) { return false; } - return showLineLabelBG.getBoolean(series); + return this.showLineLabelBG.getBoolean(series); } - - public void setShowLineLabelBG(int series, boolean doShow) { + public void setShowLineLabelBG(final int series, final boolean doShow) { this.showLineLabelBG.setBoolean(series, doShow); } - public Color getLineLabelBGColor(int series) { + private Color getLineLabelBGColor(final int series) { if (this.lineLabelBGColors.size() <= series) { return null; } @@ -457,11 +411,11 @@ return this.lineLabelBGColors.get(series); } - public void setLineLabelBGColor(int series, Color color) { + public void setLineLabelBGColor(final int series, final Color color) { this.lineLabelBGColors.put(series, color); } - public Color getLineLabelTextColor(int series) { + private Color getLineLabelTextColor(final int series) { if (this.lineLabelTextColors.size() <= series) { return null; } @@ -469,35 +423,33 @@ return this.lineLabelTextColors.get(series); } - public void setLineLabelTextColor(int series, Color color) { + public void setLineLabelTextColor(final int series, final Color color) { this.lineLabelTextColors.put(series, color); } - public void setLineLabelFont(Font font, int series) { + public void setLineLabelFont(final Font font, final int series) { this.lineLabelFonts.put(series, font); } - public Font getLineLabelFont(int series) { + private Font getLineLabelFont(final int series) { return this.lineLabelFonts.get(series); } - /** * True if the given item of given dataset has the smallest * X value within this set. */ - public boolean isMinimumX(XYDataset dataset, int series, int item) { + private boolean isMinimumX(final XYDataset dataset, final int series, final int item) { return dataset.getXValue(series, item) == getMinimumX(dataset, series); } - /** * Get Minimum X Value of a given series in a dataset. * The value is stored for later use if queried the first time. */ - public double getMinimumX(XYDataset dataset, int series) { - Integer key = Integer.valueOf(series); - Double old = seriesMinimumX.get(key); + private double getMinimumX(final XYDataset dataset, final int series) { + final Integer key = Integer.valueOf(series); + final Double old = this.seriesMinimumX.get(key); if (old != null) { return old.doubleValue(); @@ -508,35 +460,33 @@ double min = Double.MAX_VALUE; for (int i = 0, n = dataset.getItemCount(series); i < n; i++) { - double tmpValue = dataset.getXValue(series, i); + final double tmpValue = dataset.getXValue(series, i); if (tmpValue < min) { min = tmpValue; } } - seriesMinimumX.put(key, Double.valueOf(min)); + this.seriesMinimumX.put(key, Double.valueOf(min)); return min; } - /** * True if the given item of given dataset has the smallest * Y value within this set. */ - public boolean isMinimum(XYDataset dataset, int series, int item) { + private boolean isMinimum(final XYDataset dataset, final int series, final int item) { return dataset.getYValue(series, item) == getMinimum(dataset, series); } - /** * Get Minimum Y Value of a given series in a dataset. * The value is stored for later use if queried the first time. */ - public double getMinimum(XYDataset dataset, int series) { - Integer key = Integer.valueOf(series); - Double old = seriesMinimum.get(key); + private double getMinimum(final XYDataset dataset, final int series) { + final Integer key = Integer.valueOf(series); + final Double old = this.seriesMinimum.get(key); if (old != null) { return old.doubleValue(); @@ -547,35 +497,33 @@ double min = Double.MAX_VALUE; for (int i = 0, n = dataset.getItemCount(series); i < n; i++) { - double tmpValue = dataset.getYValue(series, i); + final double tmpValue = dataset.getYValue(series, i); if (tmpValue < min) { min = tmpValue; } } - seriesMinimum.put(key, Double.valueOf(min)); + this.seriesMinimum.put(key, Double.valueOf(min)); return min; } - /** * True if the given item of given dataset has the biggest * Y value within this set. */ - public boolean isMaximum(XYDataset dataset, int series, int item) { + private boolean isMaximum(final XYDataset dataset, final int series, final int item) { return dataset.getYValue(series, item) == getMaximum(dataset, series); } - /** * Get maximum Y Value of a given series in a dataset. * The value is stored for later use if queried the first time. */ - public double getMaximum(XYDataset dataset, int series) { - Integer key = Integer.valueOf(series); - Double old = seriesMaximum.get(key); + private double getMaximum(final XYDataset dataset, final int series) { + final Integer key = Integer.valueOf(series); + final Double old = this.seriesMaximum.get(key); if (old != null) { return old.doubleValue(); @@ -586,16 +534,15 @@ double max = -Double.MAX_VALUE; for (int i = 0, n = dataset.getItemCount(series); i < n; i++) { - double tmpValue = dataset.getYValue(series, i); + final double tmpValue = dataset.getYValue(series, i); if (tmpValue > max) { max = tmpValue; } } - seriesMaximum.put(key, Double.valueOf(max)); + this.seriesMaximum.put(key, Double.valueOf(max)); return max; } -} -// vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : +} \ No newline at end of file