├── .classpath ├── .github └── FUNDING.yml ├── .project ├── .settings ├── org.eclipse.jdt.core.prefs └── org.eclipse.m2e.core.prefs ├── .travis.yml ├── LICENSE.txt ├── README.md ├── pom.xml └── src └── main └── java └── com └── github └── javafx └── charts └── zooming ├── BarChartSample.java ├── LineChartSample.java ├── MiniTest.java ├── ScatterChartSample.java └── ZoomManager.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: [kerner1000] 4 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | javafx-chart-zooming 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.m2e.core.maven2Builder 15 | 16 | 17 | 18 | 19 | 20 | org.eclipse.jdt.core.javanature 21 | org.eclipse.m2e.core.maven2Nature 22 | 23 | 24 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8 3 | org.eclipse.jdt.core.compiler.compliance=1.8 4 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 5 | org.eclipse.jdt.core.compiler.source=1.8 6 | -------------------------------------------------------------------------------- /.settings/org.eclipse.m2e.core.prefs: -------------------------------------------------------------------------------- 1 | activeProfiles= 2 | eclipse.preferences.version=1 3 | resolveWorkspaceProjects=true 4 | version=1 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | jdk: 3 | - oraclejdk8 4 | # Use JDK 8u45. The above line just causes the use of a minor version of Java 8. 5 | addons: 6 | apt: 7 | packages: 8 | - oracle-java8-installer 9 | script: "mvn -q clean package" 10 | notifications: 11 | email: 12 | recipients: 13 | - kerner1000@gmail.com 14 | on_failure: change # default: always 15 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JavaFX Chart Zooming 2 | 3 | [![Build Status](https://travis-ci.org/kerner1000/javafx-chart-zooming.svg?branch=master)](https://travis-ci.org/kerner1000/javafx-chart-zooming) 4 | [![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/kerner1000/javafx-chart-zooming/blob/master/LICENSE.txt) 5 | [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.kerner1000/javafx-chart-zooming/badge.svg)](https://maven-badges.herokuapp.com/maven-central/com.github.silicosciences/javafx-chart-zooming) 6 | 7 | ![Demo 1](https://j.gifs.com/xGN7rz.gif) 8 | 9 | ![Demo 2](https://j.gifs.com/zmNYl7.gif) 10 | 11 | ![Demo 3](https://j.gifs.com/qjXMEk.gif) 12 | 13 | ## HoTo use 14 | There is only one class that is realizing the zooming functionality: 15 | [ZoomManager](https://github.com/kerner1000/javafx-chart-zooming/blob/master/src/main/java/com/github/javafx/charts/zooming/ZoomManager.java). 16 | 17 | Check out the examples on how to use the ZoomManager: 18 | [Examples](https://github.com/kerner1000/javafx-chart-zooming/blob/master/src/main/java/com/github/javafx/charts/zooming/). 19 | 20 | ### Maven 21 | This project is synced to Maven Central, so you can just add the following dependency to your project: 22 | 23 | ```xml 24 | 25 | com.github.kerner1000 26 | javafx-chart-zooming 27 | 0.0.8 28 | 29 | ``` 30 | ### Eclipse RCP/ OSGi 31 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4.0.0 4 | com.github.kerner1000 5 | javafx-chart-zooming 6 | 0.0.10-SNAPSHOT 7 | 8 | org.sonatype.oss 9 | oss-parent 10 | 9 11 | 12 | 13 | 14 | kerner 15 | Alexander Kerner 16 | alexkerner1000@gmail.com 17 | 18 | Project Manager 19 | Architect 20 | 21 | 22 | 23 | 24 | 25 | The Apache Software License, Version 2.0 26 | http://www.apache.org/licenses/LICENSE-2.0.txt 27 | 28 | 29 | 30 | git:git@github.com:kerner1000/javafx-chart-zooming.git 31 | scm:git:git@github.com:kerner1000/javafx-chart-zooming.git 32 | scm:git:git@github.com:kerner1000/javafx-chart-zooming.git 33 | HEAD 34 | 35 | 36 | 37 | 38 | 39 | sonatype-nexus-snapshots 40 | Sonatype Nexus snapshot repository 41 | https://oss.sonatype.org/content/repositories/snapshots 42 | 43 | 44 | sonatype-nexus-staging 45 | Sonatype Nexus release repository 46 | https://oss.sonatype.org/service/local/staging/deploy/maven2/ 47 | 48 | 49 | 50 | 51 | 52 | 53 | maven-compiler-plugin 54 | 3.6.0 55 | 56 | 1.8 57 | 1.8 58 | 59 | 60 | 61 | org.apache.maven.plugins 62 | maven-release-plugin 63 | 64 | 65 | org.apache.maven.plugins 66 | maven-javadoc-plugin 67 | 2.10.2 68 | 69 | 70 | attach-javadocs 71 | 72 | jar 73 | 74 | 75 | -Xdoclint:none 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /src/main/java/com/github/javafx/charts/zooming/BarChartSample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package com.github.javafx.charts.zooming; 21 | 22 | import javafx.application.Application; 23 | import javafx.scene.Scene; 24 | import javafx.scene.chart.BarChart; 25 | import javafx.scene.chart.CategoryAxis; 26 | import javafx.scene.chart.NumberAxis; 27 | import javafx.scene.chart.XYChart; 28 | import javafx.scene.layout.StackPane; 29 | import javafx.stage.Stage; 30 | 31 | public class BarChartSample extends Application { 32 | final static String austria = "Austria"; 33 | final static String brazil = "Brazil"; 34 | final static String france = "France"; 35 | final static String italy = "Italy"; 36 | final static String usa = "USA"; 37 | 38 | public static void main(final String[] args) { 39 | launch(args); 40 | } 41 | 42 | @Override 43 | public void start(final Stage stage) { 44 | stage.setTitle("Bar Chart Sample"); 45 | final CategoryAxis xAxis = new CategoryAxis(); 46 | final NumberAxis yAxis = new NumberAxis(); 47 | final BarChart bc = new BarChart(xAxis, yAxis); 48 | bc.setTitle("Country Summary"); 49 | xAxis.setLabel("Country"); 50 | yAxis.setLabel("Value"); 51 | 52 | final XYChart.Series series1 = new XYChart.Series(); 53 | series1.setName("2003"); 54 | series1.getData().add(new XYChart.Data(austria, 25601.34)); 55 | series1.getData().add(new XYChart.Data(brazil, 20148.82)); 56 | series1.getData().add(new XYChart.Data(france, 10000)); 57 | series1.getData().add(new XYChart.Data(italy, 35407.15)); 58 | series1.getData().add(new XYChart.Data(usa, 12000)); 59 | 60 | final XYChart.Series series2 = new XYChart.Series(); 61 | series2.setName("2004"); 62 | series2.getData().add(new XYChart.Data(austria, 57401.85)); 63 | series2.getData().add(new XYChart.Data(brazil, 41941.19)); 64 | series2.getData().add(new XYChart.Data(france, 45263.37)); 65 | series2.getData().add(new XYChart.Data(italy, 117320.16)); 66 | series2.getData().add(new XYChart.Data(usa, 14845.27)); 67 | 68 | final XYChart.Series series3 = new XYChart.Series(); 69 | series3.setName("2005"); 70 | series3.getData().add(new XYChart.Data(austria, 45000.65)); 71 | series3.getData().add(new XYChart.Data(brazil, 44835.76)); 72 | series3.getData().add(new XYChart.Data(france, 18722.18)); 73 | series3.getData().add(new XYChart.Data(italy, 17557.31)); 74 | series3.getData().add(new XYChart.Data(usa, 92633.68)); 75 | 76 | // DO NOT ADD DATA TO CHART 77 | // bc.getData().addAll(series1, series2, series3); 78 | final StackPane pane = new StackPane(); 79 | pane.getChildren().add(bc); 80 | final Scene scene = new Scene(pane, 500, 400); 81 | new ZoomManager(pane, bc, series1, series2, series3); 82 | stage.setScene(scene); 83 | stage.show(); 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/main/java/com/github/javafx/charts/zooming/LineChartSample.java: -------------------------------------------------------------------------------- 1 | package com.github.javafx.charts.zooming; 2 | 3 | import javafx.application.Application; 4 | import javafx.scene.Scene; 5 | import javafx.scene.chart.LineChart; 6 | import javafx.scene.chart.NumberAxis; 7 | import javafx.scene.chart.XYChart; 8 | import javafx.scene.layout.StackPane; 9 | import javafx.stage.Stage; 10 | 11 | public class LineChartSample extends Application { 12 | 13 | public static void main(final String[] args) { 14 | launch(args); 15 | } 16 | 17 | @Override 18 | public void start(final Stage stage) { 19 | stage.setTitle("Line Chart Sample"); 20 | // defining the axes 21 | final NumberAxis xAxis = new NumberAxis(); 22 | final NumberAxis yAxis = new NumberAxis(); 23 | xAxis.setAutoRanging(true); 24 | xAxis.setForceZeroInRange(false); 25 | yAxis.setAutoRanging(true); 26 | yAxis.setForceZeroInRange(false); 27 | xAxis.setLabel("Number of Month"); 28 | // creating the chart 29 | final LineChart lineChart = new LineChart(xAxis, yAxis); 30 | 31 | lineChart.setTitle("Stock Monitoring, 2010"); 32 | // defining a series 33 | final XYChart.Series series = new XYChart.Series(); 34 | series.setName("My portfolio"); 35 | // populating the series with data 36 | series.getData().add(new XYChart.Data(1, 23)); 37 | series.getData().add(new XYChart.Data(2, 14)); 38 | series.getData().add(new XYChart.Data(3, 15)); 39 | series.getData().add(new XYChart.Data(4, 24)); 40 | series.getData().add(new XYChart.Data(5, 34)); 41 | series.getData().add(new XYChart.Data(6, 36)); 42 | series.getData().add(new XYChart.Data(7, 22)); 43 | series.getData().add(new XYChart.Data(8, 45)); 44 | series.getData().add(new XYChart.Data(9, 43)); 45 | series.getData().add(new XYChart.Data(10, 17)); 46 | series.getData().add(new XYChart.Data(11, 29)); 47 | series.getData().add(new XYChart.Data(12, 25)); 48 | 49 | // DO NOT ADD DATA TO CHART 50 | // bc.getData().addAll(series1, series2, series3); 51 | final StackPane pane = new StackPane(); 52 | pane.getChildren().add(lineChart); 53 | final Scene scene = new Scene(pane, 500, 400); 54 | new ZoomManager(pane, lineChart, series); 55 | stage.setScene(scene); 56 | stage.show(); 57 | } 58 | } -------------------------------------------------------------------------------- /src/main/java/com/github/javafx/charts/zooming/MiniTest.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package com.github.javafx.charts.zooming; 20 | 21 | import javafx.application.Application; 22 | import javafx.event.EventHandler; 23 | import javafx.scene.Scene; 24 | import javafx.scene.chart.BarChart; 25 | import javafx.scene.chart.CategoryAxis; 26 | import javafx.scene.chart.NumberAxis; 27 | import javafx.scene.chart.XYChart; 28 | import javafx.scene.input.MouseEvent; 29 | import javafx.scene.layout.StackPane; 30 | import javafx.stage.Stage; 31 | 32 | public class MiniTest extends Application { 33 | 34 | final static String austria = "Austria"; 35 | final static String brazil = "Brazil"; 36 | final static String france = "France"; 37 | final static String italy = "Italy"; 38 | final static String usa = "USA"; 39 | 40 | public static void main(final String[] args) { 41 | launch(args); 42 | 43 | } 44 | 45 | @Override 46 | public void start(final Stage stage) throws Exception { 47 | 48 | final CategoryAxis xAxis = new CategoryAxis(); 49 | final NumberAxis yAxis = new NumberAxis(); 50 | final BarChart chart = new BarChart(xAxis, yAxis); 51 | final XYChart.Series series1 = new XYChart.Series(); 52 | series1.setName("2003"); 53 | series1.getData().add(new XYChart.Data(austria, 25601.34)); 54 | series1.getData().add(new XYChart.Data(brazil, 20148.82)); 55 | series1.getData().add(new XYChart.Data(france, 10000)); 56 | series1.getData().add(new XYChart.Data(italy, 35407.15)); 57 | series1.getData().add(new XYChart.Data(usa, 12000)); 58 | chart.getData().add(series1); 59 | chart.setOnMouseClicked(new EventHandler() { 60 | @Override 61 | public void handle(final MouseEvent event) { 62 | if (chart.getData().isEmpty()) { 63 | chart.getData().add(series1); 64 | } else { 65 | chart.getData().clear(); 66 | } 67 | } 68 | }); 69 | final StackPane pane = new StackPane(); 70 | pane.getChildren().add(chart); 71 | final Scene scene = new Scene(pane, 800, 600); 72 | stage.setScene(scene); 73 | stage.show(); 74 | } 75 | 76 | } 77 | -------------------------------------------------------------------------------- /src/main/java/com/github/javafx/charts/zooming/ScatterChartSample.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | package com.github.javafx.charts.zooming; 21 | 22 | import javafx.application.Application; 23 | import javafx.scene.Scene; 24 | import javafx.scene.chart.NumberAxis; 25 | import javafx.scene.chart.ScatterChart; 26 | import javafx.scene.chart.XYChart; 27 | import javafx.scene.layout.StackPane; 28 | import javafx.stage.Stage; 29 | 30 | public class ScatterChartSample extends Application { 31 | 32 | public static void main(final String[] args) { 33 | launch(args); 34 | } 35 | 36 | @SuppressWarnings({ "rawtypes", "unchecked" }) 37 | @Override 38 | public void start(final Stage stage) { 39 | stage.setTitle("Scatter Chart Sample"); 40 | final NumberAxis xAxis = new NumberAxis(0, 10, 1); 41 | final NumberAxis yAxis = new NumberAxis(-100, 500, 100); 42 | xAxis.setAutoRanging(true); 43 | xAxis.setForceZeroInRange(false); 44 | yAxis.setAutoRanging(true); 45 | yAxis.setForceZeroInRange(false); 46 | final ScatterChart sc = new ScatterChart(xAxis, yAxis); 47 | xAxis.setLabel("Age (years)"); 48 | yAxis.setLabel("Returns to date"); 49 | sc.setTitle("Investment Overview"); 50 | 51 | final XYChart.Series series1 = new XYChart.Series<>(); 52 | series1.setName("Equities"); 53 | series1.getData().add(new XYChart.Data(4.2, 193.2)); 54 | series1.getData().add(new XYChart.Data(2.8, 33.6)); 55 | series1.getData().add(new XYChart.Data(6.2, 24.8)); 56 | series1.getData().add(new XYChart.Data(1, 14)); 57 | series1.getData().add(new XYChart.Data(1.2, 26.4)); 58 | series1.getData().add(new XYChart.Data(4.4, 114.4)); 59 | series1.getData().add(new XYChart.Data(8.5, 323)); 60 | series1.getData().add(new XYChart.Data(6.9, 289.8)); 61 | series1.getData().add(new XYChart.Data(9.9, 287.1)); 62 | series1.getData().add(new XYChart.Data(0.9, -9)); 63 | series1.getData().add(new XYChart.Data(3.2, 150.8)); 64 | series1.getData().add(new XYChart.Data(4.8, 20.8)); 65 | series1.getData().add(new XYChart.Data(7.3, -42.3)); 66 | series1.getData().add(new XYChart.Data(1.8, 81.4)); 67 | series1.getData().add(new XYChart.Data(7.3, 110.3)); 68 | series1.getData().add(new XYChart.Data(2.7, 41.2)); 69 | 70 | final XYChart.Series series2 = new XYChart.Series<>(); 71 | series2.setName("Mutual funds"); 72 | series2.getData().add(new XYChart.Data(5.2, 229.2)); 73 | series2.getData().add(new XYChart.Data(2.4, 37.6)); 74 | series2.getData().add(new XYChart.Data(3.2, 49.8)); 75 | series2.getData().add(new XYChart.Data(1.8, 134)); 76 | series2.getData().add(new XYChart.Data(3.2, 236.2)); 77 | series2.getData().add(new XYChart.Data(7.4, 114.1)); 78 | series2.getData().add(new XYChart.Data(3.5, 323)); 79 | series2.getData().add(new XYChart.Data(9.3, 29.9)); 80 | series2.getData().add(new XYChart.Data(8.1, 287.4)); 81 | 82 | // DO NOT ADD DATA TO CHART 83 | // sc.getData().addAll(series1, series2); 84 | 85 | final StackPane pane = new StackPane(); 86 | pane.getChildren().add(sc); 87 | final Scene scene = new Scene(pane, 500, 400); 88 | new ZoomManager(pane, sc, series1, series2); 89 | stage.setScene(scene); 90 | stage.show(); 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/main/java/com/github/javafx/charts/zooming/ZoomManager.java: -------------------------------------------------------------------------------- 1 | /** 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package com.github.javafx.charts.zooming; 21 | 22 | import java.util.Arrays; 23 | import java.util.Collection; 24 | import java.util.Iterator; 25 | import java.util.List; 26 | import java.util.Objects; 27 | 28 | import javafx.beans.property.ObjectProperty; 29 | import javafx.beans.property.SimpleObjectProperty; 30 | import javafx.collections.FXCollections; 31 | import javafx.collections.ObservableList; 32 | import javafx.event.EventHandler; 33 | import javafx.geometry.Bounds; 34 | import javafx.geometry.Point2D; 35 | import javafx.scene.Node; 36 | import javafx.scene.chart.Axis; 37 | import javafx.scene.chart.XYChart; 38 | import javafx.scene.chart.XYChart.Data; 39 | import javafx.scene.chart.XYChart.Series; 40 | import javafx.scene.input.MouseButton; 41 | import javafx.scene.input.MouseEvent; 42 | import javafx.scene.layout.Pane; 43 | import javafx.scene.paint.Color; 44 | import javafx.scene.shape.Rectangle; 45 | 46 | public class ZoomManager { 47 | 48 | static ObservableList> deepCopySeries(final Collection> data) { 49 | final ObservableList> backup = FXCollections.observableArrayList(); 50 | for (final Series s : data) { 51 | backup.add(deepCopySeries(s)); 52 | } 53 | return backup; 54 | } 55 | 56 | static XYChart.Series deepCopySeries(final XYChart.Series series) { 57 | final XYChart.Series result = new XYChart.Series<>(); 58 | result.setName(series.getName()); 59 | result.setData(deepCopySeriesData(series.getData())); 60 | return result; 61 | } 62 | 63 | static ObservableList> deepCopySeriesData( 64 | final Collection> data) { 65 | final ObservableList> result = FXCollections.observableArrayList(); 66 | for (final Data i : data) { 67 | result.add(new Data<>(i.getXValue(), i.getYValue())); 68 | } 69 | return result; 70 | } 71 | 72 | static ObservableList extractXValues(final ObservableList> data) { 73 | final ObservableList result = FXCollections.observableArrayList(); 74 | for (final Data d : data) { 75 | result.add(d.getXValue()); 76 | } 77 | return result; 78 | } 79 | 80 | static ObservableList extractYValues(final ObservableList> data) { 81 | final ObservableList result = FXCollections.observableArrayList(); 82 | for (final Data d : data) { 83 | result.add(d.getYValue()); 84 | } 85 | return result; 86 | } 87 | 88 | static Object getObject(final Axis axis, final double cooridnate) { 89 | final Object object = axis.getValueForDisplay(cooridnate); 90 | return object; 91 | } 92 | 93 | static Node getRootNode(final Node node) { 94 | Node n = node; 95 | while (n.getParent() != null) { 96 | n = n.getParent(); 97 | } 98 | return n; 99 | } 100 | 101 | private final ObservableList> series; 102 | 103 | private final XYChart chart; 104 | 105 | private volatile boolean zoomed; 106 | 107 | /** 108 | * 109 | * 110 | * Creates a new {@code ZoomManager}. 111 | *

112 | * Due to a bug, {@code series} must not be added to the chart! If you 113 | * do so, the chart will be emtpy. 114 | *

115 | * 116 | * 117 | * @param chartParent 118 | * the chart's parent {@link Pane}. 119 | * @param chart 120 | * the {@link XYChart} to which zooming functionality is added 121 | * @param series 122 | * collection of chart data to display 123 | * @throws IllegalArgumentException 124 | * if chart data is empty or {@code null} 125 | */ 126 | public ZoomManager(final Pane chartParent, final XYChart chart, 127 | final Collection> series) { 128 | super(); 129 | this.chart = Objects.requireNonNull(chart); 130 | if (series == null || series.isEmpty()) { 131 | throw new IllegalArgumentException("No chart data given"); 132 | } 133 | this.series = FXCollections.observableArrayList(series); 134 | restoreData(); 135 | final Rectangle zoomRect = new Rectangle(); 136 | zoomRect.setManaged(false); 137 | zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5)); 138 | chartParent.getChildren().add(zoomRect); 139 | setUpZooming(zoomRect, chart); 140 | 141 | } 142 | 143 | /** 144 | * 145 | * 146 | * Creates a new {@code ZoomManager}. 147 | *

148 | * Due to a bug, {@code series} must not be added to the chart! If you 149 | * do so, the chart will be emtpy. 150 | *

151 | * 152 | * 153 | * @param chartParent 154 | * the chart's parent {@link Pane}. 155 | * @param chart 156 | * the {@link XYChart} to which zooming functionality is added 157 | * @param series 158 | * array of chart data to display 159 | * @throws IllegalArgumentException 160 | * if chart data is empty or {@code null} 161 | */ 162 | public ZoomManager(final Pane chartParent, final XYChart chart, final Series... series) { 163 | this(chartParent, chart, Arrays.asList(series)); 164 | 165 | } 166 | 167 | private void doZoom(final boolean x, final Number n1, final Number n2) { 168 | final double min = Math.min(n1.doubleValue(), n2.doubleValue()); 169 | final double max = Math.max(n1.doubleValue(), n2.doubleValue()); 170 | if (max - min > 1) { 171 | zoomed = true; 172 | final Iterator> it = chart.getData().iterator(); 173 | while (it.hasNext()) { 174 | final XYChart.Series s = it.next(); 175 | final Iterator> it2 = s.getData().iterator(); 176 | while (it2.hasNext()) { 177 | final XYChart.Data d = it2.next(); 178 | final Object value; 179 | if (x) { 180 | value = d.getXValue(); 181 | } else { 182 | value = d.getYValue(); 183 | } 184 | if (value instanceof Number) { 185 | final Number n = (Number) value; 186 | final double dd = n.doubleValue(); 187 | if (dd < min || dd > max) { 188 | it2.remove(); 189 | } else { 190 | } 191 | } 192 | if (s.getData().isEmpty()) { 193 | it.remove(); 194 | } 195 | } 196 | } 197 | } else { 198 | // System.out.println("Skip tiny zoom"); 199 | } 200 | 201 | } 202 | 203 | private void doZoom(final boolean x, final Object o1, final Object o2) { 204 | if (o1 instanceof Number && o2 instanceof Number) { 205 | doZoom(x, (Number) o1, (Number) o2); 206 | } else if (o1 instanceof String || o2 instanceof String) { 207 | doZoom(x, (String) o1, (String) o2); 208 | } else { 209 | final int wait = 0; 210 | } 211 | } 212 | 213 | private void doZoom(final boolean x, String s1, String s2) { 214 | if (s1 == null && s2 == null) { 215 | return; 216 | } 217 | if (s1 == null) { 218 | s1 = s2; 219 | } 220 | if (s2 == null) { 221 | s2 = s1; 222 | } 223 | 224 | final Iterator> it = chart.getData().iterator(); 225 | while (it.hasNext()) { 226 | final XYChart.Series s = it.next(); 227 | final List values; 228 | if (x) { 229 | values = extractXValues(s.getData()); 230 | } else { 231 | values = extractYValues(s.getData()); 232 | } 233 | final int index1 = values.indexOf(s1); 234 | final int index2 = values.indexOf(s2); 235 | final int lower = Math.min(index1, index2); 236 | final int upper = Math.max(index1, index2); 237 | final Iterator> it2 = s.getData().iterator(); 238 | while (it2.hasNext()) { 239 | final Data d = it2.next(); 240 | final Object value; 241 | if (x) { 242 | value = d.getXValue(); 243 | } else { 244 | value = d.getYValue(); 245 | } 246 | final int index = values.indexOf(value); 247 | if (index != -1 && (index < lower || index > upper)) { 248 | it2.remove(); 249 | } 250 | } 251 | } 252 | } 253 | 254 | private void restoreData() { 255 | // make a tmp variable of data, since we will modify it but need to be 256 | // able to restore 257 | final ObservableList> backup2 = deepCopySeries(series); 258 | chart.getData().setAll(backup2); 259 | 260 | } 261 | 262 | private void setUpZooming(final Rectangle rect, final XYChart chart) { 263 | 264 | setUpZoomingRectangle(rect); 265 | 266 | } 267 | 268 | /** 269 | * Displays a colored rectangle that will indicate zooming boundaries 270 | * 271 | * @param rect 272 | */ 273 | private void setUpZoomingRectangle(final Rectangle rect) { 274 | 275 | /* 276 | * The chart background. Needed to get the correct rectangle boundaries. 277 | */ 278 | final Node chartBackground = chart.lookup(".chart-plot-background"); 279 | final ObjectProperty mouseAnchor = new SimpleObjectProperty<>(); 280 | chart.setOnMousePressed(new EventHandler() { 281 | @Override 282 | public void handle(final MouseEvent event) { 283 | mouseAnchor.set(new Point2D(event.getX(), event.getY())); 284 | } 285 | }); 286 | chart.setOnMouseClicked(new EventHandler() { 287 | @Override 288 | public void handle(final MouseEvent event) { 289 | if (event.getButton().equals(MouseButton.PRIMARY)) { 290 | if (zoomed && event.getClickCount() == 2) { 291 | restoreData(); 292 | zoomed = false; 293 | event.consume(); 294 | } 295 | } 296 | } 297 | }); 298 | chart.setOnMouseDragged(new EventHandler() { 299 | @Override 300 | public void handle(final MouseEvent event) { 301 | final double x = event.getX(); 302 | final double y = event.getY(); 303 | rect.setX(Math.min(x, mouseAnchor.get().getX())); 304 | rect.setY(Math.min(y, mouseAnchor.get().getY())); 305 | rect.setWidth(Math.abs(x - mouseAnchor.get().getX())); 306 | rect.setHeight(Math.abs(y - mouseAnchor.get().getY())); 307 | } 308 | }); 309 | chart.setOnMouseReleased(new EventHandler() { 310 | @Override 311 | public void handle(final MouseEvent event) { 312 | 313 | // final Bounds bb = chartBackground.sceneToLocal(rect.getBoundsInLocal()); 314 | final Bounds bb = chartBackground.parentToLocal(rect.getBoundsInParent()); 315 | 316 | final double minx = bb.getMinX(); 317 | final double maxx = bb.getMaxX(); 318 | 319 | final double miny = bb.getMinY(); 320 | final double maxy = bb.getMaxY(); 321 | 322 | doZoom(true, chart.getXAxis().getValueForDisplay(minx), chart.getXAxis().getValueForDisplay(maxx)); 323 | 324 | doZoom(false, chart.getYAxis().getValueForDisplay(miny), chart.getYAxis().getValueForDisplay(maxy)); 325 | 326 | rect.setWidth(0); 327 | rect.setHeight(0); 328 | } 329 | }); 330 | } 331 | 332 | } 333 | --------------------------------------------------------------------------------