通过鼠标左键单击图表我想通过创建文本区域矩形来编写文本,以便能够调整大小和移动.
任何帮助真的很感激
编辑:您好sarcan非常感谢您的回复.
我尝试了你的代码,它编译并绘制带有注释的区域图表,非常棒的工作!
我现在需要更改您的代码,以便能够在鼠标单击鼠标时键入键盘键,而不是现在打印注释.
以下是您的完整代码
import javafx.application.Application;
import javafx.beans.InvalidationListener;
import javafx.beans.Observable;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.scene.Node;
import javafx.scene.Scene;
import javafx.scene.chart.AreaChart;
import javafx.scene.chart.Axis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.chart.XYChart.Data;
import javafx.scene.chart.XYChart.Series;
import javafx.scene.control.Label;
import javafx.scene.input.MouseButton;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Circle;
import javafx.stage.Stage;
/**
*
* @author sarcan
*/
public class SampleApp extends Application {
public class SampleChart extends AreaChart<Number, Number> {
public SampleChart() {
super(new NumberAxis(), new NumberAxis());
getXAxis().setLabel("X");
getYAxis().setLabel("Y");
final Series<Number, Number> data = new Series<Number, Number>();
data.setName("Dummy data");
data.getData().addAll(
new Data<Number, Number>(0,4),
new Data<Number, Number>(1,5),
new Data<Number, Number>(2,6),
new Data<Number, Number>(3,5),
new Data<Number, Number>(4,5),
new Data<Number, Number>(5,7),
new Data<Number, Number>(6,8),
new Data<Number, Number>(7,9),
new Data<Number, Number>(8,7)
);
getData().add(data);
}
}
public class ChartAnnotationNode {
private final Node _node;
private double _x;
private double _y;
public ChartAnnotationNode(final Node node, final double x, final double y) {
_node = node;
_x = x;
_y = y;
}
public Node getNode() {
return _node;
}
public double getX() {
return _x;
}
public double getY() {
return _y;
}
public void setX(final double x) {
_x = x;
}
public void setY(final double y) {
_y = y;
}
}
public class ChartAnnotationOverlay extends Pane {
private ObservableList<ChartAnnotationNode> _annotationNodes;
private XYChart<Number, Number> _chart;
public ChartAnnotationOverlay(final XYChart<Number, Number> chart) {
_chart = chart;
/* Create a list to hold your annotations */
_annotationNodes = FXCollections.observableArrayList();
/* This will be our update listener, to be invoked whenever the chart changes or annotations are added */
final InvalidationListener listener = new InvalidationListener() {
@Override
public void invalidated(final Observable observable) {
update();
}
};
_chart.needsLayoutProperty().addListener(listener);
_annotationNodes.addListener(listener);
/* Add new annotations by shift-clicking */
setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(final MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.isShiftDown())
addAnnotation(mouseEvent.getX(), mouseEvent.getY());
}
});
}
/**
* Invoked whenever the chart changes or annotations are added. This basically does a relayout of the annotation nodes.
*/
private void update(){
getChildren().clear();
final Axis<Number> xAxis = _chart.getXAxis();
final Axis<Number> yAxis = _chart.getYAxis();
/* For each annotation, add a circle indicating the position and the custom node right next to it */
for (ChartAnnotationNode annotation : _annotationNodes) {
final double x = xAxis.localToParent(xAxis.getDisplayPosition(annotation.getX()), 0).getX() + _chart.getPadding().getLeft();
final double y = yAxis.localToParent(0,yAxis.getDisplayPosition(annotation.getY())).getY() + _chart.getPadding().getTop();
final Circle indicator = new Circle(3);
indicator.setStroke(Color.BLUEVIOLET);
indicator.setCenterX(x);
indicator.setCenterY(y);
getChildren().add(indicator);
final Node node = annotation.getNode();
getChildren().add(node);
node.relocate(x + 10, y - node.prefHeight(Integer.MAX_VALUE) / 2);
node.autosize();
}
}
/**
* Add a new annotation for the given display coordinate.
*/
private void addAnnotation(final double displayX, final double displayY){
final Axis<Number> xAxis = _chart.getXAxis();
final Axis<Number> yAxis = _chart.getYAxis();
final double x = (xAxis.getValueForDisplay(xAxis.parentToLocal(displayX, 0).getX() - _chart.getPadding().getLeft())).doubleValue();
final double y = (yAxis.getValueForDisplay(yAxis.parentToLocal(0, displayY).getY() - _chart.getPadding().getTop())).doubleValue();
if (xAxis.isValueOnAxis(x) && yAxis.isValueOnAxis(y))
_annotationNodes.add(new ChartAnnotationNode(new Label("Annotation "+System.currentTimeMillis()), x, y));
}
}
@Override
public void start(final Stage stage) throws Exception {
final SampleChart chart = new SampleChart();
final ChartAnnotationOverlay overlay = new ChartAnnotationOverlay(chart);
final StackPane stackPane = new StackPane();
stackPane.getChildren().addAll(chart, overlay);
final Scene scene = new Scene(stackPane);
stage.setScene(scene);
stage.setWidth(800);
stage.setHeight(600);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
1)我首先将图表放在StackPane中.在图表的顶部,我会在鼠标单击时放置一个锚定窗格,其中包含文本字段.
2)当用户点击图表时,我会使用图表的轴来确定点击是否在绘图区域内以及点击了哪个"值"(使用NumberAxis#getValueForDisplay().
3)然后我会将监听器添加到图表中,以便收到任何更改(内容,宽度,高度......)的通知,并调整文本区域的位置以始终显示接近相同的值.
调整大小/直接,如果这给您带来任何麻烦,请告诉我们.
编辑:根据要求,这里是一些示例代码.下面的代码提供了一个简化示例,允许您通过按住Shift键单击将文本节点(我称之为注释)添加到图表中.拖动或编辑注释很简单,但我希望保持示例简洁.
让我们从定义示例图表开始:
public class SampleChart extends AreaChart<Number, Number> {
public SampleChart() {
super(new NumberAxis(), new NumberAxis());
getXAxis().setLabel("X");
getYAxis().setLabel("Y");
final Series<Number, Number> data = new Series<Number, Number>();
data.setName("Dummy data");
data.getData().addAll(
new Data<Number, Number>(0,4),
new Data<Number, Number>(1,5),
new Data<Number, Number>(2,6),
new Data<Number, Number>(3,5),
new Data<Number, Number>(4,5),
new Data<Number, Number>(5,7),
new Data<Number, Number>(6,8),
new Data<Number, Number>(7,9),
new Data<Number, Number>(8,7)
);
getData().add(data);
}
}
Run Code Online (Sandbox Code Playgroud)
到目前为止没什么好看的,我只是用一些随机的模拟数据创建一个面积图.
对于文本节点(或注释),我创建了一个简单的POJO,其中包含带注释的X/Y值(不是显示位置)并获取要呈现的自定义节点:
public class ChartAnnotationNode {
private final Node _node;
private double _x;
private double _y;
public ChartAnnotationNode(final Node node, final double x, final double y) {
_node = node;
_x = x;
_y = y;
}
public Node getNode() {
return _node;
}
public double getX() {
return _x;
}
public double getY() {
return _y;
}
public void setX(final double x) {
_x = x;
}
public void setY(final double y) {
_y = y;
}
}
Run Code Online (Sandbox Code Playgroud)
有趣的东西发生在我称之为叠加层的内容中:一个透明面板,将放置在图表上方.请注意,我没有像最初建议的那样选择AnchorPane,尽管这样做也会有效.此外,这种实现并不是最有效的方法,但我希望保持示例简单.
public class ChartAnnotationOverlay extends Pane {
private ObservableList<ChartAnnotationNode> _annotationNodes;
private XYChart<Number, Number> _chart;
public ChartAnnotationOverlay(final XYChart<Number, Number> chart) {
_chart = chart;
/* Create a list to hold your annotations */
_annotationNodes = FXCollections.observableArrayList();
/* This will be our update listener, to be invoked whenever the chart changes or annotations are added */
final InvalidationListener listener = new InvalidationListener() {
@Override
public void invalidated(final Observable observable) {
update();
}
};
_chart.needsLayoutProperty().addListener(listener);
_annotationNodes.addListener(listener);
/* Add new annotations by shift-clicking */
setOnMouseClicked(new EventHandler<MouseEvent>() {
@Override
public void handle(final MouseEvent mouseEvent) {
if (mouseEvent.getButton() == MouseButton.PRIMARY && mouseEvent.isShiftDown())
addAnnotation(mouseEvent.getX(), mouseEvent.getY());
}
});
}
/**
* Invoked whenever the chart changes or annotations are added. This basically does a relayout of the annotation nodes.
*/
private void update(){
getChildren().clear();
final Axis<Number> xAxis = _chart.getXAxis();
final Axis<Number> yAxis = _chart.getYAxis();
/* For each annotation, add a circle indicating the position and the custom node right next to it */
for (ChartAnnotationNode annotation : _annotationNodes) {
final double x = xAxis.localToParent(xAxis.getDisplayPosition(annotation.getX()), 0).getX() + _chart.getPadding().getLeft();
final double y = yAxis.localToParent(0,yAxis.getDisplayPosition(annotation.getY())).getY() + _chart.getPadding().getTop();
final Circle indicator = new Circle(3);
indicator.setStroke(Color.BLUEVIOLET);
indicator.setCenterX(x);
indicator.setCenterY(y);
getChildren().add(indicator);
final Node node = annotation.getNode();
getChildren().add(node);
node.relocate(x + 10, y - node.prefHeight(Integer.MAX_VALUE) / 2);
node.autosize();
}
}
/**
* Add a new annotation for the given display coordinate.
*/
private void addAnnotation(final double displayX, final double displayY){
final Axis<Number> xAxis = _chart.getXAxis();
final Axis<Number> yAxis = _chart.getYAxis();
final double x = (xAxis.getValueForDisplay(xAxis.parentToLocal(displayX, 0).getX() - _chart.getPadding().getLeft())).doubleValue();
final double y = (yAxis.getValueForDisplay(yAxis.parentToLocal(0, displayY).getY() - _chart.getPadding().getTop())).doubleValue();
if (xAxis.isValueOnAxis(x) && yAxis.isValueOnAxis(y))
_annotationNodes.add(new ChartAnnotationNode(new Label("Annotation "+System.currentTimeMillis()), x, y));
}
}
Run Code Online (Sandbox Code Playgroud)
棘手的部分是视图和显示之间的坐标转换.要获取给定值的显示位置,可以调用Axis#getDisplayPosition(...),但返回的坐标将位于轴的坐标空间中.调用将其Axis#localToParent转换为图表的坐标空间.通常情况下,您希望能够只使用这些坐标,但图表的默认填充为5像素,由于某种原因无法正确转换.
这是一个小型测试应用程序将它们放在一起:
public class SampleApp extends Application {
@Override
public void start(final Stage stage) throws Exception {
final SampleChart chart = new SampleChart();
final ChartAnnotationOverlay overlay = new ChartAnnotationOverlay(chart);
final StackPane stackPane = new StackPane();
stackPane.getChildren().addAll(chart, overlay);
final Scene scene = new Scene(stackPane);
stage.setScene(scene);
stage.setWidth(800);
stage.setHeight(600);
stage.show();
}
public static void main(String[] args) {
Application.launch(args);
}
}
Run Code Online (Sandbox Code Playgroud)
现在你有了覆盖代码+翻译坐标背后的想法,拖动节点也应该很简单.拖动注释的节点时,获取其显示位置,添加拖动增量,将其转换为值并将其应用于注释实例.
希望这会使事情变得更加清晰.
| 归档时间: |
|
| 查看次数: |
3139 次 |
| 最近记录: |