From 9f10adccb7ebcde3b27990258ebce9ed2aea885c Mon Sep 17 00:00:00 2001 From: "fabien.le-houedec" Date: Tue, 24 Mar 2026 13:15:49 +0100 Subject: [PATCH 1/2] Claude : initial working PoC --- .idea/.gitignore | 8 ++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 ++ .idea/tpWeb.iml | 9 ++ .idea/vcs.xml | 6 ++ README.md | 223 ++++++++++++++++++++++++++++++++++++++++++++++ canvas.html | 8 +- controller.js | 68 +++++++++++++- interaction.js | 45 ++++++++-- main.js | 26 ++---- model.js | 55 +++++++++++- view.js | 30 ++++++- 12 files changed, 452 insertions(+), 40 deletions(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/tpWeb.iml create mode 100644 .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..9a897b6 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Ignored default folder with query files +/queries/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..7e43925 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..1fd8606 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/tpWeb.iml b/.idea/tpWeb.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/tpWeb.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index ab95039..8480194 100644 --- a/README.md +++ b/README.md @@ -1 +1,224 @@ TP Web : Javascript et HTML5 + +# La réalisation +L’objectif de ce TP consiste à créer une application Web pour faire du dessin vectoriel, i.e. pour dessiner des rectangles, des lignes, ainsi que définir leur couleur et leur épaisseur de trait. La figure ci-dessous montre l’état de l’application et donc l’objectif à atteindre. +Pour cela, vous allez utiliser le patron d'architecture MVC (Modèle-Vue-Contrôleur) ainsi que l'élément HTML5 Canvas. +Le fichier fourni canvas.css décrit des styles utilisés par le programme. Ne vous en souciez pas. Le fichier canvas.html est un document HTML décrivant la structure du programme : un Canvas, des boutons à bascule (toggle button), un sélectionneur de couleur (widget HTML5) et un bouton fléché (spinner) permettant de choisir l'épaisseur de trait. Ce document importe le document css (ligne 7) et les documents Javascript nécessaires à l’exécution du programme Web (ligne 26-30). Ces documents Javascript vous sont fournis mais sont vides et devront donc être complétés. +Avant de commencer le TP, les deux sections suivantes introduisent les notions nécessaires à sa réalisation. + + + +# MVC + + +MVC (Modèle-Vue-Contrôleur) est un patron d'architecture IHM. Il sera étudié plus en détails en 4 INFO. Ce patron suggère d'organiser la structure d'un logiciel en 3 composants : +Le Modèle définit le modèle de données du logiciel. Dans notre cas il s'agira de définir les concepts d'un dessin (dessin, forme, etc.) et leurs propriétés (couleur, etc.). Le modèle ne doit pas dépendre d'une quelconque librairie graphique, il est indépendant de ces possibles représentations graphiques. +La Vue est une représentation graphique possible du modèle. On peut évidemment avoir plusieurs vues d'un même modèle. Dans notre cas, la vue va consister à peindre dans un canvas HTML5 les formes du modèle. +Le Contrôleur est la partie interactive du patron. Il a pour but transformer les interactions réalisées par l'utilisateur en commandes allant modifier le modèle. + +Javascript +Javascript est actuellement le langage de programmation de scripts utilisé pour apporter du comportement à des pages Web. Javascript est en fait une implémentation du standard ECMAScript. Un script Javascript s'intègre nativement dans une page HTML de différentes manières possibles dont : + + est une balise HTML permettant d'inclure un script Javascript dans une page. + permet ici d'écrire directement du Javascript dans la balise script. + + +Une instruction Javascript prend la forme suivante : +var canvas = document.getElementById('myCanvas'); + +où canvas est déclaré comme étant une variable. Javascript est un langage à typage faible et dynamique : faible, car on ne déclare pas le type d'une variable, d'un paramètre ; dynamique, car on peut changer le type d'une variable. Par exemple on peut écrire : +var maVariable = 10 ; +maVariable = "Fooo!" ; + +Vous noterez qu'il est possible d'accéder au contenu d'une page Web via la variable globale document. On peut également rechercher un élément dans une page Web en utilisant son id défini dans la page HTML : + + + + + + + + + +Javascript permet de définir des fonctions, par exemple : +function getMousePosition(canvas, evt) { +var rect = canvas.getBoundingClientRect(); +return { +x: evt.x - rect.left, +y: evt.x - rect.top +}; +}; + +Les paramètres ne sont également pas typés. On peut également appeler une fonction sans fournir tous les paramètres. Par exemple : +getMousePosition(monCanvas, monEvt) ; est l'appel classique, tandis que +getMousePosition(monCanvas) ; fonctionne également à la différence que le paramètre evt n'aura pas de valeur dans la fonction. +Vous noterez que l'on peut retourner plusieurs valeurs en même temps : +var res = getMousePosition(monCanvas, monEvt) ; +La variable res contiendra 2 valeurs : x et y comme défini dans la fonction getMousePosition. On peut donc afficher ces deux valeurs de la manière suivante : + +console.log(res.x); +console.log(res.y); + +Un tableau s'écrit de la manière suivante : +var monTableau = new Array(); +L'ajout d'un élément dans un tableau : +monTableau.push(elt); + +Le parcours d'un tableau : +monTableau.forEach(function(eltDuTableau) { console.log(eltDuTableau) }); + +Étant donnée l’énumération suivante : +var editingMode = { rect: 0, line: 1 }; + +L'instruction switch s'utilise de la manière suivante. + +switch(this.currEditingMode){ +case editingMode.rect: { +break; +} +case editingMode.line: { +break; +} +} + + + +Javascript est un langage de programmation orienté objet. Cependant il ne permet pas de définir des classes mais des prototypes. Un prototype est un objet à partir duquel il est possible d'en créer de nouveaux (des duplicata). Pour ce TP, il n'est pas nécessaire de comprendre finement cette nuance. D'ailleurs, dans une optique de simplicité nous parlerons de classes par la suite. Donc, la définition d'une classe (en fait d'un objet mais nous allons utiliser le terme classe pour simplifier les explications) se fait de la manière suivante : + +function Humain(poids, taille) { +this.poids = poids; +this.taille = taille; +}; + +Humain.prototype.indiceMasseCorporelle = function () { +return this.poids / this.taille * this.taille; +}; + +Il s'agît donc d'une fonction dont le nom commence par une majuscule (Humain). Cette fonction est en fait le constructeur de l'objet pouvant prendre des paramètres (ici, poids et taille). Il est recommandé de déclarer les attributs d'une classe (this.poids et this.taille). La variable this correspond au contexte de l'objet courant. +Une classe peut avoir des fonctions (ici, indiceMasseCorporelle). Une fonction d'une classe peut manipuler les attributs de celle-ci lorsqu’elle est attachée à son prototype. Ne l'oubliez pas ! +L'instanciation d'un objet se fait de la manière suivante : + +var monHumain = new Humain(60, 170) ; + +Il est possible de définir des sous-classes : + +function Femme(poids, taille) { +Humain.call(this, poids, taille); +}; +Femme.prototype = new Humain(); + +La ligne Femme.prototype = new Human(); permet de définir Femme comme étant un sous-type de Humain. +La ligne Humain.call(this, poids, taille); permet d’éxécuter la fonction “Humain” avec comme contexte “this” et comme arguments “poids” et “taille”. C’est comme appeler le constructeur de la super-classe (Humain). On peut voir cela comme le super de Java. +Il est possible de rajouter des fonctions après la définition d'une classe. Vous allez utiliser ce principe pour rajouter dans le modèle une fonction d'affichage. Par exemple : + +Humain.prototype.indiceMasseGrasse = function() { +// Pour appeler l'éventuelle opération de la classe supérieure (le « super ») : +// NomDeLaClasseSupérieure.prototype.indiceMasseGrasse.call(this) ; +return this.indiceMasseCorporelle()*1.2 + this.age*0.23 – 5.4 ; +}; + +Cela rajoute dans la classe Humain la fonction indiceMasseGrasse. Cet ajout peut être effectué n'importe où après la déclaration de la classe. + +Le canvas est un objet HTML5 sur lequel il est possible de brancher des fonctions pour notamment récupérer les événements souris : + +canvas.addEventListener('mousedown', this.maFctGérantLaPression, false); +canvas.addEventListener('mousemove', this.maFctGérantLeDéplacement, false); +canvas.addEventListener('mouseup', this.maFctGérantLeRelâchement, false); + +Vous allez devoir utiliser ces 3 lignes pour brancher l'interaction glisser-déposer (cf. section suivante) au canvas de la page Web. + +Nous avons uniquement présenté les concepts Javascript nécessaires pour ce TP. Voici quels liens indispensables pour une maîtrise plus approfondie : +https://developer.mozilla.org/en-US/docs/Web/JavaScript +https://github.com/airbnb/javascript +https://en.wikibooks.org/wiki/JavaScript +http://www.html5canvastutorials.com/ + +De plus, la plupart des navigateurs actuels fournissent des outils de développement très utiles ! Par exemple sous Firefox, le menu « Développeur Web » dans le menu « Outils » référence un ensemble d'outils intégrés dans Firefox, notamment la « Console web » à ouvrir pour le TP. + +Interaction : le glisser-déposer (Drag-n-Drop) +Chose peu commune, vous allez commencer l'éditeur par l'implémentation d'une interaction homme-machine courante, le Drag-n-Drop (glisser-déposer, DnD) dans le fichier interaction.js. Le DnD consiste en la suite d'événements suivante s'effectuant à l'aide de la souris : une pression (santé !), des déplacements, un relâchement. Le DnD sera utilisé dans notre application Web pour dessiner des rectangles et des lignes. +Créer une classe DnD contenant les 4 attributs suivants initialisé à 0 : les coordonnées de la position initiale du DnD ; celles de la position finale. Ces attributs seront utilisés plus tard lors de la création de formes. +Déclarer 3 fonctions à cette classe correspondant aux 3 types d'événements à gérer. Pensez à lier (bind) chaque fonction à la classe. Ces fonctions prennent en entrée un attribut evt correspondant à l'événement produit lors de l'utilisation de la souris. Un tel événement possède les attributs x et y. +Implémenter ces fonctions. Elles ont pour but de définir la valeur des attributs. Cela va nécessiter de définir un nouvel attribut dans la classe car le code des fonctions liées aux déplacements et au relâchement doit être exécuté uniquement si une pression a été effectuée au préalable. Utiliser la fonction getMousePosition qui va placer le point de l’événement relativement à la position du canvas. +Enregistrer chaque fonction auprès du canvas (addEventListener). +Appeler dans chacune des 3 fonctions console.log pour afficher dans la console Javascript de votre navigateur les coordonnées de chaque événement lors de l'exécution de l'interaction. Vous pouvez maintenant tester le bon fonctionnement de l'interaction en ouvrant la page canvas.html dans votre navigateur, en affichant la console Web et en exécutant un DnD sur la zone de dessin (en gris). + +Le modèle +Vous allez maintenant développer le modèle (au sens MVC) de l'application Web. Ce modèle doit représenter un dessin (classe Drawing) se composant de formes (utilisez pour cela Array pour gérer la liste des formes d’un dessin), une forme étant soit un rectangle(classe Rectangle), soit une ligne (classe Line). +Une forme possède une couleur et une épaisseur de trait. Un rectangle possède des coordonnées de son point haut-gauche, une largeur et une hauteur. Une ligne possède les coordonnées de ses deux points. +Implémenter les 4 classes nécessaires pour définir le modèle dans le fichier model.js. Pensez à dé-commenter les lignes nécessaires dans le fichier main.html. + +La vue +La vue est une représentation graphique possible du modèle. Dans notre cas, le modèle est déjà hautement graphique et nous allons donc feinter pour minimiser le développement à faire grâce à la « flexibilité » de Javascript. En effet, Javascript permet de rajouter dans une classe déjà définie des fonctions. + + +Le code peut ressembler à quelque chose comme cela + +Rectangle.prototype.paint = function(ctx) { +//TODO Manager color +ctx.beginPath(); +ctx.rect(this.getInitX(), this.getInitY(), this.getFinalX(), this.getFinalY()); +ctx.stroke(); +}; + +Line.prototype.paint = function(ctx) { +//TODO Manager color +ctx.beginPath(); +ctx.moveTo(this.getInitX(), this.getInitY()); +ctx.lineTo(this.getFinalX(), this.getFinalY()); +ctx.stroke(); +}; + +Drawing.prototype.paint = function(ctx) { +//console.log(this.getForms()); +ctx.fillStyle = '#F0F0F0'; // set canvas' background color +ctx.fillRect(0, 0, canvas.width, canvas.height); +this.getForms().forEach(function (eltDuTableau) { +// now fill the canvas +eltDuTableau.paint(ctx); +}); +}; + + +Utiliser cette fonctionnalité pour ajouter les fonctions d'affichage (fonction paint) dans chacune des classes. La fonction paint de la classe Forme configurera juste la couleur et l'épaisseur du trait du contexte du canvas. Ces fonctions paint prendront donc en paramètre le contexte du canvas. La fonction paint de la classe Dessin peindra la fond du canvas en gris clair (copier-coller les lignes 10 et 11 du fichier main.js). +Vous pouvez utiliser pour dessiner votre rectangle. +> ctx.rect(initX,initY,finalX,finalY); +> ctx.stroke(); + +Tester votre code avec le code mis en commentaire dans le fichier main.js. +Le contrôleur +Vous allez maintenant rendre l'application interactive en définissant un interacteur. Un interacteur est une sorte d'outil que l'utilisateur manipule pour réaliser des actions. Dans notre cas, l'interacteur sera un crayon (Pencil dans le fichier controler.js) que l'utilisateur va manipuler pour ajouter des formes au dessin. Comme vous pouvez le constater le crayon est paramétrable (couleur, épaisseur, type de forme). +La première étape consiste à lier une interaction DnD à Pencil. Dans chacune des 3 fonctions de DnD, ajouter un appel aux fonctions interactor.onInteractionStart(this);, interactor.onInteractionUpdate(this);, interactor.onInteractionEnd(this);. Ces fonctions n'existent pas encore mais elles ont pour but de notifier l'interacteur d'une modification de l'interaction. +Implémenter ces 3 fonctions dans la classe Pencil. Elles devront créer une forme (en utilisant l'attribut this.currentShape, la forme créée sera un Rectangle ou Ligne en fonction de l'attribut this.currEditingMode), la mettre à jour lorsque l'utilisateur bouge la souris et l'ajouter au dessin lors du relâchement. N'oubliez pas d'appeler la fonction paint de la classe Dessin pour mettre à jour la vue à chaque étape. +Pour modifier le style des formes créées, l'utilisateur doit pouvoir utiliser les widgets fournis (boutons et spinner). Dans la classe Pencil, lier chacun de ces widgets à une fonction modifiant les attributs de la classe Pencil (this.currLineWidth, this.currColour et this.currEditingMode). + +Liste des modifications +Vous allez compléter l'application avec une liste des modifications apportées au dessin. Cela va permettre de supprimer une forme précédemment dessinée. Pour implémenter cette nouvelle fonctionnalité, il va falloir modifier la page actuelle via Javascript. On utilisera uniquement l'API de base que propose Javascript pour manipuler le Document Object Model (DOM). Le DOM est la représentation arborescente du contenu de la page. + +Ajouter une fonction updateShapeList dans la vue pour afficher la liste des formes. La liste sera contenue dans l'élément dont l'ID est shapeList. Chaque forme aura un affichage différent en fonction de son type (ligne, rectangle). Adapter le contrôleur pour appeler cette nouvelle fonction à chaque fois qu'une nouvelle forme est dessinée. +Modifier updateShapeList pour ajouter le bouton suivant devant chaque élément de la liste. + +Définir le comportement du bouton pour supprimer la forme correspondante dans le dessin. +Si vous avez le temps, compléter l'éditeur avec la création d'autres formes (ellipse, polygone, etc.), d'autres paramètre (style de la ligne, etc.) ou bien des boutons undo/redo. + +Pour exemple, je vous fournis des éléments de solution et une version en typescript ici. +https://github.com/barais/drawwebvallillajs + + +Q. 16 Bonus. Déploiement sur un CDN (Content Delivery NEtwork comme github page. + +Qu’est-ce qu’un CDN ? +Un CDN (Content Delivery Network) est constitué d’un groupe de serveurs situés à différents endroits dans le monde. Ces emplacements sont appelés points de présence (PoP). Grâce à des règles que vous avez définies, ils redistribuent localement le contenu de vos serveurs en mettant en cache les fichiers qui n’ont pas besoin d’être mis à jour régulièrement. +Ce principe simple permet de dynamiser et d’optimiser vos sites web internationaux tout en améliorant l’expérience utilisateur de votre public à l’échelle mondiale.Un CDN vous permet d’améliorer les performances de votre site Internet et la vitesse de téléchargement des fichiers, grâce aux points de présence (PoP) de votre fournisseur (ici github) distribués dans le monde entier. La réduction du temps de latence vous permet d’optimiser les taux de conversion tout en améliorant votre référencement. +Parmi les principaux avantages: +Sécurité renforcée, vitesse améliorée et meilleure expérience utilisateur. En éloignant votre serveur de la première ligne et en laissant la solution CDN Infrastructure gérer le trafic, vous réduisez les risques d’attaque en permettant au réseau d’absorber davantage de demandes. En utilisant un CDN, vous êtes moins exposé aux vulnérabilités. +Optimisation du référencement dans chaque pays. Augmentez les résultats de recherche grâce à l’optimisation du référencement pour chaque pays disposant d’un point de présence. CDN Infrastructure permet d’accélérer les temps de chargement des pages et améliore la réactivité des sites et des applications. L’expérience utilisateur s’en trouve considérablement améliorée. +Réduction des coûts d’hébergement et ROI court. Il n’est pas nécessaire d’acheter plus de matériel pour proposer plus de contenu. CDN Infrastructure gère vos besoins croissants en matière de trafic à votre place. Votre serveur back-end est moins sollicité, ce qui réduit vos coûts informatiques. Vous êtes également plus proche géographiquement de vos utilisateurs finaux, ce qui vous permet de consommer moins de ressources. + +Ceux qui ont encore fini trop vite peuvent regarder le TP déploiement avec présence d’un front et d’un back sur sa propre infrastructure de serveur. + +Pour ceux qui ont terminé trop tôt ;). Déployez votre application comme une page github-page. +Je vous laisser suivre le tutoriel ici. +https://pages.github.com/ diff --git a/canvas.html b/canvas.html index 137ca82..af7d53c 100644 --- a/canvas.html +++ b/canvas.html @@ -44,10 +44,10 @@ - - + + - - + + diff --git a/controller.js b/controller.js index 273ce32..9518084 100644 --- a/controller.js +++ b/controller.js @@ -2,16 +2,76 @@ var editingMode = { rect: 0, line: 1 }; function Pencil(ctx, drawing, canvas) { - this.currEditingMode = editingMode.line; + this.ctx = ctx; + this.drawing = drawing; + this.canvas = canvas; + this.currEditingMode = editingMode.rect; this.currLineWidth = 5; this.currColour = '#000000'; - this.currentShape = 0; + this.currentShape = null; - // Liez ici les widgets à la classe pour modifier les attributs présents ci-dessus. + // Liaison des widgets aux attributs du Pencil + document.getElementById('butRect').addEventListener('change', function() { + this.currEditingMode = editingMode.rect; + }.bind(this)); + + document.getElementById('butLine').addEventListener('change', function() { + this.currEditingMode = editingMode.line; + }.bind(this)); + + document.getElementById('spinnerWidth').addEventListener('change', function(evt) { + this.currLineWidth = parseInt(evt.target.value); + }.bind(this)); + + document.getElementById('colour').addEventListener('change', function(evt) { + this.currColour = evt.target.value; + }.bind(this)); new DnD(canvas, this); +} - // Implémentez ici les 3 fonctions onInteractionStart, onInteractionUpdate et onInteractionEnd +Pencil.prototype.onInteractionStart = function(dnd) { + switch (this.currEditingMode) { + case editingMode.rect: + this.currentShape = new Rectangle(dnd.initX, dnd.initY, 0, 0, this.currLineWidth, this.currColour); + break; + case editingMode.line: + this.currentShape = new Line(dnd.initX, dnd.initY, dnd.initX, dnd.initY, this.currLineWidth, this.currColour); + break; + } + this.drawing.paint(this.ctx, this.canvas); }; +Pencil.prototype.onInteractionUpdate = function(dnd) { + if (!this.currentShape) return; + switch (this.currEditingMode) { + case editingMode.rect: + this.currentShape.setWidth(dnd.finalX - this.currentShape.getInitX()); + this.currentShape.setHeight(dnd.finalY - this.currentShape.getInitY()); + break; + case editingMode.line: + this.currentShape.setX2(dnd.finalX); + this.currentShape.setY2(dnd.finalY); + break; + } + // Redessiner le dessin existant puis la forme en cours + this.drawing.paint(this.ctx, this.canvas); + this.currentShape.paint(this.ctx); +}; +Pencil.prototype.onInteractionEnd = function(dnd) { + if (!this.currentShape) return; + switch (this.currEditingMode) { + case editingMode.rect: + this.currentShape.setWidth(dnd.finalX - this.currentShape.getInitX()); + this.currentShape.setHeight(dnd.finalY - this.currentShape.getInitY()); + break; + case editingMode.line: + this.currentShape.setX2(dnd.finalX); + this.currentShape.setY2(dnd.finalY); + break; + } + this.drawing.addForm(this.currentShape); + this.currentShape = null; + this.drawing.paint(this.ctx, this.canvas); +}; diff --git a/interaction.js b/interaction.js index 5f09822..c345a26 100644 --- a/interaction.js +++ b/interaction.js @@ -2,11 +2,43 @@ // La création d'un Dnd requière un canvas et un interacteur. // L'interacteur viendra dans un second temps donc ne vous en souciez pas au départ. function DnD(canvas, interactor) { - // Définir ici les attributs de la 'classe' - - // Developper les 3 fonctions gérant les événements - - // Associer les fonctions précédentes aux évènements du canvas. + this.initX = 0; + this.initY = 0; + this.finalX = 0; + this.finalY = 0; + this.pressed = false; + + this.onMouseDown = function(evt) { + var pos = getMousePosition(canvas, evt); + this.pressed = true; + this.initX = pos.x; + this.initY = pos.y; + console.log("mousedown:", pos.x, pos.y); + if (interactor) interactor.onInteractionStart(this); + }.bind(this); + + this.onMouseMove = function(evt) { + if (!this.pressed) return; + var pos = getMousePosition(canvas, evt); + this.finalX = pos.x; + this.finalY = pos.y; + console.log("mousemove:", pos.x, pos.y); + if (interactor) interactor.onInteractionUpdate(this); + }.bind(this); + + this.onMouseUp = function(evt) { + if (!this.pressed) return; + var pos = getMousePosition(canvas, evt); + this.pressed = false; + this.finalX = pos.x; + this.finalY = pos.y; + console.log("mouseup:", pos.x, pos.y); + if (interactor) interactor.onInteractionEnd(this); + }.bind(this); + + canvas.addEventListener('mousedown', this.onMouseDown, false); + canvas.addEventListener('mousemove', this.onMouseMove, false); + canvas.addEventListener('mouseup', this.onMouseUp, false); }; @@ -18,6 +50,3 @@ function getMousePosition(canvas, evt) { y: evt.clientY - rect.top }; }; - - - diff --git a/main.js b/main.js index c3fbf34..2f391c7 100644 --- a/main.js +++ b/main.js @@ -2,25 +2,9 @@ var canvas = document.getElementById('myCanvas'); var ctx = canvas.getContext('2d'); -canvas.width=800 -canvas.height=600 - -// Code temporaire pour tester le DnD -new DnD(canvas); -ctx.fillStyle = '#F0F0F0'; // set canvas' background color -ctx.fillRect(0, 0, canvas.width, canvas.height); // now fill the canvas -///// - -// Code temporaire pour tester l'affiche de la vue -//var rec = new Rectangle(10, 20, 50, 100, 5, '#00CCC0'); -//rec.paint(ctx); -//var ligne = new Rectangle(10, 20, 50, 100, 5, '#00CCC0'); -//ligne.paint(ctx); -// tester également Dessin. -//// - -// Code final à utiliser pour manipuler Pencil. -//var drawing = new Drawing(); -//var pencil = new Pencil(ctx, drawing, canvas); -//drawing.paint(ctx, canvas); +canvas.width = 800; +canvas.height = 600; +var drawing = new Drawing(); +var pencil = new Pencil(ctx, drawing, canvas); +drawing.paint(ctx, canvas); diff --git a/model.js b/model.js index cd7fb5f..b7f0811 100644 --- a/model.js +++ b/model.js @@ -1,3 +1,54 @@ -// Implémenter ici les 4 classes du modèle. -// N'oubliez pas l'héritage ! +// Classe de base : Shape +function Shape(lineWidth, colour) { + this.lineWidth = lineWidth; + this.colour = colour; +} + +// Classe Rectangle +function Rectangle(initX, initY, width, height, lineWidth, colour) { + Shape.call(this, lineWidth, colour); + this.initX = initX; + this.initY = initY; + this.width = width; + this.height = height; +} +Rectangle.prototype = new Shape(); + +Rectangle.prototype.getInitX = function() { return this.initX; }; +Rectangle.prototype.getInitY = function() { return this.initY; }; +Rectangle.prototype.getWidth = function() { return this.width; }; +Rectangle.prototype.getHeight = function() { return this.height; }; +Rectangle.prototype.setWidth = function(w) { this.width = w; }; +Rectangle.prototype.setHeight = function(h) { this.height = h; }; + +// Classe Line +function Line(x1, y1, x2, y2, lineWidth, colour) { + Shape.call(this, lineWidth, colour); + this.x1 = x1; + this.y1 = y1; + this.x2 = x2; + this.y2 = y2; +} +Line.prototype = new Shape(); + +Line.prototype.getX1 = function() { return this.x1; }; +Line.prototype.getY1 = function() { return this.y1; }; +Line.prototype.getX2 = function() { return this.x2; }; +Line.prototype.getY2 = function() { return this.y2; }; +Line.prototype.setX2 = function(x) { this.x2 = x; }; +Line.prototype.setY2 = function(y) { this.y2 = y; }; + +// Classe Drawing +function Drawing() { + this.forms = new Array(); +} + +Drawing.prototype.getForms = function() { return this.forms; }; + +Drawing.prototype.addForm = function(form) { this.forms.push(form); }; + +Drawing.prototype.removeForm = function(form) { + var idx = this.forms.indexOf(form); + if (idx > -1) this.forms.splice(idx, 1); +}; diff --git a/view.js b/view.js index 5d00c9e..6dbcc19 100644 --- a/view.js +++ b/view.js @@ -1,2 +1,30 @@ -// Implémenter ici les fonctions paint à ajouter dans chacune des classes du modèle. +// Fonctions paint ajoutées aux classes du modèle. + +Shape.prototype.paint = function(ctx) { + ctx.strokeStyle = this.colour; + ctx.lineWidth = this.lineWidth; +}; + +Rectangle.prototype.paint = function(ctx) { + Shape.prototype.paint.call(this, ctx); + ctx.beginPath(); + ctx.rect(this.getInitX(), this.getInitY(), this.getWidth(), this.getHeight()); + ctx.stroke(); +}; + +Line.prototype.paint = function(ctx) { + Shape.prototype.paint.call(this, ctx); + ctx.beginPath(); + ctx.moveTo(this.getX1(), this.getY1()); + ctx.lineTo(this.getX2(), this.getY2()); + ctx.stroke(); +}; + +Drawing.prototype.paint = function(ctx, canvas) { + ctx.fillStyle = '#F0F0F0'; + ctx.fillRect(0, 0, canvas.width, canvas.height); + this.getForms().forEach(function(shape) { + shape.paint(ctx); + }); +}; From 607339c91dd523a1fd64832b5c2ea69e78e0f887 Mon Sep 17 00:00:00 2001 From: "fabien.le-houedec" Date: Tue, 24 Mar 2026 13:16:42 +0100 Subject: [PATCH 2/2] add git ignore --- .gitignore | 1 + .idea/.gitignore | 8 -------- .idea/misc.xml | 6 ------ .idea/modules.xml | 8 -------- .idea/tpWeb.iml | 9 --------- .idea/vcs.xml | 6 ------ 6 files changed, 1 insertion(+), 37 deletions(-) create mode 100644 .gitignore delete mode 100644 .idea/.gitignore delete mode 100644 .idea/misc.xml delete mode 100644 .idea/modules.xml delete mode 100644 .idea/tpWeb.iml delete mode 100644 .idea/vcs.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c8935 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +.idea/ \ No newline at end of file diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 9a897b6..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Ignored default folder with query files -/queries/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/misc.xml b/.idea/misc.xml deleted file mode 100644 index 7e43925..0000000 --- a/.idea/misc.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 1fd8606..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/tpWeb.iml b/.idea/tpWeb.iml deleted file mode 100644 index d6ebd48..0000000 --- a/.idea/tpWeb.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file