Dans JavaFx, Canvas est un composant définissant une zone qui permet de dessiner programmatiquement des formes et des couleurs.
https://openjfx.io/javadoc/25/javafx.graphics/javafx/scene/canvas/package-summary.html
## Cas d'utilisation
• jeux 2D
• Graphismes personnalisés
• Animations
• Dessin interactifs (ex : application de dessin)
## Canvas
https://openjfx.io/javadoc/25/javafx.graphics/javafx/scene/canvas/Canvas.html
## GraphicContext
Le GraphicContext est comme la palette d'outils de dessin.
On va sélectionner des couleurs de remplissage, de trait, un type d'outil.
Puis on va indiquer ce qu'on veut dessiner avec des jeux de coordonées.
## Dessiner
On charge le `GraphicsContext` du canvas.
```java
Canvas canvas = new Canvas(320, 320);
GraphicsContext gc = canvas.getGraphicsContext2D();
```
On peut ensuite utiliser les méthodes de l'API pour dessiner les formes.
![[image-60.png|240x127]]
### Dessiner un rectangle jaune
```java
// Choix du remplissage
gc.setFill(Color.BLANCHEDALMOND);
// Dessiner un rectangle avec le remplissage courant
// aux coordonnées x:75, y:75
// de largeur w:303
// de hauteur h:303
gc.fillRect(0, 0, 303, 303);
```
![[image-52.png|240x260]]
### Tracer une ligne rouge
```java
// Choix de la couleur des traits
gc.setStroke(Color.RED);
// Tracer une ligne
// depuis les coordonnées x:20, y:40
// vers les coordonnées x:156, y:204
gc.strokeLine(20,40,156,204);
// Equivalent à
gc.moveTo(20, 40);
gc.lineTo(156, 204);
gc.stroke();
```
![[image-53.png|240x259]]
### Dessiner un ovale
```java
// Dessiner le tracé d'un ovale
gc.strokeOval (50, 50, 50, 50);
```
![[image-61.png|240x259]]
---
```java
// Dessiner le remplissage d'un ovale
gc. setFill(Color.GREEN);
gc.fillOval(20, 30, 50, 75);
```
![[image-62.png|240x260]]
### Découvrir à l'aide de la Javadoc
A vous de découvrir les autres possibilité de dessin à l'aide de la Javadoc
https://openjfx.io/javadoc/25/javafx.graphics/javafx/scene/canvas/GraphicsContext.html
## Style des formes
```java
gc.setFill(Color.ORANGE);
gc.fillRect(30, 20, 150, 50);
```
![[image-63.png|240x258]]
---
```java
gc.setStroke(Color.BLUEVIOLET); gc.setLineWidth(4);
gc.strokeLine(75, 100, 100, 189);
```
![[image-64.png|240x260]]
---
```java
// Violet - Opacité 25%
gc.setFill(Color.rgb(255, 0, 255, 0.25));
gc. fillRect(50, 50, 100, 100);
```
![[image-65.png|240x260]]
---
```java
gc.setFill(new LinearGradient(
0, 0, 1, 0,
true, CycleMethod.NO_CYCLE,
new Stop(0, Color.YELLOWGREEN), new Stop(1, Color.PURPLE))
);
gc.fillRect(30, 75, 150, 75);
```
> [!example]- Code avec nom des arguments
> ![[image-67.png]]
![[image-66.png|240x259]]
## Exemple : dessiner une grille de 3x3
![[image-51.png|240x260]]
Code avec les noms des attributs
![[image-50.png|320x370]]
### Code complet de la grille
```java
package school.coda.javafx.javafx_canvas;
import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Group;
import javafx.scene.Scene;
import javafx.scene.canvas.Canvas;
import javafx.scene.canvas.GraphicsContext;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;
import javafx.scene.paint.Color;
import javafx.stage.Stage;
public class CanvasApplication extends Application {
@Override
public void start(Stage stage) {
final Canvas canvas = new Canvas(320, 320);
GraphicsContext gc = canvas.getGraphicsContext2D();
// Choix du remplissage
gc.setFill(Color.BLANCHEDALMOND);
// Dessiner un rectangle avec le remplissage courant
// aux coordonnées x:75, y:75
// de largeur w:303
// de hauteur h:303
gc.fillRect(0, 0, 303, 303);
// Choix de la couleur des traits
gc.setStroke(Color.BLACK);
// Dessiner le contour d'un rectangle
gc.strokeRect(0,0,303,303);
// Lignes verticales
gc.strokeLine(101,0,101,303);
gc.strokeLine(202,0,202,303);
// Lignes horizontales
gc.strokeLine(0,101,303,101);
gc.strokeLine(0,202,303,202);
Group group = new Group();
group.getChildren().add(canvas);
BorderPane root = new BorderPane(group);
root.setPadding(new Insets(20));
Scene scene = new Scene(root, 340, 340, Color.WHITE);
stage.setScene(scene);
stage.show();
}
}
```
### Réutilisation dans une méthode
On pourrait extraire ce code dans une méthode paramétrée pour dessiner des grilles différentes.
Cela permettrait de le **réutiliser**.
```java
void drawGrid(
GraphicsContext gc,
int cellNumber,
int cellWidth, int cellHeight,
Color fillColor, Color lineColor) {
// Voir le code complet en fin de ce chapitre
}
```
Exemples d'utilisation
![[image-58.png]]
![[image-51.png|240x260]]
---
![[image-54.png]]
![[image-55.png|240x259]]
---
![[image-57.png]]
![[image-56.png|240x260]]
### Code de la méthode de grille complet
```java
private static void drawGrid(
GraphicsContext gc,
int cellNumber,
int cellWidth, int cellHeight,
Color fillColor, Color lineColor) {
int gridWidth = (cellNumber * cellWidth) + cellNumber;
int gridHeight = (cellNumber * cellHeight) + cellNumber;
// Choix du remplissage
gc.setFill(fillColor);
// Dessiner un rectangle avec le remplissage courant
// aux coordonnées x:75, y:75
// de largeur w:303
// de hauteur h:303
gc.fillRect(0, 0, gridWidth, gridHeight);
// Choix de la couleur des traits
gc.setStroke(lineColor);
// Dessiner le contour d'un rectangle
gc.strokeRect(0, 0, gridWidth, gridHeight);
// Lignes verticales
for (int i = 1; i < cellNumber; i++) {
// Ligne verticale
gc.strokeLine((cellWidth * i) + i, 0, (cellWidth * i) + i, gridHeight);
// Ligne horizontale
gc.strokeLine(0, (cellHeight * i) + i, gridWidth, (cellHeight * i) + i);
}
}
```
## Path
Pour faire un tracé complet.
```java
// Un seul style appliqué au même tracé
gc.setStroke(Color.BLUE);
gc.setLineWidth(2);
gc.moveTo(0, 0);
gc.lineTo(50, 100);
// C'est le dernier style appliqué qui l'emporte
gc.setStroke(Color.RED);
gc.setLineWidth(5);
gc.moveTo(0, 100);
gc.lineTo(50, 0);
gc.stroke();
```
![[image-68.png|119x170]]
---
```java
// Styles différents appliqués à plusieurs tracés
gc.beginPath();
gc.setStroke(Color.BLUE);
gc.setLineWidth(2);
gc.strokeLine(0, 200, 250, 250);
gc.stroke();
gc.beginPath ();
gc.setStroke(Color.RED);
gc.setLineWidth(5);
gc.strokeLine(0, 250, 250, 200);
gc.stroke();
```
![[image-69.png|240x90]]
## Animation
60 fois par seconde (60FPS) :
• Effacer le contenu du canvas
• Mettre à jour les données
• Redessiner le contenu
### Commencer une animation
`AnimationTimer` va appeler une fonction plusieurs fois par seconde selon la fréquence de rafraîchissement de votre écran :
60 MHZ = 60 fois par seconde
### AnimationTimer
## Créer un timer
```java
// On crée une classe anonyme qui étend de AnimationTimer
AnimationTimer animationTimer = new AnimationTimer(){
@Override
public void handle(long now) {
System.out.println("now is : "+now);
}
};
animationTimer.start();
```
```text
now is : 4067831897913875
now is : 4067831914539750
now is : 4067831931191833
now is : 4067831947870833
now is : 4067831964577458
now is : 4067831981191000
now is : 4067831997799416
now is : 4067832014572583
```
### Exemple d'animation
```java
AnimationTimer animationTimer = new AnimationTimer(){
private double x = 50;
private final double speed = 2;
@Override
public void handle(long now) {
x += speed;
// Effacer le canvas
gc. clearRect(0, 0, canvas.getWidth(), canvas.getHeight());
// Dessiner une forme à une position différente
gc.strokeOval(x, 75, 40, 60);
}
};
animationTimer.start();
```
![[javafx-canvas-animation 1.mp4]]
## À suivre
[[7.4 - Fxgl]]
[[8.1 - Introduction à l’écoconception en Java]]