Mercurial > dive4elements > river
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 |