For my project I have to realize a zoomable lineChart. I found many code of zoom but none of them is working. In fact, I think that the problem is the fact that my windows is divided in many windows, and in 4 of these windows, there are the charts. Thus, the zoom looks like it works but when I use the zoom, the new axis is not what it's supposed to be :
1) I'm choosing where i want to zoom :
https://imgur.com/a/j6LwrsH
2) chart is "reloading" with new axis :
https://imgur.com/a/SyeqnEV
public class ZoomableLineChart<X extends Number, Y extends Number> extends LineChart<X, Y> {
private final Region userTrackArea = new Region();
XYChart.Series series;
double valueX;
double valueY;
BorderPane chartContainer;
public ZoomableLineChart( Axis xAxis, Axis yAxis, XYChart.Series series, BorderPane border, double valueX, double valueY ) {
super(xAxis, yAxis);
this.chartContainer = border;
this.valueX = valueX;
this.valueX = valueX;
final LineChart<Number, Number> chart = createChart();
chart.getData().add(series);
final StackPane StackChartContainer = new StackPane();
StackChartContainer.getChildren().add(chart);
StackChartContainer.setOnMouseClicked(this::handleMouseTrackingClicked);
final Rectangle zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
StackChartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, chart);
final HBox controls = new HBox();
controls.setSpacing(10);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
final Button zoomButton = new Button("Zoom");
final Button resetButton = new Button("Reset");
zoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
doZoom(zoomRect, chart);
}
});
resetButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final NumberAxis xAxis = (NumberAxis)chart.getXAxis();
xAxis.setLowerBound(0);
xAxis.setUpperBound(100);
final NumberAxis yAxis = (NumberAxis)chart.getYAxis();
yAxis.setLowerBound(0);
yAxis.setUpperBound(100);
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
});
final BooleanBinding disableControls =
zoomRect.widthProperty().lessThan(5)
.or(zoomRect.heightProperty().lessThan(5));
zoomButton.disableProperty().bind(disableControls);
controls.getChildren().add(zoomButton);
controls.getChildren().add(resetButton);
border.setCenter(StackChartContainer);
border.setBottom(controls);
}
private void handleMouseTrackingClicked(final MouseEvent mouseEvent) {
final NumberAxis xAxis = (NumberAxis) getXAxis();
final NumberAxis yAxis = (NumberAxis) getYAxis();
final double mouseX = mouseEvent.getX();
final double mouseY = mouseEvent.getY();
valueX = xAxis.getValueForDisplay(mouseX).doubleValue();
valueY = yAxis.getValueForDisplay(mouseY).doubleValue();
// System.out.printf("Mouse %f %f -> value %f (%f %f) %f (%f %f)", mouseX, mouseY,
// valueX, xAxis.getLowerBound(), xAxis.getUpperBound(),
// valueY, yAxis.getLowerBound(), yAxis.getUpperBound()).println();
System.out.println(valueX + "," + valueY);
}
public static BorderPane creerGrapheZoomable(XYChart.Series series, BorderPane chartContainer) {
final LineChart<Number, Number> chart = createChart();
chart.getData().add(series);
final StackPane StackChartContainer = new StackPane();
StackChartContainer.getChildren().add(chart);
final Rectangle zoomRect = new Rectangle();
zoomRect.setManaged(false);
zoomRect.setFill(Color.LIGHTSEAGREEN.deriveColor(0, 1, 1, 0.5));
StackChartContainer.getChildren().add(zoomRect);
setUpZooming(zoomRect, chart);
final HBox controls = new HBox();
controls.setSpacing(10);
controls.setPadding(new Insets(10));
controls.setAlignment(Pos.CENTER);
final Button zoomButton = new Button("Zoom");
final Button resetButton = new Button("Reset");
zoomButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
doZoom(zoomRect, chart);
}
});
resetButton.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
final NumberAxis xAxis = (NumberAxis)chart.getXAxis();
xAxis.setLowerBound(0);
xAxis.setUpperBound(100);
final NumberAxis yAxis = (NumberAxis)chart.getYAxis();
yAxis.setLowerBound(0);
yAxis.setUpperBound(100);
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
});
final BooleanBinding disableControls =
zoomRect.widthProperty().lessThan(5)
.or(zoomRect.heightProperty().lessThan(5));
zoomButton.disableProperty().bind(disableControls);
controls.getChildren().add(zoomButton);
controls.getChildren().add(resetButton);
chartContainer.setCenter(StackChartContainer);
chartContainer.setBottom(controls);
return chartContainer;
}
private static LineChart<Number, Number> createChart() {
final NumberAxis xAxis = createAxis();
final NumberAxis yAxis = createAxis();
final LineChart<Number, Number> chart = new LineChart<>(xAxis, yAxis);
chart.setAnimated(false);
chart.setCreateSymbols(false);
return chart ;
}
private static NumberAxis createAxis() {
final NumberAxis xAxis = new NumberAxis();
xAxis.setAutoRanging(false);
xAxis.setLowerBound(0);
xAxis.setUpperBound(100);
return xAxis;
}
private static void setUpZooming(final Rectangle rect, final Node zoomingNode) {
final ObjectProperty<Point2D> mouseAnchor = new SimpleObjectProperty<>();
zoomingNode.setOnMousePressed(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
System.out.println("Mouse Event OK");
mouseAnchor.set(new Point2D(event.getX(), event.getY()));
System.out.println(event.getX() + " " + event.getY() );
rect.setWidth(0);
rect.setHeight(0);
}
});
zoomingNode.setOnMouseDragged(new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent event) {
double x = event.getX();
double y = event.getY();
rect.setX(Math.min(x, mouseAnchor.get().getX()));
rect.setY(Math.min(y, mouseAnchor.get().getY()));
System.out.println(x + ' ' + y);
rect.setWidth(Math.abs(x - mouseAnchor.get().getX()));
rect.setHeight(Math.abs(y - mouseAnchor.get().getY()));
}
});
}
private static void doZoom(Rectangle zoomRect, LineChart<Number, Number> chart) {
Point2D zoomTopLeft = new Point2D(zoomRect.getX(), zoomRect.getY());
Point2D zoomBottomRight = new Point2D(zoomRect.getX() + zoomRect.getWidth(), zoomRect.getY() + zoomRect.getHeight());
final NumberAxis yAxis = (NumberAxis) chart.getYAxis();
Point2D yAxisInScene = yAxis.localToScene(0, 0);
final NumberAxis xAxis = (NumberAxis) chart.getXAxis();
Point2D xAxisInScene = xAxis.localToScene(0, 0);
double xOffset = zoomTopLeft.getX() - yAxisInScene.getX() ;
double yOffset = zoomBottomRight.getY() - xAxisInScene.getY();
double xAxisScale = xAxis.getScale();
double yAxisScale = yAxis.getScale();
xAxis.setLowerBound(xAxis.getLowerBound() + xOffset / xAxisScale);
xAxis.setUpperBound(xAxis.getLowerBound() + zoomRect.getWidth() / xAxisScale);
yAxis.setLowerBound(yAxis.getLowerBound() + yOffset / yAxisScale);
yAxis.setUpperBound(yAxis.getLowerBound() - zoomRect.getHeight() / yAxisScale);
System.out.println(yAxis.getLowerBound() + " , " + yAxis.getUpperBound());
zoomRect.setWidth(0);
zoomRect.setHeight(0);
}
public int getValueX() {
return (int) valueX;
}
public int getValueY() {
return (int) valueY;
}
}
Related
I have JavaFX project and I need coordinates of each dot in the orange line from image bellow.
https://i.stack.imgur.com/A7zVa.png
I spent a lot of hours googling but I can not find a solution.
It is a simple application. I need those coordinates beacuse I need to make G CODE for CNC machine.
My Code is:
public class KS2 extends Application {
private LineChart<Number, Number> chart;
#Override
public void start(Stage primaryStage) throws Exception {
final NumberAxis xAxis = new NumberAxis(0.0, 150.0, 2);
final NumberAxis yAxis = new NumberAxis(0.0, 100.0, 2);
// Flip the axis
// yAxis.setScaleY(-1);
Rectangle r = new Rectangle(0, 0, 80, 50);
r.setFill(Color.TRANSPARENT);
r.setStrokeWidth(0.5);
r.setStroke(Color.BLACK);
this.chart = new LineChart<Number, Number>(xAxis, yAxis) {
#Override
public void layoutPlotChildren() {
super.layoutPlotChildren();
r.getTransforms().setAll(chartDisplayTransform(xAxis, yAxis));
// note nodes don't get removed from the plot children, and this method may be
// called often:
if (!getPlotChildren().contains(r)) {
getPlotChildren().add(r);
}
}
};
this.chart.setAnimated(false);
XYChart.Series series = new XYChart.Series();
series.getData().add(new XYChart.Data(54, 50));
series.getData().add(new XYChart.Data(80, 0));
//series.setName("My portfolio");
this.chart.getData().add(series);
VBox vbox = new VBox(this.chart);
Scene scene = new Scene(vbox, 400, 200);
primaryStage.setScene(scene);
primaryStage.setHeight(600);
primaryStage.setWidth(400);
primaryStage.show();
}
private Transform chartDisplayTransform(NumberAxis xAxis, NumberAxis yAxis) {
return new Affine(xAxis.getScale(), 0, xAxis.getDisplayPosition(0), 0, yAxis.getScale(),
yAxis.getDisplayPosition(0));
}
public static void main(String[] args) {
Application.launch(args);
}
}
So I'm making a game where the enemies follow the player and the player kills them. How do I make the enemies' ImageViews follow the player.
I have tried some if sentences but I actually have no idea. I also searched everywhere but I only find other people doing it with Swing and I get really confused with a lot of things. I use Javafx btw.
public class Main extends Application{
private static final int HEIGHT = 720;
private static final int WIDTH = 1280;
Scene scene;
BorderPane root, htpLayout;
VBox buttons, paragraphs, images;
Button startButton, htpButton, htpReturnButton, leaderboardButton, exitButton;
Text gameName, paragraph1, paragraph2, paragraph3;
Pane gameLayout;
ImageView background;
Game game = new Game();
Player player = new Player();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage window) throws Exception {
root = new BorderPane();
background = new ImageView("stick mob slayer background.png");
background.fitWidthProperty().bind(window.widthProperty());
background.fitHeightProperty().bind(window.heightProperty());
root.getChildren().add(background);
htpLayout = new BorderPane();
buttons = new VBox(15);
scene = new Scene(root, WIDTH, HEIGHT);
scene.getStylesheets().add("mobslayer/style.css");
gameName = new Text("Mob Slayer Unlimited");
gameName.setFont(Font.font("Complex", 50));
gameName.setFill(Color.WHITE);
root.setAlignment(gameName, Pos.CENTER_LEFT);
root.setTop(gameName);
startButton = new Button("Start Game");
startButton.setOnAction(e -> window.setScene(game.getScene()));
htpButton = new Button("How To Play");
htpButton.setOnAction(e -> scene.setRoot(htpLayout));
leaderboardButton = new Button("Leaderboard");
exitButton = new Button("Exit");
exitButton.setOnAction(e -> Platform.exit());
buttons.getChildren().addAll(startButton, htpButton, leaderboardButton, exitButton);
root.setCenter(buttons);
buttons.setAlignment(Pos.CENTER);
paragraphs = new VBox(30);
paragraph1 = new Text("Objektive\nNär spelet börjar kommer huvudkaraktären möta monster.\n"
+ "Ju längre in i spelet du kommer, ju fler och svårare monster dyker upp.\n"
+ "Ditt mål är att överleva så länge som möjligt.");
paragraph1.setFont(Font.font("Dubai", 13));
paragraph1.setFill(Color.BLACK);
paragraph2 = new Text("Movement\nAlla monster dras imot dig, så du måste akta dig.\n"
+ "Detta gör du med hjälp av piltangenterna.");
paragraph2.setFont(Font.font("Dubai", 13));
paragraph2.setFill(Color.BLACK);
paragraph3 = new Text("Special Effects\nDu kan också attackera tillbaka med en lätt attack(c)\n"
+ "eller med en specialattack(space) som dödar alla monster på skärmen.\n"
+ "Du kan dasha(x) för att röra dig snabbare åt ett håll.");
paragraph3.setFont(Font.font("Dubai", 13));
paragraph3.setFill(Color.BLACK);
paragraphs.getChildren().addAll(paragraph1, paragraph2, paragraph3);
htpReturnButton = new Button("Return");
htpReturnButton.setOnAction(e->scene.setRoot(root));
htpLayout.setBottom(htpReturnButton);
htpLayout.setAlignment(htpReturnButton,Pos.TOP_CENTER);
images = new VBox(30);
// Image image1 = new Image(new FileInputStream("resources\\cod zombies.jpg"));
// final ImageView image11 = new ImageView(image1);
// image11.setFitHeight(100);
// image11.setFitWidth(100);
// image11.setPreserveRatio(true);
//
// Image image2 = new Image(new FileInputStream("resources\\arrowkeys.png")) ;
// final ImageView image22 = new ImageView(image2);
// image22.setFitHeight(100);
// image22.setFitWidth(100);
// image22.setPreserveRatio(true);
//
// Image image3 = new Image(new FileInputStream("resources\\keys.png")) ;
// final ImageView image33 = new ImageView(image3);
// image33.setFitHeight(100);
// image33.setFitWidth(100);
// image33.setPreserveRatio(true);
//
// images.getChildren().addAll(image11, image22, image33);
//
paragraphs.setAlignment(Pos.TOP_LEFT);
htpLayout.setLeft(paragraphs);
htpLayout.setRight(images);
window.setTitle("Mob Slayer Unlimited");
window.setScene(scene);
window.setResizable(false);
window.show();
}
}
public class Game {
private static final int HEIGHT = 720;
private static final int WIDTH = 1280;
private Scene scene;
Pane root;
Text health, stamina, wave, kills;
int waveCounter = 1, killCounter = 0;
Button restartButton, pauseButton;
Line limitUp;
Player player = new Player();
Enemies enemy = new Enemies();
public Game() {
health = new Text(50, 30, "HP: " + player.getHealth());
health.setFont(Font.font("BankGothic Lt BT", 30));
health.setFill(Color.WHITE);
stamina = new Text(50, 80, "STAMINA: " + player.getStamina());
stamina.setFont(Font.font("BankGothic Lt BT", 30));
stamina.setFill(Color.WHITE);
wave = new Text(1050, 30, "WAVE: " + waveCounter);
wave.setFont(Font.font("BankGothic Lt BT", 30));
wave.setFill(Color.WHITE);
kills = new Text(1050, 80, "KILLS: " + killCounter);
kills.setFont(Font.font("BankGothic Lt BT", 30));
kills.setFill(Color.WHITE);
restartButton = new Button("RESTART");
restartButton.setFont(Font.font("BankGothic Lt BT", 30));
restartButton.setOnAction(e -> restart());
restartButton.setLayoutX(350);
restartButton.setLayoutY(20);
pauseButton = new Button("PAUSE");
pauseButton.setFont(Font.font("BankGothic Lt BT", 30));
pauseButton.setOnAction(e -> restart());
pauseButton.setLayoutX(650);
pauseButton.setLayoutY(20);
limitUp = new Line(0, 100, 1280, 100);
limitUp.setStroke(Color.WHITE);
root = new Pane(player.getSlayer(), limitUp, player.getSlayerHitbox(), health, stamina, wave, kills, restartButton, pauseButton, enemy.getEnemy());
root.setStyle("-fx-background-color: black");
enemy.enemyMovement();
movePlayerTo(WIDTH / 2, HEIGHT / 2);
scene = new Scene(root, WIDTH, HEIGHT);
scene.setOnKeyPressed(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W: player.goUp = true; break;
case S: player.goDown = true; break;
case A: player.goLeft = true; break;
case D: player.goRight = true; break;
case K: player.running = true; break;
}
}
});
scene.setOnKeyReleased(new EventHandler<KeyEvent>() {
#Override
public void handle(KeyEvent event) {
switch (event.getCode()) {
case W: player.goUp = false; break;
case S: player.goDown = false; break;
case A: player.goLeft = false; break;
case D: player.goRight = false; break;
case K: player.running = false; break;
}
}
});
AnimationTimer timer = new AnimationTimer() {
#Override
public void handle(long now) {
int dx = 0, dy = 0;
if (player.goUp) dy -= 2;
if (player.goDown) dy += 2;
if (player.goRight) dx += 2;
if (player.goLeft) dx -= 2;
if (player.running) { dx *= 2; dy *= 2; }
enemy.enemyMovement();
movePlayerBy(dx, dy);
}
};
timer.start();
}
public Scene getScene() {
return scene;
}
// I took this methods for movement from Github
public void movePlayerBy(int dx, int dy) {
if (dx == 0 && dy == 0) return;
final double cx = player.getSlayer().getBoundsInLocal().getWidth() / 2;
final double cy = player.getSlayer().getBoundsInLocal().getHeight() / 2;
double x = cx + player.getSlayer().getLayoutX() + dx;
double y = cy + player.getSlayer().getLayoutY() + dy;
movePlayerTo(x, y);
}
public void movePlayerTo(double x, double y) {
final double cx = player.getSlayer().getBoundsInLocal().getWidth() / 2;
final double cy = player.getSlayer().getBoundsInLocal().getHeight() / 2;
if (x - cx >= 0 &&
x + cx <= WIDTH &&
y - cy >= 0 &&
y + cy <= HEIGHT) {
player.getSlayer().relocate(x - cx, y - cy);
player.getSlayerHitbox().relocate(x - cx + 37, y - cy + 35);
}
}
public class Player {
private int health;
private int damage;
private int stamina;
private Image slayerImage;
private ImageView slayer;
private Rectangle slayerHitbox;
boolean running, goUp, goDown, goRight, goLeft;
public Player () {
health = 5;
damage = 1;
stamina = 5;
slayerImage = new Image("stick mob slayer.png", 100, 100, true, true);
slayer = new ImageView(slayerImage);
slayerHitbox = new Rectangle(10, 50);
}
public int getDamage() {
return damage;
}
public void setDamage(int damage) {
this.damage = damage;
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getStamina() {
return stamina;
}
public void setStamina(int stamina) {
this.stamina = stamina;
}
public ImageView getSlayer() {
return slayer;
}
public Rectangle getSlayerHitbox() {
slayerHitbox.setFill(Color.TRANSPARENT);
return slayerHitbox;
}
}
public class Enemies {
private int health;
private int speed;
private Image enemyImage;
private ImageView enemy;
private Rectangle enemyHitbox;
Player player = new Player();
public Enemies () {
health = 1;
speed = 1;
enemyImage = new Image("stick enemy.png", 100, 100, true, true);
enemy = new ImageView(enemyImage);
enemyHitbox = new Rectangle(10, 50);
}
public int getHealth() {
return health;
}
public void setHealth(int health) {
this.health = health;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public ImageView getEnemy () {
return enemy;
}
public Rectangle getEnemyHitbox() {
enemyHitbox.setFill(Color.YELLOW);
return enemyHitbox;
}
}
This is everything I have done so far. I would appreciate any help. If possible I would like to know how to make the enemies appear from random spots of the borders of the screen as well. Thanks in advance.
you should try first something more simple like implementing A* path search algo or some grid with some units on it before trying todo a game and having such questions
i have following code:
final TreeMap<Integer, Double> ADLMap = new TreeMap<>();
public static void main(String[] args) {
launch(args);
}
#Override
public void start(Stage stage) {
final String currency = "currreny";
ADL(currency);
stage.setTitle("Line Chart Sample");
//defining the axes
final NumberAxis xAxis = new NumberAxis();
final NumberAxis yAxis = new NumberAxis();
xAxis.setLabel("Number of Month");
//creating the chart
final LineChart<Number, Number> lineChart = new LineChart<Number, Number>(xAxis, yAxis);
lineChart.setTitle("Stock Monitoring, 2010");
//defining a series
XYChart.Series ADLChart = new XYChart.Series();
XYChart.Series regularChart = new XYChart.Series();
ADLChart.setName("My portfolio");
chartMap.entrySet().forEach(entry -> regularChart.getData().add(new XYChart.Data(entry.getKey(), entry.getValue())));
//populating the series with data
ADLMap.entrySet().forEach(entry -> ADLChart.getData().add(new XYChart.Data(entry.getKey(), entry.getValue())));
System.out.println(ADLMap);
lineChart.setCreateSymbols(false);
Scene scene = new Scene(lineChart, 1200, 1000);
//lineChart.getData().add(regularChart);
lineChart.getData().add(ADLChart);
stage.setScene(scene);
stage.show();
final double SCALE_DELTA = 1.1;
lineChart.setOnScroll(new EventHandler<ScrollEvent>() {
public void handle(ScrollEvent event) {
event.consume();
if (event.getDeltaY() == 0) {
return;
}
double scaleFactor = (event.getDeltaY() > 0) ? SCALE_DELTA : 1 / SCALE_DELTA;
lineChart.setScaleX(lineChart.getScaleX() * scaleFactor);
lineChart.setScaleY(lineChart.getScaleY() * scaleFactor);
}
});
lineChart.setOnMousePressed(new EventHandler<MouseEvent>() {
public void handle(MouseEvent event) {
if (event.getClickCount() == 2) {
lineChart.setScaleX(1.0);
lineChart.setScaleY(1.0);
}
}
});
}
private void ADL(final String currency) {
double counter = -4000000.0;
int mapCounter = 0;
while (counter < 4000000) {
ADLMap.put(mapCounter++, counter++);
}
}
the Map contains following values:
keys n+1 n€IN
Values from range from -10.000.000 to + 10.000.000
My Problem: It doesn't plot values at all. At least i cannot see any.
Can someone please help?
My mistake was that a complex algorithm produced an inifnity nuber which was placed in the TreeMap. The Graph couldn't plot it ofc.
first of all, I've just started with JavaFX and Java in general, so be patient with me :) I was wondering how can I keep a shape , in my case a Circle,bounded into the scene in JavaFX during the movement?
This is my Circle class
public class NewCircle extends Circle {
public NewCircle (double x, double y , double radius, Color colore){
super(x,y,radius);
this.setFill(colore);
this.setOnMousePressed(circleOnMousePressedEventHandler);
this.setOnMouseDragged(circleOnMouseDraggedEventHandler);
}
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;
double centerX = this.getCenterX();
double centerY = this.getCenterY();
double radius = this.getRadius();
EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>(){
#Override
public void handle(MouseEvent t){
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
orgTranslateX = ((Circle) (t.getSource())).getTranslateX();
orgTranslateY = ((Circle) (t.getSource())).getTranslateY();
}
};
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler =
new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
((Circle)(t.getSource())).setTranslateX(newTranslateX);
((Circle)(t.getSource())).setTranslateY(newTranslateY);
}
};
}
Make sure the none of the bounds of the dragged node crosses the scene bounds:
double orgSceneX, orgSceneY;
double orgTranslateX, orgTranslateY;
EventHandler<MouseEvent> circleOnMousePressedEventHandler = new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
orgSceneX = t.getSceneX();
orgSceneY = t.getSceneY();
Node source = (Node) t.getSource();
orgTranslateX = source.getTranslateX();
orgTranslateY = source.getTranslateY();
}
};
EventHandler<MouseEvent> circleOnMouseDraggedEventHandler
= new EventHandler<MouseEvent>() {
#Override
public void handle(MouseEvent t) {
Node source = (Node) t.getSource();
Bounds sceneBounds = source.getScene().getRoot().getLayoutBounds();
Bounds localBounds = source.getBoundsInLocal();
double offsetX = t.getSceneX() - orgSceneX;
double offsetY = t.getSceneY() - orgSceneY;
double newTranslateX = orgTranslateX + offsetX;
double newTranslateY = orgTranslateY + offsetY;
// restirct x movement to scene bounds
if (offsetX >= 0) {
if (localBounds.getMaxX() + newTranslateX > sceneBounds.getMaxX()) {
newTranslateX = sceneBounds.getMaxX() - localBounds.getMaxX();
}
} else {
if (localBounds.getMinX() + newTranslateX < 0) {
newTranslateX = -localBounds.getMinX();
}
}
// restrict y movement to scene bounds
if (offsetY >= 0) {
if (localBounds.getMaxY() + newTranslateY > sceneBounds.getMaxY()) {
newTranslateY = sceneBounds.getMaxY() - localBounds.getMaxY();
}
} else {
if (localBounds.getMinY() + newTranslateY < 0) {
newTranslateY = -localBounds.getMinY();
}
}
source.setTranslateX(newTranslateX);
source.setTranslateY(newTranslateY);
}
};
#Override
public void start(Stage primaryStage) {
Circle circle = new Circle(100, 100, 50);
circle.setOnMousePressed(circleOnMousePressedEventHandler);
circle.setOnMouseDragged(circleOnMouseDraggedEventHandler);
Pane root = new Pane(circle);
Scene scene = new Scene(root, 400, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
I have a dynamic Area Chart and I want to add a green point on the last point where my chart is displayed(the recent value on my chart).For example with displaying the line border i want a big green point to be displayed on my area chart? I'm working with an example shown here .
How to do this? There's my code:
public class essaijfree2 extends ApplicationFrame {
private static final String TITLE = "Dynamic Series";
private static final String START = "Start";
private static final String STOP = "Stop";
private static final float MINMAX = 100;
private static final int COUNT = 2 * 60;
private static final int FAST = 100;
private static final int SLOW = FAST * 5;
private static final Random random = new Random();
private Timer timer;
public essaijfree2(final String title) {
super(title);
final DynamicTimeSeriesCollection dataset =
new DynamicTimeSeriesCollection(1, COUNT, new Second());
dataset.setTimeBase(new Second(0, 0, 0, 1, 1, 2011));
dataset.addSeries(gaussianData(), 0, "Gaussian data");
JFreeChart chart = createChart(dataset);
XYPlot xyPlot = (XYPlot) chart.getPlot();
XYDifferenceRenderer r = new XYDifferenceRenderer(Color.green,Color.red, true);
xyPlot.setRenderer(r);
final JComboBox combo = new JComboBox();
combo.addItem("Fast");
combo.addItem("Slow");
combo.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
if ("Fast".equals(combo.getSelectedItem())) {
timer.setDelay(FAST);
} else {
timer.setDelay(SLOW);
}
}
});
this.add(new ChartPanel(chart), BorderLayout.CENTER);
JPanel btnPanel = new JPanel(new FlowLayout());
btnPanel.add(combo);
this.add(btnPanel, BorderLayout.SOUTH);
timer = new Timer(FAST, new ActionListener() {
float[] newData = new float[1];
#Override
public void actionPerformed(ActionEvent e) {
newData[0] = randomValue();
dataset.advanceTime();
dataset.appendData(newData);
}
});
}
private float randomValue() {
return (float) (random.nextGaussian() * MINMAX / 3);
}
private float[] gaussianData() {
float[] a = new float[COUNT];
for (int i = 0; i < a.length; i++) {
a[i] = randomValue();
}
return a;
}
private JFreeChart createChart(final XYDataset dataset) {
final JFreeChart result = ChartFactory.createXYAreaChart(
TITLE, "hh:mm:ss", "milliVolts", dataset,PlotOrientation.VERTICAL, true, true, false);
final XYPlot plot = result.getXYPlot();
ValueAxis domain = plot.getDomainAxis();
domain.setAutoRange(true);
ValueAxis range = plot.getRangeAxis();
range.setRange(-MINMAX, MINMAX);
return result;
}
public void start() {
timer.start();
}
public static void main(final String[] args) {
EventQueue.invokeLater(new Runnable() {
#Override
public void run() {
essaijfree2 demo = new essaijfree2(TITLE);
demo.pack();
RefineryUtilities.centerFrameOnScreen(demo);
demo.setVisible(true);
demo.start();
}
});
}
I'd look at an XYShapeAnnotation positioned at the coordinates of the last added datum. Some examples are seen here. You can use a RadialGradientPaint with varying alpha to get the halo effect. I've never tried doing it dynamically, but XYPlot includes the methods addAnnotation() and removeAnnotation(); both notify all registered listeners.
I recommend to create your own XYAnnotation that a) doesn´t used predefined x and y values but instead picks them from the dataset and that b) uses a shape whose bounds are defined in Java2D space so that the shape size remains constant when you zoom in.
Here is an example:
public class ItemAnnotationDemo {
public static void main(String[] args) {
int count = 20;
double[][] data = new double[2][count];
for(int i = 0; i < count; i++){
data[0][i] = i;
data[1][i] = i;
}
DefaultXYDataset dataset = new DefaultXYDataset();
dataset.addSeries("Values", data);
NumberAxis xAxis = new NumberAxis("x axis");
NumberAxis yAxis = new NumberAxis("y axis");
XYItemRenderer renderer = new XYLineAndShapeRenderer(true, true);
renderer.addAnnotation(new XYItemAnnotation(
new Rectangle2D.Double(-10, -8, 20, 16),
new Color(128,128,128,128),
new BasicStroke(3.0f),
Color.RED,0,Integer.MAX_VALUE));
XYPlot plot = new XYPlot(dataset, xAxis, yAxis, renderer);
JFreeChart chart = new JFreeChart(plot);
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.getContentPane().add(new ChartPanel(chart));
frame.pack();
frame.setVisible(true);
}
}
class XYItemAnnotation extends AbstractXYAnnotation{
private Shape shape;
private Paint outline;
private Paint fill;
private Stroke stroke;
private int si;
private int ii;
public XYItemAnnotation(Shape shape, Paint fillPaint, Stroke outlineStroke, Paint outlinePaint, int seriesIndex, int itemIndex){
super();
this.shape = shape;
this.fill = fillPaint;
this.stroke = outlineStroke;
this.outline = outlinePaint;
this.si = seriesIndex;
this.ii = itemIndex;
}
public void draw(Graphics2D g2, XYPlot plot, Rectangle2D dataArea, ValueAxis domainAxis, ValueAxis rangeAxis, int datasetIndex, PlotRenderingInfo info){
XYDataset dataset = plot.getDataset(datasetIndex);
if(dataset == null) return;
if(si > dataset.getSeriesCount() - 1 ) return;
int item = Math.max(0, ii);
item = Math.min(item, dataset.getItemCount(si) - 1);
double dx = dataset.getXValue(si, item);
double dy = dataset.getYValue(si, item);
if(Double.isNaN(dx) || Double.isNaN(dy)) return;
if(!domainAxis.getRange().contains(dx) || !rangeAxis.getRange().contains(dy)) return;
PlotOrientation orientation = plot.getOrientation();
RectangleEdge domainEdge = Plot.resolveDomainAxisLocation(
plot.getDomainAxisLocation(), orientation);
RectangleEdge rangeEdge = Plot.resolveRangeAxisLocation(
plot.getRangeAxisLocation(), orientation);
double jx = domainAxis.valueToJava2D(dx, dataArea, domainEdge);
double jy = rangeAxis.valueToJava2D(dy, dataArea, rangeEdge);
if (orientation == PlotOrientation.HORIZONTAL) {
double temp = jx;
jx = jy;
jy = temp;
}
Shape trans = ShapeUtilities.createTranslatedShape(shape, jx, jy);
g2.setPaint(fill);
g2.fill(trans);
g2.setPaint(outline);
g2.setStroke(stroke);
g2.draw(trans);
}
}