From da25721f52c0dfd903e3554a291e24a2f8e9bb32 Mon Sep 17 00:00:00 2001 From: Andrea Cavalli Date: Tue, 7 Dec 2021 00:46:15 +0100 Subject: [PATCH] Initial commit --- .gitignore | 182 ++++ .preview.png | Bin 0 -> 145635 bytes README.md | 5 + pom.xml | 35 + .../jlinegraph/AWTBufferedGraphRenderer.java | 19 + .../cavallium/jlinegraph/AWTGraphExample.java | 108 +++ .../jlinegraph/AWTGraphRenderer.java | 793 ++++++++++++++++++ .../java/it/cavallium/jlinegraph/Bezier.java | 118 +++ .../java/it/cavallium/jlinegraph/Color.java | 36 + .../java/it/cavallium/jlinegraph/Graph.java | 3 + .../cavallium/jlinegraph/GraphAxisStyle.java | 5 + .../it/cavallium/jlinegraph/GraphBounds.java | 94 +++ .../it/cavallium/jlinegraph/GraphColors.java | 7 + .../it/cavallium/jlinegraph/GraphData.java | 10 + .../it/cavallium/jlinegraph/GraphFonts.java | 3 + .../it/cavallium/jlinegraph/GraphStyle.java | 6 + .../cavallium/jlinegraph/IGraphRenderer.java | 6 + .../it/cavallium/jlinegraph/NiceScale.java | 111 +++ .../it/cavallium/jlinegraph/RasterSize.java | 3 + .../it/cavallium/jlinegraph/SeriesData.java | 5 + .../it/cavallium/jlinegraph/SeriesStyle.java | 19 + .../java/it/cavallium/jlinegraph/Vertex.java | 3 + 22 files changed, 1571 insertions(+) create mode 100644 .gitignore create mode 100644 .preview.png create mode 100644 README.md create mode 100644 pom.xml create mode 100644 src/main/java/it/cavallium/jlinegraph/AWTBufferedGraphRenderer.java create mode 100644 src/main/java/it/cavallium/jlinegraph/AWTGraphExample.java create mode 100644 src/main/java/it/cavallium/jlinegraph/AWTGraphRenderer.java create mode 100644 src/main/java/it/cavallium/jlinegraph/Bezier.java create mode 100644 src/main/java/it/cavallium/jlinegraph/Color.java create mode 100644 src/main/java/it/cavallium/jlinegraph/Graph.java create mode 100644 src/main/java/it/cavallium/jlinegraph/GraphAxisStyle.java create mode 100644 src/main/java/it/cavallium/jlinegraph/GraphBounds.java create mode 100644 src/main/java/it/cavallium/jlinegraph/GraphColors.java create mode 100644 src/main/java/it/cavallium/jlinegraph/GraphData.java create mode 100644 src/main/java/it/cavallium/jlinegraph/GraphFonts.java create mode 100644 src/main/java/it/cavallium/jlinegraph/GraphStyle.java create mode 100644 src/main/java/it/cavallium/jlinegraph/IGraphRenderer.java create mode 100644 src/main/java/it/cavallium/jlinegraph/NiceScale.java create mode 100644 src/main/java/it/cavallium/jlinegraph/RasterSize.java create mode 100644 src/main/java/it/cavallium/jlinegraph/SeriesData.java create mode 100644 src/main/java/it/cavallium/jlinegraph/SeriesStyle.java create mode 100644 src/main/java/it/cavallium/jlinegraph/Vertex.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..2d0faf7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,182 @@ +# ---> Maven +target/ +pom.xml.tag +pom.xml.releaseBackup +pom.xml.versionsBackup +pom.xml.next +release.properties +dependency-reduced-pom.xml +buildNumber.properties +.mvn/timing.properties +# https://github.com/takari/maven-wrapper#usage-without-binary-jar +.mvn/wrapper/maven-wrapper.jar + +# ---> Java +# Compiled class file +*.class + +# Log file +*.log + +# BlueJ files +*.ctxt + +# Mobile Tools for Java (J2ME) +.mtj.tmp/ + +# Package Files # +*.jar +*.war +*.nar +*.ear +*.zip +*.tar.gz +*.rar + +# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml +hs_err_pid* + +# ---> Linux +*~ + +# temporary files which can be created if a process still has a handle open of a deleted file +.fuse_hidden* + +# KDE directory preferences +.directory + +# Linux trash folder which might appear on any partition or disk +.Trash-* + +# .nfs files are created when an open file is removed but is still being accessed +.nfs* + +# ---> Windows +# Windows thumbnail cache files +Thumbs.db +Thumbs.db:encryptable +ehthumbs.db +ehthumbs_vista.db + +# Dump file +*.stackdump + +# Folder config file +[Dd]esktop.ini + +# Recycle Bin used on file shares +$RECYCLE.BIN/ + +# Windows Installer files +*.cab +*.msi +*.msix +*.msm +*.msp + +# Windows shortcuts +*.lnk + +# ---> macOS +# General +.DS_Store +.AppleDouble +.LSOverride + +# Icon must end with two \r +Icon + + +# Thumbnails +._* + +# Files that might appear in the root of a volume +.DocumentRevisions-V100 +.fseventsd +.Spotlight-V100 +.TemporaryItems +.Trashes +.VolumeIcon.icns +.com.apple.timemachine.donotpresent + +# Directories potentially created on remote AFP share +.AppleDB +.AppleDesktop +Network Trash Folder +Temporary Items +.apdisk + +# ---> JetBrains +# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm +# Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 + +# User-specific stuff +.idea/**/workspace.xml +.idea/**/tasks.xml +.idea/**/usage.statistics.xml +.idea/**/dictionaries +.idea/**/shelf + +# Generated files +.idea/**/contentModel.xml + +# Sensitive or high-churn files +.idea/**/dataSources/ +.idea/**/dataSources.ids +.idea/**/dataSources.local.xml +.idea/**/sqlDataSources.xml +.idea/**/dynamic.xml +.idea/**/uiDesigner.xml +.idea/**/dbnavigator.xml + +# Gradle +.idea/**/gradle.xml +.idea/**/libraries + +# Gradle and Maven with auto-import +# When using Gradle or Maven with auto-import, you should exclude module files, +# since they will be recreated, and may cause churn. Uncomment if using +# auto-import. +# .idea/artifacts +# .idea/compiler.xml +# .idea/jarRepositories.xml +# .idea/modules.xml +# .idea/*.iml +# .idea/modules +# *.iml +# *.ipr + +# CMake +cmake-build-*/ + +# Mongo Explorer plugin +.idea/**/mongoSettings.xml + +# File-based project format +*.iws + +# IntelliJ +out/ + +# mpeltonen/sbt-idea plugin +.idea_modules/ + +# JIRA plugin +atlassian-ide-plugin.xml + +# Cursive Clojure plugin +.idea/replstate.xml + +# Crashlytics plugin (for Android Studio and IntelliJ) +com_crashlytics_export_strings.xml +crashlytics.properties +crashlytics-build.properties +fabric.properties + +# Editor-based Rest Client +.idea/httpRequests + +# Android studio 3.1+ serialized cache file +.idea/caches/build_file_checksums.ser + +/.idea/ diff --git a/.preview.png b/.preview.png new file mode 100644 index 0000000000000000000000000000000000000000..1ed97af972763dd09eb2fdb6c0a2150087975df0 GIT binary patch literal 145635 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

{%R5%%c1?#9WFNXaN$Ef%5zW|+G@}Aqb(NKA> zt7Pi7%uAhH_>z+G?IqG(8m(6{HENumu?A<1JaGO-IHN9a({%%Dlg`J-9&F$&Qw@+x zo??Ej=^E0MAmsYXkCbgK5FmU@l*l}g<7SD1YFxX%cnYv6MDJe*VrO1OLDA(pK9`cK3M7f3>Psd6 z1H$b8*E<~$15@(gQSu95!%HviFtw#Uw}OyMad_VwA2;PY5&-6y&0UQYXP!I+4(eYN zwQTFh*od434NDk<`gJb?w~Z`ZC3}{^uTR8H4qW|4nNqfp_S{}3w?%BVutA<)W6|?; zQkAI|6}Htwl{er{Gl@1ZIr8`GJgs{xh3IRx%8zMTLF*jqvyhegGG>)fKXkpX0Q|Sd z@Z!A$g2}kTFDSQDxcfQC-e|$?R2k`hgAw}&b}uNpQSA(~6oRyr+8RY@S@4Z}ztGUEKvzj>p?VH&e!p1Q zN45os^)NL#Z7m(L(2Ys-+CgW2$WlUc-Yd@$i=nHJtz4wm=NS*;_qa6L4NgD5rjbTq zssBqn7zdiWis>duW|Ii4gj8tNg&8K}I|yvQ1VyW=R={Pj8p?KvpTR?K_7V@_&3Vrm zj$V1oFYdh|&#dL~=&16;2#lv5pV0&WtyIxn%y`-eEc7qFq z`QoBbbN|p%u1(LV0{!autS~`abIIuDs4M!X##WoEHi~C}x|D*S?nk zC}~)f=;`Sn!a#8?U0r$-_-fmI7{oQ_`S>zH!_-NdPhw+Z^WCLq7e5as^*10@Ljgr= z?y1Yfi$J^}Spq+4M}vWiPv~~@Ld|?T@{nL;s7Gy{SIVdBjJ#v@7c^}lHu{HFQ_BSf zaH-?S6%fEOv&wjx(1$Ef_o~|t>Db%blSaYj`RV7uSdEC7n3&xxsypjOIt

k#O#X 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 literal 0 HcmV?d00001 diff --git a/README.md b/README.md new file mode 100644 index 0000000..b650cb1 --- /dev/null +++ b/README.md @@ -0,0 +1,5 @@ +# JLineGraph + +Small library to draw line graphs in java + +![.preview.png](.preview.png) diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..03b8c3f --- /dev/null +++ b/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + it.cavallium + jlinegraph + 1.0-SNAPSHOT + + + 17 + 17 + + + + mchv + MCHV Apache Maven Packages + https://mvn.mchv.eu/repository/mchv/ + + + + + mchv-release-distribution + MCHV Release Apache Maven Packages Distribution + https://mvn.mchv.eu/repository/mchv + + + mchv-snapshot-distribution + MCHV Snapshot Apache Maven Packages Distribution + https://mvn.mchv.eu/repository/mchv-snapshot + + + + \ No newline at end of file diff --git a/src/main/java/it/cavallium/jlinegraph/AWTBufferedGraphRenderer.java b/src/main/java/it/cavallium/jlinegraph/AWTBufferedGraphRenderer.java new file mode 100644 index 0000000..572bd5e --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/AWTBufferedGraphRenderer.java @@ -0,0 +1,19 @@ +package it.cavallium.jlinegraph; + +import java.awt.Graphics2D; +import java.awt.image.BufferedImage; + +public class AWTBufferedGraphRenderer implements IGraphRenderer { + + @Override + public BufferedImage renderGraph(Graph graph, RasterSize totalSize) { + BufferedImage image = new BufferedImage((int) totalSize.width(), + (int) totalSize.height(), + BufferedImage.TYPE_INT_ARGB + ); + Graphics2D graphics2D = image.createGraphics(); + AWTGraphRenderer.renderGraph(graphics2D, graph, totalSize); + return image; + } + +} diff --git a/src/main/java/it/cavallium/jlinegraph/AWTGraphExample.java b/src/main/java/it/cavallium/jlinegraph/AWTGraphExample.java new file mode 100644 index 0000000..834a426 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/AWTGraphExample.java @@ -0,0 +1,108 @@ +package it.cavallium.jlinegraph; + +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.util.List; +import javax.swing.JComponent; +import javax.swing.JFrame; +import javax.swing.WindowConstants; + +public class AWTGraphExample { + + private static final GraphColors GRAPH_COLOR = GraphColors.DARK; + + public static void main(String[] args) { + var jf = new JFrame("Graph"); + jf.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); + jf.setLocationByPlatform(true); + var jp = new JComponent() { + @Override + protected void paintComponent(Graphics g) { + generateGraph(this.getWidth(), this.getHeight(), (Graphics2D) g); + } + }; + jf.setBackground(GRAPH_COLOR.background().toColor()); + jf.add(jp); + jf.setPreferredSize(new Dimension(800, 600)); + jf.pack(); + jf.setVisible(true); + } + + private static void generateGraph(int w, int h, Graphics2D g2d) { + var g = new Graph("Example", new GraphData(List.of( + new SeriesData(List.of( + new Vertex(-3, -3), + new Vertex(0, 0), + new Vertex(3, 1), + new Vertex(3.5, 7), + new Vertex(7, 0.5), + new Vertex(15, 14) + ), true, "Data1"), + new SeriesData(List.of( + new Vertex(-3, -2), + new Vertex(0, 3), + new Vertex(1, 1), + new Vertex(2, 5), + new Vertex(3, 6), + new Vertex(4, 7), + new Vertex(5, 4), + new Vertex(6, 3), + new Vertex(7, 1), + new Vertex(8, 10), + new Vertex(9, 12), + new Vertex(10, 13), + new Vertex(11, 15), + new Vertex(12, 11), + new Vertex(13, 15), + new Vertex(14, 10), + new Vertex(15, 4) + ), true, "Data2"), + new SeriesData(List.of( + new Vertex(-3, -1), + new Vertex(0, 3), + new Vertex(4, 4), + new Vertex(8, 3), + new Vertex(12, 4), + new Vertex(15, 3) + ), true, "Data3"), + new SeriesData(List.of( + new Vertex(4.4, 5.2), + new Vertex(6.4, 7.2), + new Vertex(8.4, 5.2), + new Vertex(6.4, 3.2), + new Vertex(4.4, 5.2) + ), false, "full oval"), + new SeriesData(List.of( + new Vertex(-6+4.4, 5.8), + new Vertex(-6+6.4, 7.8), + new Vertex(-6+8.4, 5.8), + new Vertex(-6+6.4, 3.8), + new Vertex(-6+4.4, 5.8) + ), false, "oval line"), + new SeriesData(List.of( + new Vertex(3.3+4, 2.3+8), + new Vertex(3.3+5, 2.3+7), + new Vertex(3.3+8, 2.3+5), + new Vertex(3.3+6, 2.3+3) + ), false, "open path") + )), + new GraphStyle(List.of( + new SeriesStyle(new Color(0f, 1f, 0f, 1f), 1, 1, 0, 1d), + new SeriesStyle(new Color(1f, 0f, 0f, 1f), 1, 0, 0, 1d), + new SeriesStyle(new Color(0.5f, 1f, 1f, 1f), 0, 1, 0.3, 1d), + new SeriesStyle(new Color(0.5f, 1f, 0.5f, 1f), 0, 0, 1, 1d), + new SeriesStyle(new Color(0.5f, 1f, 0.5f, 1f), 0, 1, 0.3, 1d), + new SeriesStyle(new Color(1f, 1f, 0.7f, 1f), 1.5, 2, 0, 1d) + ), + new GraphAxisStyle("X axis", true, "%.2fs"::formatted), + new GraphAxisStyle("Y axis", true, "%.2fm"::formatted), + GRAPH_COLOR, + new GraphFonts(10f, 18f, 12f, 12f), + 2f, + true + )); + var r = new AWTGraphRenderer(); + r.renderGraph(g, new RasterSize(w, h)).drawTo(g2d); + } +} diff --git a/src/main/java/it/cavallium/jlinegraph/AWTGraphRenderer.java b/src/main/java/it/cavallium/jlinegraph/AWTGraphRenderer.java new file mode 100644 index 0000000..6d7e290 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/AWTGraphRenderer.java @@ -0,0 +1,793 @@ +package it.cavallium.jlinegraph; + +import it.cavallium.jlinegraph.AWTGraphRenderer.AWTDrawer; +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.FontMetrics; +import java.awt.Graphics2D; +import java.awt.RenderingHints; +import java.awt.Shape; +import java.awt.font.GlyphVector; +import java.awt.geom.Ellipse2D; +import java.awt.geom.GeneralPath; +import java.awt.geom.Line2D; +import java.awt.geom.Path2D; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; +import java.util.Objects; + +public class AWTGraphRenderer implements IGraphRenderer { + + private static final int MAX_LABELS = 1000; + + @Override + public AWTDrawer renderGraph(Graph graph, RasterSize totalSize) { + return graphics2D -> renderGraph(graphics2D, graph, totalSize); + } + + public static void renderGraph(Graphics2D graphics2D, Graph graph, RasterSize totalSize) { + graphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + graphics2D.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC); + graphics2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY); + graphics2D.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_GASP); + graphics2D.setRenderingHint(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON); + graphics2D.setRenderingHint(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_ENABLE); + graphics2D.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE); + graphics2D.setRenderingHint(RenderingHints.KEY_RESOLUTION_VARIANT, RenderingHints.VALUE_RESOLUTION_VARIANT_DPI_FIT); + + Font defaultFont = graphics2D.getFont().deriveFont((float) graph.style().fonts().global()); + Font valuesFont = defaultFont.deriveFont((float) graph.style().fonts().valueLabel()); + Font axisNameFont = defaultFont.deriveFont((float) graph.style().fonts().axisName()); + + var defaultFontMetrics = graphics2D.getFontMetrics(defaultFont); + var valuesFontMetrics = graphics2D.getFontMetrics(valuesFont); + var axisNameFontMetrics = graphics2D.getFontMetrics(axisNameFont); + + var graphBounds = graph.data().bounds(); + var x = graph.style().x(); + var y = graph.style().y(); + var scaleX = new NiceScale(graphBounds.minX(), graphBounds.maxX()); + scaleX.setMaxTicks(20); + var scaleY = new NiceScale(graphBounds.minY(), graphBounds.maxY()); + scaleY.setMaxTicks(20); + var topPadding = defaultFontMetrics.getHeight() + valuesFontMetrics.getHeight() / 2d; + var leftPadding = defaultFontMetrics.getHeight(); + var rightPadding = defaultFontMetrics.getHeight() + + valuesFontMetrics.stringWidth(y.valueFormat().apply(graphBounds.maxX())) / 2d; + var bottomPadding = defaultFontMetrics.getHeight(); + var xValueLineLength = valuesFontMetrics.getHeight(); + var yValueLineLength = valuesFontMetrics.getHeight(); + var xValuesHeight = valuesFontMetrics.getHeight(); + var xValuesToXAxisNamePadding = (x.show() ? valuesFontMetrics.getHeight() : 0); + var xAxisNameHeight = (x.show() ? axisNameFontMetrics.getHeight() : 0); + var yAxisNameWidth = (y.show() ? axisNameFontMetrics.getHeight() : 0); + var yValuesToYAxisNamePadding = (y.show() ? valuesFontMetrics.getHeight() : 0); + + var graphHeight + // Start with total height + = totalSize.height() + // Remove the padding on top + - topPadding + // Remove the x value lines length + - xValueLineLength + // Remove the values height + - xValuesHeight + // Remove the space between the values and the axis name + - xValuesToXAxisNamePadding + // Remove x-axis name height + - xAxisNameHeight + // Remove the padding on bottom + - bottomPadding; + + var xValueLineOffset = topPadding + graphHeight; + + var yLabels = getYLabels(graph, graphHeight, valuesFontMetrics, scaleY); + RasterSize yLabelsAreaSize = computeYLabelsAreaSize(graphHeight, valuesFontMetrics, yLabels); + var yValuesWidth = yLabelsAreaSize.width(); + var yValueLineOffset = leftPadding + yAxisNameWidth + yValuesToYAxisNamePadding + yValuesWidth; + + var graphWidth + // Start with total width + = totalSize.width() + // Remove the padding on left + - leftPadding + // Remove y-axis name "90deg height" + - yAxisNameWidth + // Remove the space between the values and the axis name + - yValuesToYAxisNamePadding + // Remove the y values width + - yValuesWidth + // Remove the y value lines length + - yValueLineLength + // Remove the padding on right + - rightPadding; + + Font seriesNameFont = null; + FontMetrics seriesNameFontMetrics = null; + + if (graph.style().showLegend()) { + double legendSizeW; + double legendSizeH; + + seriesNameFont = defaultFont.deriveFont((float) graph.style().fonts().seriesName()); + seriesNameFontMetrics = graphics2D.getFontMetrics(seriesNameFont); + legendSizeW = getLegendSizeW(graph, seriesNameFontMetrics); + legendSizeH = getLegendSizeH(graph, seriesNameFontMetrics); + + if (legendSizeW > graphWidth / 3d || legendSizeH > graphHeight / 2.5d) { + var newFontSizeW = (float) (seriesNameFont.getSize() * ((graphWidth / 3d) / legendSizeW)); + var newFontSizeH = (float) (seriesNameFont.getSize() * ((graphHeight / 2.5d) / legendSizeH)); + seriesNameFont = seriesNameFont.deriveFont(Math.min(newFontSizeW, newFontSizeH)); + seriesNameFontMetrics = graphics2D.getFontMetrics(seriesNameFont); + } + } + + var xLabels = getXLabels(graph, graphWidth, valuesFontMetrics, scaleX); + + RasterSize yAxisNameCenterOffset = new RasterSize(valuesFontMetrics.getHeight(), valuesFontMetrics.getHeight() + // Add half of graph height + + graphHeight / 2); + + RasterSize yValuesOffset = new RasterSize(leftPadding + // Add y axis name "90deg height" + + yAxisNameWidth + // Add the space between the values and the axis name + + yValuesToYAxisNamePadding, topPadding); + + RasterSize graphOffset = new RasterSize(leftPadding + + yAxisNameWidth + + yValuesToYAxisNamePadding + + yValuesWidth + + yValueLineLength, topPadding); + RasterSize xValuesOffset = new RasterSize(graphOffset.width(), xValueLineOffset + xValueLineLength); + + RasterSize xAxisNameCenterOffset = new RasterSize(leftPadding + + yAxisNameWidth + + yValuesToYAxisNamePadding + + yValuesWidth + + yValueLineLength + // Add half of graph width + + graphWidth / 2, topPadding + // Add graph height + + graphHeight + // Add the x value lines length + + xValueLineLength + // Add the x values height + + xValuesHeight + // Add the space between the values and the axis name + + xValuesToXAxisNamePadding + // Add x-axis half name height + + axisNameFontMetrics.getHeight() / 2d); + + RasterSize graphSize = new RasterSize(graphWidth, graphHeight); + + var bgColor = graph.style().colors().background().toColor(); + var fgColor = graph.style().colors().foreground().toColor(); + var strokeWidth = graph.style().strokeWidth(); + var defaultStroke = new BasicStroke((float) strokeWidth, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, BasicStroke.JOIN_MITER); + + try { + graphics2D.setBackground(bgColor); + graphics2D.clearRect(0, 0, (int) totalSize.width(), (int) totalSize.height()); + + if (graphHeight < 0) { + return; + } + if (graphWidth < 0) { + return; + } + + renderGraphBorders(graphics2D, graph, graphOffset, graphSize, defaultStroke); + if (y.show()) { + renderYAxisName(graphics2D, graph, yAxisNameCenterOffset, axisNameFont, axisNameFontMetrics); + } + if (x.show()) { + renderXAxisName(graphics2D, graph, xAxisNameCenterOffset, axisNameFont, axisNameFontMetrics); + } + renderYAxisValueLabels(graphics2D, + graph, + valuesFont, + valuesFontMetrics, + yValueLineOffset, + yValueLineLength, + yLabels, + yLabelsAreaSize, + yValuesOffset, + defaultStroke + ); + renderXAxisValueLabels(graphics2D, + graph, + valuesFont, + valuesFontMetrics, + xValueLineOffset, + xValueLineLength, + xLabels, xValuesOffset, + defaultStroke + ); + + + var seriesGraphics2D = (Graphics2D) graphics2D.create(); + seriesGraphics2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); + try { + seriesGraphics2D.setClip(new Rectangle2D.Double(graphOffset.width() - defaultStroke.getLineWidth(), + graphOffset.height() - defaultStroke.getLineWidth(), + graphSize.width() + defaultStroke.getLineWidth() * 2d, + graphSize.height() + defaultStroke.getLineWidth() * 2d + )); + + var zeroLineStroke = new BasicStroke((float) strokeWidth, + BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND, + 10.0f, + new float[]{2.0f, 3.0f}, + 0.0f + ); + var zeroLineColor = graph.style().colors().foreground().multiplyOpacity(0.5f).toColor(); + + if ((graphBounds.minY() < 0 && graphBounds.maxY() > 0) + || (graphBounds.minY() > 0 && graphBounds.maxY() < 0)) { + double rasterZeroY = graphOffset.height() + graphSize.height() + - ((-graphBounds.minY()) / (graphBounds.maxY() - graphBounds.minY())) * graphSize.height(); + seriesGraphics2D.setColor(zeroLineColor); + seriesGraphics2D.setStroke(zeroLineStroke); + seriesGraphics2D.draw(new Line2D.Double(graphOffset.width(), + rasterZeroY, + graphOffset.width() + graphWidth, + rasterZeroY + )); + } + if ((graphBounds.minX() < 0 && graphBounds.maxX() > 0) + || (graphBounds.minX() > 0 && graphBounds.maxX() < 0)) { + double rasterZeroX = graphOffset.width() + + ((-graphBounds.minX()) / (graphBounds.maxX() - graphBounds.minX())) * graphSize.width(); + seriesGraphics2D.setColor(zeroLineColor); + seriesGraphics2D.setStroke(zeroLineStroke); + seriesGraphics2D.draw(new Line2D.Double( + rasterZeroX, + graphOffset.height(), + rasterZeroX, + graphOffset.height() + graphHeight + )); + } + + int i = 0; + for (SeriesData series : graph.data().series()) { + var seriesStyleSize = graph.style().seriesStyles().size(); + if (graph.style().seriesStyles().isEmpty()) { + throw new IllegalArgumentException("No styles found"); + } + SeriesStyle style = graph.style().seriesStyles().get(i % seriesStyleSize); + BasicStroke seriesStroke = getSeriesStroke(style, strokeWidth); + BasicStroke seriesPointsStroke = getSeriesPointsStroke(style, strokeWidth); + drawSeries(seriesGraphics2D, graphBounds, + graphOffset, + graphSize, + series, + style, + seriesStroke, + seriesPointsStroke + ); + i++; + } + } finally { + seriesGraphics2D.dispose(); + } + + if (graph.style().showLegend()) { + drawSeriesLegend(graphics2D, + graph, + graphOffset, + graphSize, + seriesNameFont, + seriesNameFontMetrics, + defaultStroke, + fgColor, + strokeWidth + ); + } + } finally { + graphics2D.dispose(); + } + } + + private static void drawSeriesLegend(Graphics2D graphics2D, + Graph graph, + RasterSize graphOffset, + RasterSize graphSize, + Font seriesNameFont, + FontMetrics seriesNameFontMetrics, + BasicStroke defaultStroke, + Color fgColor, + double strokeWidth) { + double seriesPadding = getSeriesPadding(seriesNameFontMetrics); + double seriesMargin = getSeriesMargin(seriesNameFontMetrics); + double seriesPreviewLineWidth = seriesNameFontMetrics.getHeight() * 2; + double singleSeriesHeight = seriesNameFontMetrics.getHeight(); + + double legendSizeW = getLegendSizeW(graph, seriesNameFontMetrics); + double legendSizeH = getLegendSizeH(graph, seriesNameFontMetrics); + + double legendOffsetX = graphOffset.width() + + graphSize.width() + - seriesMargin + - legendSizeW; + double legendOffsetY = graphOffset.height() + + seriesMargin; + + var legendRect = new Rectangle2D.Double(legendOffsetX, legendOffsetY, legendSizeW, legendSizeH); + + graphics2D.setStroke(defaultStroke); + + graphics2D.setColor(graph.style().colors().background().multiplyOpacity(0.75f).toColor()); + graphics2D.fill(legendRect); + graphics2D.setColor(fgColor); + graphics2D.draw(legendRect); + + int i = 0; + for (SeriesData series : graph.data().series()) { + var seriesStyleSize = graph.style().seriesStyles().size(); + if (graph.style().seriesStyles().isEmpty()) { + throw new IllegalArgumentException("No styles found"); + } + SeriesStyle style = graph.style().seriesStyles().get(i % seriesStyleSize); + + var seriesName = series.name(); + var stroke = new BasicStroke((float) (strokeWidth * 2f), BasicStroke.CAP_BUTT, BasicStroke.JOIN_MITER); + graphics2D.setColor(style.color().overrideOpacity(1.0f).toColor()); + graphics2D.setStroke(stroke); + var lineOffsetX = legendOffsetX + seriesPadding; + var currentOffsetY = legendOffsetY + seriesPadding / 2d + + i * (seriesPadding / 2d + singleSeriesHeight + seriesPadding / 2d) + + seriesPadding / 2d; + var lineOffsetY = currentOffsetY + singleSeriesHeight / 2d; + graphics2D.draw(new Line2D.Double(lineOffsetX, lineOffsetY, lineOffsetX + seriesPreviewLineWidth, lineOffsetY)); + var textOffsetX = lineOffsetX + seriesPreviewLineWidth + seriesPadding; + var textOffsetY = currentOffsetY + seriesNameFontMetrics.getAscent(); + graphics2D.setColor(fgColor); + graphics2D.setFont(seriesNameFont); + graphics2D.fill(generateShapeFromText(graphics2D, seriesName, textOffsetX, textOffsetY)); + i++; + } + } + + private static double getSeriesMargin(FontMetrics seriesNameFontMetrics) { + return seriesNameFontMetrics.getHeight() * 2d / 3d; + } + + private static double getLegendSizeW(Graph graph, FontMetrics seriesNameFontMetrics) { + double seriesPadding = getSeriesPadding(seriesNameFontMetrics); + double seriesTextMaxWidth = getSeriesTextMaxWidth(graph, seriesNameFontMetrics); + double seriesPreviewLineWidth = seriesNameFontMetrics.getHeight() * 2; + return seriesPadding + + seriesTextMaxWidth + + seriesPadding + + seriesPreviewLineWidth + + seriesPadding; + } + + private static double getSeriesPadding(FontMetrics seriesNameFontMetrics) { + return seriesNameFontMetrics.getHeight() / 3d; + } + + private static double getLegendSizeH(Graph graph, FontMetrics seriesNameFontMetrics) { + int seriesCount = graph.data().series().size(); + double seriesPadding = getSeriesPadding(seriesNameFontMetrics); + double singleSeriesHeight = seriesNameFontMetrics.getHeight(); + return seriesPadding / 2d + + seriesCount * (seriesPadding / 2d + singleSeriesHeight + seriesPadding / 2d) + + seriesPadding / 2d; + } + + private static double getSeriesTextMaxWidth(Graph graph, FontMetrics seriesNameFontMetrics) { + double seriesTextMaxWidth = 0; + for (SeriesData series : graph.data().series()) { + var seriesName = series.name(); + var seriesNameRasterWidth = seriesNameFontMetrics.stringWidth(seriesName); + if (seriesTextMaxWidth < seriesNameRasterWidth) { + seriesTextMaxWidth = seriesNameRasterWidth; + } + } + return seriesTextMaxWidth; + } + + private static void drawSeries(Graphics2D seriesGraphics2D, + GraphBounds graphBounds, + RasterSize graphOffset, + RasterSize graphSize, + SeriesData series, + SeriesStyle style, + BasicStroke seriesStroke, + BasicStroke seriesPointsStroke) { + var lineColor = style.color().toColor(); + var areaColor = style.color().multiplyOpacity((float) style.areaOpacity()).toColor(); + var points = new java.awt.geom.Point2D.Double[series.vertices().size()]; + + double rasterMinY = graphOffset.height() + graphSize.height() + - ((0 - graphBounds.minY()) / (graphBounds.maxY() - graphBounds.minY())) * graphSize.height(); + int i = 0; + for (Vertex vertex : series.vertices()) { + double rasterX = graphOffset.width() + + ((vertex.x() - graphBounds.minX()) / (graphBounds.maxX() - graphBounds.minX())) * graphSize.width(); + double rasterY = graphOffset.height() + graphSize.height() + - ((vertex.y() - graphBounds.minY()) / (graphBounds.maxY() - graphBounds.minY())) * graphSize.height(); + points[i] = new java.awt.geom.Point2D.Double(rasterX, rasterY); + i++; + } + // Sort points if it's a function + if (series.isFunction()) { + Arrays.sort(points, Comparator.comparingDouble(Point2D.Double::getX)); + } + + seriesGraphics2D.setStroke(seriesPointsStroke); + if (style.pointsWeight() != 0) { + seriesGraphics2D.setColor(lineColor); + for (var point : points) { + seriesGraphics2D.fill(new Ellipse2D.Double(point.getX() - seriesPointsStroke.getLineWidth(), + point.getY() - seriesPointsStroke.getLineWidth(), + seriesPointsStroke.getLineWidth() * 2f, + seriesPointsStroke.getLineWidth() * 2f + ) {}); + } + } + if (style.lineWeight() != 0 || style.areaOpacity() > 0d) { + if (style.smoothness() > 0d && points.length >= 3) { + var mPath = new GeneralPath(Path2D.WIND_NON_ZERO, points.length); + var areaPath = new GeneralPath(Path2D.WIND_NON_ZERO, points.length); + + if (series.isFunction()) { + areaPath.moveTo(points[0].x, rasterMinY); + mPath.moveTo(points[0].x, points[0].y); + areaPath.lineTo(points[0].x, points[0].y); + } else { + areaPath.moveTo(points[0].x, points[0].y); + mPath.moveTo(points[0].x, points[0].y); + } + + double SMOOTHNESS = style.smoothness() / 2d; // higher is smoother, but don't go over 0.5 + + if (!series.isFunction()) { + Point2D.Double[] bezierPoints; + final boolean closedPath = Objects.equals(points[points.length - 1], points[0]); + if (closedPath) { + bezierPoints = new Point2D.Double[points.length + 2]; + bezierPoints[0] = points[points.length - 2]; + System.arraycopy(points, 0, bezierPoints, 1, points.length); + bezierPoints[bezierPoints.length - 1] = points[1]; + } else { + bezierPoints = points; + } + var bez = new Bezier(bezierPoints); + Point2D[] b = bez.getPoints(); + + if (!closedPath) { + mPath.quadTo(b[0].getX(), b[0].getY(), bezierPoints[1].x, bezierPoints[1].getY()); + areaPath.quadTo(b[0].getX(), b[0].getY(), bezierPoints[1].x, bezierPoints[1].getY()); + } + + for (int w = 2; w < bezierPoints.length - 1; w++) { + Point2D b0 = b[2 * w - 3]; + Point2D b1 = b[2 * w - 2]; + double cp1X = b0.getX(); + double cp1Y = b0.getY(); + double cp2X = b1.getX(); + double cp2Y = b1.getY(); + double endPointX = bezierPoints[w].getX(); + double endPointY = bezierPoints[w].getY(); + mPath.curveTo(cp1X, cp1Y, cp2X, cp2Y, endPointX, endPointY); + areaPath.curveTo(cp1X, cp1Y, cp2X, cp2Y, endPointX, endPointY); + } + + if (!closedPath) { + mPath.quadTo(b[b.length - 1].getX(), + b[b.length - 1].getY(), + bezierPoints[bezierPoints.length - 1].x, + bezierPoints[bezierPoints.length - 1].getY() + ); + areaPath.quadTo(b[b.length - 1].getX(), + b[b.length - 1].getY(), + bezierPoints[bezierPoints.length - 1].x, + bezierPoints[bezierPoints.length - 1].getY() + ); + } + } else { + // calculate smooth path + double lX = 0, lY = 0; + int size = points.length; + for (int pointIndex=1; pointIndex 0d) { + seriesGraphics2D.setColor(areaColor); + seriesGraphics2D.fill(areaPath); + } + if (style.lineWeight() != 0) { + seriesGraphics2D.setStroke(seriesStroke); + seriesGraphics2D.setColor(lineColor); + seriesGraphics2D.draw(mPath); + } + } else { + var areaPath = new Path2D.Double(); + var path = new Path2D.Double(); + if (points.length > 0) { + areaPath.moveTo(points[0].x, rasterMinY); + } + boolean first = true; + for (Point2D.Double point : points) { + if (first) { + path.moveTo(point.getX(), point.getY()); + first = false; + } else { + path.lineTo(point.getX(), point.getY()); + } + areaPath.lineTo(point.getX(), point.getY()); + } + if (points.length > 0) { + areaPath.moveTo(points[points.length - 1].x, rasterMinY); + areaPath.closePath(); + } + if (style.areaOpacity() > 0d) { + seriesGraphics2D.setStroke(seriesStroke); + seriesGraphics2D.setColor(areaColor); + seriesGraphics2D.fill(areaPath); + } + if (style.lineWeight() != 0) { + seriesGraphics2D.setStroke(seriesStroke); + seriesGraphics2D.setColor(lineColor); + seriesGraphics2D.draw(path); + } + } + } + } + + private static BasicStroke getSeriesStroke(SeriesStyle seriesStyle, double defaultStrokeWidth) { + return new BasicStroke((float) (defaultStrokeWidth * seriesStyle.lineWeight()), + BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND + ); + } + + private static BasicStroke getSeriesPointsStroke(SeriesStyle seriesStyle, double defaultStrokeWidth) { + return new BasicStroke((float) (defaultStrokeWidth * 2d * seriesStyle.pointsWeight()), + BasicStroke.CAP_ROUND, + BasicStroke.JOIN_ROUND + ); + } + + private static void renderYAxisName(Graphics2D graphics2D, + Graph graph, + RasterSize yAxisNameCenterOffset, + Font axisNameFont, + FontMetrics axisNameFontMetrics) { + var fgColor = graph.style().colors().foreground().toColor(); + graphics2D.setColor(fgColor); + graphics2D.setFont(axisNameFont); + + var title = graph.style().y().title(); + + var previousTransform = graphics2D.getTransform(); + graphics2D.rotate(Math.toRadians(-90), + yAxisNameCenterOffset.width(), + yAxisNameCenterOffset.height() + ); + graphics2D.fill(generateShapeFromText(graphics2D, + title, + yAxisNameCenterOffset.width() - axisNameFontMetrics.stringWidth(title) / 2d, + yAxisNameCenterOffset.height() + axisNameFontMetrics.getHeight() / 2d - axisNameFontMetrics.getDescent() + )); + graphics2D.setTransform(previousTransform); + } + + private static void renderYAxisValueLabels(Graphics2D graphics2D, + Graph graph, + Font valuesFont, + FontMetrics valuesFontMetrics, + double yValueLineOffset, + int yValueLineLength, + List yLabels, + RasterSize yLabelsAreaSize, + RasterSize yValuesOffset, + BasicStroke defaultStroke) { + graphics2D.setFont(valuesFont); + graphics2D.setStroke(defaultStroke); + graphics2D.setColor(graph.style().colors().foreground().toColor()); + yLabels.forEach(label -> { + var lineStartOffsetY = yValuesOffset.height() + label.rasterOffset(); + var currentLineOffsetX = label.formattedText().isBlank() ? yValueLineLength / 3d : 0; + var currentLineLength = yValueLineLength + (label.formattedText().isBlank() ? -yValueLineLength / 3d : 0); + graphics2D.draw(new Line2D.Double(yValueLineOffset + currentLineOffsetX, + lineStartOffsetY, + yValueLineOffset + currentLineOffsetX + currentLineLength, + lineStartOffsetY + )); + graphics2D.fill(generateShapeFromText(graphics2D, + label.formattedText(), + yValuesOffset.width() + yLabelsAreaSize.width() - valuesFontMetrics.stringWidth(label.formattedText()), + yValuesOffset.height() + label.rasterOffset() + valuesFontMetrics.getHeight() / 2d - valuesFontMetrics.getDescent() + )); + }); + } + + private static void renderXAxisName(Graphics2D graphics2D, + Graph graph, + RasterSize xAxisNameCenterOffset, + Font axisNameFont, + FontMetrics axisNameFontMetrics) { + var fgColor = graph.style().colors().foreground().toColor(); + graphics2D.setColor(fgColor); + graphics2D.setFont(axisNameFont); + + var title = graph.style().x().title(); + + graphics2D.fill(generateShapeFromText(graphics2D, + title, + xAxisNameCenterOffset.width() - axisNameFontMetrics.stringWidth(title) / 2d, + xAxisNameCenterOffset.height() + axisNameFontMetrics.getHeight() / 2d - axisNameFontMetrics.getDescent() + )); + } + + private static void renderXAxisValueLabels(Graphics2D graphics2D, + Graph graph, + Font valuesFont, + FontMetrics valuesFontMetrics, + double xValueLineOffset, + int xValueLineLength, + List xLabels, + RasterSize xValuesOffset, + BasicStroke defaultStroke) { + graphics2D.setFont(valuesFont); + graphics2D.setStroke(defaultStroke); + graphics2D.setColor(graph.style().colors().foreground().toColor()); + xLabels.forEach(label -> { + var lineStartOffsetX = xValuesOffset.width() + label.rasterOffset(); + var currentLineLength = label.formattedText().isBlank() ? xValueLineLength / 1.5d : xValueLineLength; + //noinspection SuspiciousNameCombination + graphics2D.draw(new Line2D.Double(lineStartOffsetX, xValueLineOffset, lineStartOffsetX, xValueLineOffset + currentLineLength)); + graphics2D.fill(generateShapeFromText(graphics2D, + label.formattedText(), + xValuesOffset.width() + label.rasterOffset() - valuesFontMetrics.stringWidth(label.formattedText()) / 2d, + xValuesOffset.height() + valuesFontMetrics.getHeight() + )); + }); + } + + private static void renderGraphBorders(Graphics2D graphics2D, + Graph graph, + RasterSize graphOffset, + RasterSize graphSize, + BasicStroke defaultStroke) { + var fgColor = graph.style().colors().foreground().toColor(); + graphics2D.setColor(fgColor); + graphics2D.setStroke(defaultStroke); + graphics2D.draw(new Rectangle2D.Double(graphOffset.width(), + graphOffset.height(), + graphSize.width(), + graphSize.height() + )); + } + + private static RasterSize computeYLabelsAreaSize(double graphHeight, FontMetrics valuesFontMetrics, List yLabels) { + double maxLabelWidth = 0d; + for (LabelWithOffset yLabel : yLabels) { + var currentMaxLabelWidth = valuesFontMetrics.stringWidth(yLabel.formattedText); + if (currentMaxLabelWidth > maxLabelWidth) { + maxLabelWidth = currentMaxLabelWidth; + } + } + + return new RasterSize(maxLabelWidth, graphHeight); + } + + record LabelWithOffset(double value, double rasterOffset, String formattedText) {} + + /** + * @return rendered labels + */ + private static List getXLabels(Graph graph, + double labelsAreaWidth, + FontMetrics valuesFontMetrics, + NiceScale scaleX) { + var bounds = graph.data().bounds(); + var minX = bounds.minX(); + var maxX = bounds.maxX(); + var format = graph.style().x().valueFormat(); + double singleRasterOffset = labelsAreaWidth / ((maxX - minX) / scaleX.getTickSpacing()); + + ArrayList labels = new ArrayList<>(); + + int i = 0; + double prevRasterLabelEndOffset = -Double.MAX_VALUE; + double currentRasterOffset = 0; + double currentValue = minX; + while (currentValue <= maxX && i < MAX_LABELS && (scaleX.getTickSpacing() > 0)) { + var formatted = format.apply(currentValue); + var stringWidth = valuesFontMetrics.stringWidth(formatted); + if (currentRasterOffset - stringWidth / 2d > prevRasterLabelEndOffset) { + labels.add(new LabelWithOffset(currentValue, currentRasterOffset, formatted)); + prevRasterLabelEndOffset = currentRasterOffset + stringWidth / 2d; + } else { + labels.add(new LabelWithOffset(currentValue, currentRasterOffset, "")); + } + + i++; + currentValue = minX + i * scaleX.getTickSpacing(); + currentRasterOffset = i * singleRasterOffset; + } + return labels; + } + + /** + * @return rendered labels + */ + private static List getYLabels(Graph graph, + double labelsAreaHeight, + FontMetrics valuesFontMetrics, + NiceScale scaleY) { + var bounds = graph.data().bounds(); + var minY = bounds.minY(); + var maxY = bounds.maxY(); + var format = graph.style().y().valueFormat(); + double singleRasterOffset = labelsAreaHeight / ((maxY - minY) / scaleY.getTickSpacing()); + double stringTop = valuesFontMetrics.getAscent(); + double stringBottom = valuesFontMetrics.getDescent(); + + ArrayList labels = new ArrayList<>(); + + int i = 0; + double prevRasterLabelEndOffset = Double.MAX_VALUE; + double currentRasterOffset = labelsAreaHeight; + double currentValue = minY; + while (currentValue <= maxY && i < MAX_LABELS && (scaleY.getTickSpacing() > 0)) { + if (currentRasterOffset + stringBottom < prevRasterLabelEndOffset) { + labels.add(new LabelWithOffset(currentValue, currentRasterOffset, format.apply(currentValue))); + prevRasterLabelEndOffset = currentRasterOffset - stringTop; + } else { + labels.add(new LabelWithOffset(currentValue, currentRasterOffset, "")); + } + + i++; + currentValue = minY + i * scaleY.getTickSpacing(); + currentRasterOffset = labelsAreaHeight - i * singleRasterOffset; + } + + return labels; + } + + public static Shape generateShapeFromText(Graphics2D graphics2D, String string, double x, double y) { + GlyphVector vector = graphics2D.getFont().createGlyphVector(graphics2D.getFontRenderContext(), string); + return vector.getOutline((float) x, (float) y);// - (float) vector.getVisualBounds().getY()); + } + + public interface AWTDrawer { + + void drawTo(Graphics2D graphics2D); + } +} diff --git a/src/main/java/it/cavallium/jlinegraph/Bezier.java b/src/main/java/it/cavallium/jlinegraph/Bezier.java new file mode 100644 index 0000000..16292e4 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/Bezier.java @@ -0,0 +1,118 @@ +package it.cavallium.jlinegraph; + +/* + * Copyright (c) 2005 David Benson + * + * See LICENSE file in distribution for licensing details of this source file + */ + +import java.awt.Point; +import java.awt.geom.Point2D; + +/** + * Interpolates given points by a bezier curve. The first + * and the last two points are interpolated by a quadratic + * bezier curve; the other points by a cubic bezier curve. + * + * Let p a list of given points and b the calculated bezier points, + * then one get the whole curve by: + * + * sharedPath.moveTo(p[0]) + * sharedPath.quadTo(b[0].x, b[0].getY(), p[1].x, p[1].getY()); + * + * for(int i = 2; i < p.length - 1; i++ ) { + * Point b0 = b[2*i-3]; + * Point b1 = b[2*i-2]; + * sharedPath.curveTo(b0.x, b0.getY(), b1.x, b1.getY(), p[i].x, p[i].getY()); + * } + * + * sharedPath.quadTo(b[b.length-1].x, b[b.length-1].getY(), p[n - 1].x, p[n - 1].getY()); + * + * @author krueger + */ +public class Bezier { + + private static final float AP = 0.5f; + private Point2D[] bPoints; + + /** + * Creates a new Bezier curve. + * @param points + */ + public Bezier(Point2D[] points) { + int n = points.length; + if (n < 3) { + // Cannot create bezier with less than 3 points + return; + } + bPoints = new Point[2 * (n - 2)]; + double paX, paY; + double pbX = points[0].getX(); + double pbY = points[0].getY(); + double pcX = points[1].getX(); + double pcY = points[1].getY(); + for (int i = 0; i < n - 2; i++) { + paX = pbX; + paY = pbY; + pbX = pcX; + pbY = pcY; + pcX = points[i + 2].getX(); + pcY = points[i + 2].getY(); + double abX = pbX - paX; + double abY = pbY - paY; + double acX = pcX - paX; + double acY = pcY - paY; + double lac = Math.sqrt(acX * acX + acY * acY); + acX = acX /lac; + acY = acY /lac; + + double proj = abX * acX + abY * acY; + proj = proj < 0 ? -proj : proj; + double apX = proj * acX; + double apY = proj * acY; + + double p1X = pbX - AP * apX; + double p1Y = pbY - AP * apY; + bPoints[2 * i] = new Point((int) p1X, (int) p1Y); + + acX = -acX; + acY = -acY; + double cbX = pbX - pcX; + double cbY = pbY - pcY; + proj = cbX * acX + cbY * acY; + proj = proj < 0 ? -proj : proj; + apX = proj * acX; + apY = proj * acY; + + double p2X = pbX - AP * apX; + double p2Y = pbY - AP * apY; + bPoints[2 * i + 1] = new Point((int) p2X, (int) p2Y); + } + } + + /** + * Returns the calculated bezier points. + * @return the calculated bezier points + */ + public Point2D[] getPoints() { + return bPoints; + } + + /** + * Returns the number of bezier points. + * @return number of bezier points + */ + public int getPointCount() { + return bPoints.length; + } + + /** + * Returns the bezier points at position i. + * @param i + * @return the bezier point at position i + */ + public Point2D getPoint(int i) { + return bPoints[i]; + } + +} \ No newline at end of file diff --git a/src/main/java/it/cavallium/jlinegraph/Color.java b/src/main/java/it/cavallium/jlinegraph/Color.java new file mode 100644 index 0000000..8a9e524 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/Color.java @@ -0,0 +1,36 @@ +package it.cavallium.jlinegraph; + +public record Color(float red, float green, float blue, float alpha) { + + public Color { + if (red < 0d || red > 1.0d) { + throw new IndexOutOfBoundsException(); + } + if (green < 0d || green > 1.0d) { + throw new IndexOutOfBoundsException(); + } + if (blue < 0d || blue > 1.0d) { + throw new IndexOutOfBoundsException(); + } + if (alpha < 0d || alpha > 1.0d) { + throw new IndexOutOfBoundsException(); + } + } + + public static Color fromRGB(int rgb) { + var col = new java.awt.Color(rgb); + return new Color(col.getRed() / 255f, col.getGreen() / 255f, col.getBlue() / 255f, 1); + } + + public java.awt.Color toColor() { + return new java.awt.Color(red, green, blue, alpha); + } + + public Color multiplyOpacity(float alpha) { + return new Color(red, green, blue, this.alpha * alpha); + } + + public Color overrideOpacity(float alpha) { + return new Color(red, green, blue, alpha); + } +} diff --git a/src/main/java/it/cavallium/jlinegraph/Graph.java b/src/main/java/it/cavallium/jlinegraph/Graph.java new file mode 100644 index 0000000..437c8dd --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/Graph.java @@ -0,0 +1,3 @@ +package it.cavallium.jlinegraph; + +public record Graph(String name, GraphData data, GraphStyle style) {} diff --git a/src/main/java/it/cavallium/jlinegraph/GraphAxisStyle.java b/src/main/java/it/cavallium/jlinegraph/GraphAxisStyle.java new file mode 100644 index 0000000..366f0ac --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/GraphAxisStyle.java @@ -0,0 +1,5 @@ +package it.cavallium.jlinegraph; + +import java.util.function.Function; + +public record GraphAxisStyle(String title, boolean show, Function valueFormat) {} diff --git a/src/main/java/it/cavallium/jlinegraph/GraphBounds.java b/src/main/java/it/cavallium/jlinegraph/GraphBounds.java new file mode 100644 index 0000000..1160dbf --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/GraphBounds.java @@ -0,0 +1,94 @@ +package it.cavallium.jlinegraph; + +import java.util.List; + +public record GraphBounds(double minX, double minY, double maxX, double maxY) { + + private static final GraphBounds EMPTY = new GraphBounds(0, 0, 0, 0); + + public static GraphBounds fromSeriesData(List seriesDataList, + boolean includeOriginX, + boolean includeOriginY) { + var merged = merge(seriesDataList + .stream() + .map(bound -> fromSeriesData(bound, includeOriginX, includeOriginY)) + .toList()); + return adjustZero(merged, includeOriginX, includeOriginY); + } + + private static GraphBounds adjustZero(GraphBounds bounds, boolean showZeroX, boolean showZeroY) { + double minX = bounds.minX(); + double minY = bounds.minY(); + double maxX = bounds.maxX(); + double maxY = bounds.maxY(); + if (showZeroY) { + minY = Math.min(0, bounds.minY()); + maxY = Math.max(0, bounds.maxY()); + } + if (showZeroX) { + minX = Math.min(0, bounds.minX()); + maxX = Math.max(0, bounds.maxX()); + } + return new GraphBounds(minX, minY, maxX, maxY); + } + + public static GraphBounds merge(List list) { + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = -Double.MAX_VALUE; + double maxY = -Double.MAX_VALUE; + boolean empty = true; + for (GraphBounds graphBounds : list) { + if (empty) { + empty = false; + } + if (minX > graphBounds.minX()) { + minX = graphBounds.minX(); + } + if (maxX < graphBounds.maxX()) { + maxX = graphBounds.maxX(); + } + if (minY > graphBounds.minY()) { + minY = graphBounds.minY(); + } + if (maxY < graphBounds.maxY()) { + maxY = graphBounds.maxY(); + } + } + if (empty) { + return EMPTY; + } else { + return new GraphBounds(minX, minY, maxX, maxY); + } + } + + public static GraphBounds fromSeriesData(SeriesData seriesData, boolean showZeroX, boolean showZeroY) { + double minX = Double.MAX_VALUE; + double minY = Double.MAX_VALUE; + double maxX = -Double.MAX_VALUE; + double maxY = -Double.MAX_VALUE; + boolean empty = true; + for (Vertex vertex : seriesData.vertices()) { + if (empty) { + empty = false; + } + if (minX > vertex.x()) { + minX = vertex.x(); + } + if (maxX < vertex.x()) { + maxX = vertex.x(); + } + if (minY > vertex.y()) { + minY = vertex.y(); + } + if (maxY < vertex.y()) { + maxY = vertex.y(); + } + } + if (empty) { + return EMPTY; + } else { + return adjustZero(new GraphBounds(minX, minY, maxX, maxY), showZeroX, showZeroY); + } + } +} diff --git a/src/main/java/it/cavallium/jlinegraph/GraphColors.java b/src/main/java/it/cavallium/jlinegraph/GraphColors.java new file mode 100644 index 0000000..d264477 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/GraphColors.java @@ -0,0 +1,7 @@ +package it.cavallium.jlinegraph; + +public record GraphColors(Color background, Color foreground) { + + public static GraphColors DARK = new GraphColors(new Color(0.1f, 0.1f, 0.1f, 1f), new Color(0.9f, 0.9f, 0.9f, 1f)); + public static GraphColors LIGHT = new GraphColors(new Color(1.0f, 1.0f, 1.0f, 1f), new Color(0.0f, 0.0f, 0.0f, 1f)); +} diff --git a/src/main/java/it/cavallium/jlinegraph/GraphData.java b/src/main/java/it/cavallium/jlinegraph/GraphData.java new file mode 100644 index 0000000..e5b2d93 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/GraphData.java @@ -0,0 +1,10 @@ +package it.cavallium.jlinegraph; + +import java.util.List; + +public record GraphData(List series, GraphBounds bounds) { + + public GraphData(List series) { + this(series, GraphBounds.fromSeriesData(series, false, false)); + } +} diff --git a/src/main/java/it/cavallium/jlinegraph/GraphFonts.java b/src/main/java/it/cavallium/jlinegraph/GraphFonts.java new file mode 100644 index 0000000..5bdcaa4 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/GraphFonts.java @@ -0,0 +1,3 @@ +package it.cavallium.jlinegraph; + +public record GraphFonts(double global, double axisName, double seriesName, double valueLabel) {} diff --git a/src/main/java/it/cavallium/jlinegraph/GraphStyle.java b/src/main/java/it/cavallium/jlinegraph/GraphStyle.java new file mode 100644 index 0000000..76512fd --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/GraphStyle.java @@ -0,0 +1,6 @@ +package it.cavallium.jlinegraph; + +import java.util.List; + +public record GraphStyle(List seriesStyles, GraphAxisStyle x, GraphAxisStyle y, GraphColors colors, + GraphFonts fonts, double strokeWidth, boolean showLegend) {} diff --git a/src/main/java/it/cavallium/jlinegraph/IGraphRenderer.java b/src/main/java/it/cavallium/jlinegraph/IGraphRenderer.java new file mode 100644 index 0000000..83a0264 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/IGraphRenderer.java @@ -0,0 +1,6 @@ +package it.cavallium.jlinegraph; + +public interface IGraphRenderer { + + T renderGraph(Graph graph, RasterSize size); +} diff --git a/src/main/java/it/cavallium/jlinegraph/NiceScale.java b/src/main/java/it/cavallium/jlinegraph/NiceScale.java new file mode 100644 index 0000000..8305402 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/NiceScale.java @@ -0,0 +1,111 @@ +package it.cavallium.jlinegraph; + +@SuppressWarnings("FieldCanBeLocal") +public class NiceScale { + + private double minPoint; + private double maxPoint; + private double maxTicks = 10; + private double tickSpacing; + private double range; + private double niceMin; + private double niceMax; + + /** + * Instantiates a new instance of the NiceScale class. + * + * @param min the minimum data point on the axis + * @param max the maximum data point on the axis + */ + public NiceScale(double min, double max) { + this.minPoint = min; + this.maxPoint = max; + calculate(); + } + + /** + * Calculate and update values for tick spacing and nice + * minimum and maximum data points on the axis. + */ + private void calculate() { + this.range = niceNum(maxPoint - minPoint, false); + this.tickSpacing = niceNum(range / (maxTicks - 1), true); + this.niceMin = + Math.floor(minPoint / tickSpacing) * tickSpacing; + this.niceMax = + Math.ceil(maxPoint / tickSpacing) * tickSpacing; + } + + /** + * Returns a "nice" number approximately equal to range Rounds + * the number if round = true Takes the ceiling if round = false. + * + * @param range the data range + * @param round whether to round the result + * @return a "nice" number to be used for the data range + */ + private double niceNum(double range, boolean round) { + double exponent; /** exponent of range */ + double fraction; /** fractional part of range */ + double niceFraction; /** nice, rounded fraction */ + + exponent = Math.floor(Math.log10(range)); + fraction = range / Math.pow(10, exponent); + + if (round) { + if (fraction < 1.5) + niceFraction = 1; + else if (fraction < 3) + niceFraction = 2; + else if (fraction < 7) + niceFraction = 5; + else + niceFraction = 10; + } else { + if (fraction <= 1) + niceFraction = 1; + else if (fraction <= 2) + niceFraction = 2; + else if (fraction <= 5) + niceFraction = 5; + else + niceFraction = 10; + } + + return niceFraction * Math.pow(10, exponent); + } + + /** + * Sets the minimum and maximum data points for the axis. + * + * @param minPoint the minimum data point on the axis + * @param maxPoint the maximum data point on the axis + */ + public void setMinMaxPoints(double minPoint, double maxPoint) { + this.minPoint = minPoint; + this.maxPoint = maxPoint; + calculate(); + } + + /** + * Sets maximum number of tick marks we're comfortable with + * + * @param maxTicks the maximum number of tick marks for the axis + */ + public void setMaxTicks(double maxTicks) { + this.maxTicks = maxTicks; + calculate(); + } + + public double getNiceMin() { + return niceMin; + } + + public double getNiceMax() { + return niceMax; + } + + public double getTickSpacing() { + return tickSpacing; + } +} \ No newline at end of file diff --git a/src/main/java/it/cavallium/jlinegraph/RasterSize.java b/src/main/java/it/cavallium/jlinegraph/RasterSize.java new file mode 100644 index 0000000..c0fcec9 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/RasterSize.java @@ -0,0 +1,3 @@ +package it.cavallium.jlinegraph; + +public record RasterSize(double width, double height) {} diff --git a/src/main/java/it/cavallium/jlinegraph/SeriesData.java b/src/main/java/it/cavallium/jlinegraph/SeriesData.java new file mode 100644 index 0000000..1fdbb29 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/SeriesData.java @@ -0,0 +1,5 @@ +package it.cavallium.jlinegraph; + +import java.util.List; + +public record SeriesData(List vertices, boolean isFunction, String name) {} diff --git a/src/main/java/it/cavallium/jlinegraph/SeriesStyle.java b/src/main/java/it/cavallium/jlinegraph/SeriesStyle.java new file mode 100644 index 0000000..8270181 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/SeriesStyle.java @@ -0,0 +1,19 @@ +package it.cavallium.jlinegraph; + +public record SeriesStyle(Color color, double pointsWeight, double lineWeight, double areaOpacity, double smoothness) { + + public SeriesStyle { + if (pointsWeight != 0 && (pointsWeight < 1d || pointsWeight > 4.0d)) { + throw new IndexOutOfBoundsException(); + } + if (lineWeight != 0 && (lineWeight < 1d || lineWeight > 4.0d)) { + throw new IndexOutOfBoundsException(); + } + if (areaOpacity < 0d || areaOpacity > 1.0d) { + throw new IndexOutOfBoundsException(); + } + if (smoothness < 0d || smoothness > 1.0d) { + throw new IndexOutOfBoundsException(); + } + } +} diff --git a/src/main/java/it/cavallium/jlinegraph/Vertex.java b/src/main/java/it/cavallium/jlinegraph/Vertex.java new file mode 100644 index 0000000..a51c4b5 --- /dev/null +++ b/src/main/java/it/cavallium/jlinegraph/Vertex.java @@ -0,0 +1,3 @@ +package it.cavallium.jlinegraph; + +public record Vertex(double x, double y) {}