/* =================== * Orson Charts - Demo * =================== * * Copyright (c) 2013-2016, Object Refinery Limited. * All rights reserved. * * http://www.object-refinery.com/orsoncharts/index.html * * 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 the Object Refinery Limited 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 OBJECT REFINERY LIMITED 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. * * Note that the above terms apply to the demo source only, and not the * Orson Charts library. * */ package com.orsoncharts.demo.fx; import static javafx.application.Application.launch; import java.awt.Dimension; import java.awt.geom.Dimension2D; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Map; import java.util.logging.Level; import java.util.logging.Logger; import javafx.application.Application; import javafx.beans.value.ObservableValue; import javafx.geometry.Orientation; import javafx.scene.Node; import javafx.scene.Scene; import javafx.scene.control.SplitPane; import javafx.scene.control.Tab; import javafx.scene.control.TabPane; import javafx.scene.control.TreeItem; import javafx.scene.control.TreeView; import javafx.scene.layout.BorderPane; import javafx.scene.layout.StackPane; import javafx.stage.Stage; import javafx.scene.web.WebEngine; import javafx.scene.web.WebView; import com.orsoncharts.Chart3D; import com.orsoncharts.data.Dataset3D; import com.orsoncharts.data.category.CategoryDataset3D; import com.orsoncharts.demo.AreaChart3D1; import com.orsoncharts.demo.DemoDescription; import com.orsoncharts.demo.SampleData; import com.orsoncharts.fx.Chart3DCanvas; import com.orsoncharts.fx.Chart3DViewer; import com.orsoncharts.graphics3d.Dimension3D; import com.orsoncharts.graphics3d.Drawable3D; import com.orsoncharts.interaction.fx.FXChart3DMouseEvent; /** * Demo application for Orson Charts in JavaFX. */ public class OrsonChartsFXDemo extends Application { private static final String PREFIX = "com.orsoncharts.demo.fx."; private Map<String, DemoDescription> descriptions; private SplitPane splitter; private WebView chartDescription; /** * Creates a new demo instance. */ public OrsonChartsFXDemo() { super(); this.descriptions = new HashMap<String, DemoDescription>(); } @Override public void start(Stage stage) throws Exception { TabPane tabPane = new TabPane(); Tab tab1 = new Tab(); tab1.setText("Demos"); tab1.setClosable(false); SplitPane sp = new SplitPane(); final StackPane sp1 = new StackPane(); sp1.getChildren().add(createTreeView()); final BorderPane sp2 = new BorderPane(); sp2.setCenter(createChartPane()); sp.getItems().addAll(sp1, sp2); sp.setDividerPositions(0.3f, 0.6f); tab1.setContent(sp); tabPane.getTabs().add(tab1); Tab tab2 = new Tab(); tab2.setText("About"); tab2.setClosable(false); WebView browser = new WebView(); WebEngine webEngine = browser.getEngine(); webEngine.load(getClass().getResource("/com/orsoncharts/demo/about.html").toString()); tab2.setContent(browser); tabPane.getTabs().add(tab2); Scene scene = new Scene(tabPane, 1024, 768); stage.setScene(scene); stage.setTitle("Orson Charts JavaFX Demo"); stage.show(); } private static final String ABOUT_PREFIX = "/com/orsoncharts/demo/"; private StackPane createTreeView() { TreeItem<String> rootItem = new TreeItem<String> ("Orson Charts", null); rootItem.setExpanded(true); TreeItem<String> categoryChartsNode = new TreeItem<String>("Category Charts"); categoryChartsNode.setExpanded(true); rootItem.getChildren().add(categoryChartsNode); DemoDescription d = new DemoDescription(PREFIX + "AreaChart3DFXDemo1", "AreaChart3DFXDemo1.java", ABOUT_PREFIX + "AreaChart3D1.html"); this.descriptions.put(d.getFileName(), d); TreeItem<String> n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "AreaChart3DFXDemo2", "AreaChart3DFXDemo2.java", ABOUT_PREFIX + "AreaChart3D2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "BarChart3DFXDemo1", "BarChart3DFXDemo1.java", ABOUT_PREFIX + "BarChart3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "BarChart3DFXDemo2", "BarChart3DFXDemo2.java", ABOUT_PREFIX + "BarChart3D2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "CategoryMarkerFXDemo1", "CategoryMarkerFXDemo1.java", ABOUT_PREFIX + "CategoryMarkerDemo1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "LineChart3DFXDemo1", "LineChart3DFXDemo1.java", ABOUT_PREFIX + "LineChart3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "LineChart3DFXDemo2", "LineChart3DFXDemo2.java", ABOUT_PREFIX + "LineChart3D2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "StackedBarChart3DFXDemo1", "StackedBarChart3DFXDemo1.java", ABOUT_PREFIX + "StackedBarChart3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "StackedBarChart3DFXDemo2", "StackedBarChart3DFXDemo2.java", ABOUT_PREFIX + "StackedBarChart3D2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "StackedBarChart3DFXDemo3", "StackedBarChart3DFXDemo3.java", ABOUT_PREFIX + "StackedBarChart3D3.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); categoryChartsNode.getChildren().add(n); TreeItem<String> pieChartsNode = new TreeItem<String>("Pie Charts"); rootItem.getChildren().add(pieChartsNode); d = new DemoDescription(PREFIX + "PieChart3DFXDemo1", "PieChart3DFXDemo1.java", ABOUT_PREFIX + "PieChart3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); pieChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "PieChart3DFXDemo2", "PieChart3DFXDemo2.java", ABOUT_PREFIX + "PieChart3D2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); pieChartsNode.getChildren().add(n); TreeItem<String> xyzChartsNode = new TreeItem<String>("XYZ Charts"); rootItem.getChildren().add(xyzChartsNode); d = new DemoDescription(PREFIX + "RangeMarkerFXDemo1", "RangeMarkerFXDemo1.java", ABOUT_PREFIX + "RangeMarker1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "ScatterPlot3DFXDemo1", "ScatterPlot3DFXDemo1.java", ABOUT_PREFIX + "ScatterPlot3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "ScatterPlot3DFXDemo2", "ScatterPlot3DFXDemo2.java", ABOUT_PREFIX + "ScatterPlot3D2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "ScatterPlot3DFXDemo3", "ScatterPlot3DFXDemo3.java", ABOUT_PREFIX + "ScatterPlot3D3.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "SurfaceRendererFXDemo1", "SurfaceRendererFXDemo1.java", ABOUT_PREFIX + "SurfaceRenderer1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "SurfaceRendererFXDemo2", "SurfaceRendererFXDemo2.java", ABOUT_PREFIX + "SurfaceRenderer2.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "XYZBarChart3DFXDemo1", "XYZBarChart3DFXDemo1.java", ABOUT_PREFIX + "XYZBarChart3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); d = new DemoDescription(PREFIX + "XYZLineChart3DFXDemo1", "XYZLineChart3DFXDemo1.java", ABOUT_PREFIX + "XYZLineChart3D1.html"); this.descriptions.put(d.getFileName(), d); n = new TreeItem<String>(d.getFileName()); xyzChartsNode.getChildren().add(n); TreeView<String> tree = new TreeView<String> (rootItem); tree.getSelectionModel().selectedItemProperty().addListener( (ObservableValue<? extends TreeItem<String>> observableValue, TreeItem<String> oldItem, TreeItem<String> newItem) -> { selectDemo(newItem.getValue()); }); StackPane root = new StackPane(); root.getChildren().add(tree); return root; } private Method getMethod(String name, Class c) { Method[] methods = c.getDeclaredMethods(); for (Method method: methods) { if (method.getName().equals(name)) { return method; } } return null; } private double margin = 0.25; public void zoomToFit(Drawable3D drawable, Dimension size) { int w = (int) (size.getWidth() * (1.0 - this.margin)); int h = (int) (size.getHeight() * (1.0 - this.margin)); Dimension2D target = new Dimension(w, h); Dimension3D d3d = drawable.getDimensions(); float distance = drawable.getViewPoint().optimalDistance(target, d3d, drawable.getProjDistance()); drawable.getViewPoint().setRho(distance); } private void selectDemo(String name) { DemoDescription demoDesc = this.descriptions.get(name); if (demoDesc != null) { try { BorderPane borderPane = (BorderPane) this.splitter.getItems().get(0); Node oldnode = borderPane.getCenter(); if (oldnode instanceof Chart3DViewer) { Chart3DViewer c = (Chart3DViewer) oldnode; c.prefWidthProperty().unbind(); c.prefHeightProperty().unbind(); } // get the class by reflection Class<?> c = Class.forName(demoDesc.getClassName()); Method m0 = getMethod("createDemoNode", c); if (m0 != null) { Node node = (Node) m0.invoke(null, (Object[]) null); borderPane.setCenter(node); if (node instanceof Chart3DViewer) { Chart3DViewer v = (Chart3DViewer) node; v.addEventHandler(FXChart3DMouseEvent.MOUSE_CLICKED, (FXChart3DMouseEvent event) -> { System.out.println(event.getElement()); }); v.prefWidthProperty().bind(borderPane.widthProperty()); v.prefHeightProperty().bind(borderPane.heightProperty()); zoomToFit(v.getChart(), new Dimension( (int) borderPane.getWidth(), (int) borderPane.getHeight())); } } else { Method m1 = getMethod("createDataset", c); Method m2 = getMethod("createChart", c); Dataset3D dataset = (Dataset3D) m1.invoke(null, (Object[]) null); Chart3D chart = (Chart3D) m2.invoke(null, new Object[] { dataset }); Chart3DCanvas canvas = new Chart3DCanvas(chart); borderPane.setCenter(canvas); canvas.widthProperty().bind(borderPane.widthProperty()); canvas.heightProperty().bind(borderPane.heightProperty()); canvas.zoomToFit(canvas.getWidth(), canvas.getHeight()); } String urlStr = c.getResource(demoDesc.getDescriptionFileName()).toString(); this.chartDescription.getEngine().load(urlStr); } catch (ClassNotFoundException ex) { Logger.getLogger(OrsonChartsFXDemo.class.getName()).log(Level.SEVERE, null, ex); } catch (SecurityException ex) { Logger.getLogger(OrsonChartsFXDemo.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { Logger.getLogger(OrsonChartsFXDemo.class.getName()).log(Level.SEVERE, null, ex); } catch (IllegalArgumentException ex) { Logger.getLogger(OrsonChartsFXDemo.class.getName()).log(Level.SEVERE, null, ex); } catch (InvocationTargetException ex) { Logger.getLogger(OrsonChartsFXDemo.class.getName()).log(Level.SEVERE, null, ex); } } } private SplitPane createChartPane() { CategoryDataset3D dataset = SampleData.createCompanyRevenueDataset(); Chart3D chart = AreaChart3D1.createChart(dataset); Chart3DViewer viewer = new Chart3DViewer(chart); this.splitter = new SplitPane(); splitter.setOrientation(Orientation.VERTICAL); final BorderPane borderPane = new BorderPane(); borderPane.setCenter(viewer); // Bind canvas size to stack pane size. viewer.prefWidthProperty().bind(borderPane.widthProperty()); viewer.prefHeightProperty().bind(borderPane.heightProperty()); final StackPane sp2 = new StackPane(); this.chartDescription = new WebView(); WebEngine webEngine = chartDescription.getEngine(); webEngine.load(AreaChart3D1.class.getResource("AreaChart3D1.html").toString()); sp2.getChildren().add(chartDescription); splitter.getItems().addAll(borderPane, sp2); splitter.setDividerPositions(0.70f, 0.30f); return splitter; } /** * @param args the command line arguments */ public static void main(String[] args) { launch(args); } }