Mercurial > dive4elements > river
changeset 8910:d9c89651bd67
Area chart layers may now have an 'arebgpattern'. Real pattern yet to be defined.
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/AreaFillPattern.java Thu Feb 22 18:46:37 2018 +0100 @@ -0,0 +1,75 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.jfree; + +import java.awt.Color; +import java.awt.image.BufferedImage; +import java.awt.image.BufferedImageOp; +import java.awt.image.LookupOp; +import java.io.IOException; + +import javax.imageio.ImageIO; + +import org.apache.log4j.Logger; + +/** + * Fill patterns for area styles. + * REMARK: if this enum is changed, probably the ui in StyleEditorWindow must be changed too + * + * @author Gernot Belger + */ +public enum AreaFillPattern { + + pattern1("/images/areapatterns/pattern1.png"); + + private static Logger log = Logger.getLogger(AreaFillPattern.class); + + private static final BufferedImage MISSING_IMAGE = new BufferedImage(16, 16, BufferedImage.TYPE_INT_RGB); + + private final String imagePath; + + private BufferedImage image = null; + + AreaFillPattern(final String imagePath) { + this.imagePath = imagePath; + } + + public BufferedImage getImage(final Color color) { + + if (this.image == null) + this.image = loadImage(); + + if (color == null) + return this.image; + + /* + * apply color and transparency, the .png must be encoded as 32bit images (rgba), with only black as non transparent + * color + */ + final int numComponents = this.image.getColorModel().getNumComponents(); + if (numComponents != 4) { + log.warn(String.format("Pattern image must be a 32bit image (rgba): %s", this.imagePath)); + return this.image; + } + + final BufferedImageOp lookup = new LookupOp(new ColorMapper(Color.black, color), null); + return lookup.filter(this.image, null); + } + + private BufferedImage loadImage() { + try { + return ImageIO.read(getClass().getResource(this.imagePath)); + } + catch (final IOException e) { + log.error(String.format("failed ot load pattern: %s", this.imagePath), e); + return MISSING_IMAGE; + } + } +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/ColorMapper.java Thu Feb 22 18:46:37 2018 +0100 @@ -0,0 +1,43 @@ +/** Copyright (C) 2017 by Bundesanstalt für Gewässerkunde + * Software engineering by + * Björnsen Beratende Ingenieure GmbH + * Dr. Schumacher Ingenieurbüro für Wasser und Umwelt + * + * This file is Free Software under the GNU AGPL (>=v3) + * and comes with ABSOLUTELY NO WARRANTY! Check out the + * documentation coming with Dive4Elements River for details. + */ +package org.dive4elements.river.jfree; + +import java.awt.Color; +import java.awt.image.LookupTable; + +final class ColorMapper extends LookupTable { + + private final int[] from; + private final int[] to; + + public ColorMapper(final Color from, final Color to) { + super(0, 4); + + this.from = new int[] { from.getRed(), from.getGreen(), from.getBlue(), from.getAlpha(), }; + this.to = new int[] { to.getRed(), to.getGreen(), to.getBlue(), to.getAlpha(), }; + } + + @Override + public int[] lookupPixel(final int[] src, final int[] dest) { + final int[] out = dest == null ? new int[src.length] : dest; + + // REMARK: only compare rgb, so we even keep the transparency level + if (src[0] == this.from[0] && src[1] == this.from[1] && src[2] == this.from[2]) { + out[0] = this.to[0]; + out[1] = this.to[1]; + out[2] = this.to[2]; + out[2] = src[3]; + } else { + System.arraycopy(src, 0, out, 0, src.length); + } + + return out; + } +} \ No newline at end of file
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StableXYDifferenceRenderer.java Thu Feb 22 18:44:28 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StableXYDifferenceRenderer.java Thu Feb 22 18:46:37 2018 +0100 @@ -407,9 +407,6 @@ * @see #getPositivePaint() */ public void setPositivePaint(Paint paint) { - if (paint == null) { - throw new IllegalArgumentException("Null 'paint' argument."); - } this.positivePaint = paint; fireChangeEvent(); } @@ -433,9 +430,6 @@ * @see #getNegativePaint() */ public void setNegativePaint(Paint paint) { - if (paint == null) { - throw new IllegalArgumentException("Null 'paint' argument."); - } this.negativePaint = paint; notifyListeners(new RendererChangeEvent(this)); } @@ -1774,9 +1768,13 @@ } if (l_path.intersects(x_dataArea)) { - x_graphics.setPaint(x_positive ? getPositivePaint() - : getNegativePaint()); + + final Paint paint = x_positive ? getPositivePaint(): getNegativePaint(); + if( paint != null ) { + x_graphics.setPaint(paint); x_graphics.fill(l_path); + } + if (drawOutline) { x_graphics.setStroke(this.outlineStroke); x_graphics.setPaint(this.outlinePaint);
--- a/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java Thu Feb 22 18:44:28 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/jfree/StyledAreaSeriesCollection.java Thu Feb 22 18:46:37 2018 +0100 @@ -10,7 +10,12 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Paint; import java.awt.Stroke; +import java.awt.TexturePaint; +import java.awt.geom.Ellipse2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.BufferedImage; import org.jfree.data.xy.XYSeriesCollection; @@ -23,6 +28,7 @@ * The display options can be used to control the z-order and the axis of the * dataset. */ +// FIXME: bad abstraction: the only purpose of this derivation is to apply specific styles. This should rather be solved similar to the XYSTyle. public class StyledAreaSeriesCollection extends XYSeriesCollection { private static final long serialVersionUID = 5274940965666948237L; @@ -71,6 +77,7 @@ applyOutlineStyle(renderer); applyShowLine(renderer); applyShowAreaLabel(renderer); + applyPointStyle(renderer); if (mode == FILL_MODE.UNDER) { renderer.setAreaCalculationMode( StableXYDifferenceRenderer.CALCULATE_NEGATIVE_AREA); @@ -89,19 +96,17 @@ return renderer; } - - private void applyFillColor(StableXYDifferenceRenderer renderer) { - Color paint = theme.parseAreaBackgroundColor(); - - int transparency = theme.parseAreaTransparency(); - if (transparency > 0 && paint != null) { - paint = new Color( - paint.getRed(), - paint.getGreen(), - paint.getBlue(), - (int)((100 - transparency) * 2.55f)); + private void applyFillColor(final StableXYDifferenceRenderer renderer) { + + final boolean showArea = theme.parseShowArea(); + if( !showArea ) { + renderer.setPositivePaint(null); + renderer.setNegativePaint(null); + return; } + Paint paint = parseFillPaint(); + if (paint != null && this.getMode() == FILL_MODE.ABOVE) { renderer.setPositivePaint(paint); renderer.setNegativePaint(new Color(0,0,0,0)); @@ -113,11 +118,40 @@ else { if (paint == null) paint = new Color(177, 117, 102); + renderer.setPositivePaint(paint); renderer.setNegativePaint(paint); } } + private Paint parseFillPaint() { + final Color paint = this.theme.parseAreaBackgroundColor(); + final int transparency = theme.parseAreaTransparency(); + + final Color alphaPaint = withAlpha(paint, transparency); + + final AreaFillPattern pattern = this.theme.parseAreaBackgroundPattern(); + + if( pattern == null ) + return alphaPaint; + + final BufferedImage image = pattern.getImage(alphaPaint); + + final Rectangle2D anchor = new Rectangle2D.Double(0,0, image.getWidth(), image.getHeight()); + return new TexturePaint(image, anchor); + } + + private Color withAlpha(final Color color, final int transparency) { + + if (transparency <= 0 || color == null) + return color; + + return new Color( + color.getRed(), + color.getGreen(), + color.getBlue(), + (int)((100 - transparency) * 2.55f)); + } private void applyShowShape(StableXYDifferenceRenderer renderer) { boolean show = theme.parseAreaShowBorder(); @@ -126,7 +160,9 @@ private void applyShowLine(StableXYDifferenceRenderer renderer) { - boolean show = theme.parseShowLine(); + /* FIXME: strange: this will enable/disable showing the 'point' shapes at each vertex. */ + /* FIXME: this will also now be overridden by the option 'showpoints' */ + final boolean show = theme.parseShowLine(); renderer.setShapesVisible(show); } @@ -161,6 +197,27 @@ renderer.setOutlineStroke(stroke); } + private void applyPointStyle(final StableXYDifferenceRenderer renderer) { + + final boolean showPoints = this.theme.parseShowPoints(); + renderer.setShapesVisible(showPoints); + + if( showPoints ) + { + final int size = theme.parsePointWidth(); + final int dim = 2 * size; + + final Ellipse2D pointShape = new Ellipse2D.Double(-size, -size, dim, dim); + final Color pointColor = theme.parsePointColor(); + + renderer.setSeriesPaint(0, pointColor); + renderer.setSeriesPaint(1, pointColor); + + renderer.setSeriesShape(0, pointShape); + renderer.setSeriesShape(1, pointShape); + } + } + public boolean shouldCalculateRange() { return theme.parseCalculateRange(); }
--- a/artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java Thu Feb 22 18:44:28 2018 +0100 +++ b/artifacts/src/main/java/org/dive4elements/river/themes/ThemeDocument.java Thu Feb 22 18:46:37 2018 +0100 @@ -13,6 +13,7 @@ import java.util.HashMap; import java.util.Map; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import org.dive4elements.artifacts.CallMeta; import org.dive4elements.river.artifacts.model.MapserverStyle; @@ -21,6 +22,7 @@ import org.dive4elements.river.artifacts.model.MapserverStyle.Label; import org.dive4elements.river.artifacts.model.MapserverStyle.Style; import org.dive4elements.river.artifacts.resources.Resources; +import org.dive4elements.river.jfree.AreaFillPattern; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; @@ -102,6 +104,8 @@ public final static String AREA_BACKGROUND_COLOR = "areabgcolor"; + private static final String AREA_BACKGROUND_PATTERN = "areabgpattern"; + public final static String SYMBOL = "symbol"; public final static String SHOW_MINIMUM = "showminimum"; @@ -825,5 +829,19 @@ private String getCalculateRangeString() { return getValue(CALCULATE_RANGE); } + + public AreaFillPattern parseAreaBackgroundPattern() { + final String patternName = getValue(AREA_BACKGROUND_PATTERN); + if( StringUtils.isBlank(patternName) ) + return null; + + try { + return AreaFillPattern.valueOf(patternName); + } + catch (Exception e) { + log.error(String.format("%s: invalid pattern name: %s", AREA_BACKGROUND_PATTERN, patternName), e); + return null; + } + } } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 :
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Thu Feb 22 18:44:28 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.java Thu Feb 22 18:46:37 2018 +0100 @@ -1178,6 +1178,8 @@ String areabgcolor(); + String areabgpattern(); + String areashowborder(); String areashowbg(); @@ -1423,13 +1425,17 @@ String error_no_sedimentloadinfo_data(); String sinfo(); - + String sinfo_flowdepth_export(); String sinfo_flowdepth_report(); String sinfo_flow_depth(); - String sinfo_flowdepth_twinpanel_no_pair_selected(); + String sinfo_flowdepth_twinpanel_no_pair_selected(); + + String sinfo_flow_depths(); + + String sinfo_tkhs(); } // vim:set ts=4 sw=4 si et sta sts=4 fenc=utf8 : \ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Thu Feb 22 18:44:28 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants.properties Thu Feb 22 18:46:37 2018 +0100 @@ -636,6 +636,7 @@ showmiddleheight = Show middle depth fillcolor = Fill Color areabgcolor = Fill Color +areabgpattern = Fill Pattern areashowborder = Show area border areashowbg = Show area background areabordercolor = Border color @@ -761,4 +762,6 @@ sinfo_flowdepth_export = Flie\u00dftiefen Export sinfo_flowdepth_report = Flie\u00dftiefen Bericht sinfo_flow_depth = Flie\u00dftiefen -sinfo_flowdepth_twinpanel_no_pair_selected = Error - at least one input pair must be selected \ No newline at end of file +sinfo_flowdepth_twinpanel_no_pair_selected = Error - at least one input pair must be selected +sinfo_flow_depths = Flie\u00dftiefen +sinfo_tkhs = Transportk\u00f6rperh\u00f6hen \ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Thu Feb 22 18:44:28 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_de.properties Thu Feb 22 18:46:37 2018 +0100 @@ -635,11 +635,12 @@ showborder = Linie anzeigen transparent = Transparent transparency = Transparenz -showarea = Show area +showarea = Fl\u00e4che anzeigen showarealabel = Fl\u00e4che beschriften showmiddleheight = Mittlere Tiefe anzeigen fillcolor = F\u00fcllfarbe areabgcolor = F\u00fcllfarbe +areabgpattern = Fl\u00e4chentyp areashowborder = Fl\u00e4chenumrandung areashowbg = Fl\u00e4chenhintergrund areabordercolor = Umrandungsfarbe @@ -753,4 +754,6 @@ sinfo_flowdepth_export = Flie\u00dftiefen Export sinfo_flowdepth_report = Flie\u00dftiefen Bericht sinfo_flow_depth = Flie\u00dftiefen -sinfo_flowdepth_twinpanel_no_pair_selected = Fehler - kein Paar zur Differenzenbildung gew\u00e4hlt. \ No newline at end of file +sinfo_flowdepth_twinpanel_no_pair_selected = Fehler - kein Paar zur Differenzenbildung gew\u00e4hlt. +sinfo_flow_depths = Flie\u00dftiefen +sinfo_tkhs = Transportk\u00f6rperh\u00f6hen \ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties Thu Feb 22 18:44:28 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/FLYSConstants_en.properties Thu Feb 22 18:46:37 2018 +0100 @@ -615,6 +615,7 @@ showmiddleheight = Show middle depth fillcolor = Fill Color areabgcolor = Fill Color +areabgpattern = Fill Pattern areashowborder = Show area border areashowbg = Show area background areabordercolor = Border color @@ -790,4 +791,6 @@ sinfo_flowdepth_export = Flie\u00dftiefen Export sinfo_flowdepth_report = Flie\u00dftiefen Bericht sinfo_flow_depth = Flie\u00dftiefen -sinfo_flowdepth_twinpanel_no_pair_selected = Error - at least one input pair must be selected \ No newline at end of file +sinfo_flowdepth_twinpanel_no_pair_selected = Error - at least one input pair must be selected +sinfo_flow_depths = Flie\u00dftiefen +sinfo_tkhs = Transportk\u00f6rperh\u00f6hen \ No newline at end of file
--- a/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/StyleEditorWindow.java Thu Feb 22 18:44:28 2018 +0100 +++ b/gwt-client/src/main/java/org/dive4elements/river/client/client/ui/StyleEditorWindow.java Thu Feb 22 18:46:37 2018 +0100 @@ -294,6 +294,7 @@ // Done via array to keep the order. String[] sets = {"showlines", + "showborder", "showpoints", "linetype", "linesize", @@ -372,6 +373,7 @@ * @return The dynamic form for the attribute property. */ protected DynamicForm createPropertyUI( + // FIXME: display name (which comes from the server side) is not used but i10n happens on client side,, String dname, String name, String type, @@ -535,6 +537,9 @@ f.setValueMap(valueMap); f.setValue(value); } + else if (type.equals("areapattern")) { + f = createAreaPetternUi(name, value); + } else if (type.equals("font")) { f = new SelectItem(name, MSG.getString(name)); LinkedHashMap<String, String> valueMap = @@ -587,6 +592,33 @@ } + private FormItem createAreaPetternUi(String name, String value) { + final FormItem f = new SelectItem(name, MSG.getString(name)); + + f.setImageURLPrefix(GWT.getHostPageBaseURL() + "images/areapattern-"); + f.setImageURLSuffix(".png"); + f.setValueIconHeight(20); + f.setValueIconWidth(80); + + final LinkedHashMap<String, String> valueMap = new LinkedHashMap<String, String>(); + final Map<String, String> valueIcons = new LinkedHashMap<String, String>(); + + // FIXME: ugly, using knowledge of available patterns at this point, creating redundancy with AreaFillPattern enum. + // But the whole code does it like that, so this is 'flys style' + final String[] patterns = new String[] {"pattern1", "x"}; + for (int i = 0; i < patterns.length; i++) { + final String pattern = patterns[i]; + + valueMap.put(pattern, ""); + valueIcons.put(pattern, pattern); + } + + f.setValueIcons(valueIcons); + f.setValueMap(valueMap); + f.setValue(value); + return f; + } + protected FormItem createLineSizeUI(FormItem f) { LinkedHashMap<String, String> valueIcons = new LinkedHashMap<String, String>();