-
-
Save james-d/7252698 to your computer and use it in GitHub Desktop.
| import java.util.Collections; | |
| import java.util.Random; | |
| import javafx.application.Application; | |
| import javafx.beans.binding.BooleanBinding; | |
| import javafx.beans.property.ObjectProperty; | |
| import javafx.beans.property.SimpleObjectProperty; | |
| import javafx.collections.FXCollections; | |
| import javafx.collections.ObservableList; | |
| import javafx.event.ActionEvent; | |
| import javafx.event.EventHandler; | |
| import javafx.geometry.Insets; | |
| import javafx.geometry.Point2D; | |
| import javafx.geometry.Pos; | |
| import javafx.scene.Node; | |
| import javafx.scene.Scene; | |
| import javafx.scene.chart.Axis; | |
| import javafx.scene.chart.LineChart; | |
| import javafx.scene.chart.NumberAxis; | |
| import javafx.scene.chart.XYChart.Data; | |
| import javafx.scene.chart.XYChart.Series; | |
| import javafx.scene.control.Button; | |
| import javafx.scene.input.MouseEvent; | |
| import javafx.scene.layout.BorderPane; | |
| import javafx.scene.layout.HBox; | |
| import javafx.scene.layout.StackPane; | |
| import javafx.scene.paint.Color; | |
| import javafx.scene.shape.Rectangle; | |
| import javafx.stage.Stage; | |
| public class ZoomableLineChart extends Application { | |
| private static final int NUM_DATA_POINTS = 1000 ; | |
| @Override | |
| public void start(Stage primaryStage) { | |
| final LineChart<Number, Number> chart = createChart(); | |
| final StackPane chartContainer = new StackPane(); | |
| chartContainer.getChildren().add(chart); | |
| final Rectangle zoomRect = new Rectangle(); | |
| zoomRect.setManaged(false); | |
| zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5)); | |
| chartContainer.getChildren().add(zoomRect); | |
| setUpZooming(zoomRect, chart); | |
| final HBox controls = new HBox(10); | |
| controls.setPadding(new Insets(10)); | |
| controls.setAlignment(Pos.CENTER); | |
| final Button zoomButton = new Button("Zoom"); | |
| final Button resetButton = new Button("Reset"); | |
| zoomButton.setOnAction(new EventHandler<ActionEvent>() { | |
| @Override | |
| public void handle(ActionEvent event) { | |
| doZoom(zoomRect, chart); | |
| } | |
| }); | |
| resetButton.setOnAction(new EventHandler<ActionEvent>() { | |
| @Override | |
| public void handle(ActionEvent event) { | |
| final NumberAxis xAxis = (NumberAxis)chart.getXAxis(); | |
| xAxis.setLowerBound(0); | |
| xAxis.setUpperBound(1000); | |
| final NumberAxis yAxis = (NumberAxis)chart.getYAxis(); | |
| yAxis.setLowerBound(0); | |
| yAxis.setUpperBound(1000); | |
| zoomRect.setWidth(0); | |
| zoomRect.setHeight(0); | |
| } | |
| }); | |
| final BooleanBinding disableControls = | |
| zoomRect.widthProperty().lessThan(5) | |
| .or(zoomRect.heightProperty().lessThan(5)); | |
| zoomButton.disableProperty().bind(disableControls); | |
| controls.getChildren().addAll(zoomButton, resetButton); | |
| final BorderPane root = new BorderPane(); | |
| root.setCenter(chartContainer); | |
| root.setBottom(controls); | |
| final Scene scene = new Scene(root, 600, 400); | |
| primaryStage.setScene(scene); | |
| primaryStage.show(); | |
| } | |
| private LineChart<Number, Number> createChart() { | |
| final NumberAxis xAxis = createAxis(); | |
| final NumberAxis yAxis = createAxis(); | |
| final LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis); | |
| chart.setAnimated(false); | |
| chart.setCreateSymbols(false); | |
| chart.setData(generateChartData()); | |
| return chart ; | |
| } | |
| private NumberAxis createAxis() { | |
| final NumberAxis xAxis = new NumberAxis(); | |
| xAxis.setAutoRanging(false); | |
| xAxis.setLowerBound(0); | |
| xAxis.setUpperBound(1000); | |
| return xAxis; | |
| } | |
| private ObservableList<Series<Number, Number>> generateChartData() { | |
| final Series<Number, Number> series = new Series<>(); | |
| series.setName("Data"); | |
| final Random rng = new Random(); | |
| for (int i=0; i<NUM_DATA_POINTS; i++) { | |
| Data<Number, Number> dataPoint = new Data<Number, Number>(i, rng.nextInt(1000)); | |
| series.getData().add(dataPoint); | |
| } | |
| return FXCollections.observableArrayList(Collections.singleton(series)); | |
| } | |
| private void setUpZooming(final Rectangle rect, final Node zoomingNode) { | |
| final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>(); | |
| zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() { | |
| @Override | |
| public void handle(MouseEvent event) { | |
| mouseAnchor.set(new Point2D(event.getX(), event.getY())); | |
| rect.setWidth(0); | |
| rect.setHeight(0); | |
| } | |
| }); | |
| zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() { | |
| @Override | |
| public void handle(MouseEvent event) { | |
| double x = event.getX(); | |
| double y = event.getY(); | |
| rect.setX(Math.min(x, mouseAnchor.get().getX())); | |
| rect.setY(Math.min(y, mouseAnchor.get().getY())); | |
| rect.setWidth(Math.abs(x - mouseAnchor.get().getX())); | |
| rect.setHeight(Math.abs(y - mouseAnchor.get().getY())); | |
| } | |
| }); | |
| } | |
| private void doZoom(Rectangle zoomRect, LineChart<Number, Number> chart) { | |
| Point2D zoomTopLeft = new Point2D(zoomRect.getX(), zoomRect.getY()); | |
| Point2D zoomBottomRight = new Point2D(zoomRect.getX() + zoomRect.getWidth(), zoomRect.getY() + zoomRect.getHeight()); | |
| final NumberAxis yAxis = (NumberAxis) chart.getYAxis(); | |
| Point2D yAxisInScene = yAxis.localToScene(0, 0); | |
| final NumberAxis xAxis = (NumberAxis) chart.getXAxis(); | |
| Point2D xAxisInScene = xAxis.localToScene(0, 0); | |
| double xOffset = zoomTopLeft.getX() - yAxisInScene.getX() ; | |
| double yOffset = zoomBottomRight.getY() - xAxisInScene.getY(); | |
| double xAxisScale = xAxis.getScale(); | |
| double yAxisScale = yAxis.getScale(); | |
| xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale); | |
| xAxis.setUpperBound(xAxis.getLowerBound() + zoomRect.getWidth() / xAxisScale); | |
| yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale); | |
| yAxis.setUpperBound(yAxis.getLowerBound() - zoomRect.getHeight() / yAxisScale); | |
| System.out.println(yAxis.getLowerBound() + " " + yAxis.getUpperBound()); | |
| zoomRect.setWidth(0); | |
| zoomRect.setHeight(0); | |
| } | |
| public static void main(String[] args) { | |
| launch(args); | |
| } | |
| } |
@polisettyManoj
Hey i just saw your post.
Step 1. Create class called Data -> Example Company (AAPL)
Step 2. There are just a few changes you need to make
- Make a ComboBox Field within MainApp
`private ComboBox companyComboBox;
private String symbol;'
-
From the class company, you are going to make two fields that are called symbol and company -> make getMethods
-
Make a constructor for the Company class
- Company
- Parameters: String symbol, String name
- super
-this.symbol = symbol -
Make a method called getCompanies()
public static List<Company> getCompanies() { List<Company> company =new ArrayList<>(); list.add(new Company("AAPL", "AAPL"); return company }
Part 3: Head back to MainApp -
create a field called listCompany
- ObservableList listCompany = FXCollections.observableArrayList();
-
within the init Method
-ComboBox<Company> companyComboBox = new ComboBox<>(); companyComboBox.setItems(listCompany);
- companyComboBox.getSelectionModel().selectedItemProperty().addListener((
ChangeListener<? super Company>)
(ObservableValue<? extends Company> observable, Company oldValue, Company newValue) -> {
if (newValue.getSymbol != null) {
symbol = newValue.getSymbol();
// call to method start()
start();
} else {
// do something else
}
} -
next add companyComboBox to Hbox
-
`private static void start() {
executor = Executors.newCachedThreadPool(r -> { Thread thread = new Thread(r); thread.setDaemon(true); return thread; }); AddToQueue add = new AddToQueue(); executor.execute(add); prepareTimeline();}`
-
and finally to add the real-time data
- Data is provided by "https://github.com/WojciechZankowski/iextrading4j"
- private static class AddToQueue implements Runnable {private IEXTradingClient iexTradingClient; private Quote quote; @Override public void run() { try { BigDecimal last = getQuotes().getLatestPrice(); BigDecimal volume = getQuotes().getLatestVolume(); queue1.add(last); queue2.add(volume); Thread.sleep(1000); executor.execute(this); } catch (InterruptedException e) { e.printStackTrace(); } } private Quote getQuotes() { new LiveStockQuoteService(symbol); iexTradingClient = IEXTradingClient.create(); this.quote = iexTradingClient.executeRequest(new QuoteRequestBuilder() .withSymbol(symbol) .build()); return quote; }}
-
The rest should be pretty easy to do yourself
There's a small bug in this, where the zoom is actually a bit to the right of the zoom band that you see visually. This is caused by the yAxis point (0,0) being at the top-left of the yAxis, and not taking into account the thickness of the axis. When the code gets the xOffset, it should take into acount the right side of the axis, not the left.
Line 150 should be as follows:
double xOffset = zoomTopLeft.getX() - (yAxisInScene.getX() + yAxis.getWidth());
Line 150 should be as follows:
double xOffset = zoomTopLeft.getX() - (yAxisInScene.getX() - yAxis.getWidth());
how can i implement the same functionality to a Real time line chart..Can any one help me ?? Thanks in advance :) @james-d #james-d help needed :)
this is my sample code for real-time line chart...