comparison artifacts/src/main/java/org/dive4elements/river/exports/AbstractChartGenerator.java @ 9496:d8e753d0fdb9

stripedArea introduced for Assessment Scheme/Bewertungsschema
author gernotbelger
date Wed, 26 Sep 2018 15:48:05 +0200
parents 094ed9d1f2ad
children 853f2dafc16e
comparison
equal deleted inserted replaced
9495:bb278c927b66 9496:d8e753d0fdb9
10 package org.dive4elements.river.exports; 10 package org.dive4elements.river.exports;
11 11
12 import java.awt.BasicStroke; 12 import java.awt.BasicStroke;
13 import java.awt.Color; 13 import java.awt.Color;
14 import java.awt.Font; 14 import java.awt.Font;
15 import java.awt.Paint;
16 import java.awt.Stroke; 15 import java.awt.Stroke;
17 import java.awt.TexturePaint;
18 import java.awt.geom.Rectangle2D;
19 import java.awt.image.BufferedImage;
20 import java.io.IOException; 16 import java.io.IOException;
21 import java.io.OutputStream; 17 import java.io.OutputStream;
22 import java.text.DateFormat; 18 import java.text.DateFormat;
23 import java.util.ArrayList; 19 import java.util.ArrayList;
24 import java.util.Collection; 20 import java.util.Collection;
36 import org.apache.log4j.Logger; 32 import org.apache.log4j.Logger;
37 import org.dive4elements.artifactdatabase.CollectionCallContext; 33 import org.dive4elements.artifactdatabase.CollectionCallContext;
38 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet; 34 import org.dive4elements.artifactdatabase.state.ArtifactAndFacet;
39 import org.dive4elements.artifactdatabase.state.Settings; 35 import org.dive4elements.artifactdatabase.state.Settings;
40 import org.dive4elements.artifacts.Artifact; 36 import org.dive4elements.artifacts.Artifact;
41 import org.dive4elements.artifacts.ArtifactCollection;
42 import org.dive4elements.artifacts.ArtifactNamespaceContext; 37 import org.dive4elements.artifacts.ArtifactNamespaceContext;
43 import org.dive4elements.artifacts.CallContext; 38 import org.dive4elements.artifacts.CallContext;
44 import org.dive4elements.artifacts.CallMeta; 39 import org.dive4elements.artifacts.CallMeta;
45 import org.dive4elements.artifacts.PreferredLocale; 40 import org.dive4elements.artifacts.PreferredLocale;
46 import org.dive4elements.artifacts.common.utils.XMLUtils; 41 import org.dive4elements.artifacts.common.utils.XMLUtils;
54 import org.dive4elements.river.jfree.AxisDataset; 49 import org.dive4elements.river.jfree.AxisDataset;
55 import org.dive4elements.river.jfree.Bounds; 50 import org.dive4elements.river.jfree.Bounds;
56 import org.dive4elements.river.jfree.DoubleBounds; 51 import org.dive4elements.river.jfree.DoubleBounds;
57 import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer; 52 import org.dive4elements.river.jfree.EnhancedLineAndShapeRenderer;
58 import org.dive4elements.river.jfree.RiverAnnotation; 53 import org.dive4elements.river.jfree.RiverAnnotation;
59 import org.dive4elements.river.jfree.StableXYDifferenceRenderer;
60 import org.dive4elements.river.jfree.Style; 54 import org.dive4elements.river.jfree.Style;
61 import org.dive4elements.river.jfree.StyledAreaSeriesCollection;
62 import org.dive4elements.river.jfree.StyledSeries; 55 import org.dive4elements.river.jfree.StyledSeries;
56 import org.dive4elements.river.jfree.StyledXYDataset;
63 import org.dive4elements.river.themes.ThemeDocument; 57 import org.dive4elements.river.themes.ThemeDocument;
64 import org.dive4elements.river.utils.Formatter;
65 import org.jfree.chart.JFreeChart; 58 import org.jfree.chart.JFreeChart;
66 import org.jfree.chart.LegendItem; 59 import org.jfree.chart.LegendItem;
67 import org.jfree.chart.LegendItemCollection; 60 import org.jfree.chart.LegendItemCollection;
68 import org.jfree.chart.axis.NumberAxis; 61 import org.jfree.chart.axis.NumberAxis;
69 import org.jfree.chart.plot.XYPlot; 62 import org.jfree.chart.plot.XYPlot;
476 protected final void generateTitles(final JFreeChart chart) { 469 protected final void generateTitles(final JFreeChart chart) {
477 /* add metadata title before real title */ 470 /* add metadata title before real title */
478 addMetadataSubtitle(chart); 471 addMetadataSubtitle(chart);
479 472
480 /* add the real chart title, but as subtitle after the metadata */ 473 /* add the real chart title, but as subtitle after the metadata */
481 final String chartTitle = getChartTitle(this.context); 474 final String chartTitle = getChartTitle(this.context);
482 if (chartTitle != null) { 475 if (chartTitle != null) {
483 final TextTitle title = new TextTitle(chartTitle, JFreeChart.DEFAULT_TITLE_FONT); 476 final TextTitle title = new TextTitle(chartTitle, JFreeChart.DEFAULT_TITLE_FONT);
484 chart.addSubtitle(title); 477 chart.addSubtitle(title);
485 } 478 }
486 479
487 addSubtitles(this.context, chart); 480 addSubtitles(this.context, chart);
488 } 481 }
489 482
490
491 /** 483 /**
492 * Adds a metadata sub-title to the chart if it gets exported 484 * Adds a metadata sub-title to the chart if it gets exported
493 */ 485 */
494 protected final void addMetadataSubtitle(final JFreeChart chart) { 486 protected final void addMetadataSubtitle(final JFreeChart chart) {
495 if ((!isExport() || !isExportMetadata())) 487 if ((!isExport() || !isExportMetadata()))
501 /** The default font. */ 493 /** The default font. */
502 final Font titleFont = new Font("SansSerif", Font.ITALIC, 10); 494 final Font titleFont = new Font("SansSerif", Font.ITALIC, 10);
503 495
504 final TextTitle subtitle = new TextTitle(text, titleFont); 496 final TextTitle subtitle = new TextTitle(text, titleFont);
505 subtitle.setHorizontalAlignment(HorizontalAlignment.LEFT); 497 subtitle.setHorizontalAlignment(HorizontalAlignment.LEFT);
506 subtitle.setMargin(new RectangleInsets(10,10,10,10)); 498 subtitle.setMargin(new RectangleInsets(10, 10, 10, 10));
507 499
508 chart.addSubtitle(subtitle); 500 chart.addSubtitle(subtitle);
509 } 501 }
510 502
511 private Collection<String> buildMetadata() { 503 private Collection<String> buildMetadata() {
514 506
515 if (!(this.context instanceof CollectionCallContext)) { 507 if (!(this.context instanceof CollectionCallContext)) {
516 /* should never happen */ 508 /* should never happen */
517 return Collections.emptyList(); 509 return Collections.emptyList();
518 } 510 }
519
520 final CollectionCallContext ccc = (CollectionCallContext) this.context;
521 final ArtifactCollection collection = ccc.getCollection();
522 511
523 final List<String> subtitles = new ArrayList<>(); 512 final List<String> subtitles = new ArrayList<>();
524 513
525 /* version */ 514 /* version */
526 final String version = FLYS.VERSION; 515 final String version = FLYS.VERSION;
815 for (final XYDataset dataset : axisDataset.getDatasets()) { 804 for (final XYDataset dataset : axisDataset.getDatasets()) {
816 try { 805 try {
817 plot.setDataset(datasetIndex, dataset); 806 plot.setDataset(datasetIndex, dataset);
818 plot.mapDatasetToRangeAxis(datasetIndex, axisIndex); 807 plot.mapDatasetToRangeAxis(datasetIndex, axisIndex);
819 808
820 applyThemes(plot, dataset, datasetIndex, axisDataset.isArea(dataset)); 809 applyThemes(plot, dataset, datasetIndex);
821 810
822 datasetIndex++; 811 datasetIndex++;
823 } 812 }
824 catch (final RuntimeException re) { 813 catch (final RuntimeException re) {
825 log.error(re); 814 log.error(re);
837 * Shall be implemented by subclasses. 826 * Shall be implemented by subclasses.
838 */ 827 */
839 protected abstract NumberAxis createYAxis(final int index); 828 protected abstract NumberAxis createYAxis(final int index);
840 829
841 /** 830 /**
842 * @param idx 831 * @param datasetIndex
843 * "index" of dataset/series (first dataset to be drawn has 832 * "index" of dataset/series (first dataset to be drawn has
844 * index 0), correlates with renderer index. 833 * index 0), correlates with renderer index.
845 * @param isArea 834 * @param isArea
846 * true if the series describes an area and shall be rendered 835 * true if the series describes an area and shall be rendered
847 * as such. 836 * as such.
848 */ 837 */
849 private void applyThemes(final XYPlot plot, final XYDataset series, final int idx, final boolean isArea) { 838 private void applyThemes(final XYPlot plot, final XYDataset dataset, final int datasetIndex) {
850 if (isArea) 839
851 applyAreaTheme(plot, (StyledAreaSeriesCollection) series, idx); 840 final Font legendFont = createLegendLabelFont();
841
842 if (dataset instanceof StyledXYDataset)
843 ((StyledXYDataset) dataset).applyTheme(this.context.getMeta(), plot, datasetIndex, legendFont);
852 else 844 else
853 applyLineTheme(plot, series, idx); 845 applyLineTheme(plot, dataset, datasetIndex, legendFont);
854 } 846 }
855 847
856 /** 848 /**
857 * Expands a given range if it collapses into one point. 849 * Expands a given range if it collapses into one point.
858 * 850 *
881 * This value is not used in the current implementation. 873 * This value is not used in the current implementation.
882 * 874 *
883 * @return a new instance of EnhancedLineAndShapeRenderer. 875 * @return a new instance of EnhancedLineAndShapeRenderer.
884 */ 876 */
885 private XYLineAndShapeRenderer createRenderer(final XYPlot plot, final int idx) { 877 private XYLineAndShapeRenderer createRenderer(final XYPlot plot, final int idx) {
886 log.debug("Create EnhancedLineAndShapeRenderer for idx: " + idx);
887
888 final EnhancedLineAndShapeRenderer r = new EnhancedLineAndShapeRenderer(true, false); 878 final EnhancedLineAndShapeRenderer r = new EnhancedLineAndShapeRenderer(true, false);
889
890 r.setPlot(plot); 879 r.setPlot(plot);
891
892 return r; 880 return r;
893 } 881 }
894 882
895 /** 883 /**
896 * This method applies the themes defined in the series itself. Therefore, 884 * This method applies the themes defined in the series itself. Therefore,
901 * The plot. 889 * The plot.
902 * @param dataset 890 * @param dataset
903 * The XYDataset which needs to support Series objects. 891 * The XYDataset which needs to support Series objects.
904 * @param idx 892 * @param idx
905 * The index of the renderer / dataset. 893 * The index of the renderer / dataset.
906 */ 894 * @param legendFont2
907 private void applyLineTheme(final XYPlot plot, final XYDataset dataset, final int idx) { 895 */
896 private void applyLineTheme(final XYPlot plot, final XYDataset dataset, final int idx, final Font legendFont) {
908 log.debug("Apply LineTheme for dataset at index: " + idx); 897 log.debug("Apply LineTheme for dataset at index: " + idx);
909 898
910 final LegendItemCollection lic = new LegendItemCollection(); 899 final LegendItemCollection lic = new LegendItemCollection();
911 final LegendItemCollection anno = plot.getFixedLegendItems(); 900 final LegendItemCollection anno = plot.getFixedLegendItems();
912
913 final Font legendFont = createLegendLabelFont();
914 901
915 final XYLineAndShapeRenderer renderer = createRenderer(plot, idx); 902 final XYLineAndShapeRenderer renderer = createRenderer(plot, idx);
916 903
917 for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) { 904 for (int s = 0, num = dataset.getSeriesCount(); s < num; s++) {
918 final Series series = getSeriesOf(dataset, s); 905 final Series series = getSeriesOf(dataset, s);
947 } 934 }
948 935
949 plot.setFixedLegendItems(lic); 936 plot.setFixedLegendItems(lic);
950 937
951 plot.setRenderer(idx, renderer); 938 plot.setRenderer(idx, renderer);
952 }
953
954 /**
955 * @param plot
956 * The plot.
957 * @param area
958 * A StyledAreaSeriesCollection object.
959 * @param idx
960 * The index of the dataset.
961 */
962 private final void applyAreaTheme(final XYPlot plot, final StyledAreaSeriesCollection area, final int idx) {
963 final LegendItemCollection lic = new LegendItemCollection();
964 final LegendItemCollection anno = plot.getFixedLegendItems();
965
966 final Font legendFont = createLegendLabelFont();
967
968 log.debug("Registering an 'area'renderer at idx: " + idx);
969
970 final StableXYDifferenceRenderer dRenderer = new StableXYDifferenceRenderer();
971
972 if (area.getMode() == StyledAreaSeriesCollection.FILL_MODE.UNDER) {
973 dRenderer.setPositivePaint(createTransparentPaint());
974 }
975
976 plot.setRenderer(idx, dRenderer);
977
978 area.applyTheme(dRenderer);
979
980 // i18n
981 dRenderer.setAreaLabelNumberFormat(Formatter.getFormatter(this.context.getMeta(), 2, 4));
982
983 dRenderer.setAreaLabelTemplate(Resources.getMsg(this.context.getMeta(), "area.label.template", "Area=%sm2"));
984
985 final LegendItem legendItem = dRenderer.getLegendItem(idx, 0);
986 if (legendItem != null) {
987 legendItem.setLabelFont(legendFont);
988 lic.add(legendItem);
989 } else {
990 log.warn("Could not get LegentItem for renderer: " + idx + ", series-idx " + 0);
991 }
992
993 if (anno != null) {
994 lic.addAll(anno);
995 }
996
997 plot.setFixedLegendItems(lic);
998 }
999
1000 /**
1001 * Returns a transparently textured paint.
1002 *
1003 * @return a transparently textured paint.
1004 */
1005 private static Paint createTransparentPaint() {
1006 // TODO why not use a transparent color?
1007 final BufferedImage texture = new BufferedImage(1, 1, BufferedImage.TYPE_4BYTE_ABGR);
1008
1009 return new TexturePaint(texture, new Rectangle2D.Double(0d, 0d, 0d, 0d));
1010 } 939 }
1011 940
1012 private void preparePDFContext(final CallContext context) { 941 private void preparePDFContext(final CallContext context) {
1013 final int[] dimension = getExportDimension(); 942 final int[] dimension = getExportDimension();
1014 943
1067 996
1068 final AxisDataset axisDataset = getAxisDataset(idx); 997 final AxisDataset axisDataset = getAxisDataset(idx);
1069 998
1070 final Bounds[] xyBounds = ChartHelper.getBounds(dataset); 999 final Bounds[] xyBounds = ChartHelper.getBounds(dataset);
1071 1000
1072 if (xyBounds == null) { 1001 // if (xyBounds == null) {
1073 log.warn("Skip XYDataset for Axis (invalid ranges): " + idx); 1002 // log.warn("Skip XYDataset for Axis (invalid ranges): " + idx);
1074 return; 1003 // return;
1075 } 1004 // }
1076 1005
1077 if (visible) { 1006 if (visible) {
1078 if (log.isDebugEnabled()) { 1007 if (log.isDebugEnabled()) {
1079 log.debug("Add new AxisDataset at index: " + idx); 1008 log.debug("Add new AxisDataset at index: " + idx);
1080 log.debug("X extent: " + xyBounds[0]); 1009 if (xyBounds != null) {
1081 log.debug("Y extent: " + xyBounds[1]); 1010 log.debug("X extent: " + xyBounds[0]);
1011 log.debug("Y extent: " + xyBounds[1]);
1012 }
1082 } 1013 }
1083 1014
1084 axisDataset.addDataset(dataset); 1015 axisDataset.addDataset(dataset);
1085 } 1016 }
1017
1018 /* No range merging, for areas extending to infinity this causes problems. */
1019 if (xyBounds == null || StyledSeriesBuilder.isBigDoubleValue(xyBounds[1].getLower()) || StyledSeriesBuilder.isBigDoubleValue(xyBounds[1].getLower()))
1020 return;
1086 1021
1087 combineXBounds(xyBounds[0], 0); 1022 combineXBounds(xyBounds[0], 0);
1088 combineYBounds(xyBounds[1], idx); 1023 combineYBounds(xyBounds[1], idx);
1089 } 1024 }
1090 1025

http://dive4elements.wald.intevation.org