Javafx 2 chart resize with freehand draw

2019-07-19 01:08发布

问题:

I have a code to draw freehand on a XYChart in JavaFX 2.0 I have a problem when I do a resize chart. When I do resize I have translating problem with freehand draws

When I resize the new draw appears initially out of scale, but after a little "chart move" the draw it fixes itself.

How can I improve it?

My code is:

package testjavafxapplication;

import javafx.application.Application;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.geometry.Bounds;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.stage.Stage;
import javafx.scene.Scene;
import javafx.scene.chart.LineChart;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.scene.transform.Scale;
import javafx.scene.transform.Transform;
import javafx.scene.transform.Translate;

public class FreehandResize extends Application {

 private CategoryAxis xAxis = new CategoryAxis();
 private NumberAxis yAxis = new NumberAxis(0.53000, 0.53910, 0.0001);
 private LineChart<String, Number> lineChart = new LineChart<String, Number>       (xAxis, yAxis);
 private Path path;
 private double initialWidth;
 private double initialheight;
 private Translate translate = new Translate(0, 0);
 private Scale scale = new Scale(1, 1);
 private ChangeListener<Number> changeListener = new ChangeListener<Number>() {

    @Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
  Bounds y_axisBounds = yAxis.getBoundsInLocal();
  double xOffset = y_axisBounds.getMaxX();

  translate.setX(xOffset);

  Bounds chartBounds = lineChart.getBoundsInLocal();
  scale.setX((chartBounds.getWidth() - xOffset) / initialWidth);
  scale.setY((chartBounds.getHeight() - xAxis.getBoundsInLocal().getHeight()) / initialheight);
    }
  };
private EventHandler<MouseEvent> mouseHandler = new EventHandler<MouseEvent>() {

@Override
public void handle(MouseEvent mouseEvent) {

  double targetX = (mouseEvent.getX() - translate.getX()) / scale.getX();
  double targetY = mouseEvent.getY() / scale.getY();

  if (mouseEvent.getEventType() == MouseEvent.MOUSE_PRESSED) {
    path.getElements().add(new MoveTo(targetX, targetY));
  } else if (mouseEvent.getEventType() == MouseEvent.MOUSE_DRAGGED) {
    path.getElements().add(new LineTo(targetX, targetY));
  }
}

 };

   @Override
   public void start(Stage stage) {
   stage.setTitle("Resize line plot");

   yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {

  @Override
  public String toString(Number object) {
    return String.format("%6.4f", object);
  }
});

lineChart.setCreateSymbols(false);
lineChart.setAlternativeRowFillVisible(false);

XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data("Jan", 0.53185));
series1.getData().add(new XYChart.Data("Feb", 0.532235));
series1.getData().add(new XYChart.Data("Mar", 0.53234));
series1.getData().add(new XYChart.Data("Apr", 0.538765));
series1.getData().add(new XYChart.Data("May", 0.53442));
series1.getData().add(new XYChart.Data("Jun", 0.534658));
series1.getData().add(new XYChart.Data("Jul", 0.53023));
series1.getData().add(new XYChart.Data("Aug", 0.53001));
series1.getData().add(new XYChart.Data("Sep", 0.53589));
series1.getData().add(new XYChart.Data("Oct", 0.53476));
series1.getData().add(new XYChart.Data("Nov", 0.530123));
series1.getData().add(new XYChart.Data("Dec", 0.53035));
lineChart.getData().addAll(series1);

BorderPane pane = new BorderPane();
pane.setCenter(lineChart);

Scene scene = new Scene(pane, 800, 600);
stage.setScene(scene);

path = new Path();
path.setStrokeWidth(2);
path.setStroke(Color.CHOCOLATE);

ObservableList<Transform> transforms = path.getTransforms();
transforms.add(0, translate);
transforms.add(1, scale);

scene.setOnMouseClicked(mouseHandler);
scene.setOnMouseDragged(mouseHandler);
scene.setOnMouseEntered(mouseHandler);
scene.setOnMouseExited(mouseHandler);
scene.setOnMouseMoved(mouseHandler);
scene.setOnMousePressed(mouseHandler);
scene.setOnMouseReleased(mouseHandler);

pane.getChildren().add(path);

scene.widthProperty().addListener(changeListener);
scene.heightProperty().addListener(changeListener);

stage.show();
Bounds axisBounds = yAxis.getBoundsInLocal();
double xOffset = axisBounds.getMaxX();
translate.setX(xOffset);

Bounds chartBounds = lineChart.getBoundsInLocal();
initialWidth = chartBounds.getWidth() - xOffset;
initialheight = chartBounds.getHeight() - xAxis.getBoundsInLocal().getHeight();
 }

   public static void main(String[] args) {
    launch(args);

   }
 }

回答1:

It seems you coordinates are based on wrong anchors. You need to find a node which contains graph itself and work only with this node's coordinates, not axis or scene.

I would even advise to add all mouse events to that node instead of scene to avoid excessive coordinates translation.

Another advise would be use ScenicView tool to investigate your application and see which nodes has what coordinates and verify your math.