Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JavaFX 2.x : How to edit lines drawned on XY LineChart?

This code draw lines on a chart by left mouse click and move

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 Lines 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);

    Lines.MouseHandler mh = new Lines.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;

public MouseHandler( Pane pane ) {
    this.pane = pane;
}    
@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 = null;
            gotFirst = false;
        }
    } 
        else {
            if( line != null ) {
                x2 = event.getX();
                y2 = event.getY();
                // update line
                line.setEndX( x2 );
                line.setEndY( y2 );
        }
      }
    }
  }
}

My question is: how to edit such lines once plotted?

In example, once one or more line(s) are drawn I would like to select one of these, and by right mouse click and using a pop-up menu, delete it, modify length, (to make it shorter or longer) or change line slope.

Thanks all.

like image 735
Alberto acepsut Avatar asked Oct 06 '22 02:10

Alberto acepsut


1 Answers

The following modifications will add functionality to move the line when dragged with left mouse button. Also, the line will be removed when clicked with right mouse button.

This is the line handler callback class.

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();
    }

}

Create the line handler in mouse handler class:

    private LineHandler lineHandler;

    public MouseHandler( Pane pane ) {
        this.pane = pane;
        lineHandler = new LineHandler(pane);
    }

Add the handler to each line in the else clause of !gotFirst

            } 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;
            }

You can add the line remove functionality to a popup event.

like image 154
Bhupen Avatar answered Oct 10 '22 02:10

Bhupen