package org.gillius.jfxutils.examples;
import javafx.animation.Animation;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.control.Slider;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Region;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Duration;
import org.gillius.jfxutils.JFXUtil;
import org.gillius.jfxutils.chart.ChartPanManager;
import org.gillius.jfxutils.chart.FixedFormatTickFormatter;
import org.gillius.jfxutils.chart.JFXChartUtil;
import org.gillius.jfxutils.chart.StableTicksAxis;
import java.text.SimpleDateFormat;
import java.util.TimeZone;
public class Test extends Application {
public static void main( String[] args ) {
launch( args );
}
@FXML
private LineChart<Number, Number> chart;
@FXML
private Slider valueSlider;
@FXML
private Label outputLabel;
private XYChart.Series<Number, Number> series;
private long startTime;
private Timeline addDataTimeline;
@FXML
void addSample() {
series.getData().add(new XYChart.Data(1, 23));
series.getData().add(new XYChart.Data(2, 14));
series.getData().add(new XYChart.Data(3, 15));
series.getData().add(new XYChart.Data(4, 24));
series.getData().add(new XYChart.Data(5, 34));
series.getData().add(new XYChart.Data(6, 36));
series.getData().add(new XYChart.Data(7, 22));
series.getData().add(new XYChart.Data(8, 45));
series.getData().add(new XYChart.Data(9, 43));
series.getData().add(new XYChart.Data(10, 17));
series.getData().add(new XYChart.Data(11, 29));
series.getData().add(new XYChart.Data(12, 25));
}
@FXML
void autoZoom() {
chart.getXAxis().setAutoRanging( true );
chart.getYAxis().setAutoRanging( true );
}
@FXML
void toggleAdd() {
switch ( addDataTimeline.getStatus() ) {
case PAUSED:
case STOPPED:
addDataTimeline.play();
chart.getXAxis().setAutoRanging( true );
chart.getYAxis().setAutoRanging( true );
//Animation looks horrible if we're updating a lot
chart.setAnimated( false );
chart.getXAxis().setAnimated( false );
chart.getYAxis().setAnimated( false );
break;
case RUNNING:
addDataTimeline.stop();
//Return the animation since we're not updating a lot
chart.setAnimated( true );
chart.getXAxis().setAnimated( true );
chart.getYAxis().setAnimated( true );
break;
default:
throw new AssertionError( "Unknown status" );
}
}
@Override
public void start( Stage stage ) throws Exception {
FXMLLoader loader = new FXMLLoader( getClass().getResource( "Charting.fxml" ) );
Region contentRootRegion = (Region) loader.load();
StackPane root = JFXUtil.createScalePane( contentRootRegion, 960, 540, false );
Scene scene = new Scene( root, root.getPrefWidth(), root.getPrefHeight() );
stage.setScene( scene );
stage.setTitle( "Charting Example" );
stage.show();
}
@FXML
void initialize() {
startTime = System.currentTimeMillis();
//Set chart to format dates on the X axis
// SimpleDateFormat format = new SimpleDateFormat( "HH:mm:ss" );
// format.setTimeZone( TimeZone.getTimeZone( "GMT" ) );
// ((StableTicksAxis) chart.getXAxis()).setAxisTickFormatter(
// new FixedFormatTickFormatter( format ) );
series = new XYChart.Series<Number, Number>();
series.setName( "Data" );
chart.getData().add( series );
addDataTimeline = new Timeline( new KeyFrame(
Duration.millis( 250 ),
new EventHandler<ActionEvent>() {
@Override
public void handle( ActionEvent actionEvent ) {
addSample();
}
}
));
addDataTimeline.setCycleCount( Animation.INDEFINITE );
chart.setOnMouseMoved( new EventHandler<MouseEvent>() {
@Override
public void handle( MouseEvent mouseEvent ) {
double xStart = chart.getXAxis().getLocalToParentTransform().getTx();
double axisXRelativeMousePosition = mouseEvent.getX() - xStart;
}
} );
//Panning works via either secondary (right) mouse or primary with ctrl held down
ChartPanManager panner = new ChartPanManager( chart );
panner.setMouseFilter( new EventHandler<MouseEvent>() {
@Override
public void handle( MouseEvent mouseEvent ) {
if ( mouseEvent.getButton() == MouseButton.SECONDARY ||
( mouseEvent.getButton() == MouseButton.PRIMARY &&
mouseEvent.isShortcutDown() ) ) {
//let it through
} else {
mouseEvent.consume();
}
}
} );
panner.start();
//Zooming works only via primary mouse button without ctrl held down
JFXChartUtil.setupZooming( chart, new EventHandler<MouseEvent>() {
@Override
public void handle( MouseEvent mouseEvent ) {
if ( mouseEvent.getButton() != MouseButton.PRIMARY ||
mouseEvent.isShortcutDown() )
mouseEvent.consume();
}
} );
JFXChartUtil.addDoublePrimaryClickAutoRangeHandler( chart );
}
}
这是我的折线图代码。它一直运行良好,直到我尝试在Xaxis上插入一个字符串。我希望有这个图表,但在Xaxis上有字符串。我收到了这个错误: javafx.scene.chart.CategoryAxis无法强制转换为javafx.scene.chart.ValueAxis
答案 0 :(得分:0)
问题在于您将图表定义为LineChart<Number, Number>
。
要制作包含String
X值和Number
Y值的图表,您应将通用参数设置为:
LineChart<String, Number> chart;
然后很可能你想使用CategoryAxis:
一个轴实现,适用于每个字符串类别 值作为沿轴的唯一类别(刻度线)。
注意:由于图表来自FXML文件,您还必须更新FXML文件。
示例:
CategoryAxis xAxis = new CategoryAxis();
NumberAxis yAxis = new NumberAxis();
LineChart<String,Number> chart = new LineChart<String,Number>(xAxis,yAxis);
此外,您还必须更新系列的声明和初始化:
private XYChart.Series<String, Number> series;
...
series = new XYChart.Series<String, Number>();
然后您可以将数据添加到此系列中:
series.getData().add(new XYChart.Data("SomeString", 23));
您可以查看原始教程的Creating Categories for a Line Chart section (example 3-4) 。
<强>更新强>
它发现JFXUtils package used仅在ValueAxis
的情况下不支持zomming。一种可能的解决方案是为条形图创建缩放,如this answer中建议的那样。