From 2ca9fa5ff2304ef373bfe948594e5803394436a9 Mon Sep 17 00:00:00 2001 From: Nirus2000 <45203494+Nirus2000@users.noreply.github.com> Date: Sat, 15 Oct 2022 15:37:18 +0200 Subject: [PATCH 1/3] Little update for your pull request 1. Press SHIFT + mouse button 1 for drawing. 1.1. SHIFT + mouse button 1 can be released while aiming at the second point. 2. Press mouse button 1 resets the diagram again 3. Textbox revised, but I had no time to add the translations. 4. Fixed point 1 is greater than point 2. (Calculation error) 5. I think the painting delay is fixed 6. Rename Crosshair feature to MeasureLine 7. Delete Crosshair painter The position of the textbox should be better positioned now. If it is very far to the right in the chart, it is no longer displayed. Maybe it should be drawn via `setupTooltip();`. Have fun... :beer: :beer: :beer: :beer: :beer: Alex --- .../portfolio/ui/views/SecuritiesChart.java | 141 +++++++++--------- 1 file changed, 69 insertions(+), 72 deletions(-) diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java index d263160d35..b937a170ce 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java @@ -40,8 +40,8 @@ import org.swtchart.ICustomPaintListener; import org.swtchart.ILegend; import org.swtchart.ILineSeries; -import org.swtchart.IPlotArea; import org.swtchart.ILineSeries.PlotSymbolType; +import org.swtchart.IPlotArea; import org.swtchart.ISeries; import org.swtchart.ISeries.SeriesType; import org.swtchart.LineStyle; @@ -387,7 +387,7 @@ public SecuritiesChart(Composite parent, Client client, CurrencyConverter conver legend.setPosition(SWT.BOTTOM); legend.setVisible(true); - new CrosshairPainter(chart); + new MeasureLinePainter(chart); } public IntervalOption getIntervalOption() @@ -966,10 +966,14 @@ private void addLimitLines(ChartInterval chartInterval, ChartRange range) LimitPrice limitAttribute = (LimitPrice) val; - // unwrap because ReadOnlyClient only contains/provides default - // attributes - Optional attributeName = ReadOnlyClient.unwrap(client).getSettings().getAttributeTypes() - .filter(attr -> attr.getId().equals(key)).findFirst(); + Optional attributeName = ReadOnlyClient.unwrap(client) // unwrap + // because + // ReadOnlyClient + // only + // contains/provides + // default + // attributes + .getSettings().getAttributeTypes().filter(attr -> attr.getId().equals(key)).findFirst(); // could not find name of limit attribute --> don't draw if (attributeName.isEmpty()) return; @@ -1618,13 +1622,13 @@ private Optional getMovingAveragePurchasePrice(Client filteredClient, Cu .map(r -> r.getMovingAverageCostPerSharesHeld().getAmount() / Values.Quote.divider()); } - private class CrosshairPainter implements Listener + private class MeasureLinePainter implements Listener { TimelineChart chart; Point p1; Point p2; - private CrosshairPainter(TimelineChart chart) + private MeasureLinePainter(TimelineChart chart) { this.chart = chart; ((IPlotArea) chart.getPlotArea()).addCustomPaintListener(new ICustomPaintListener() @@ -1632,62 +1636,55 @@ private CrosshairPainter(TimelineChart chart) @Override public void paintControl(PaintEvent e) { - if (p1 == null) - return; - - if (p2 == null) - { - if (!redrawOnMove) - drawCrosshair(e, p1.x, p1.y); - + if (p1 == null || p2 == null) return; - } - + drawMeasureLine(e, p1, p2); } - private void drawCrosshair(PaintEvent e, int mouseX, int mouseY) - { - e.gc.setLineStyle(SWT.LINE_SOLID); - e.gc.setForeground(Colors.ICON_ORANGE); - // draw crosshair - e.gc.drawLine(mouseX, 0, mouseX, e.height); - e.gc.drawLine(0, mouseY, e.width, mouseY); - - // draw x- and y-value - LocalDate date = Instant - .ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(mouseX)) - .atZone(ZoneId.systemDefault()).toLocalDate(); - e.gc.drawText(Values.Date.format(date), mouseX + 5, e.height - 20, true); - e.gc.drawText(String.valueOf(chart.getAxisSet().getYAxis(0).getDataCoordinate(mouseY)), - e.width - 80, mouseY + 5, true); - } - private void drawMeasureLine(PaintEvent e, Point p1, Point p2) { + double yValP1; + double yValP2; + e.gc.setLineStyle(SWT.LINE_SOLID); e.gc.setForeground(Colors.ICON_ORANGE); - - e.gc.drawLine(p1.x, p1.y, p2.x,p2.y); - e.gc.setBackground(Colors.ICON_ORANGE); - e.gc.fillOval(p1.x-2, p1.y-2, 4, 4); - e.gc.fillOval(p2.x-2, p2.y-2, 4, 4); - - double yValP1 = getYValue(p1); - double yValP2 = getYValue(p2); - - String text = "P1: " + yValP1 + System.lineSeparator() - + "P2: " + yValP2 + System.lineSeparator() - + "P2/P1: " + new DecimalFormat("#.##%").format(yValP2/yValP1) + System.lineSeparator() - + "P2/P1-1: " + new DecimalFormat("+#.##%;-#.##%").format(yValP2/yValP1 - 1); - + + e.gc.drawLine(p1.x, p1.y, p2.x, p2.y); + e.gc.setForeground(Colors.theme().defaultForeground()); + e.gc.fillOval(p1.x - 2, p1.y - 2, 4, 4); + e.gc.fillOval(p2.x - 2, p2.y - 2, 4, 4); + + if (p1.x < p2.x) + { + yValP1 = getYValue(p1); + yValP2 = getYValue(p2); + } + else + { + yValP1 = getYValue(p2); + yValP2 = getYValue(p1); + } + + String text = "P1: " + new DecimalFormat(Values.Quote.pattern()).format(yValP1) // //$NON-NLS-1$ + + System.lineSeparator() // + + "P2: " + new DecimalFormat(Values.Quote.pattern()).format(yValP2) // //$NON-NLS-1$ + + System.lineSeparator() // + + "absolute Abweichung: " // //$NON-NLS-1$ + + new DecimalFormat(Values.Quote.pattern()).format(yValP2 - yValP1) + + System.lineSeparator() // + + "relative Abweichung: " // //$NON-NLS-1$ + + new DecimalFormat(Values.Percent.pattern()).format(1 - (yValP1 - yValP2) / yValP2) + + System.lineSeparator() // + + "prozentuale Abweichung: " // //$NON-NLS-1$ + + new DecimalFormat(Values.Percent.pattern()).format((yValP2 - yValP1) / yValP1); + Point txtExtend = e.gc.textExtent(text); - e.gc.setBackground(Colors.SIDEBAR_TEXT); - - e.gc.fillRectangle((p1.x + p2.x) / 2 - 5, (p1.y + p2.y) / 2 - 5, txtExtend.x + 10, txtExtend.y + 10); - e.gc.setForeground(Colors.GRAY); - e.gc.drawRectangle((p1.x + p2.x) / 2 - 5, (p1.y + p2.y) / 2 - 5, txtExtend.x + 10, txtExtend.y + 10); - e.gc.setForeground(Colors.ICON_ORANGE); + + e.gc.fillRectangle((p1.x + p2.x) / 2 - 5, (p1.y + p2.y) / 2 - 5, txtExtend.x + 10, + txtExtend.y + 10); + e.gc.drawRectangle((p1.x + p2.x) / 2 - 5, (p1.y + p2.y) / 2 - 5, txtExtend.x + 10, + txtExtend.y + 10); e.gc.drawText(text, (p1.x + p2.x) / 2, (p1.y + p2.y) / 2); } @@ -1696,7 +1693,7 @@ public boolean drawBehindSeries() { return false; } - + private double getYValue(Point p) { return chart.getAxisSet().getYAxis(0).getDataCoordinate(p.y); @@ -1715,38 +1712,38 @@ public void handleEvent(Event e) { switch (e.type) { - case SWT.MouseMove: - if (redrawOnMove) - { - p2 = new Point(e.x, e.y); - chart.redraw(); - } - - return; case SWT.MouseDown: - if (e.button==1) + if ((e.stateMask & SWT.SHIFT) != 0 && e.button == 1) { p2 = null; p1 = new Point(e.x, e.y); redrawOnMove = true; chart.redraw(); } - - // delete/erase crosshair on right mouse click - if (e.button == 3) + + return; + case SWT.MouseMove: + if (redrawOnMove) { - p1 = null; - p2 = null; + p2 = new Point(e.x, e.y); chart.redraw(); } - + return; case SWT.MouseUp: - if (e.button == 1) + if (e.button == 1 && !redrawOnMove) + { + p1 = null; + p2 = null; + chart.redraw(); + } + + if ((e.stateMask & SWT.SHIFT) == 0 && e.button == 1) { redrawOnMove = false; chart.redraw(); } + return; default: return; From 0edf727f61837977c4b65778378bc94fdaee33ac Mon Sep 17 00:00:00 2001 From: Nirus2000 <45203494+Nirus2000@users.noreply.github.com> Date: Sat, 15 Oct 2022 16:22:46 +0200 Subject: [PATCH 2/3] Add start and end date in measurement line Add start and end date in measurement line --- .../portfolio/ui/views/SecuritiesChart.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java index b937a170ce..a6dfbd64a2 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java @@ -381,13 +381,13 @@ public SecuritiesChart(Composite parent, Client client, CurrencyConverter conver chart.getPlotArea().addPaintListener(event -> customPaintListeners.forEach(l -> l.paintControl(event))); chart.getPlotArea().addPaintListener(event -> customBehindPaintListener.forEach(l -> l.paintControl(event))); - setupTooltip(); - ILegend legend = chart.getLegend(); legend.setPosition(SWT.BOTTOM); legend.setVisible(true); new MeasureLinePainter(chart); + + setupTooltip(); } public IntervalOption getIntervalOption() @@ -1644,6 +1644,8 @@ public void paintControl(PaintEvent e) private void drawMeasureLine(PaintEvent e, Point p1, Point p2) { + LocalDate StartDate; + LocalDate EndDate; double yValP1; double yValP2; @@ -1659,16 +1661,22 @@ private void drawMeasureLine(PaintEvent e, Point p1, Point p2) { yValP1 = getYValue(p1); yValP2 = getYValue(p2); + + StartDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p1.x)).atZone(ZoneId.systemDefault()).toLocalDate(); + EndDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p2.x)).atZone(ZoneId.systemDefault()).toLocalDate(); } else { yValP1 = getYValue(p2); yValP2 = getYValue(p1); + + StartDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p2.x)).atZone(ZoneId.systemDefault()).toLocalDate(); + EndDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p1.x)).atZone(ZoneId.systemDefault()).toLocalDate(); } - String text = "P1: " + new DecimalFormat(Values.Quote.pattern()).format(yValP1) // //$NON-NLS-1$ + String text = "P1: " + new DecimalFormat(Values.Quote.pattern()).format(yValP1) + " (" + StartDate + ")" // //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + System.lineSeparator() // - + "P2: " + new DecimalFormat(Values.Quote.pattern()).format(yValP2) // //$NON-NLS-1$ + + "P2: " + new DecimalFormat(Values.Quote.pattern()).format(yValP2) + " (" + EndDate + ")" // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + System.lineSeparator() // + "absolute Abweichung: " // //$NON-NLS-1$ + new DecimalFormat(Values.Quote.pattern()).format(yValP2 - yValP1) From fa827475102398e40bbd4c220cbf4ee97a37396d Mon Sep 17 00:00:00 2001 From: Nirus2000 <45203494+Nirus2000@users.noreply.github.com> Date: Sun, 16 Oct 2022 07:27:35 +0200 Subject: [PATCH 3/3] Switch to toLocalDateTime --- .../portfolio/ui/views/SecuritiesChart.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java index a6dfbd64a2..db6e1060e6 100644 --- a/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java +++ b/name.abuchen.portfolio.ui/src/name/abuchen/portfolio/ui/views/SecuritiesChart.java @@ -1644,8 +1644,8 @@ public void paintControl(PaintEvent e) private void drawMeasureLine(PaintEvent e, Point p1, Point p2) { - LocalDate StartDate; - LocalDate EndDate; + LocalDateTime StartDate; + LocalDateTime EndDate; double yValP1; double yValP2; @@ -1662,21 +1662,21 @@ private void drawMeasureLine(PaintEvent e, Point p1, Point p2) yValP1 = getYValue(p1); yValP2 = getYValue(p2); - StartDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p1.x)).atZone(ZoneId.systemDefault()).toLocalDate(); - EndDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p2.x)).atZone(ZoneId.systemDefault()).toLocalDate(); + StartDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p1.x)).atZone(ZoneId.systemDefault()).toLocalDateTime(); + EndDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p2.x)).atZone(ZoneId.systemDefault()).toLocalDateTime(); } else { yValP1 = getYValue(p2); yValP2 = getYValue(p1); - StartDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p2.x)).atZone(ZoneId.systemDefault()).toLocalDate(); - EndDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p1.x)).atZone(ZoneId.systemDefault()).toLocalDate(); + StartDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p2.x)).atZone(ZoneId.systemDefault()).toLocalDateTime(); + EndDate = Instant.ofEpochMilli((long) chart.getAxisSet().getXAxis(0).getDataCoordinate(p1.x)).atZone(ZoneId.systemDefault()).toLocalDateTime(); } - - String text = "P1: " + new DecimalFormat(Values.Quote.pattern()).format(yValP1) + " (" + StartDate + ")" // //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + + String text = "P1: " + new DecimalFormat(Values.Quote.pattern()).format(yValP1) + " (" + Values.DateTime.format(StartDate) + ")" // //$NON-NLS-1$//$NON-NLS-2$//$NON-NLS-3$ + System.lineSeparator() // - + "P2: " + new DecimalFormat(Values.Quote.pattern()).format(yValP2) + " (" + EndDate + ")" // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + + "P2: " + new DecimalFormat(Values.Quote.pattern()).format(yValP2) + " (" + Values.DateTime.format(EndDate) + ")" // //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ + System.lineSeparator() // + "absolute Abweichung: " // //$NON-NLS-1$ + new DecimalFormat(Values.Quote.pattern()).format(yValP2 - yValP1)