Update chart WIP

This commit is contained in:
Manfred Karrer 2016-07-24 17:50:14 +02:00
parent f743bb88a8
commit bdad86526a
9 changed files with 391 additions and 78 deletions

View file

@ -73,18 +73,29 @@
-demo-bar-fill: #cccccc;
}
.chart-plot-background {
-fx-background-color: transparent;
.volume-bar {
-fx-padding: 5;
-demo-bar-fill: #91b1cc;
-fx-background-color: #91b1cc;
-fx-background-insets: 0, 1, 2;
}
.default-color0.chart-series-line {
.volume-bar.bg {
-demo-bar-fill: #91b1cc;
}
.volume-bar {
-fx-effect: dropshadow(two-pass-box, rgba(0, 0, 0, 0.4), 10, 0.0, 2, 4);
}
/*.default-color0.chart-series-line {
-fx-stroke: blue;
}
.default-color0.chart-line-symbol {
-fx-background-color: red, green;
}
}*/
.chart-alternative-row-fill {
@ -97,6 +108,7 @@
-fx-background-color: transparent;
}
/*
.chart-legend {
-fx-background-color: transparent;
-fx-padding: 20px;
@ -105,4 +117,4 @@
.chart-legend-item-symbol {
-fx-background-radius: 0;
}
*/

View file

@ -21,7 +21,7 @@ import io.bitsquare.common.UserThread;
import io.bitsquare.gui.common.view.ActivatableViewAndModel;
import io.bitsquare.gui.common.view.FxmlView;
import io.bitsquare.gui.main.markets.trades.candlestick.CandleStickChart;
import io.bitsquare.gui.main.markets.trades.candlestick.MyBarChart;
import io.bitsquare.gui.main.markets.trades.candlestick.VolumeChart;
import io.bitsquare.gui.util.BSFormatter;
import io.bitsquare.locale.CryptoCurrency;
import io.bitsquare.locale.FiatCurrency;
@ -36,7 +36,6 @@ import javafx.collections.ListChangeListener;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.geometry.Side;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.*;
@ -45,6 +44,7 @@ import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.util.Callback;
import javafx.util.StringConverter;
import org.bitcoinj.core.Coin;
import org.bitcoinj.utils.Fiat;
import org.fxmisc.easybind.EasyBind;
import org.fxmisc.easybind.Subscription;
@ -54,6 +54,7 @@ import org.slf4j.LoggerFactory;
import javax.inject.Inject;
import java.util.Date;
import java.util.concurrent.TimeUnit;
@FxmlView
public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesChartsViewModel> {
@ -70,10 +71,9 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
private ToggleGroup toggleGroup;
private NumberAxis timeAxisX, priceAxisY, volumeAxisY;
private CategoryAxis volumeAxisX;
private XYChart.Series<Number, Number> priceSeries;
private XYChart.Series<String, Number> volumeSeries;
private MyBarChart<String, Number> volumeChart;
private XYChart.Series<Number, Number> volumeSeries;
private VolumeChart volumeChart;
private CandleStickChart priceChart;
private final ListChangeListener<XYChart.Data<Number, Number>> itemsChangeListener;
@ -88,7 +88,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
super(model);
this.formatter = formatter;
itemsChangeListener = c -> updateChartData();
itemsChangeListener = c -> UserThread.runAfter(() -> updateChartData(), 20, TimeUnit.MILLISECONDS);
}
@Override
@ -99,7 +99,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
final VBox tableVBox = getTableBox();
StackPane stackPane = new StackPane();
stackPane.getChildren().addAll(volumeChart, priceChart);
stackPane.getChildren().addAll(priceChart, volumeChart);
root.getChildren().addAll(currencyHBox, toggleBarHBox, stackPane, tableVBox);
@ -157,9 +157,14 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
///////////////////////////////////////////////////////////////////////////////////////////
private void createChart() {
volumeSeries = new XYChart.Series<>();
timeAxisX = new NumberAxis(0, model.upperBound + 1, 1);
timeAxisX.setTickUnit(1);
timeAxisX.setMinorTickCount(0);
timeAxisX.setForceZeroInRange(false);
timeAxisX.setLabel("Date/Time");
timeAxisX.setTickLabelFormatter(getTimeAxisStringConverter());
volumeAxisX = new CategoryAxis();
volumeSeries = new XYChart.Series<>();
volumeAxisY = new NumberAxis();
volumeAxisY.setForceZeroInRange(false);
@ -168,23 +173,20 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
volumeAxisY.setTickLabelFormatter(getVolumeStringConverter());
volumeAxisY.setSide(Side.RIGHT);
volumeChart = new MyBarChart<>(volumeAxisX, volumeAxisY);
NumberAxis volumeAxisX = new NumberAxis(0, model.upperBound + 1, 1);
volumeAxisX.setTickLabelsVisible(false);
volumeAxisX.setTickMarkVisible(false);
volumeAxisX.lookup(".axis-minor-tick-mark").setOpacity(0);
volumeChart = new VolumeChart(volumeAxisX, volumeAxisY);
volumeChart.setData(FXCollections.observableArrayList(volumeSeries));
volumeChart.setAnimated(true);
volumeChart.setAnimated(false);
volumeChart.setMinHeight(300);
volumeChart.setPadding(new Insets(0, 0, -10, 75));
volumeChart.setPadding(new Insets(0, 0, 40, 69));
volumeChart.setLegendVisible(false);
priceSeries = new XYChart.Series<>();
timeAxisX = new NumberAxis(0, model.upperBound + 1, 1);
timeAxisX.setTickUnit(1);
timeAxisX.setMinorTickCount(0);
timeAxisX.setForceZeroInRange(false);
timeAxisX.setLabel("Date/Time");
timeAxisX.setTickLabelFormatter(getTimeAxisStringConverter());
priceAxisY = new NumberAxis();
priceAxisY.setForceZeroInRange(false);
priceAxisY.setAutoRanging(true);
@ -197,7 +199,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
priceChart.setLegendVisible(false);
priceChart.setAnimated(true);
priceChart.setMinHeight(300);
priceChart.setPadding(new Insets(0, 75, -10, 0));
priceChart.setPadding(new Insets(0, 69, 0, 0));
priceChart.setAlternativeRowFillVisible(false);
priceChart.setAlternativeColumnFillVisible(false);
priceChart.setHorizontalGridLinesVisible(false);
@ -213,7 +215,11 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
priceChart.getData().clear();
priceChart.setData(FXCollections.observableArrayList(priceSeries));
volumeSeries.getData().clear();
volumeSeries = new XYChart.Series<>();
volumeSeries.getData().setAll(model.volumeItems);
volumeChart.getData().clear();
volumeChart.setData(FXCollections.observableArrayList(volumeSeries));
}
@NotNull
@ -261,7 +267,7 @@ public class TradesChartsView extends ActivatableViewAndModel<VBox, TradesCharts
@Override
public String toString(Number object) {
// comes as double
return formatter.formatFiat(Fiat.valueOf(model.getCurrencyCode(), new Double((double) object).longValue()));
return formatter.formatCoin(Coin.valueOf(new Double((double) object).longValue()));
}
@Override

View file

@ -60,7 +60,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
final ObjectProperty<TradeCurrency> tradeCurrency = new SimpleObjectProperty<>();
private final HashMapChangedListener mapChangedListener;
ObservableList<XYChart.Data<Number, Number>> priceItems = FXCollections.observableArrayList();
ObservableList<XYChart.Data<String, Number>> volumeItems = FXCollections.observableArrayList();
ObservableList<XYChart.Data<Number, Number>> volumeItems = FXCollections.observableArrayList();
private P2PService p2PService;
final ObservableList<TradeStatistics> tradeStatistics = FXCollections.observableArrayList();
@ -162,7 +162,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
.collect(Collectors.toList()));
volumeItems.setAll(candleDataList.stream()
.map(e -> new XYChart.Data<String, Number>(String.valueOf(e.tick), e.open, new CandleStickExtraValues(e.close, e.high, e.low, e.average)))
.map(e -> new XYChart.Data<Number, Number>(e.tick, e.accumulatedAmount))
.collect(Collectors.toList()));
}
@ -171,17 +171,17 @@ class TradesChartsViewModel extends ActivatableViewModel {
long close = 0;
long high = 0;
long low = 0;
long volume = 0;
long amount = 0;
long accumulatedVolume = 0;
long accumulatedAmount = 0;
for (TradeStatistics item : set) {
final long tradePriceAsLong = item.tradePriceAsLong;
low = (low != 0) ? Math.min(low, tradePriceAsLong) : tradePriceAsLong;
high = (high != 0) ? Math.max(high, tradePriceAsLong) : tradePriceAsLong;
volume += item.getTradeVolume().value;
amount += item.tradeAmountAsLong;
accumulatedVolume += item.getTradeVolume().value;
accumulatedAmount += item.tradeAmountAsLong;
}
long averagePrice = Math.round(volume * Coin.COIN.value / amount);
long averagePrice = Math.round(accumulatedVolume * Coin.COIN.value / accumulatedAmount);
List<TradeStatistics> list = new ArrayList<>(set);
list.sort((o1, o2) -> (o1.tradeDateAsTime < o2.tradeDateAsTime ? -1 : (o1.tradeDateAsTime == o2.tradeDateAsTime ? 0 : 1)));
@ -190,7 +190,7 @@ class TradesChartsViewModel extends ActivatableViewModel {
close = list.get(list.size() - 1).tradePriceAsLong;
}
boolean isBullish = close > open;
return new CandleData(tick, open, close, high, low, averagePrice, amount, volume, isBullish);
return new CandleData(tick, open, close, high, low, averagePrice, accumulatedAmount, accumulatedVolume, isBullish);
}

View file

@ -7,19 +7,19 @@ public class CandleData {
public final long high;
public final long low;
public final long average;
public final long amount;
public final long volume;
public final long accumulatedAmount;
public final long accumulatedVolume;
public final boolean isBullish;
public CandleData(long tick, long open, long close, long high, long low, long average, long amount, long volume, boolean isBullish) {
public CandleData(long tick, long open, long close, long high, long low, long average, long accumulatedAmount, long accumulatedVolume, boolean isBullish) {
this.tick = tick;
this.open = open;
this.close = close;
this.high = high;
this.low = low;
this.average = average;
this.amount = amount;
this.volume = volume;
this.accumulatedAmount = accumulatedAmount;
this.accumulatedVolume = accumulatedVolume;
this.isBullish = isBullish;
}
}

View file

@ -1,31 +0,0 @@
package io.bitsquare.gui.main.markets.trades.candlestick;
import javafx.collections.ObservableList;
import javafx.scene.chart.Axis;
import javafx.scene.chart.BarChart;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MyBarChart<X, Y> extends BarChart<X, Y> {
private static final Logger log = LoggerFactory.getLogger(MyBarChart.class);
public MyBarChart(Axis<X> xAxis, Axis<Y> yAxis) {
super(xAxis, yAxis);
}
public MyBarChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<Series<X, Y>> data) {
super(xAxis, yAxis, data);
}
public MyBarChart(Axis<X> xAxis, Axis<Y> yAxis, ObservableList<Series<X, Y>> data, double categoryGap) {
super(xAxis, yAxis, data, categoryGap);
}
@Override
protected void dataItemAdded(Series<X, Y> series, int itemIndex, Data<X, Y> item) {
if (getPlotChildren().contains(item.getNode()))
getPlotChildren().remove(item.getNode());
super.dataItemAdded(series, itemIndex, item);
}
}

View file

@ -69,9 +69,11 @@ public class TooltipContent extends GridPane {
}
public void update(double open, double close, double high, double low) {
openValue.setText(toolTipStringConverter.toString(open));
closeValue.setText(toolTipStringConverter.toString(close));
highValue.setText(toolTipStringConverter.toString(high));
lowValue.setText(toolTipStringConverter.toString(low));
if (toolTipStringConverter != null) {
openValue.setText(toolTipStringConverter.toString(open));
closeValue.setText(toolTipStringConverter.toString(close));
highValue.setText(toolTipStringConverter.toString(high));
lowValue.setText(toolTipStringConverter.toString(low));
}
}
}

View file

@ -0,0 +1,77 @@
/*
* Copyright (c) 2008, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* - Neither the name of Oracle Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.bitsquare.gui.main.markets.trades.candlestick;
import javafx.scene.Group;
import javafx.scene.layout.Region;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Candle node used for drawing a candle
*/
public class VolumeBar extends Group {
private static final Logger log = LoggerFactory.getLogger(VolumeBar.class);
private Region bar = new Region();
private String seriesStyleClass;
private String dataStyleClass;
VolumeBar(String seriesStyleClass, String dataStyleClass, StringConverter<Number> toolTipStringConverter) {
setAutoSizeChildren(false);
bar.setOpacity(0.7);
getChildren().add(bar);
this.seriesStyleClass = seriesStyleClass;
this.dataStyleClass = dataStyleClass;
updateStyleClasses();
}
public void setSeriesAndDataStyleClasses(String seriesStyleClass, String dataStyleClass) {
this.seriesStyleClass = seriesStyleClass;
this.dataStyleClass = dataStyleClass;
updateStyleClasses();
}
public void update(double volume, double candleWidth) {
updateStyleClasses();
if (candleWidth == -1)
candleWidth = bar.prefWidth(-1);
log.error("closeOffset " + volume);
bar.resizeRelocate(-candleWidth / 2, 0, candleWidth, Math.max(5, volume));
}
private void updateStyleClasses() {
bar.getStyleClass().setAll("volume-bar", seriesStyleClass, dataStyleClass, "bg");
}
}

View file

@ -0,0 +1,247 @@
/*
* Copyright (c) 2008, 2014, Oracle and/or its affiliates.
* All rights reserved. Use is subject to license terms.
*
* This file is available and licensed under the following license:
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the distribution.
* - Neither the name of Oracle Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package io.bitsquare.gui.main.markets.trades.candlestick;
import javafx.animation.FadeTransition;
import javafx.event.ActionEvent;
import javafx.scene.Node;
import javafx.scene.chart.Axis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.util.Duration;
import javafx.util.StringConverter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
/**
* A candlestick chart is a style of bar-chart used primarily to describe price movements of a security, derivative,
* or currency over time.
* <p>
* The Data Y value is used for the opening price and then the close, high and low values are stored in the Data's
* extra value property using a CandleStickExtraValues object.
*/
public class VolumeChart extends XYChart<Number, Number> {
private static final Logger log = LoggerFactory.getLogger(CandleStickChart.class);
private StringConverter<Number> toolTipStringConverter;
// -------------- CONSTRUCTORS ----------------------------------------------
/**
* Construct a new CandleStickChart with the given axis.
*
* @param xAxis The x axis to use
* @param yAxis The y axis to use
*/
public VolumeChart(Axis<Number> xAxis, Axis<Number> yAxis) {
super(xAxis, yAxis);
}
// -------------- METHODS ------------------------------------------------------------------------------------------
public final void setToolTipStringConverter(StringConverter<Number> toolTipStringConverter) {
this.toolTipStringConverter = toolTipStringConverter;
}
/**
* Called to update and layout the content for the plot
*/
@Override
protected void layoutPlotChildren() {
// we have nothing to layout if no data is present
if (getData() == null) {
return;
}
// update volumeBar positions
for (int seriesIndex = 0; seriesIndex < getData().size(); seriesIndex++) {
XYChart.Series<Number, Number> series = getData().get(seriesIndex);
Iterator<XYChart.Data<Number, Number>> iter = getDisplayedDataIterator(series);
while (iter.hasNext()) {
XYChart.Data<Number, Number> item = iter.next();
double x = getXAxis().getDisplayPosition(getCurrentDisplayedXValue(item));
double y = getYAxis().getDisplayPosition(getCurrentDisplayedYValue(item));
Node itemNode = item.getNode();
if (itemNode instanceof VolumeBar) {
VolumeBar volumeBar = (VolumeBar) itemNode;
double candleWidth = -1;
if (getXAxis() instanceof NumberAxis) {
NumberAxis xa = (NumberAxis) getXAxis();
candleWidth = xa.getDisplayPosition(xa.getTickUnit()) * 0.90; // use 90% width between ticks
}
volumeBar.update(y, candleWidth);
// position the volumeBar
volumeBar.setLayoutX(x);
volumeBar.setLayoutY(y);
}
}
}
}
@Override
protected void dataItemChanged(XYChart.Data<Number, Number> item) {
}
@Override
protected void dataItemAdded(XYChart.Series<Number, Number> series, int itemIndex, XYChart.Data<Number, Number> item) {
Node volumeBar = createCandle(getData().indexOf(series), item, itemIndex);
if (getPlotChildren().contains(volumeBar))
getPlotChildren().remove(volumeBar);
if (shouldAnimate()) {
volumeBar.setOpacity(0);
getPlotChildren().add(volumeBar);
// fade in new volumeBar
FadeTransition ft = new FadeTransition(Duration.millis(500), volumeBar);
ft.setToValue(1);
ft.play();
} else {
getPlotChildren().add(volumeBar);
}
}
@Override
protected void dataItemRemoved(XYChart.Data<Number, Number> item, XYChart.Series<Number, Number> series) {
final Node node = item.getNode();
if (shouldAnimate()) {
// fade out old volumeBar
FadeTransition ft = new FadeTransition(Duration.millis(500), node);
ft.setToValue(0);
ft.setOnFinished((ActionEvent actionEvent) -> {
getPlotChildren().remove(node);
});
ft.play();
} else {
getPlotChildren().remove(node);
}
}
@Override
protected void seriesAdded(XYChart.Series<Number, Number> series, int seriesIndex) {
// handle any data already in series
for (int j = 0; j < series.getData().size(); j++) {
XYChart.Data item = series.getData().get(j);
Node volumeBar = createCandle(seriesIndex, item, j);
if (shouldAnimate()) {
volumeBar.setOpacity(0);
getPlotChildren().add(volumeBar);
// fade in new volumeBar
FadeTransition ft = new FadeTransition(Duration.millis(500), volumeBar);
ft.setToValue(1);
ft.play();
} else {
getPlotChildren().add(volumeBar);
}
}
}
@Override
protected void seriesRemoved(XYChart.Series<Number, Number> series) {
// remove all volumeBar nodes
for (XYChart.Data<Number, Number> d : series.getData()) {
final Node volumeBar = d.getNode();
if (shouldAnimate()) {
// fade out old volumeBar
FadeTransition ft = new FadeTransition(Duration.millis(500), volumeBar);
ft.setToValue(0);
ft.setOnFinished((ActionEvent actionEvent) -> {
getPlotChildren().remove(volumeBar);
});
ft.play();
} else {
getPlotChildren().remove(volumeBar);
}
}
}
/**
* Create a new VolumeBar node to represent a single data item
*
* @param seriesIndex The index of the series the data item is in
* @param item The data item to create node for
* @param itemIndex The index of the data item in the series
* @return New volumeBar node to represent the give data item
*/
private Node createCandle(int seriesIndex, final XYChart.Data item, int itemIndex) {
Node volumeBar = item.getNode();
// check if volumeBar has already been created
if (volumeBar instanceof VolumeBar) {
((VolumeBar) volumeBar).setSeriesAndDataStyleClasses("series" + seriesIndex, "data" + itemIndex);
} else {
volumeBar = new VolumeBar("series" + seriesIndex, "data" + itemIndex, toolTipStringConverter);
item.setNode(volumeBar);
}
return volumeBar;
}
/**
* This is called when the range has been invalidated and we need to update it. If the axis are auto
* ranging then we compile a list of all data that the given axis has to plot and call invalidateRange() on the
* axis passing it that data.
*/
@Override
protected void updateAxisRange() {
// For volumeBar stick chart we need to override this method as we need to let the axis know that they need to be able
// to cover the whole area occupied by the high to low range not just its center data value
final Axis<Number> xa = getXAxis();
final Axis<Number> ya = getYAxis();
List<Number> xData = null;
List<Number> yData = null;
if (xa.isAutoRanging()) {
xData = new ArrayList<Number>();
}
if (ya.isAutoRanging()) {
yData = new ArrayList<Number>();
}
if (xData != null || yData != null) {
for (XYChart.Series<Number, Number> series : getData()) {
for (XYChart.Data<Number, Number> data : series.getData()) {
if (xData != null) {
xData.add(data.getXValue());
}
if (yData != null)
yData.add(data.getYValue());
}
}
if (xData != null) {
xa.invalidateRange(xData);
}
if (yData != null) {
ya.invalidateRange(yData);
}
}
}
}

View file

@ -62,8 +62,8 @@ public class TradesChartsViewModelTest {
assertEquals(high, candleData.high);
assertEquals(low, candleData.low);
assertEquals(average, candleData.average);
assertEquals(amount, candleData.amount);
assertEquals(volume, candleData.volume);
assertEquals(amount, candleData.accumulatedAmount);
assertEquals(volume, candleData.accumulatedVolume);
assertEquals(isBullish, candleData.isBullish);
}
}