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]]