Reputation: 2022
This code plots a XY LineChart and (code thanks to Bhupendra) draw lines on chart by left mouse click and if mouse hover, line get selected turns to red and can be deleted or moved.
import javafx.application.Application;
import javafx.event.EventHandler;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.chart.CategoryAxis;
import javafx.scene.chart.LineChart;
import javafx.scene.chart.NumberAxis;
import javafx.scene.chart.XYChart;
import javafx.scene.control.Label;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.shape.LineTo;
import javafx.scene.shape.MoveTo;
import javafx.scene.shape.Path;
import javafx.stage.Stage;
public class LinesEdit extends Application {
Path path;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) {
final CategoryAxis xAxis = new CategoryAxis();
final NumberAxis yAxis = new NumberAxis(1, 21, 0.1);
yAxis.setTickUnit(1);
yAxis.setPrefWidth(35);
yAxis.setMinorTickCount(10);
yAxis.setTickLabelFormatter(new NumberAxis.DefaultFormatter(yAxis) {
@Override
public String toString(Number object) {
String label;
label = String.format("%7.2f", object.floatValue());
return label;
}
});
final LineChart<String, Number> lineChart = new LineChart<String, Number>(xAxis, yAxis);
lineChart.setCreateSymbols(false);
lineChart.setAlternativeRowFillVisible(false);
lineChart.setLegendVisible(false);
XYChart.Series series1 = new XYChart.Series();
series1.getData().add(new XYChart.Data("Jan", 1));
series1.getData().add(new XYChart.Data("Feb", 4));
series1.getData().add(new XYChart.Data("Mar", 2.5));
series1.getData().add(new XYChart.Data("Apr", 5));
series1.getData().add(new XYChart.Data("May", 6));
series1.getData().add(new XYChart.Data("Jun", 8));
series1.getData().add(new XYChart.Data("Jul", 12));
series1.getData().add(new XYChart.Data("Aug", 8));
series1.getData().add(new XYChart.Data("Sep", 11));
series1.getData().add(new XYChart.Data("Oct", 13));
series1.getData().add(new XYChart.Data("Nov", 10));
series1.getData().add(new XYChart.Data("Dec", 20));
BorderPane bp = new BorderPane();
bp.setCenter(lineChart);
Scene scene = new Scene(bp, 800, 600);
lineChart.setAnimated(false);
lineChart.getData().addAll(series1);
LinesEdit.MouseHandler mh = new LinesEdit.MouseHandler( bp );
bp.setOnMouseClicked( mh );
bp.setOnMouseMoved( mh );
stage.setScene(scene);
path = new Path();
path.setStrokeWidth(1);
path.setStroke(Color.BLACK);
scene.setOnMouseDragged(mh);
scene.setOnMousePressed(mh);
bp.getChildren().add(path);
stage.setScene(scene);
stage.show();
}
class MouseHandler implements EventHandler< MouseEvent > {
private boolean gotFirst = false;
private Line line;
private Pane pane;
private double x1, y1, x2, y2;
private LineHandler lineHandler;
public MouseHandler( Pane pane ) {
this.pane = pane;
lineHandler = new LineHandler(pane);
}
class LineHandler implements EventHandler< MouseEvent > {
double x, y;
Pane pane;
public LineHandler(Pane pane){
this.pane = pane;
}
@Override
public void handle( MouseEvent e ) {
Line l = (Line) e.getSource();
// remove line on right click
if( e.getEventType() == MouseEvent.MOUSE_PRESSED
&& e.isSecondaryButtonDown() ) {
pane.getChildren().remove( l );
} else if( e.getEventType() == MouseEvent.MOUSE_DRAGGED
&& e.isPrimaryButtonDown() ) {
double tx = e.getX();
double ty = e.getY();
double dx = tx - x;
double dy = ty - y;
l.setStartX( l.getStartX() + dx );
l.setStartY( l.getStartY() + dy );
l.setEndX( l.getEndX() + dx );
l.setEndY( l.getEndY() + dy );
x = tx;
y = ty;
} else if( e.getEventType() == MouseEvent.MOUSE_ENTERED ) {
// just to show that the line is selected
x = e.getX();
y = e.getY();
l.setStroke( Color.RED );
} else if( e.getEventType() == MouseEvent.MOUSE_EXITED ) {
l.setStroke( Color.BLACK );
}
// should not pass event to the parent
e.consume();
}
}
@Override
public void handle( MouseEvent event ) {
if( event.getEventType() == MouseEvent.MOUSE_CLICKED ) {
if( !gotFirst ) {
x1 = x2 = event.getX();
y1 = y2 = event.getY();
line = new Line( x1, y1, x2, y2 );
pane.getChildren().add( line );
gotFirst = true;
}
else {
line.setOnMouseEntered( lineHandler );
line.setOnMouseExited( lineHandler );
line.setOnMouseDragged( lineHandler );
line.setOnMousePressed( lineHandler );
// to consume the event
line.setOnMouseClicked( lineHandler );
line.setOnMouseReleased( lineHandler );
line = null;
gotFirst = false;
}
}
else {
if( line != null ) {
x2 = event.getX();
y2 = event.getY();
// update line
line.setEndX( x2 );
line.setEndY( y2 );
}
}
}
}
}
What I would like to do now is to change line length or slope by selecting one of the end or tail points (A and B in the picture) and set new end x,y point
How to accomplish this?
Thanks.
Upvotes: 1
Views: 2666
Reputation: 1320
Use the following class instead of Line
...
public class EditLine extends Parent {
private static final double radius = 5;
private Line line;
private Circle c1, c2;
private class MouseHandler implements EventHandler< MouseEvent > {
private boolean isfirst;
public MouseHandler( boolean first ) {
isfirst = first;
}
public void handle( MouseEvent event ) {
if( event.getEventType() == MouseEvent.MOUSE_ENTERED ) {
if( isfirst )
c1.setOpacity( 1 );
else c2.setOpacity( 1 );
} else if( event.getEventType() == MouseEvent.MOUSE_EXITED ) {
if( isfirst )
c1.setOpacity( 0 );
else c2.setOpacity( 0 );
} else if( event.getEventType() == MouseEvent.MOUSE_DRAGGED ) {
double x = event.getSceneX();
double y = event.getSceneY();
if( isfirst ) {
line.setStartX( x );
line.setStartY( y );
c1.setCenterX( x );
c1.setCenterY( y );
} else {
line.setEndX( x );
line.setEndY( y );
c2.setCenterX( x );
c2.setCenterY( y );
}
}
}
}
public EditLine( double x1, double y1, double x2, double y2 ) {
line = new Line( x1, y1, x2, y2 );
line.setMouseTransparent( true );
c1 = new Circle( x1, y1, radius, Color.RED );
c1.setOpacity( 0 );
MouseHandler mh1 = new MouseHandler( true );
c1.setOnMouseEntered( mh1 );
c1.setOnMouseExited( mh1 );
c1.setOnMouseDragged( mh1 );
c2 = new Circle( x2, y2, radius, Color.RED );
c2.setOpacity( 0 );
MouseHandler mh2 = new MouseHandler( false );
c2.setOnMouseEntered( mh2 );
c2.setOnMouseExited( mh2 );
c2.setOnMouseDragged( mh2 );
getChildren().addAll( c1, c2, line );
}
}
Upvotes: 4