{"id":17691678,"url":"https://github.com/b2renger/introduction_p5js","last_synced_at":"2025-05-12T13:30:42.545Z","repository":{"id":149682882,"uuid":"73009548","full_name":"b2renger/Introduction_p5js","owner":"b2renger","description":"This is a french introduction to p5*js","archived":false,"fork":false,"pushed_at":"2020-06-18T09:24:10.000Z","size":23522,"stargazers_count":38,"open_issues_count":5,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-03-15T06:14:51.191Z","etag":null,"topics":["creative-coding","css","html","javascript","p5js","socket-io","webaudio","webgl"],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/b2renger.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-11-06T18:14:11.000Z","updated_at":"2025-03-05T11:04:49.000Z","dependencies_parsed_at":null,"dependency_job_id":"2635fdb8-4984-4632-949e-c7a555205405","html_url":"https://github.com/b2renger/Introduction_p5js","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b2renger%2FIntroduction_p5js","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b2renger%2FIntroduction_p5js/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b2renger%2FIntroduction_p5js/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/b2renger%2FIntroduction_p5js/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/b2renger","download_url":"https://codeload.github.com/b2renger/Introduction_p5js/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246553021,"owners_count":20795834,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["creative-coding","css","html","javascript","p5js","socket-io","webaudio","webgl"],"created_at":"2024-10-24T12:09:37.902Z","updated_at":"2025-04-01T08:31:30.902Z","avatar_url":"https://github.com/b2renger.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Introduction_p5js\n\nThis is a french introduction to [p5*js](http://p5js.org)\n\nP5js est un projet issu de [processing](https://processing.org/) qui est un langage de programmation basé sur java orienté vers la création graphique et interactive. P5js a pour but de transposer l'esprit de processing au web et donc au langage javascript. C'est un framework simple d'accès pour les débutants avec une bonne documentation et une communauté active. \n\nSi jamais vous ne connaissez ni processing, ni p5js, il peut-être intéressant de jeter un oeil à la vidéo d'introduction de [Hello Processing](https://hello.processing.org/) qui vous donnera un aperçu assez complet de ce qu'il est possibble de faire avec ce genre d'outils.\n\nP5js propose l'intégration dans un canvas html5 d'un maximum de fonction pour le dessin et d'animation, des possibilités d'interaction à travers différentes interfaces homme machine (clavier, souris, webcam, micro ...), ou encore avec les composants d'une page web et un support partiel mais en développement de webgl.\n\nDe nombreuses bibliothèques viennent offrir de nouvelles possibilité, mais il p5js peut naturellement s'interfacer avec n'importe quelle bibliothèques js.\n\nP5js est différent de processing.js par le fait que le langage de base est le js. Lorsqu'on utilise processing.js on a générallement développé un programme avec processing et on utilise processing.js pour traduire le programme en javascript qui devient alors exécutable dans une page web. Avec p5js on code directement en javascript un langage natif pour les navigateurs.\n\nCette introduction va couvrir l'essentiel du workflow avec p5js, présenter les différentes fonctions de dessin et la base de la programmation en js (conditions, boucles for, variables, fonctions, utilisation de tableaux et prototypage d'objets javascript et à la toute fin des exemples couvrant les bases de la 3D avec webgl et de l'audio avec la web audio api = waa).\n\nVous pourrez retrouver l'intégralité du code détaillé ici sur le dépôt [github](https://github.com/b2renger/Introduction_p5js).\n\nNote cette introduction a été écrite avec ces versions de p5js :\n- p5.js v0.5.7 February 08, 2017\n- p5.dom.js v0.3.1 Jan 3, 2017\n- p5.sound.js v0.3.2 2016-11-01\n\nDepuis p5js intègre directement la bibliothèque \"dom\", qui permet d'interagir avec les éléments html classiques d'une page web. Cela ne derait pas avoir d'incidence en terme de code. N'hésitez cependant pas à créer une \"issue\" si jamais vous rencontrez un soucis avec cela.\n\n\n## Contenu\n\n* [Comment travailler avec p5js](#Comment-travailler-avec-p5js)\u003cbr\u003e\n  * [Openprocessing](#Openprocessing)\n  * [Editor en ligne](#Editor)\n  * [Ajout du mode p5js dans processing](#Ajout-du-mode-p5js-dans-processing)\n  * [Developpeur web](#Developpeur-web)\n  * [Installation et configuration de Visual Studio Code ](#Installation-et-configuration-de-Visual-Studio-Code )\n  * [Des bibliotheques pour ajouter de nouvelles fonctions](#Des-bibliotheques-pour-ajouter-de-nouvelles-fonctions)\n\n* [Les principes de base](#Les-principes-de-base)\u003cbr\u003e\n  * [HTML et JS](#HTML-et-JS)\n  * [p5js](#p5js)\n\n* [Dessiner avec la souris](#Dessiner-avec-la-souris)\u003cbr\u003e\n\t*\t[Les couleurs et la transparence](#Les-couleurs-et-la-transparence)\u003cbr\u003e\n\t*\t[Utilisation de variables](#Utilisation-de-variables---simuler-un-pinceau) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/01_dessiner_01/index.html)\u003cbr\u003e\n\t*\t[Construire des symetriques](#Construire-des-symetries) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/01_dessiner_02/index.html)\u003cbr\u003e\n\t*\t[Creer des fonctions javascript](#Fonctions)\u003cbr\u003e\n\t*\t[Utiliser les transformations de l'espace : effet spirographe](#Transformation-du-repere---effet-spirographe) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/01_dessiner_04/index.html)\u003cbr\u003e\n\t*\t[Conditions, boucles et coordonnées polaires : effet \"spray-can\"](#Conditions-et-coordonnees-polaires) - [**DEMO 1**](https://b2renger.github.io/Introduction_p5js/01_dessiner_05/index.html) - [**DEMO 2**](https://b2renger.github.io/Introduction_p5js/01_dessiner_06/index.html)\u003cbr\u003e\n\t\t*\t[Conditions : \"if\"](#Conditions-if())\u003cbr\u003e\n\t\t*\t[Coordonnées polaires](#Coordonnees-polaires)\u003cbr\u003e\n\t\t*\t[Boucles : \"for\"](#Boucles-for())\u003cbr\u003e \n\n* [DOM](#dom)\u003cbr\u003e\n\t*\t[Installation de p5.dom.js](#Installation-de-p5.dom.js) - [**DEMO 1**](https://b2renger.github.io/Introduction_p5js/02_dom_01/index.html) - [**DEMO 2**](https://b2renger.github.io/Introduction_p5js/02_dom_02/index.html)\u003cbr\u003e\n\t\t*\t[Modifier et ajouter des objets html5 avec du code javascript](#Modifier-et-ajouter-des-objets-html5-avec-du-code-javascript)\u003cbr\u003e\n\t\t*\t[Styliser avec du css](#Styliser-avec-du-css)\u003cbr\u003e\n\t*\t[Utilisation de video](#Video) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/02_dom_03/index.html)\u003cbr\u003e\n\t*\t[Manipulation dun flux vidéo](#Transformations-de-video) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/02_dom_04/index.html)\u003cbr\u003e\n\t*\t[Mode instance de p5js](#Mode-instance) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/02_dom_05/index.html)\u003cbr\u003e\n\t*\t[Exemple de site web](#Exemple-de-site-web)\u003cbr\u003e\n\n* [Websocket](#Websocket-et-SocketIO) - [**DEMO1**](https://www.openprocessing.org/sketch/390650) - [**DEMO2**](https://www.openprocessing.org/sketch/390497)\u003cbr\u003e\n\t* [Utilisation de la bibliothèque Socket IO](#SocketIO)\u003cbr\u003e\n\t* [Format JSON soit JavaScript Object Notation](#Format-JSON-soit-JavaScript-Object-Notation)\u003cbr\u003e\n\t* [Envoyer et Recevoir des informations](#Envoyer-et-Recevoir-des-informations)\u003cbr\u003e\n\t* [NodeJs et serveur local](#Node-et-serveur-local)\u003cbr\u003e\n\n* [Quicksettings.js et les fonctions callback](#Quicksettings.js-et-les-fonctions-callback)  - [**DEMO**](https://b2renger.github.io/Introduction_p5js/99_quicksettings/index.html)\u003cbr\u003e\n\n* [Animer un mouvement](#Animer-un-mouvement)\u003cbr\u003e\n  * [Balle rebondissant contre les parois](#Balle-dans-une-boite) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/04_animation_01/index.html)\u003cbr\u003e\n  * [Suivre la souris](#Suivre-la-souris) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/04_animation_02/index.html) - [**DEMO2**](https://b2renger.github.io/Introduction_p5js/04_animation_02_penner_position/index.html)\u003cbr\u003e\n  * [Suivre la souris avec des forces](#Suivre-la-souris-avec-des-forces) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/04_animation_03/index.html)\u003cbr\u003e\n  * [Croissance de tentacules](#Croissance-de-tentacules) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/04_animation_04/index.html)\u003cbr\u003e\n* [Objets en js](#Objets-en-js)\u003cbr\u003e\n    * [Objets et instances](#Objets-et-instances) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/05_objets_01/index.html)\u003cbr\u003e\n    * [Des tableaux remplis avec des objets\n](#Des-tableaux-remplis-avec-des-objets) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/05_objets_02/index.html)\u003cbr\u003e\n    * [Pour aller un peu plus loin](#Pour-aller-un-peu-plus-loin) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/05_objets_03/index.html)\u003cbr\u003e\n* [Webgl pour la 3D](#Webgl-pour-la-3D)\u003cbr\u003e\n    * [Caméra, lumière, la bibliothèque Quicksettings.js](#Webgl-pour-la-3D) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/06_webgl_01/index.html)\u003cbr\u003e\n    * [Algorithme de \"dla\", appliquer des textures](#Webgl-pour-la-3D) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/06_webgl_02/index.html)\u003cbr\u003e\n    * [Tentacules revisitées en 3D](#Webgl-pour-la-3D) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/06_webgl_03/index.html)\u003cbr\u003e\n    * [Génération d'arbres](#Webgl-pour-la-3D) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/06_webgl_04/index.html)\u003cbr\u003e\n    * [Algorithme de \"flocking\"](#Webgl-pour-la-3D) - [**DEMO**](https://b2renger.github.io/Introduction_p5js/06_webgl_05/index.html)\u003cbr\u003e \n* [Audio et p5.sound](#Audio-et-p5.sound)\u003cbr\u003e\n    * [Utiliser des soundfonts, pour une palette sonore variée](#Audio-et-p5.sound) -- [**DEMO**](https://b2renger.github.io/Introduction_p5js/07_audio_01_soundfont/index.html)\u003cbr\u003e\n    * [Jouer des fichier audio, utiliser des effets et construire un séquenceur](#Audio-et-p5.sound) -- [**DEMO**](https://b2renger.github.io/Introduction_p5js/07_audio_02_stepsequencer/index.html)\u003cbr\u003e\n    * [Lecture de fichier audio avancée : sampler granulaire](#Audio-et-p5.sound) -- [**DEMO**](https://b2renger.github.io/Introduction_p5js/07_audio_03_granular/index.html)\u003cbr\u003e\n    * [Synthèse FM monophonique](#Audio-et-p5.sound) -- [**DEMO**](https://b2renger.github.io/Introduction_p5js/07_audio_04_synthese_simple/index.html)\u003cbr\u003e\n    * [Synthèse additive polyphonique](#Audio-et-p5.sound) -- [**DEMO**](https://b2renger.github.io/Introduction_p5js/07_audio_05_synthese_avancee/index.html)\u003cbr\u003e\n    * [Visualisation audio](#Audio-et-p5.sound) -- [**DEMO**](https://b2renger.github.io/Introduction_p5js/07_audio_06_audioviz/index.html)\u003cbr\u003e\n* [Ressources](#ressources)\u003cbr\u003e\n* [Références](#references)\u003cbr\u003e\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n## Comment travailler avec p5js\n\nVous avez plusieurs possibilités : des éditeurs en ligne (si vous souhaitez que votre programme soit directement en ligne sans avoir à la publier sur un site web), un mode pour l'IDE processing (qui permet de continuer à travailler dans un environnement que vous connaissez bien si vous utilisez déjà processing), ou encore l'usage des bibliothèques js directement - comme le feront les usagers ayant déjà des connaissances en html/CSS. \n\nNous allons privilégier cette dernière solution, mais par soucis d'exhaustivité les différentes options sont quand même présentées.\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n\n### openprocessing\n\nOpenprocessing est une plateforme collaborative qui permet de coder avec p5js ou processing.js. Il suffit de créer un compte gratuit et de cliquer sur 'create a new sketch' et c'est partit ! Openprocessing permet d'uploader des images, des vidéos ou des sons et supporte plusieurs bibliothèques y compris un bibliothèque websocket qui permet à plusieurs utilisateur d'interagir à distance dans un même canvas.\n\n[Openprocessing](http://openprocessing.org)\n\nLa plupart des exemples de ce cours seront probablement porté sur openprocessing à une date indéfinie. Mais vous pouvez copier l'intégralité du fichier \"sketch.js\" de n'importe quel dossier dans l'éditeur de code d'openprocessing, puis de cliquer sur \"run\".\n\nIl est aussi possible d'intégrer des bibliothèques javascript externes voici un exemple pour faire cela : https://www.openprocessing.org/sketch/385808\n\nOpenprocessing est pratique car il permet de se passer de serveur local et permet de créer des portofolio d'applications interactives très facilement. Actuellement openprocessing connait malheureusement quelques soucis, l'intégration de la bibliothèque DOM pose parfois problème, et le serveur websocket plante régulièrement (mais le nouveau site est récent, ces problèmes se dissiperont avec le temps)\n\n![Openprocessing](assets/openprocessing.png)\n![Openprocessing](assets/openprocessing-2.png)\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Editor\n\nIl existe un éditeur en ligne officiel dédié à P5js :\n\nhttps://editor.p5js.org/\n\n![mode p5js](assets/online-editor.png)\n\n\nVous pouvez créer un compte et vos sketchs seront sauvegardés en ligne.\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Ajout du mode p5js dans processing\n\nVous pouvez travailler avec p5js directement dans l'éditeur classique de processing.\n\nAfin d'ajouter le mode javascript à processing, il suffit de cliquer sur le petit menu déroulant en haut à droite de votre éditeur; celui-ci indique très probablement 'java' : si vous cliquez dessus vous pourrez cliquer sur 'ajouter un mode' \n![mode p5js](assets/ajout-mode-scroll.png)\n\net voire cette fenêtre apparaitre :\n![mode p5js](assets/ajout-mode.png)\n\nVous pouvez donc maintenant cliquer sur 'p5js mode' et sur 'install'.\n\nNous pouvons maintenant taper du code javascript dans l'éditeur de processing et l'éxecuter en cliquant sur le bouton 'play'. La différence principale est qu'au lieu de créer une fenêtre d'application notre programme va s'éxecuter dans un nouvel onglet de notre navigateur web !\n\nProcessing lance alors un serveur web local qui va nous permettre d'accéder à notre page comme-ci celle ci était en ligne (cela est utile particulièrement lorsqu'on ajoute des medias à notre page web : son, images etc. - en effet pour des raisons de sécurité évidentes un navigateur n'a pas les autorisations nécessaires pour aller chercher automatiquement des fichiers sur notre disque dur).    \n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Developpeur web\n\nLe plus simple est probablement de [télécharger](http://p5js.org/download/) et d'ajouter la bibliothèque js ou d'utiliser les liens cdn dans votre fichier index.html.\n\nPour rappel CDN signifie Content Delivery Network et permet de lier son code à des bibliothèques qui sont déjà hébergées en ligne.\n\nGénéralement un bon éditeur de texte suffit. Parfois il pourra être utile d'utiliser un serveur local pour servir certaines pages demandant accès à des fonctions ou fichiers spécifiques (généralement des pages utilisant des images ou des sons sous formes de fichier doivent être ouvertes avec un serveur local). Il y a des nombreuses possibilités pour cela et beaucoup de documentation en ligne : personnellement j'utilise 'sinatra' un serveur en ruby, simplehttpserver pour python peut-être une alternative, ou d'autres encore via nodejs voire même des logiciels comme mamp.\n\nUne solution intéressante peut-être Brackets : http://brackets.io/, ou visual studio code : https://code.visualstudio.com/\nCes éditeurs de texte sont faits pour le développement web, ils disposent d'une bonne ergonomie, ils permettent d'ouvrir des dossiers entiers et de naviguer à l'intérieur tout en éditant des fichiers, ils disposent d'extensions communautaires utiles (serveur web, intégration git, beautify etc.)\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Installation et configuration de Visual Studio Code \n\nVous pourrez trouver VSCode à cette adresse : https://code.visualstudio.com/\nAprès l'avoir installé et démarré vous pourrez remarquer la barre de gauche un petit icone permettant d'installer des extensions :\n\n![extension icon](assets/VSCode_extensions.png)\n\nJe vous conseille d'installer :\n- **Live Server de Ritwick Dey** (cette extension va nous permettre de servir des pages web et sera donc utile dès que nos pages auront besoin à des images ou sons stockés sur notre disque dur)\n- **p5js Snippets** (cette extension permet de fournir une forme d'autocompletion pour p5js ce qui permet d'être aidé sur la syntaxe notament)\n\nd'autres extensions qui pourraient vous être utiles :\n- **Beautify par HookyQR** (permet de ré-organiser le code selon les conventions)\n- **Markdown Preview Gihtub** par Matt Bierner (permet de visualiser localement les fichiers écrits en markdown, comme ce cours!)\n\nUne fois cela fait je vous propose d'ajouter ce cours à notre workspace de travail : \n\n- pour cela il va d'abord vous falloir télécharger  l'ensemble des fichiers depuis github, en cliquant sur le bouton vert *Clone or download* puis en cliquant sur *Download as zip*.  : https://github.com/b2renger/Introduction_p5js\n\n![github download](assets/github_download.png)\n\n- Il vous faudra dézipper le fichier, puis dans VSCode cliquer sur *File* puis *Add folder to workspace*.\n\nUne fois cela fait, vous aurez un nouveau dossier qui contient l'ensemble des exemples ainsi que ce fichier. Chaque exemple est dans un dossier qui lui est propre. Il y a un dossier *libraries* qui contient la bibliothèque *p5js* et quelques autres bibliothèques, un dossier *assets* qui contient les différentes captures d'écran utilisées dans ce fichier, et enfin le fichier *readme.md* qui contient le texte de ce cours.\n\nVisual studio devrait alors ressembler à cela :\n\n![vscode](assets/VSCode.png)\n\nSi vous souhaitez éxecuter les programmes d'exemple sur votre ordinateur il vous suffit de cliquer sur le bouton *Go Live* en bas à droite de l'interface.\n\n![vscode go live](assets/VSCode_golive.png)\n\nCela aura pour effet d'ouvrir un nouvel onglet dans votre navigateur par défaut ressembblant à ceci :\n\n![vscode liveserver](assets/VSCode_liveserver.png)\n\nVous pouvez alors cliquer sur le nom de l'exemple qui vous intéresse et celui s'éxecutera dans cet onglet.\n\nSi vous souhaitez voir ce fichier vous pouvez depuis VSCode ouvrir ce fichier en double cliquant sur son nom. Puis dans la barre d'onglet, en haut à droite cliquer sur cet icône :\n\n![vscode md](assets/VSCode_mdpreview.png)\n\nCela ouvrira dans un nouvel onglet le fichier mis en forme avec les règles établies par le format [Markdown](https://fr.wikipedia.org/wiki/Markdown).\n\nUne dernière chose ... souvenez vous bien du racourcis *Option* + *Shift* + *F* qui vous permettra de reformatter votre code.\n\nVous pouvez bien sûr ajouter d'autres dossier à votre workspace.\n\nJe vous conseille de créer un dossier de travail dans lequel vous pourrez vous exercer à ré-écrire et modifier les exemples fournis ici. N'oubliez pas de copier dans ce nouveau dossier le dossier *libraries* et je vous conseille aussi de copier le dossier *00_empty_example*. Ce dernier est une structure de dossier avec un fichier *index.html* pointant vers les bibliothèques nécessaires et un fichier *sketch.js* prêt à être utilisé dans le cadre de l'utilisation de p5js. Cela sera décrit plus en détail un peu plus bas.\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Des bibliotheques pour ajouter de nouvelles fonctions\n\nP5js recense un bon nombre de bibliothèques compatibles et revendiquant le même esprit : http://p5js.org/libraries/\nMais il peut aussi être utilisé avec n'importe quelles autres bibliothèques js. Comme vous pourrez le voir dès les premiers exemples de la partie consacrée à webgl puisque nous utiliserons la la bibliothèques [quicksettings.js](https://github.com/bit101/quicksettings)\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n## Les principes de base\n\nUn programme p5js est destiné à être utilisé dans une page web. Généralement en dispose d'un fichier *index.html* qui nous permet de définir notre page web et les fichiers ressources (liens vers les bibliothèques) et d'un fichier *sketch.js* qui va être notre programme écrit en javascript.\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### HTML et JS\n\nLe fichier *sketch.js* est lié au fichier *index.html* par une déclaration écrite dans ce dernier.\n\n```HTML\n\u003cscript language=\"javascript\" type=\"text/javascript\" src=\"sketch.js\"\u003e\u003c/script\u003e\n\n```\nLorsqu'on ouvre le fichier *index.html* celui-ci executera alors le fichier *sketch.js* dans la page web.\n\nDans le cas de nos exemples nous trouverons les bibliothèques javascripts dans un dossier **/bibliothèques** dédié : on y trouve *p5.js*, *p5.dom.js*, *p5.sound.js*.\n\nLe fichier *index.html* ressemblera donc à ceci si on utilise toutes les bibliothèques et que celles-ci sont placées dans un dossier 'libraries' :\n\n```HTML\n\u003chtml\u003e\n\u003chead\u003e\n  \u003cmeta charset=\"UTF-8\"\u003e\n  \u003cscript language=\"javascript\" type=\"text/javascript\" src=\"../libraries/p5.js\"\u003e\u003c/script\u003e\n  \u003cscript language=\"javascript\" type=\"text/javascript\" src=\"../libraries/p5.dom.js\"\u003e\u003c/script\u003e\n  \u003cscript language=\"javascript\" type=\"text/javascript\" src=\"../libraries/p5.sound.js\"\u003e\u003c/script\u003e\n  \u003cscript language=\"javascript\" type=\"text/javascript\" src=\"sketch.js\"\u003e\u003c/script\u003e\n  \u003cstyle\u003e body {padding: 0; margin: 0;} \u003c/style\u003e\n\u003c/head\u003e\n\u003cbody\u003e\n\u003c/body\u003e\n\u003c/html\u003e\n```\n\nCette définition de *index.html* correspond donc à cette organisation de dossier sur votre disque dur :\n\n![structure](assets/structure_dossier_1.png)\n![structure](assets/structure_dossier_2.png)\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### p5js\n\nNotre fichier *sketch.js* est notre code écrit en javascript. Par défaut : il contient deux fonctions nécessaires à l'éxecution des fonctions de l'api p5js (Application Programming Interface)\n\n```javascript\n\nfunction setup() {\n\n}\n\nfunction draw() {\n  \n}\n\n```\n\nLa fonction **setup()** est executée une fois à chaque chargement de la page, elle est utile pour initialiser des valeurs ou créer des éléments de page web - comme un canvas pour dessiner :\n\n```javascript\nfunction setup() {\n    // créer un objet de type HTML5 canvas aux dimensions de la fenêtre de notre navigateur\n\tcreateCanvas(windowWidth,windowHeight) \n}\n```\n\n**windowWidth** et **windowHeight** sont des **variables** disponnible dans processing pour renseigner le programme sur la taille de la fenêtre du navigateur de l'utilisateur.\n\nUne **variable** est quant à elle un espace mémoire dans le navigateur accessible par notre programme. En javascript nous devrons créer et manipuler des variables régulièrement, mais p5js dispose de certaines variables déjà nommées pour connaitre l'état du navigateur ou la position de la souris ou même encore les touches pressées par l'utilisateur.\n\nLa fonction **draw()** est elle une boucle infinie : le code entre les deux accolades est éxecuté en boucle par votre navigateur aussi vite que possible. Cela tranche avec le principe évenementiel du javascript, mais ici nous allons faire des applications interactives avec de l'animation.\n\nVous pourrez trouver la référence du langage p5js à cette adresse : http://p5js.org/reference/\n\nUne autre chose qui peut-être importante est la notion de réactivité à la fenêtre dans laquelle on dessine. Par exemple un utilisateur pourrait vouloir redimensionner la fenêtre de son navigateur pendant l'éxectution de votre page web. Pour cela il existe une fonction qui va permettre de redimensionner le canvas dans lequel on dessine à la nouvelle taille de la fenêtre du navigateur.\n\n```javascript\nfunction windowResized() {\n    // redimensionner dynamiquement notre canvas aux dimensions de la fenêtre de notre navigateur\n\tresizeCanvas(windowWidth,windowHeight) \n}\n```\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n## Dessiner avec la souris\n\nLe premier code sur lequel nous allons travailler est un programme de dessin. Lorsque vous créez un nouveau 'sketch' sur openprocessing vous vous retrouvez avec ce code sous les yeux :\n\n```javascript\n// initialisation du programme\nfunction setup() {\n  // création d'un canvas à la taille de la fenêtre du navigateur\n  createCanvas(windowWidth, windowHeight); \n  // création d'un fond gris\n  background(100);  \n  \n} \n\n// boucle d'execution de notre application\nfunction draw() {\n  // dessiner un rond à l'endroit de la souris\n  ellipse(mouseX, mouseY, 20, 20);\n}\n```\n\nChaque execution d'une boucle draw dessine un cercle de 20 pixels au coordonnées de la souris. Il faut noter que le repère de coordonnées dans p5js par défaut place l'origine, c'est à dire le point de coordonées (0,0) en haut à gauche. Les abscisses sont croissantes lorsqu'on se déplace vers la droite et les ordonnées croissantes lorsqu'on se déplace vers le bas.\n\nVous pouvez expérimenter avec ce programme pour vous en rendre compte : \n\n- https://www.openprocessing.org/sketch/388459\n\n**ellipse** est un mot clé permettant de dessiner une ellipse d'une taille précise à une endroit précis en lui passant des **paramètres**, ce sont les valeurs que l'on donne entre parenthèses :\n\n* les deux premier paramètres sont les coordonnées de l'endroit où dessiner l'ellipse\n* les deux suivant sont la largeur et la hauteur de l'ellipse.\n\n**mouseX** et **mouseY** sont des variables globales définies par processing et donnent la position de la souris au moment du calcul de l'image en les utilisant comme les deux premiers paramètres pour le dessin de notre ellipse on change la position de dessin et on dessine à l'emplacement de la souris.\n\nLa page de référence concernant l'ellipse nous renseigne sur tout cela : http://p5js.org/reference/#/p5/ellipse\n\nIl est possible de dessiner bien d'autres formes ou **primitives** en 2d ou en 3d. Il est aussi possible de composer des formes complexes à l'aide de courbes de béziers ou de vertex.\n\nVoici la page de référence sur les formes : http://p5js.org/reference/#group-Shape\n\nDans ce programme le fond n'est jamais rafraichit et donc les cercles sont dessinés les uns après les autres sur un fond gris. Si vous rajoutez la commande \n\n```javascript\nbackground(100)\n```\n\nà ce moment là : à chaque image le fond sera remplacé par un fond gris avant dessiner notre ellipse. Le résultat sera alors un rond qui suivra la position de la souris.\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Les couleurs et la transparence\n \nPour coloriser nos dessins il est possible d'utiliser les fonctions **stroke()** ou **noStroke()** et **fill()** ou **noFill()**.\n\n\"stroke\" signifie contour et permet donc de préciser la couleur du trait, et \"fill\" signifie remplissage et permet donc de préciser la couleur de remplissage de la forme. A partir du moment ou sont fonctions sont appelées, elles s'appliquent à tous les dessins qui suivent.\n\nCe programme vous permettra d'illustrer l'utilisation de ces fonctions : https://www.openprocessing.org/sketch/181425\n\nLe comportement de ces fonctions est particulièrement modulaire comme le présente la page de doc : http://p5js.org/reference/#/p5/fill\n\nPour résumer:\n\n* si vous n'utilisez qu'un paramètre vous êtes en niveau de gris : 0 = noir / 255 = blanc\n* si vous utilisez trois paramètres vous êtes en rgb : chaque paramètre étant compris entre 0 et 255 =\u003e fill(255,0,0) donnera du rouge\n* si vous utilisez quatre paramètres vous ajoutez un cannal alpha pour gérer la transparence : 0 étant transparent et 255 opaque\n* vous pouvez aussi utiliser du code hexa-décimal pour rentrer des couleurs\n* il est possible de passer du mode rgb au mode hsb grace à la fonction **colorMode()**\n\nVoici le programme précédent avec de nouvelles couleurs :\n\n```javascript\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(180,100,0);  \n  \n} \n\nfunction draw() {\n  // cercle à la position de la souris\n  fill(255,0,0,50)\n  noStroke()\n  ellipse(mouseX, mouseY, speed, speed);\n }\n ```\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Utilisation de variables - simuler un pinceau\n\nNous allons vouloir maintenant compléxifier notre programme. La première chose que nous allons faire est de rendre le dessin un peu plus sensible. L'idée serait de faire en sorte que lorsque notre geste est rapide les cercles soit gros et qu'ils soient petit quand notre geste est lent (une sorte de pinceau inversé).\n\nPour cela nous allons essayer de calculer une valeure qui soit proportionelle à la vitesse de déplacement de notre souris. P5js dispose de deux variable dédiées pour connaitre aussi la position de la souris à l'image précédente : elles s'appellent **pmouseX** et **pmouseY**. A partir de la nous pouvons calculer la moyenne du déplacement en abscisses et en ordonnées entre deux images.\n\nNous allons donc créer une variable javascript que nous allons appeler *speed* pour stocker cette valeur :\n\n```javascript\nvar speed=(abs(pmouseX-mouseX)+abs(pmouseY-mouseY))/2\n\n```\npuis utiliser cette valeur comme paramètre de la taille de nos ellipses :\n\n```javascript\nellipse(mouseX, mouseY, speed, speed)\n\n```\n\nNous pouvons aussi calculer une vraie valeur physique en calculant la magnitude du vecteur directeur du mouvement entre deux images ! Il s'agit simplement d'appliquer le théorème de Pythagore :\n\n```javascript\nvar speed=pow(pow(pmouseX-mouseX,2)+pow(pmouseY-mouseY,2),0.5)\n```\n\nNous obtenons alors notre premier exemple disponnible dans le dossier */01_dessiner_01*\n\n```javascript\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(180,100,0);  \n  \n} \n\nfunction draw() {\n  \n  var speed=(abs(pmouseX-mouseX)+abs(pmouseY-mouseY))/2\n\n  fill(255,0,0,50)\n  noStroke()\n  ellipse(mouseX, mouseY, speed, speed);\n}\n```\n\n![01_dessiner_01](assets/01_dessiner_01.png)\n\nhttps://www.openprocessing.org/sketch/388464\n\nhttps://b2renger.github.io/Introduction_p5js/01_dessiner_01/index.html\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Construire des symetries\n\nNous allons maitenant réaliser différentes symétries pour compléxifier le rendu de notre programme de dessin. Dans le cadre de notre reprère processing réaliser une symétrie est relativement simple. \n\nAvec un peu d'astuce on se rend compte qu'une symétrie axiale consiste à faire en sorte que les distance entre deux bords parallèles délimitant un espace de dessin soit la même.\n\nAinsi : \n\n```javascript\n  ellipse(mouseX, mouseY, speed, speed);\n  ellipse(mouseX, windowHeight-mouseY, speed, speed);\n```\npermet de dessiner une ellipse aux coordonnées de la souris et une par symétrie axiale horizontale au centre de notre canvas.\n\n\n```javascript\n  ellipse(mouseX, mouseY, speed, speed);\n  ellipse(windowWidth-mouseX, mouseY, speed, speed);\n```\npermet de dessiner une ellipse aux coordonnées de la souris et une par symétrie axiale verticale au centre de notre canvas.\n\net finalement : \n\n```javascript\n  ellipse(mouseX, mouseY, speed, speed);\n  ellipse(windowWidth-mouseX, windowHeight-mouseY, speed, speed);\n```\npermet de dessiner une symétrie centrale !\n\nNotre programme devient donc :\n\n```javascript\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(180,100,0);  \n  \n} \n\nfunction draw() {\n  \n  // magnitude du vecteur directeur de la souris avec pythagore\n  //var speed=pow(pow(pmouseX-mouseX,2)+pow(pmouseY-mouseY,2),0.5)/2 \n  // ou une expression beaucoup plus simple ... après tout on souhaite juste que la taille des cercles\n  // soit  dépendente de la vitesse à laquelle on bouge la souris \n  var speed=(abs(pmouseX-mouseX)+abs(pmouseY-mouseY))/2\n\n    // cercle à la position de la souris\n  fill(255,0,0,50)\n  noStroke()\n  ellipse(mouseX, mouseY, speed, speed);\n  \n  // symetrie axiale verticale\n  fill(255,0,255,50)\n  ellipse(mouseX, windowHeight-mouseY, speed, speed);\n  \n  // symetrie axiale horizontale\n  fill(0,0,255,50)\n  ellipse(windowWidth-mouseX, mouseY, speed, speed);\n  \n  // symetrie centrale\n  fill(255,255,0,50)\n  ellipse(windowWidth-mouseX, windowHeight-mouseY, speed, speed);\n}\n\n```\n\n![01_dessiner_02](assets/01_dessiner_02.png)\n\nhttps://www.openprocessing.org/sketch/388181\n\nhttps://b2renger.github.io/Introduction_p5js/01_dessiner_02/index.html\n\nPour vous exercer vous pouvez essayer de dessiner des lignes (fonction **line()**)provenant du centre de la fenêtre à la souris, ainsi qu'à ses quatres positions symétriques. Vous pouvez aussi faire varier la taille des traits grace à la fonction **strokeWeight()**. Ce qui vous donnera un résultat similaire à celui-ci\n\n![01_dessiner_03](assets/01_dessiner_03.png)\n\nhttps://www.openprocessing.org/sketch/388511\n\nhttps://b2renger.github.io/Introduction_p5js/01_dessiner_03/index.html\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Fonctions\n\nEn javascript, il est assez facile de définir de nouvelles fonctions : il suffit de créer une variable un peu particulière, une variable qui est en réalité un bout de code js. Par exemple pour créer une fonction permettant de dessiner un carré il suffit d'écrire ceci à la racine de notre fichier sketch.js (c'est à dire en dehors de la fonction draw ou de la fonction setup)\n\n```javascript\nvar draw_square = function(x,y,size){ // on crée la fonction et on définit les paramètres nécessaires\n\trect(x,y,size,size) // code nécessaire au dessin d'un carré en fonction des paramètres\n}\n```\n\nPour utiliser cette fonction, il nous suffit alors cette fois dans le **draw()** de l'appeler avec les paramètres adéquats.\n```javascript\ndraw_square(25,25,50) // dessiner un carré au coordonnées (25,25) dont le côté fait 50 pixels.\n```\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Transformation du repere - effet spirographe\n\nPour l'instant nous avons vu que le repère dans lequel on exprimait les coordonnées dans était fixe. Mais il est possible de le déplacer et de le faire tourner. Cela peu notament être utile pour faire tourner un carré autour de son centre.\n\nPour cela il faut utiliser les fonctions **translate()** et **rotate()**\n\nCet exemple interactif vous permettra probablement de mieux comprendre l'utilisation conjointe des deux fonctions. Il est aussi important de savoir qu'il existe deux fonctions **push()** et **pop()** qui fonctionnent de manière conjointe : **push()** permet de créer un nouveau repère pour le transformer et **pop()** permet de restaurer le repère original de processing. Si jamais vous utilisez push() vous devez utiliser pop() sous réserve d'avoir des erreurs à l'exécution.\n\nNous allons pouvoir maintenant faire tourner un rectangle autour de son centre en modifiant la fonction que nous avions précédement écrite :\n\n```javascript\nvar draw_rect = function(x,y,size,rot){\n  push()\n  rectMode(CENTER) // utiliser le centre du carré comme ancre de dessin\n  translate(x,y) // déplacer le repère\n  rotate(rot) // le faire tourner sur lui même en fonction d'une valeur d'angle\n  rect(0,0,size  ,size)\n  pop()\n }\n``` \n\n**push()** et **pop()** peuvent aussi être imbriqués les uns dans les autres.\n\n```javascript\nvar draw_rect = function(x,y,size,rot){\n  // nouveau repère r1\n  push() \n  rectMode(CENTER)\n  translate(x,y)\n  rotate(rot)\n  rect(0,0,size  ,size)\n\n  // nouveau repère r2 qui bénificie encore des transformation de r1\n  push() \n  translate(-50,-50) // notre rectangle va tourner autour du centre de r1 à une distance calculable par pythagore : d = pow(50*50+50*50,0.5)\n  rotate(PI/2)\n  rect(0,0,size  ,size)\n  pop() // on supprime les transformation de r2\n\n  // et on crée un nouveau repère r3 qui est donc dans l'état de r1\n  push() \n  translate(100,100) // notre rectangle va tourner autour du centre de r1 à une distance calculable par pythagore : d = pow(100*100+100*100,0.5)\n  rotate(rot*3) // et il va tourner sur lui même\n  rect(0,0,size  ,size)\n  pop() // on supprime les transformation de r3\n\n  pop() //on supprime les transformation de r1\n\n  // nous sommes de nouveau dans le repère d'origine\n}\n\n```\n\nLe programme suivant garde se principe, ajoute un niveau de rotation et  ne dessine plus de rectangles mais uniquement des lignes représentant les repères tournants les uns autour des autres :\n\n```javascript\nvar draw_lines = function(x,y,size,rot){\n\n    strokeWeight(0.15)\n  // nouveau repère r1\n  push() \n  rectMode(CENTER)\n  translate(x,y)\n  rotate(rot*0.15)\n  stroke(75)\n  // dessiner une croix\n  line(0,size,0,-size)\n  line(-size,0,size,0)\n\n  // nouveau repère r2 qui bénificie encore des transformation de r1\n  push() \n  rotate(rot)\n  translate(-size,-size) // notre croix va tourner autour du centre de r1 à une distance calculable par pythagore : d = pow(50*50+50*50,0.5)\n  rotate(PI/2)\n  stroke(50)\n  line(0,size,0,-size)\n  line(-size,0,size,0)\n  pop() // on supprime les transformation de r2\n\n  // et on crée un nouveau repère r3 qui est donc dans l'état de r1\n  push() \n  stroke(0)\n  rotate(rot)\n  translate(size*3,size*3) // notre croix va tourner autour du centre de r1 à une distance calculable par pythagore : d = pow(100*100+100*100,0.5)\n  rotate(rot*7  ) // et il va tourner sur lui même\n   // dessiner le repère\n  line(0,size,0,-size)\n  line(-size,0,size,0)\n\n  push() // on pousse un nouveau repère r4 qui bénéficie des transformation conjointe de r1 et r3\n  translate(size*2,size*2) // notre croix va tourner autour du centre de r3 à une distance calculable par pythagore : d = pow(35*35+35*35,0.5)\n  rotate(rot*2 ) // et il va tourner sur lui même\n   // dessiner le repère\n  line(0,size,0,-size)\n  line(-size,0,size,0)\n  pop() // on supprime les transformation de r4\n\n  pop() // on supprime les transformation de r3\n\n  pop() //on supprime les transformation de r1\n\n  // nous sommes de nouveau dans le repère d'origine\n}\n\n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight)\n  background(255)\n  \n} \n\nfunction draw() {\n\n\n  var size = (abs(pmouseX-mouseX) + abs(pmouseY - mouseY)) + 25\n  stroke(0)\n  fill(0,180)\n  draw_lines(mouseX, mouseY, size , frameCount/50)\n\n}\n\n\n\n```\n\n![01_dessiner_04](assets/01_dessiner_04.png)\n\nhttps://www.openprocessing.org/sketch/388514\n\nhttps://b2renger.github.io/Introduction_p5js/01_dessiner_04/index.html\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Conditions et coordonnees polaires\n\nDans cet exemple nous allons simuler l'effet d'un bombe de peinture. Nous allons utiliser : le mode de couleur HSB, une fonction spécifique utilisant des coordonées polaire pour notre dessin, et des conditions **if** pour actionner le dessin uniquement lorsque la souris est clickée et permettre de choisir la teinte en appuyant sur des touches du clavier.\n\n[**home**](#Contenu)\u003cbr\u003e\n\n#### Conditions if()\n\nCommençons par le code déjà connu :\n\n```javascript\nvar hue; // stocker la teinte d'une couleur\n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(0);  \n  hue = 255; // intialisation à bleu\n  colorMode(HSB,360,100,100,100) // appliquer le mode HSB\n} \n\nfunction draw() {\n\n  var size = (abs(pmouseX-mouseX)+abs(pmouseY-mouseY)) + 10 \n  fill(hue,100,100,25)\n  noStroke()\n  \n  if (mouseIsPressed) { // si la souris est clickée on dessine avec la fonction de dessin définie ci-dessous\n    ellipse(mouseX,mouseY,size)\n  }\n }\n ```\nPeu de choses nouvelles ici par rapport aux exemples précédent, si ce n'est l'utilisation de **colorMode()** pour appliquer le mode HSB. Et l'utilisation d'une condition **if(){}** avec la variable globale de p5 **mouseIsPressed** qui renvoit un booléen (vrai ou faux en fonction de si le bouton de la souris est actionné ou non). Le code est assez transparent lui-même : **si** (on appuie sur la souris) alors on éxecute le code entre les accolades **{}**.\n\nA l'intérieur du *draw* nous allons continuer avec l'utilisation des **if** pour permettre à l'utilisateur de choisir une teinte. Pour cela nous allons utiliser la fonction **keyIsDown()** qui permet de savoir si une touche du clavier est pressée ou non.\nNous allons donc pouvoir si une touche est appuyée changer la valeur de la variable *hue* :\n\n```javascript\n if (keyIsDown(LEFT_ARROW)) { // si la flêche de gauche est préssée\n    hue = hue -1  // on modifie la teinte\n    hue = constrain(hue,0,360) // on s'assure de rester dans le cadre des valeurs utilisables\n  }\n  else if (keyIsDown(RIGHT_ARROW)) {\n    hue = hue +1\n    hue = constrain(hue,0,360)\n  }\n```\nIl ne nous reste plus qu'à informer notre utilisateur de son choix de couleur en affichant un petit rectangle coloré en bas à gauche de notre canvas\n\n```\n // dessiner un petit carré représentant la teinte sélectionnée\n  fill(hue,100,100,100)\n  rect(0, windowHeight -25 ,25,25)\n ```\n\n[**home**](#Contenu)\u003cbr\u003e\n\n#### Coordonnees polaires\n\nLes coordonnées polaire vont nous être très utiles ici. Elles permettent d'exprimer les position d'un objet en fonction d'une distance au centre et d'un angle - autrement dit en conservant un rayon constant et en faisant varier l'angle on dessine assez facilement un cercle.\n\nNotre objectif est de remplir un cercle - dont le rayon maximal sera l'épaisseur de notre jet de peinture, de petits cercles de tailles aléatoires à chaque fois que l'on appuie sur la souris.\n\nCommençons par mettre en place une fonction pour créer notre code de dessin ent remplaçant ellipse() par une fonction que nous allons définir après, elle s'appelle **sp()** pour \"spray-paint\" et va prendre trois arguments : les position de la souris en x et y et la taille ou l'épaisseur de notre jet de peinture.\n\nDans le *draw()* nous avons maintenant :\n\n```javascript\n if (mouseIsPressed) { // si la souris est clickée on dessine avec la fonction de dessin définie ci-dessous\n    sp(mouseX,mouseY,size)\n  }\n```\n\net en dessous du *draw()* et donc en dehors de toute accolade nous pouvons créer une fonction vide qui prendra trois arguments :\n\n```javascript\n// fonction permettant de dessiner un ensemble de taches de couleurs dans un rayon défini\n// ce rayon dépendera de la vitesse de la souris\nfunction sp(x,y,size){\n  \n}\n\n```\n\nNous pouvons d'ores et déjà mettre en place nos transformation de l'espace pour avoir un repère centré autour de la position de la souris et nos informations de couleur:\n\n```javascript\n// fonction permettant de dessiner un ensemble de taches de couleurs dans un rayon défini\n// ce rayon dépendera de la vitesse de la souris\nfunction sp(x,y,size){\n  push()\n  noStroke()\n  fill(hue,100,100,30) // on applique la teinte et on garde une transparence importante\n  translate(x,y)\n  // ...\n  // utiliser une boucle for pour dessiner plein de petites ellipse remplissant un plus grand cercle de rayon size.\n  // ...\n  pop()\n}\n\n```\n\nLe commentaire \" utiliser une boucle for pour dessiner plein de petites ellipse remplissant un plus grand cercle de rayon size \" dit bien ce qu'il veut dire. Il va falloir une boucle for qui va nous permettre de répéter un certain nombre de fois la même opération - *même* ou presque puisqu'on pourra utiliser **random()** pour obtenir des paramètre au hasard pour chaque petite ellipse.\n\nIl faut que nous utilisions **random()** pour définir la position en coordonnées polaire de notre ellipse par exemple :\n\n```javascript\n \t// coordonées polaire = rayon + angle\n    var radius = random(size) \n    var angle = random(TWO_PI) // angle donné en radians et non en degrés.\n```\n\nLe problème est que nous ne pouvons pas utiliser cette valeur pour dessiner notre ellipse, puisqu'il nous faut une abscisse et une ordonnée ! Il faut donc convertir ces coordonées polaires en coordonées cartésiennnes, heureusement il existe des formules pour cela\n\n```javascript\n\t// formule de passage de coordonées polaires en coordonnées catésienne\n    var xpos = radius*cos(angle)\n    var ypos = radius*sin(angle)\n    // nous pouvons maintenant dessiner une ellipse avec un rayon aléatoire\n    var r = random(1,5)\n    ellipse(xpos,ypos,r,r)\n```\n\nCe petit programme vous permettra de mieux vous rendre compte de cela et pourra faire office de pense-bête : https://www.openprocessing.org/sketch/151087\n\n [^ home](#Contenu)\u003cbr\u003e\n\n\n#### Boucles for()\n\nIl ne nous rest plus qu'à utiliser une boucle for pour répéter ces opérations un certain nombre de fois. Une boucle **for()** s'écrit de cette manière :\n\n```javascript\nfor (var i = 0 ; i \u003c 100 ; i = i+1){\n\n}\n```\nElle prend trois arguments :\n\t* le premier est une variable qui augmentera d'une valeur à chaque éxecution du code entre les accolades\n\t* le second est une condition d'arrêt sur la variable définie avant : si *i* est inférieur / supérieur / ou égal à une valeur à ce moment on sort de la boucle et on continue l'éxecution du programme après l'accolade fermante.\n\t* le troisième est une expression pour faire évoluer notre première variable : généralement on augment sa valeur de 1, mais cela dépend de sa valeur initiale et de notre condition d'arrêt bien sûr.\n\n\nCette boucle **for()** va compter jusqu'à 99 dans la console javascript de votre navigateur.\n```javascript\nfor (var i = 0 ; i \u003c 100 ; i = i+1){\n\tconsole.log(i)\n}\n```\nNous allons modifier notre fonction de dessin en utilisant une boucle **for()** mais nous allons compliquer les choses ... en faisant en sorte que le densité - c'est à dire le nombre - de points ne soit pas trop importante notament quand l'épaisseur du jet de peinture - la variable *size* de notre fonction est petite, et qu'il n'y en ait pas trop peu quand celui-ci est plus épais. Nous allons donc faire en sorte que la condition d'arrêt de notre boucle dépende de la taille de note jet de peinture.\n\nEt nous allons aussi faire en sorte que la taille des particules de peinture soit plus grande lorsqu'elles sont proches du centre (pour avoir une meilleure couverture au centre et un éparpillement plus visible en périphérie). Pour cela nous allons utiliser la fonction **map()** de faire une règle de trois. Il faut lui donner la valeur à transformer, la valeur minimale  et la valeur maximale qu'elle peut prendre, et lui donner les valeurs minimales et maximales que l'on souhaite.\n\nainsi : \n\n```javascript\nvar dm = map(mouseX, 0, windowWidth , 20 , 50)\n```\nva transformer la position de la souris - qui est une valeur comprise entre 0 et *windowWidth* (comme on le sait déjà) - en une valeur comprise entre 20 et 50; du coup lorsque ma souris est à gauche la variable *dm* vaut 20 et lorsqu'elle est à droite de la fenêtre *dm* vaut 50.\n\nVoici le code prenant en compte tous ces changements :\n\n```javascript\n// fonction permettant de dessiner un ensemble de taches de couleurs dans un rayon défini\n// ce rayon dépendera de la vitesse de la souris\nfunction sp(x,y,size){\n  push()\n  noStroke()\n  fill(hue,100,100,30) // on applique la teinte et on garde une transparence importante\n  translate(x,y)\n  for (var i = 0 ; i \u003c size*3 ; i = i+1){ // la condition d'arrêt dépend de size !\n    // coordonées polaire = rayon + angle\n    var radius = random(size) \n    var angle = random(TWO_PI)\n    // formule de passage de coordonées polaires en coordonnées catésienne\n    var xpos = radius*cos(angle)\n    var ypos = radius*sin(angle)\n    // on dessine une ellipse dont la taille dépend de son éloignement au centre\n    ellipse(xpos, ypos, map(radius,0,size,size/5,0), map(radius,0,size,size/5,0))\n  }\n  pop()\n}\n```\n\n![01_dessiner_05](assets/01_dessiner_05.png)\n\nhttps://www.openprocessing.org/sketch/388597\n\nhttps://b2renger.github.io/Introduction_p5js/01_dessiner_05/index.html\n\n\nIl est possible aussi de reprendre notre programme précédents et de réaliser des symétries grace aux coordonées polaires et à une boucle **for()**. Ici nous spécifions le nombre de branches souhaitées par une variable.\n\n```javascript\n  var s_branch_number = 42\n\n  function setup() {\n    createCanvas(windowWidth, windowHeight); \n    background(0,0,0);  \n  } \n\n  function draw() {   \n    if(mouseIsPressed){\n      noStroke()\n      fill(255,50)  \n      // calculer les coordonées polaire en fonction des positions centrées de la souris  \n      var radius = pow(pow(windowWidth/2-mouseX,2) + pow(windowHeight/2-mouseY,2) , 0.5) // pythagore \n      var angle = atan2(windowHeight/2-mouseY, windowWidth/2-mouseX) // atan2(y,x)\n   \n     \t for (var i = 0 ; i \u003c= TWO_PI ; i = i +PI/(s_branch_number/2)){ // on réalise une boucle for pour couvrir un cercle complet\n            var x =windowWidth/2 + radius * cos(angle +i) // on ajoute i à l'angle à chaque iteration de la boucle\n            var y =windowHeight/2 + radius * sin(angle+i)\n            ellipse(x,y,5,5)\n          }\n      }    \n  }\n```\n\n![01_dessiner_06](assets/01_dessiner_06.png)\n\nhttps://www.openprocessing.org/sketch/389230\n\nhttps://b2renger.github.io/Introduction_p5js/01_dessiner_06/index.html\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n\n## DOM\n\nAujourd'hui la bibliothèque DOM est inclue directement dans p5js. Il n'est plus nécessaire de télécharger un autre fichier puis de l'inclure dans votre *index.html*. Toutes les fonctionnalités décrites ci-dessous sont disponnibles directement avec l'unique fichier *p5.js*. Les versions utilisées dans ce cours sont les suivantes \n\n- p5.js v0.5.7 February 08, 2017\n- p5.dom.js v0.3.1 Jan 3, 2017\n- p5.sound.js v0.3.2 2016-11-01\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Installation de p5.dom.js\n\nNous allons maintenant nous intéresser à la bibliothèque DOM, qui permet de manipuler des éléments HTML5 par du code p5js. Cela nous permettera de créer des sliders, des champs des textes etc. pour controller nos programmes.\n\nLa référence de la bibliothèque est disponnible ici : http://p5js.org/reference/#/libraries/p5.dom\nElle n'est malheureusement pas forcément toujours simple à comprendre à mon sens il est préférable de regarder les exemples disponnibles à cette adresse, à la rubrique DOM : http://p5js.org/examples/\n\nA partir du programme de dessin précédent nous allons créer des sliders permettant de paramétrer la couleur ainsi que la taille de notre outil de dessin, à l'aide des fonctions **createSlider()** et **createP()** de la bibliothèque DOM.\n\nTout d'abord, il faut ajouter la bibliothèque à notre page en ajoutant la ligne suivante à l'habituel fichier *index.html*\n\n```html\n\u003cscript language=\"javascript\" type=\"text/javascript\" src=\"../libraries/p5.dom.js\"\u003e\u003c/script\u003e\n```\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Modifier et ajouter des objets html5 avec du code javascript\n\nMaintenant nous pouvons utiliser les fonctions **createSlider()** et **createP()** dans le *setup()* de notre programme, car cela va créer des objets HTML5 dans notre page et nous voulons que ces objets ne soient crées qu'une seule fois au chargement de la page.\n\n```javascript\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(0);  \n  colorMode(HSB,360,100,100,100) // appliquer le mode HSB\n\n  // Créer des éléments html5\n  s_hue = createSlider(0, 360, 50); // créer un slider allant de 0 à 360, initialiser à la valeur 50.\n  s_hue.position(5, windowHeight - 30) // on le positionne en bas à gauche.\n  l_hue = createP('hue :') // créer un label pour notre slider\n  l_hue.position(5, windowHeight - 75) // positionné un peu au dessus.\n}\n```\n\nNous créeons donc deux éléments un slider et un *paragraphe* faisant office de label pour notre slider. **s_hue** est maintenant un élement de notre page, il peut réagir aux events de type *mouseOver()*. L'élement **l_hue** est lui un paragraphe. Nous pouvons accéder à la valeur de notre slider en utilisant la fonction **.value()** de cette manière :\n\n```javascript\nfill(s_hue.value(),100,100,100)\n```\n[**home**](#Contenu)\u003cbr\u003e\n\n### Styliser avec du CSS\n\nPuisque ce sont des élements html, ils peuvent aussi être stylisés par css, il suffit pour cela de créer un fichier css dans le dossier de notre page, par exemple comme celui-ci :\n\n```css\ninput[type=\"range\"]::-webkit-slider-thumb {\n    -webkit-appearance: none;\n    border: 0px;\n    border-radius: 50%;\n    height: 15px;\n    width: 15px;\n    border-radius: 50%px;\n    background: white;\n    opacity: 1;\n}\n\ninput[type=range] {\n    -webkit-appearance: none;\n    background-color: white;\n    width: 100px;\n    height: 4px;\n    opacity: 0.75;\n}\n\np{\n\tcolor: white;\n}\n```\nNotre slider et autres futurs sliders qui ressemblait à ceci : ![slider-dom](assets/slider-dom.png)\n\nRessembleront maintenant à ceci : ![slider-dom-css](assets/slider-dom-css.png)\n\nEt le texte de nos paragraphes sera blanc.\n\nIl est possible de customiser des groupes d'éléments séparement, vous pouvez vous référer à cette page : https://github.com/processing/p5.js/wiki/Beyond-the-canvas#using-a-css-stylesheet\n\nSi nous créons l'ensemble des contrôles prévus, notre code ressemblera à ceci\n\n```javascript\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(0);  \n  colorMode(HSB,360,100,100,100) // appliquer le mode HSB\n\n  // Créer des éléments html5 - ces élements peuvent être customisés par css (voir le fichier ci-joint)\n  s_hue = createSlider(0, 360, 50);\n  s_hue.position(5, windowHeight - 30)\n  l_hue = createP('hue :')\n  l_hue.position(5, windowHeight - 75)\n\n  s_sat = createSlider(0, 100, 85);\n  s_sat.position(125, windowHeight - 30)\n  l_sat = createP('saturation :')\n  l_sat.position(125, windowHeight - 75)\n\n  s_bri = createSlider(0, 100, 95);\n  s_bri.position(245, windowHeight - 30)\n  l_bri = createP('brightness :')\n  l_bri.position(245, windowHeight - 75)\n  \n  s_opacity = createSlider(2, 100, 100);\n  s_opacity.position(365, windowHeight - 30)\n  l_opacity = createP('opacity :')\n  l_opacity.position(365, windowHeight - 75)\n\n  s_brush_size = createSlider(5, 60, 40);\n  s_brush_size.position(485, windowHeight - 30)\n  l_brush = createP('size :')\n  l_brush.position(485, windowHeight - 75)\n\n }\n\nfunction draw() {\n  var size = (abs(pmouseX-mouseX)+abs(pmouseY-mouseY)) + s_brush_size.value() \n  if (mouseIsPressed) { // si la souris est clickée on dessine avec la fonction de dessin définie ci-dessous\n    sp(mouseX,mouseY,size)\n  }\n  // dessiner les paramètres sélectionnés\n  push()\n  fill(0,100)\n  rect(0, windowHeight-80 ,710,80)\n  stroke(255)\n  fill(s_hue.value(),s_sat.value(),s_bri.value(),s_opacity.value()+25)\n  ellipse(640 , windowHeight-30 ,s_brush_size.value()+5, s_brush_size.value()+5)\n  pop()   \n}\n\n// fonction permettant de dessiner un ensemble de taches de couleurs dans un rayon défini\n// ce rayon dépendera de la vitesse de la souris\nfunction sp(x,y,size){\n  push()\n  noStroke()\n  fill(s_hue.value(),s_sat.value(),s_bri.value(),s_opacity.value()) // on applique la teinte et on garde une transparence importante\n  translate(x,y)\n  for (var i = 0 ; i \u003c size*2 ; i = i+1){\n    // coordonées polaire = rayon + angle\n    var radius = random(size) \n    var angle = random(TWO_PI)\n    // formule de passage de coordonées polaires en coordonnées catésienne\n    var xpos = radius*cos(angle)\n    var ypos = radius*sin(angle)\n    // on dessine une ellipse dont la taille dépend de son éloignement\n    ellipse(xpos, ypos, map(radius,0,size,size/6,0), map(radius,0,size,size/6,0))\n  }\n  pop()\n}\n\n```\n\n![02_dom_01](assets/02_dom_01.png)\n\nhttps://www.openprocessing.org/sketch/389277\n\nhttps://b2renger.github.io/Introduction_p5js/02_dom_01/index.html\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\nL'exemple suivant *02_dom_02*, applique ces principes à notre outil de dessin symétrique. On utilise cette fois la fonction **createInput()** pour créer un champ de texte dans lequel l'utilisateur peut rentrer la valeur qu'il souhaite : nous pourrons donc choisir le nombre de branches de manière interactive.\n\n```javascript\n  function setup() {\n    createCanvas(windowWidth, windowHeight); \n    background(0,0,0);  \n    colorMode(HSB,360,100,100,100) \n    \n    // Créer des éléments html5 - ces élements peuvent être customisés par css (voir le fichier ci-joint)\n    s_hue = createSlider(0, 360, 50);\n    s_hue.position(5, windowHeight - 30)\n    l_hue = createP('hue :')\n    l_hue.position(5, windowHeight - 75)\n\n    s_sat = createSlider(0, 100, 85);\n    s_sat.position(125, windowHeight - 30)\n    l_sat = createP('saturation :')\n    l_sat.position(125, windowHeight - 75)\n\n    s_bri = createSlider(0, 100, 95);\n    s_bri.position(245, windowHeight - 30)\n    l_bri = createP('brightness :')\n    l_bri.position(245, windowHeight - 75)\n  \n    s_opacity = createSlider(2, 100, 100);\n    s_opacity.position(365, windowHeight - 30)\n    l_opacity = createP('opacity :')\n    l_opacity.position(365, windowHeight - 75)\n\n    s_brush_size = createSlider(1, 40, 15);\n    s_brush_size.position(485, windowHeight - 30)\n    l_brush = createP('size :')\n    l_brush.position(485  , windowHeight - 75)\n\n    s_branch_number = createInput(12);\n    s_branch_number.position(655, windowHeight - 30)\n    l_branch_number = createP('branch quantity  (1 - 100) :')\n    l_branch_number.position(655, windowHeight - 75)\n  } \n\n  function draw() {\n    \n    if(mouseIsPressed \u0026\u0026 !(mouseY\u003ewindowHeight-80 \u0026\u0026 mouseX\u003c 860 )){\n      noStroke()\n      fill(s_hue.value(),s_sat.value(),s_bri.value(),s_opacity.value())  \n      // calculer les coordonées polaire en fonction des positions centrées de la souris  \n      var radius = pow(pow(windowWidth/2-mouseX,2) + pow(windowHeight/2-mouseY,2) , 0.5) // pythagore \n      var angle = atan2(windowHeight/2-mouseY, windowWidth/2-mouseX) // atan2(y,x)\n  \n        for (var i = 0 ; i \u003c= TWO_PI ; i = i +PI/(s_branch_number.value()/2)){ // on réalise une boucle for pour couvrir un cercle complet\n            var x =windowWidth/2 + radius * cos(angle +i) // on ajoute i à l'angle à chaque iteration de la boucle\n            var y =windowHeight/2 + radius * sin(angle+i)\n            ellipse(x,y,s_brush_size.value(),s_brush_size.value())\n          }\n      }\n\n    // dessiner les paramètres sélectionnés\n    push()\n    fill(0,100)\n    rect(0, windowHeight-80 ,860,80)\n    stroke(255)\n    fill(s_hue.value(),s_sat.value(),s_bri.value(),s_opacity.value()+25)\n    ellipse(620 , windowHeight-30 ,s_brush_size.value()+5, s_brush_size.value()+5)\n    pop()\n    \n  }\n ```\n![02_dom_02](assets/02_dom_02.png)\n\nhttps://b2renger.github.io/Introduction_p5js/02_dom_02/index.html\n\nhttps://www.openprocessing.org/sketch/390491\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Video\n\nLa bibliothèque DOM permet d'avoir accès au microphone et à la webcam à travers le navigateur via la fonction **createCapture()** : http://p5js.org/reference/#/p5/createCapture, et de lire des vidéos.\n\n```javascript\nvar capture;\n\nfunction setup() {\n  createCanvas(390, 240);\n  capture = createCapture(VIDEO);\n  capture.size(320, 240);\n  //capture.hide();\n}\n\nfunction draw() {\n  background(255);\n  image(capture, 0, 0, 320, 240);\n}\n```\n\nCet exemple permet de créer un élément vidéo dans notre page web. Le principe est d'utiliser l'objet HTML5 dédié et de récupérer l'image à un instant t pour l'afficher dans notre canvas p5js à l'aide de la fonction **image()**.\n\nLa ligne l'instruction :\n\n```javascript\ncapture.hide()\n```\n\npermet de cacher l'élément HTML5 pour n'afficher que l'image de notre programme. \n\nVous remarquerez que les mouvements droite gauche de l'image sont inversés par rapport à l'effet \"miroir\" que l'on pourrait attendre. Il est possible d'y rémedier en utilisant la fonction **scale()** qui permet de changer l'échelle de notre système de coordonnées en précisant la nouvelle échelle pour chaque coordonnée. Pour inverser l'image horizontalement :\n\n```javascript\nscale(-1,1)\n```\nnous permet de renverser le système de coordonnées en abscisses, il faudra donc changer les informations que l'on donne pour l'affichage de notre image, qui sont dans l'ordre : *image(image à afficher, abscisse, ordonnée, largeur, hauteur)*\n\n```javascript\nimage(capture,-320,0,320,240)\n```\nl'abscisse de notre point d'ancrage pour l'image sera donc * -320 x -1 = 320 *\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Transformations de video\n\nLe javascript n'est pas forcément le langage le plus approprié pour manipuler des images et des flux vidéos en temps réel pour des questions de performances cependant il est quand même possible de faire des choses. Les fonctions que nous verrons ici peuvent être appliquée à un flux vidéo provenant d'une webcam ou à une vidéo classique, ainsi qu'à une image classique.\n\nLa fonction **tint()** permet de \"coloriser\" l'image à l'aide d'un filtre de teinte. Il suffit de passer une couleur à la fonction pour appliquer ce filtre. Par contre cette fonction est un peu différentes des fonctions **fill()**, **stroke()** qui s'appellent avant de dessiner, celle-ci s'appelle après avoir dessiner les éléments sur lequel ce filtre sera appliqué. Le filtre va en fait récupérer les pixels de la vidéo et les traiter un à un.\n\n```javascript\nvar capture; // création d'une variable pour stocker notre élement de capture vidéo\n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight);\n  capture = createCapture(VIDEO); // créer un élément html5 d'accès à la webcam\n  capture.size(windowWidth/2, windowHeight/2); // définir la résolution de captation\n  capture.hide(); // cacher l'élement vidéo HTML5\n  colorMode(HSB,360,100,100,100) // passer en mode HSB\n}\n\nfunction draw() {\n  background(255);\n  scale(-1,1)  // inverser les coordonnées pour effet miroir\n  image(capture, -windowWidth/2, 0, windowWidth/2, windowHeight/2); // afficher l'image de la capture vidéo\n  tint(map(mouseX,0,windowWidth,0,360),100,100,100) // teinter l'image précédement dessinée en fonction de la position de la souris\n}\n```\n\n![02_dom_03](assets/02_dom_03.png)\n\nhttps://b2renger.github.io/Introduction_p5js/02_dom_03/index.html\n\nhttps://www.openprocessing.org/sketch/389684\n\n\nLa fonction **filter()** permet aussi différents types d'effets : http://p5js.org/reference/#/p5/filter\n\nIl faut comprendre que si on multiplie les effets dans le même canvas ceux-ci s'ajoutent les un aux autres.\n\n```javascript\nvar capture;\n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight);\n  capture = createCapture(VIDEO);\n  capture.size(windowWidth/3, windowHeight/3);\n  capture.hide();\n}\n\nfunction draw() {\n  background(255);\n  \n  image(capture, 0, windowHeight/2, windowWidth*1/2, windowHeight/2);\n  filter('THRESHOLD',mouseX/windowWidth);\n \n  image(capture, windowWidth*1/2, 0, windowWidth*1/2, windowHeight/2);\n  filter('INVERT');\n  \n  image(capture, windowWidth*1/2, windowHeight*1/2, windowWidth*1/2, windowHeight/2);\n  filter('POSTERIZE', 2+mouseX*3/windowWidth);\n  \n  image(capture, 0, 0, windowWidth*1/2, windowHeight/2);\n}\n```\n\n![02_dom_04](assets/02_dom_04.png)\n\nhttps://b2renger.github.io/Introduction_p5js/02_dom_04/index.html\n\nhttps://www.openprocessing.org/sketch/389281\n\n\nL'usage de la vidéo en temps réel dans le navigateur pourra avoir de nombreux usages. Pour comprendre comment fonctionnent ces filtres il faut se pencher sur les fonctions **loadPixels()**, **updatePixels()**, et le tableau de pixels **pixels[]**.\n\n\t-\thttp://p5js.org/reference/#/p5/loadPixels\n\n\t-\thttp://p5js.org/reference/#/p5/updatePixels\n\n\t-\thttp://p5js.org/reference/#/p5/pixels[]\n\n\nLeur usage dépasse une simple introduction à p5js, cependant quelques ressources en anglais sont disponnibles (elles sont aussi référencées dans la rubrique *ressources*).\t\n\n\thttps://kylemcdonald.github.io/cv-examples/\n\nL'exemple sur le **threshold** applique le même algorithme que le filtre vu précédement: https://kylemcdonald.github.io/cv-examples/Thresholding/\n\nD'autres exemples peuvent être source d'inspiration pour créer de nouvelles façon d'interagir avec une page web.\n\n\t-\thttps://kylemcdonald.github.io/cv-examples/OpticalFlow/\n\n\t-\thttps://kylemcdonald.github.io/cv-examples/FaceTracking/\n\n\nJe vous conseille aussi l'excellent playlist de Daniel Shiffman sur le sujet : \n\t-\thttps://www.youtube.com/playlist?list=PLRqwX-V7Uu6aKKsDHZdDvN6oCJ2hRY_Ig\n\net tout particulièrement le checkbox miror qui restitue un flux vidéo par une grille de boîtes à cocher html activées et désactivées programmatiquement grâce à la bibliothèque dom : \n\t-\thttps://www.youtube.com/watch?v=m1G6WBvrOBE\u0026list=PLRqwX-V7Uu6aKKsDHZdDvN6oCJ2hRY_Ig\u0026index=5\n\nVous pouvez aussi consulter ce [cours](https://github.com/b2renger/p5js_image_alteration/blob/master/README.md) sur la transformation d'images à travers l'analyse de leurs pixels :\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Mode instance\n\nLe mode instance de p5js permet d'avoir plusieurs canvas utilisant p5js dans une même page web. Dans le cas de notre grille de vidéos teintées cela pourrait nous permettre de contourner le problème du chaînage des effets.\n\nIl sera alors possible de créer quatre canvas avec chacun leur accès à la webcam, leur propre filtre et leur propre interaction aussi.\n\nLe terme *instance* fait référence à la notion d'objet en javascript que nous developperons plus tard. Mais en gros il faut comprendre qu'un programme p5js répond à un fonctionnement précis : tous les sketchs p5js ont accès aux mêmes fonctionnalités, une instance de p5js permet de bénéficier d'un contexte de programmation dans lequel toutes les fonctions de p5js existent.\n\nDans la pratique il suffit d'imbriquer notre programme dans une fonction javascript et de préfixer tous les appels à des fonctions de p5js\n\n```javascript\nvar s1 // des variables pour créer les instances de nos programmes.\n\nfunction setup(){\n  s1 = new p5(sketch) // on dit que s1 est un nouveau programme de type p5js(ou une instance) et qu'il execute le programme appellé \"sketch\"\n}\n\n// on crée une nouvelle variable sketch, celle qui est appelée dans le setup\n// ce sera un programme p5js. Il est nécessaire de passer une \"instance\" de p5\n// pour pouvoir accès aux fonction de p5. C'est le \"p\" utilisé un peu partout.\n// On doit \"l'appeler\" avant chaque fonction intégrée dans p5 (par ex : p.fill(255))\nvar sketch = function(p) { \n  var capture;\n  p.setup = function() { // on créer le setup de notre programme avec \"p.\" devant le mot clé setup\n    var c = p.createCanvas(p.windowWidth/2, p.windowHeight/2); // on crée un canvas\n    c.position(0,0); // on le place dans la page\n    // initialisation de la capture\n    capture = p.createCapture(p.VIDEO);\n    capture.size(p.width, p.height);\n    capture.hide()\n  }\n  p.draw = function() {\n    p.background(255);\n    p.scale(-1,1)\n    p.image(capture, -p.width , 0, p.width, p.height);\n  }\n}\n```\n\nIl est alors possible de créer de multipes instances de programmes p5js et de les controler avec des éléments DOM, comme des boutons permettant d'activer/ désactiver l'éxecution des programmes indépendement.\n\n```javascript\nvar s1,s2,s3,s4 // des variables pour créer les instances de nos programmes.\n\nfunction setup(){\n  s1 = new p5(sketch) // on dit que s1 est un nouveau programme de type p5js(ou une instance) et qu'il execute le programme appellé \"sketch\"\n  s2 = new p5(sketch2)\n  s3 = new p5(sketch3)\n  s4 = new p5(sketch4)\n  controls(); // on initialise les boutons pour controler les programmes\n}\n\n// on crée une nouvelle variable sketch, celle qui est appelée dans le setup\n// ce sera un programme p5js. Il est nécessaire de passer une \"instance\" de p5\n// pour pouvoir accès aux fonction de p5. C'est le \"p\" utilisé un peu partout.\n// On doit \"l'appeler\" avant chaque fonction intégrée dans p5 (par ex : p.fill(255))\nvar sketch = function(p) { \n  var capture;\n  p.setup = function() { // on créer le setup de notre programme avec \"p.\" devant le mot clé setup\n    var c = p.createCanvas(p.windowWidth/2, p.windowHeight/2); // on crée un canvas\n    c.position(0,0); // on le place dans la page\n    // initialisation de la capture\n    capture = p.createCapture(p.VIDEO);\n    capture.size(p.width, p.height);\n    capture.hide()\n  }\n  p.draw = function() {\n    p.background(255);\n    p.scale(-1,1)\n    p.image(capture, -p.width , 0, p.width, p.height);\n  }\n}\n\nvar sketch2 = function(p) {\n  var capture;\n  p.setup = function() {\n    var c = p.createCanvas(p.windowWidth/2, p.windowHeight/2);\n    c.position(p.windowWidth/2,0)\n    capture = p.createCapture(p.VIDEO);\n    capture.size(p.width, p.height);\n    capture.hide()\n  }\n  p.draw = function() {\n    p.background(255);\n    p.scale(-1,1)\n    p.image(capture, -p.width , 0, p.width, p.height);\n    p.filter('POSTERIZE',4+p.mouseX/p.width);\n  }\n}\n\nvar sketch3 = function(p) {\n  var capture;\n  p.setup = function() {\n    var c = p.createCanvas(p.windowWidth/2, p.windowHeight/2);\n    c.position(0,p.windowHeight/2)\n    capture = p.createCapture(p.VIDEO);\n    capture.size(p.width, p.height);\n    capture.hide()\n  }\n  p.draw = function() {\n    p.background(255);\n    p.scale(-1,1)\n    p.image(capture, -p.width , 0, p.width, p.height);\n    p.filter('INVERT');\n  }\n}\n\nvar sketch4 = function(p) {\n  var capture;\n  p.setup = function() {\n    var c =  p.createCanvas(p.windowWidth/2, p.windowHeight/2);\n    c.position(p.windowWidth/2 , p.windowHeight/2)\n    capture = p.createCapture(p.VIDEO);\n    capture.size(p.windowWidth, p.height);\n    capture.hide();\n  }\n  p.draw = function() {\n    p.background(255);\n    p.scale(-1,1)\n    p.image(capture, -p.width, 0, p.width, p.height);\n    p.filter('THRESHOLD',p.mouseX/p.windowWidth);\n  }\n}\n\nvar b_stop1,b_start1,b_stop2,b_start2, b_start3, b_stop3, b_start4, b_stop4\n\n// Création des boutons pour mettre en pause et relancer les programmes\nfunction controls(){\n  // controles pour le premier sketch\n  b_stop1 = createButton('pause'); // on crée un bouton\n  b_stop1.position(0, 0); // on le positionne\n  // la fonction mousePressed du bouton est activé lorsqu'on clique sur le bouton\n  b_stop1.mousePressed(function sketch_off (){ // on passe en argument de la fonction mousePressed une fonction javascript\n    s1.noLoop() // cette fonction a une seulle instruction appeler noLoop sur la variable s1 qui est notre premier sketch.\n  }); \n  b_start1 = createButton('resume'); // on crée un second bouton\n  b_start1.position(50, 0);\n  b_start1.mousePressed(function sketch_on (){\n    s1.loop()\n  });\n  // controles pour le deuxième sketch\n  b_stop2 = createButton('pause');\n  b_stop2.position(windowWidth/2, 0);\n  b_stop2.mousePressed(function sketch_off (){\n    s2.noLoop()\n  });\n  b_start2 = createButton('resume');\n  b_start2.position(windowWidth/2+50, 0);\n  b_start2.mousePressed(function sketch_on (){\n    s2.loop()\n  });\n  // controles pour le troisième sketch\n  b_stop3 = createButton('pause');\n  b_stop3.position(0, windowHeight/2);\n  b_stop3.mousePressed(function sketch_off (){\n    s3.noLoop()\n  });\n  b_start3 = createButton('resume');\n  b_start3.position(50, windowHeight/2);\n  b_start3.mousePressed(function sketch_on (){\n    s3.loop()\n  });\n  // controles pour le quatrième sketch\n  b_stop4 = createButton('pause');\n  b_stop4.position(windowWidth/2, windowHeight/2);\n  b_stop4.mousePressed(function sketch_off (){\n    s4.noLoop()\n  });\n  b_start4 = createButton('resume');\n  b_start4.position(windowWidth/2 + 50, windowHeight/2);\n  b_start4.mousePressed(function sketch_on (){\n    s4.loop()\n  });\n\n}\n```\n\n![02_dom_05](assets/02_dom_05.png)\n\nhttps://b2renger.github.io/Introduction_p5js/02_dom_05/index.html\n\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n### Exemple de site web\n\nMon site web personnel est constuit à l'aide de la bibliothèque DOM de p5js. Le principe est d'utiliser un canvas pour la navigation dans les 'pages' plutôt qu'un menu classique.\n\nhttp://b2renger.github.io\n\n![b2renger website](assets/b2renger_website.png)\n\nLa partie de gauche de la page web est donc un canvas faisant fonctionner un sketch p5js. A ce niveau du cours certains aspects du code seront une peu compliqués à comprendre, mais le principe de base est simple : chaque forme géométrique représente un page, lorsque l'on passe au dessus avec la souris, les éléments html de la partie de droite sont détruits, et recrées en fonction d'un fichier csv (qui représente l'article). Le fichier csv est alors analysé et chaque ligne correspond à la création d'un élément html : paragraphe, balise vidéo, lien hypertexte, balise image ou audio etc.\n\nUn peu de documentation et un exemple simple sont disponnibles à cette adresse : http://b2renger.github.io/p5js_algae_dom/index.html\n\nPour entrer un peu dans le code, il sera nécessaire d'avoir quelques bases sur l'utilisation des objets et des tableaux en javascript.\n\nAttention le code n'est pas exemplaire : il s'agit ici plus d'une expérimentation. A priori le choix d'utiliser le csv n'est pas idéal, car il empêche d'utiliser des virgules dans le texte des paragraphes (la virgule étant le séparateur du format CSV), il serait préférable d'utiliser le format JSON. Un autre défaut est que le site n'est pas très réactif : les éléments sont parsés du format json et disposé selon un grille fixe, il serait mieux de mapper les éléments vers des div qui pourraient alors être stylisées, déplacées en fonction de la taille de la fenêtre du client etc.\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n\n## Websocket et SocketIO\n\nDans le cadre de cette découverte de p5js nous allons effleurer le sujet des websockets qui permet des informations entre plusieurs ordinateurs dans une même page web. Les utilisateurs peuvent alors collaborer.\n\nUn excellent exemple est l'application de musique collaborative **Plink** :  http://dinahmoelabs.com/#plink\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### SocketIO\n\nNous n'allons pas nous lancer dans l'écriture de code côté serveur mais nous allons nous concentrer sur l'utilisation de la bibliothèque inclue à openprocessing. \n\nSi jamais vous souhaitez vous lancer dans l'écriture d'applications websocket plus avancées, il vous faudra écrire un serveur capable d'utiliser cette technologie.\n\nLes exemples du cours seront disponnibles sur openprocessing sans avoir recours à un serveur, mais aussi executables en local à l'aide du serveur websocket écrit en nodejs dans ce tutoriel :  https://github.com/processing/p5.js/wiki/p5.js,-node.js,-socket.io\n\nNous allons donc nous attacher à modifier nos programmes de dessin pour permettre l'interaction de plusieurs utilisateurs sur la même page.\n\nTout d'abord il faut ajouter les bibliothèques DOM et socketIO à notre programme openprocessing en cliquant sur le menu (les trois points verticaux) sous le bouton *save*. \n\n![openprocessing add libraries](assets/03_socket_openprocessing.png)\n\nPuis il faut sauvegarder le programme pour s'assurer d'avoir une connection socket fonctionnelle.\n\nOn va commencer par déclarer une variable pour la connection websocket à laquelle on pourra ajouter des fonctionalités plus tard\n\n```javascript\nvar socket = io.connect(\":30000?sketch=390497\");\n\n```\n\nCette ligne de code vous est fournie dans le menu \":30000\" signifie que l'on communique via le port 3000, et \"sketch=390497\" est un identifiant pour votre programme une fois qu'il est sauvegardé. \n\n![openprocessing add libraries](assets/03_socket_info.png)\n\n\nNous allons ensuite garder la même fonction *setup()* que pour notre dernier exemple de dessin *02_Dom_02* avec les éléments de gui\n\n```javascript\n// variable pour stocker les élements DOM, sliders ...\nvar s_hue,l_hue, s_sat, l_sat, s_bri, l_bri, s_opacity, l_opacity, s_brush_size, l_brush_size, s_branch_number, l_branch_number\n\nfunction setup() {\n    createCanvas(windowWidth, windowHeight); \n    background(0,0,0);  \n    colorMode(HSB,360,100,100,100) \n    // créer l'ensemble de l'interface utilisateur\n  \ts_hue = createSlider(0, 360, 50);\n  \ts_hue.position(5, windowHeight - 30)\n  \ts_hue.size(110,AUTO)\n  \tl_hue = createP('hue ')\n  \tl_hue.style(\"color\",\"rgb(255,255,255)\")\n  \tl_hue.position(5, windowHeight - 75)\n\n  \ts_sat = createSlider(0, 100, 85);\n  \ts_sat.position(125, windowHeight - 30)\n  \ts_sat.size(110,AUTO)\n  \tl_sat = createP('saturation ')\n  \tl_sat.style(\"color\",\"rgb(255,255,255)\")\n  \tl_sat.position(125, windowHeight - 75)\n\n  \ts_bri = createSlider(0, 100, 95);\n  \ts_bri.position(245, windowHeight - 30)\n  \ts_bri.size(110,AUTO)\n  \tl_bri = createP('brightness ')\n  \tl_bri.style(\"color\",\"rgb(255,255,255)\")\n  \tl_bri.position(245, windowHeight - 75)\n  \n \ts_opacity = createSlider(2, 100, 100);\n  \ts_opacity.position(365, windowHeight - 30)\n  \ts_opacity.size(110,AUTO)\n  \tl_opacity = createP('opacity ')\n  \tl_opacity.style(\"color\",\"rgb(255,255,255)\")\n  \tl_opacity.position(365, windowHeight - 75)\n\n  \ts_brush_size = createSlider(5, 60, 40);\n  \ts_brush_size.position(485, windowHeight - 30)\n  \ts_brush_size.size(110,AUTO)\n  \tl_brush = createP('size :')\n  \tl_brush.style(\"color\",\"rgb(255,255,255)\")\n  \tl_brush.position(485, windowHeight - 75)\n  \t\n    s_branch_number = createInput(12);\n    s_branch_number.position(675, windowHeight - 30)\n    l_branch_number = createP('branch quantity  (1 - 100) :')\n    l_branch_number.style(\"color\",\"rgb(255,255,255)\")\n    l_branch_number.position(675, windowHeight - 75)   \n } \n ```\n \n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Format JSON soit JavaScript Object Notation\n\nEnsuite pour que chaque utilisateur puisse choisir son \"crayon\", il faut que les données relatives à chaque paramètre qu'il a choisit soient envoyés à la page web principale qui accepte toutes les connections des utilisateurs. Pour cela nous allons créer un objet javascript au format **JSON** qui est un format très utilisé en developpement. Le format json fonctionne avec un système de clé. Entre deux accolades, il suffit d'inscrire \"maClé : maValeur\".\n\nPar exemple, si je crée une variable javascript sur ce modèle\n\n```javascript\nvar data = {\n\ta : 320,\n\tb : 0.123\n}\n```\n\nJe peux ensuite récupérer les valeur inscrite dans l'objet *data* à la clé \"a\", en tapant :\n\n```javascript\ndata.a\n```\n\nIl est possible alors d'écrire une fonction qui pourra nous **retourner** un objet javascript encodé en JSON. Le terme **retourner** est important car jusqu'à maintenant nous n'avons écrit que des fonctions permettant de dessiner des choses, ces fonctions qui utilisent le mot-clé **return** peuvent elle former des objet javascripts selon nos besoins (un objet json, un tableau de valeur etc.)\n\n```javascript\nfunction getData(xpos, ypos ,hue,sat,bri,op,brush_size,branch_num){\n   var data = {\n    x: xpos,\n    y: ypos, \n    h: hue,\n    s: sat,\n    b: bri,\n    o: op,\n    siz : brush_size,\n    branch: branch_num\n  };\n  return data;\n}\n```\n\nUne fois que cette fonction est créee, il est possible de créer une variable comprenant toutes nos valeurs au format JSON.\n\n```javascript\nvar mesValeurs = getData(mouseX,mouseY,s_hue.value(),s_sat.value(),s_bri.value(),s_opacity.value(),s_brush_size.value(), s_branch_number.value())\n```\n\nIl est alors possible d'accéder à chacune des valeurs indépendement, pour accéder à la tailler de notre crayon\n\n```\nmesValeur.siz\n```\n\nnous permet d'accéder à cette information, nous pouvons alors réécrire notre procédure de dessin en utilisant ce même formattage :\n\n```javascript\nfunction draw_params(data){\n  noStroke()\n  fill(data.h,data.s,data.b,data.o)  // utiliser les paramètres des slides\n  var radius = pow(pow(windowWidth/2-data.x,2) + pow(windowHeight/2-data.y,2) , 0.5) // pythagore sur les positions de la souris\n  var angle = atan2(windowHeight/2-data.y, windowWidth/2-data.x) // atan2(y,x)\n  for (var i = 0 ; i \u003c= TWO_PI ; i = i +PI/(data.branch/2)){ \n    var x =windowWidth/2 + radius * cos(angle +i)\n    var y =windowHeight/2 + radius * sin(angle+i)\n    ellipse(x,y,data.siz,data.siz)\n  }\n}\n\n```\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Envoyer et Recevoir des informations\n\nIl ne nous reste maintenant plus qu'à envoyer et recevoir les paramètres via le système de socket. Le process pour émettre est très simple émettre :\n\n```javascript\nsocket.emit('params',data);\n```\n\nDans notre cas on peut placer cette instruction dans la fonction **mouseDragged()**, pour que les données soient envoyées quand l'utilisateur dessine :\n\n```javascript\nfunction mouseDragged() {\n if( !(mouseY\u003ewindowHeight-80 \u0026\u0026 mouseX\u003c 860 )){ // éviter de dessiner quand on manipule les paramètres\n    // créer l'objet data avec les paramètres\n    var data = getData(mouseX,mouseY,s_hue.value(),s_sat.value(),s_bri.value(),s_opacity.value(),s_brush_size.value(), s_branch_number.value())\n    //console.log(data);\n  \tdraw_params(data) // dessiner les formes avec les paramètres de l'utilisateur qui est connecté sur la page\n  \tsocket.emit('params',data);\n  }\n}\n```\n\npour recevoir on utilise le même principe sauf qu'au lieu de passer un objet \"data\", on peut passer une fonction javascript. En javascript on peut même écrire la fonction directement entre les parenthèses :\n\n```javascript\nsocket.on('params',function(data){\n    \tdraw_params(data); // on utilise les données reçues pour dessiner\n})\n```\n\nCe qui est une forme condensée de :\n\n```javascript\nsocket.on('params', doSomething)\nfunction doSomething (data){\n    \tdraw_params(data);\n})\n```\n\nEt voilà ! : https://www.openprocessing.org/sketch/390497\n\nVoici l'adaptation du sketch de \"spray-paint\" : https://www.openprocessing.org/sketch/390650\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Node et serveur local\n\nComme mentionné en intro vous pouvez vous référer à ce tutorial pour apprendre à coder un serveur wwebsocket avec nodeJS : https://github.com/processing/p5.js/wiki/p5.js,-node.js,-socket.io\n\nPour faire résumer et faire fonctionner les exemples fournis, il faut :\n\n-installer NodeJS\n-naviguer vers le dossier de l'exemple que vous souhaitez tester.\n-installer les dépendences, grace au node package manager, ligne de commande à taper dans une invite de commande nodejs ou un terminal.\n\n\t\t```\n\t\tnpm install socket.io\n\t\t```\n\n-lancer le serveur local : \n\t\t\n        ```\n\t\tnode servers.js\n\t\t```\n\n-se rendre sur la page :\n\n\t\t```\n\t\thttp://localhost:8080/\n\t\t```\n\n[**home**](#Contenu)\u003cbr\u003e\n\n## Quicksettings.js et les fonctions  callback\n\nLa bibliothèque quicksettings.js est une bibliothèque de GUI (General User Interface), elle permet de créer des éléments graphiques avec lequel l'utilisateur peut intéragir. Cela ressemble étrangement à ce que permet de faire la bibliothèque DOM, sauf que la bibliothèque DOM permet de faire beaucoup, plus comme modifier l'emplacement, l'apparence de n'importe quel élément d'une page web. Ici il s'agit surtout de pouvoir permettre à l'utilisateur de choisir une couleur, d'entrer du texte ou de cliquer sur un bouton pour activer / désactiver une fonctionnalité. \n\nElle possède l'avantage de placer tous les éléments qu'elle crée dans un ou plusieurs \"tiroirs\" qui sont déplaçables et qui peuvent être ouverts ou fermés. \n\nLa documentation sur la page github est simple à comprendre, elle présente les différentes fonction que l'on peut appeler pour créer des éléments gui.\n\nVous pourrez trouver un apperçu de ses fonctionnalités via cet exemple : http://bit101.github.io/quicksettings/demos/styles_demo.html\n\nCette bibliothèque ainsi que sa documentation sont hébergées ici : https://github.com/bit101/quicksettings\n\nEt elle est présente dans le dossier */libraries* des exemples de code, et elle est disponible via CDN (Content Delivery Network) : https://cdn.jsdelivr.net/quicksettings/latest/quicksettings.min.js\n\nD'ailleurs l'intégration dans openprocessing d'une bibliothèque externe nécessite que celle-ci soit disponnible via CDN.\n\nIl est cependant important de comprendre ce que sont et comment fonctionne **les fonctions de callback** ou ** fonctions de rappel**: ce sont des fonctions qui sont passées en arguments à d'autres fonctions et dont le code ne s'exécute dans certains cas et en fonction de certains évenements.\n\nPar exemple lorsqu'on appuit sur un bouton, on peut faire en sorte de créer une fonction de rappel propre au bouton et dont le code s'éxecute lorsqu'on clique sur ce bouton.\n\nDans le cas de quicksettings, il faut : créer un panneau, lui ajouter des éléments et définir des fonctions de rappel pour modfier certaines variables en fonction de l'élément modifié :\n\n```javascript\nvar settings // une variable pour stocker le panneau de controle\nvar flicker = false // une valeur à modifier\nfunction setup() {\n    createCanvas(windowWidth, windowHeight);\n    background(0)\n    // On initialise notre variable, on passe en argument la position du widget dans le canvas\n    // et le nom du groupe d'éléments gui que l'on veut créer.\n    settings = QuickSettings.create(5, 5, \"GUI\");\n    // On ajoute un élément à ce widget qui est une boîte à cocher, on passe en argument, le nom\n    // de l'élément, sa valeur initiale, et le nom de la fonction de rappel, qu'il faut définir\n    settings.addBoolean(\"Check Me\", flicker, eltChecked);\n}\n// définition de la fonction de rappel\nfunction eltChecked(val) { // val correspond à la valeur de l'élément\n    flicker = val; // on change notre variable \"flicker\" pour la remplacer par la valeur de notre gui\n    console.log(val)\n}\n\nfunction draw() {\n    // on utilise notre variable\n    if (!flicker) {\n        background(0)\n    }\n    else {\n        background(random(255))\n    }\n}\n```\n\nhttps://b2renger.github.io/Introduction_p5js/99_quicksettings/index.html\n\nNotez qu'au lieu de donner le nom de la fonction de rappel et la définir plus bas, on peut définir une fonction **anonyme** \n\nAinsi les lignes:\n```javascript\n settings.addBoolean(\"Check Me\", flicker, eltChecked);\n```\n et :\n```javascript\nfunction eltChecked(val) { // val correspond à la valeur de l'élément\n    flicker = val; // on change notre variable \"flicker\" pour la remplacer par la valeur de notre gui\n    console.log(val)\n}\n```\nPeuven-être remplacées par une seul ligne : \n```javascript\nsettings.addBoolean(\"Check Me\", flicker, function(val){flicker=val});\n```\n\nOn écrit directement une fonction sans lui donner de nom, et on précise le code à éxecuter entre les accolades. C'est souvent moins fastidieu à écrire, mais plus pénible à débugger puisque généralement notre console se plaindra d'avoir eu une erreur dans une fonction anonyme sans réellement pouvoir nous dire laquelle et où exactement dans notre code...\n\n\nDans open processing, l'intégration de cette librairie externe est disponnible ici et peut-être généralisée à n'importe qu'elle librairie js pour peu qu'elle soit disponnible via CDN :\n\nhttps://www.openprocessing.org/sketch/403496\n\nCette intégration nécessite l'usage de la fonction **preload()** qui s'éxécute avant le setup(). Le principe est de créer un élément html et de définir une source et une fonction de rappel lorsque notre source est chargée. (merci @makio135 pour l'exemple !)\n\n```javascript\nvar settings // une variable pour stocker le panneau de controle\n\n// la fonction preload est executée avant le chargement de la page et donc avant le setup\n// ici on va l'utiliser pour charger la librairie quicksettings disponnible via CDN\n// et initialiser notre gui\nfunction preload(){\n\tvar script = document.createElement( 'script' ); // on crée un nouvel 'élément script'\n  \tscript.src = 'https://cdn.jsdelivr.net/quicksettings/latest/quicksettings.min.js'; // on ajoute en source la lib (lien cdn)\n  \t// on définit ce qu'on doit faire au chargement de la page via une fonction de rappel\n  \tscript.onload = function(){\n      \t// On initialise notre variable, on passe en argument la position du widget dans le canvas\n        // et le nom du groupe d'éléments gui que l'on veut créer.\n    \tsettings = QuickSettings.create(5, 50, \"GUI\");\n    \t// On ajoute un élément à ce widget qui est une boîte à cocher, on passe en argument, le nom\n    \t// de l'élément, sa valeur initiale, et le nom de la fonction de rappel, qu'il faut définir\n    \tsettings.addBoolean(\"Check Me\", flicker, eltChecked);\n      \t\n    }\n    document.body.appendChild( script );\n}\n\n// définition de la fonction de rappel pour l'élément gui intitulé \"check me\"\nfunction eltChecked(val) { // val correspond à la valeur de l'élément\n    flicker = val; // on change notre variable \"flicker\" pour la remplacer par la valeur de notre gui\n    console.log(val)\n}\n```\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n## Animer un mouvement\n\nIl existe de nombreuses façons d'animer des déplacements d'objet, nous allons ici voir différentes modes de déplacements relativement simples. Pour réaliser des choses plus complexes il est souvent intéressant de se tourner vers de implémentations de lois physiques et donc de manipuler des vitesses, des accélérations, des forces etc. Vous trouverez des liens dans les ressources notamment avec le livre et les cours de Daniel Shiffman autour du thème [Nature of Code](http://natureofcode.com/book/chapter-2-forces/).\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Balle dans une boite\n\nNous allons maintenant à l'animation autonome d'un déplacement comme par exemple un disque qui se déplace seul et rebondit sur les bords de nôtre canvas.\n\nPour cela nous allons avoir recours à l'utilisation de **variables**. Pour rappel les variables sont des emplacements en mémoire auxquels nous avons attribué une valeur (qui peut-être : un nombre, une chaîne de caractère, un tableau ...), le fait d'utiliser une variable nous permet, d'accèder à son contenu par son nom, mais aussi de modifier sa valeur.\n\nPar exemple ce petit bout de code permet de faire se déplacer un disque vers la droite. Il utilise deux variables *xpos* et *ypos* pour conserver en mémoire la position du disque. On peut alors incrémenter la position en abscisses dans le *draw()* de notre programme.\n\n```javascript\n// on définit des variables pour stocker la position de notre disque\nvar xpos \nvar ypos \n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(100);  \n  // on initialise nos variables\n  xpos = 0\n  ypos = windowHeight/2\n  \n} \n\nfunction draw() { \n  // on dessine notre disque à la position définie par nos variable\n  ellipse(xpos, ypos, 20, 20);\n  // on augmente la position en abscisses d'une unité\n  xpos = xpos + 1\n}\n```\n\nPrécédement nous écrivions *xpos = xpos + 1*, la valeur \"1\" correspond au nombre de pixels dont le disque va se déplacer à chaque image. Si nous voulons qu'il se déplace plus vite nous pouvons écrire *xpos = xpos + 5* et si nous voulons qu'il se déplace dans l'autre sens *xpos = xpos - 5*.\n\nNous pouvons maintenant modifier un peu notre programme pour lui donner un déplacement en diagonal et en faisant en sorte que notre disque rebondisse sur les bords du canvas. Pour cela nous allons avoir besoin de déclarer deux autres variable qui nous permettrons de donner une \"grandeur\" à la vitesse de déplacement en abscisses et en ordonnées. Et nous pourrons écrire des conditions à l'aide de **if** pour gérer les rebonds.\n\n\n```javascript\n// on définit des variables pour stocker la position de notre disque\nvar xpos \nvar ypos \n// on définit des variables pour stocker la vitesse de notre disque\nvar xspeed\nvar yspeed\n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(100);  \n  // on initialise nos variables\n  xpos = windowWidth/2\n  ypos = windowHeight/2\n  xspeed = 1\n  yspeed = 1\n  \n} \n\nfunction draw() {\n  \n  // on dessine notre disque à la position définie par nos variable\n  ellipse(xpos, ypos, 20, 20);\n  // on augmente la position en abscisses de xspeed unités\n  xpos = xpos + xspeed\n  // on augmente la position en ordonnée d'yspeed unités\n  ypos = ypos + yspeed\n\n  // on vérifie que l'on ne tappe pas le bord gauche ou le bord droit\n  if (xpos \u003c 0 || xpos \u003e windowWidth){\n    xspeed = xspeed * (-1) // si c'est le cas on inverse le sens de déplacement en abscisses\n  }\n  // on vérifie que l'on ne tappe pas le haut ou le bas \n  if (ypos \u003c 0 || ypos \u003e windowHeight){\n    yspeed = yspeed * (-1) // si c'est le cas on inverse le sens de déplacement en ordonnées\n  }\n}\n```\n\nLe seul problème qui nous reste est que notre balle part toujours dans le même sens à la même vitesse. Il pourrait être tentant d'utiliser la fonction **random()** ([doc](http://p5js.org/reference/#/p5/random)), mais cela nous condamne nécessairement à avoir des balles qui ne partent que dans un seul cadran (*random(1,5)*) ou risquer d'avoir une balle dont la vitesse est très (trop) proche de zéro (*random(-5,5)*). \n\nDans ce cas, généralement le plus simple et de passer par les coordonnées polaires pour initialiser la vitesse :\n\n```javascript\nxspeed = random(2,10)*cos(random(TWO_PI))\nyspeed = random(2,10)*sin(random(TWO_PI))\n```\n*random(2,10)* va correspondre au rayon (la distance au centre) et donc à la magnitude du vecteur de vitesse que l'on va définir soit la quantité de mouvement : est-ce que mon objet se déplace vite ou lentement.\n*random(TWO_PI)* correspond naturellement à l'angle, et va nous donner l'orientation.\n\n![balle dans une boite](assets/04_animation_balle.png)\n\nhttps://b2renger.github.io/Introduction_p5js/04_animation_01/index.html\n\nhttps://www.openprocessing.org/sketch/401282\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Suivre la souris\n\nPour présenter quelquechose d'un peu plus interactif, nous allons maintenant essayer de poser les bases de ce que l'on appelle le **easing** ou aussi le **tweening**. Le principe est simple il consiste à créer une animation pour passer d'un état A à un état B.\n\nDans notre cas nous voulons faire en sorte qu'un cercle suive la souris. Nous allons donc créer deux jeux de variables, un pour stocker la position cible et un pour stocker notre position actuelle.\n\n```javascript\nvar posX, posY\nvar targetX, targetY\n```\n\nPour effectuer notre animation nous allons nous baser sur la distance à parcourir pour atteindre notre cible. Ce qui est facilement calculable pour une coordonnée :\n\n```javascript\nvar distanceX = targetX - posX\nvar distanceY = targetY - posY\n```\n\nSi à chaque image nous ajoutons à notre position une petite fraction de cette distance nous finirons par atteindre notre cible\n\n```javascriptjavascript\nposX = posX + distanceX * 0.05\nposX = posY + distanceY * 0.05\n```\n\nLa valeur \"0.05\" par laquelle nous multiplions correspond à la petite fraction de distance que nous prenons, plus elle est grande plus l'animation sera rapide (voire même instantanée pour une valeur de 1).\n\nVoici l'intégralité du code :\n\n```javascript\nvar targetX, targetY;\nvar posX, posY;\n\nfunction setup() {\n  createCanvas(windowWidth, windowHeight); \n  background(100); \n  \n  posX = windowWidth/2\n  targetX = windowWidth /2\n\n  posY = windowHeight/2\n  targetY = windowHeight /2\n} \n\nfunction draw() {\n  \n  targetX = mouseX\n  targetY = mouseY\n  \n  posX += (targetX - posX) * 0.05\n  posY += (targetY- posY) * 0.05  \n\n  ellipse(posX, posY, 20, 20);\n}\n```\n\n![suivre la souris](assets/04_animation_souris.png)\n\nhttps://b2renger.github.io/Introduction_p5js/04_animation_02/index.html\n\nhttps://www.openprocessing.org/sketch/402030\n\nLe tweening et le easing sont des sujets relativement complexes, il existe des tas de façons d'interpoler les positions, couleurs etc. Ici plus la distance est grande plus notre objet va vite et plus on se rapproche de la cible plus le mouvement en lent : on appelle ça une animation \"ease out\".\n\n\nLors de la préparation de ce cours j'ai pu implémenter ce qui fait office de référence : les équations de [Robert Penner](http://robertpenner.com/easing/). Ces équations proposent différentes fonctions (cubiques, sinusoidales...) de \"easing\" avec à chaque fois un easing en entrée (\"ease in\"), un easing en sortie (\"ease out\") et un easing en entrée et sortie (\"ease in out\").\n\nDans cet exemple, le déplacement s'effectue avec un clic de la souris et vous pouvez choisir les différents types d'interpolations, ainsi que leurs vitesses d'éxecution.\n\n![suivre la souris](assets/04_animation_penner.png)\n\nhttps://b2renger.github.io/Introduction_p5js/04_animation_02_penner_position/index.html\n\nhttps://www.openprocessing.org/sketch/401812\n\nUn second exemple applique ces interpolation au rayon et à la couleur d'un cercle : \n\nhttps://b2renger.github.io/Introduction_p5js/04_animation_02_penner_radius_color/index.html\n\nIci le code est écrit avec des fonctions, ce qui rend un peu fastidieux l'implémentation de la possibilité de choisir pour deux actions (déplacement en x et déplacement en y) à chaque un type d'interpolation et une vitesse. Ce code est plutôt destiné à être copié/collé quand on sait quelle interpolation on veut. Pour laisser le choix et avoir une implémentation un peu plus élégante il serait intéressant d'écrire une classe.\n\n\nIl existe de nombreuses bibliothèques d'animation, [tween.js](https://github.com/tweenjs/tween.js/) semble en être une référence.\n\nLe sujet peut aussi être codé en css et s'appliquer à des éléments html : https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations\n\n\n[**home**](#Contenu)\u003cbr\u003e\n\n### Suivre la souris avec des forces\n\nComme mentionné plus haut il est aussi possible d'avoir recourt à la modélisation physique et donc à l'utilisation de forces. En physique il existe une relation particulière entre la position, la vitesse et l'accélération. La vitesse est la dérivée de la position, et l'accélération est la dérivée de la vitesse. \n\nEn programmation, et à un instant t on peut calculer la vitesse et la position d'un objet en fonction de son accélération qui est une force que l'objet subit.\nEn terme de code cela s'écrit comme cela :\n\n```javascript\nvitesse = vitesse + accélération\nposition = position + vitesse\n\n```\nL'accélération elle est calculée en fonction de forces en présence : généralement une force d'attraction ou de répulsion, mais aussi une force de friction qui s'oppose au déplacement. Cette force de friction permet notament d'arréter un objet progressivement si aucune force nouvelle ne s'applique à l'objet. C'est le calcul de cette accélération qui est l'étape la plus compliquée de ce genre de simulation.\n\n\n```javascript\nvar posX, posY // stocker la position de notre objet\nvar speedX, speedY // stocker sa vitesse\nvar friction = 0.05 // un force de friction pour faire ralentir les objets (résistance de l'air)\nvar force = 10 // une force d'attraction ou de répulsion en fonction du mode choisi\n\nfunction setup() {\n    createCanvas(windowWidth, windowHeight); \n    background(100); \n    \n    posX = windowWidth/2\n    speedX = random(0.5,2)*cos(random(TWO_PI))\n    \n    posY = windowHeight/2\n    speedY = random(0.5,2)*sin(random(TWO_PI))\n} \n\nfunction draw() {\n    // on utilise des vecteur pour stocker les positions, vitesses, cibles, cela facilite l'appel des fonctions de calcul\n    var vtarget = createVector(mouseX,mouseY)// un vecteur qui représente les coordonnées de notre cible.\n    var vpos = createVector(posX, posY) // un vecteur qui represente notre position\n    \n    // on ré-initialise l'accélération\n    var accX = 0\n    var accY = 0\n    // on calcule un force de friction : une résistance au mouvement, pour que notre objet s'arrête s'il n'est \n    // plus soumis à aucune force. Cette force doit être inversement proportionnelle au déplacement et donc à \n    // la vitesse pour ralentir l'objet en mouvement\n    var frict = createVector(speedX,speedY);\n    frict.normalize(); // cette opération ne permet de conserver que la direction du vecteur / l'orientation\n    frict.mult(-1) // on inverse le vecteur vitesse normalié pour qu'il soit opposé au déplacement\n    frict.mult(friction) // on multiplie par notre coefficient de friction\n    // on ajoute ce résultat à l'accélération que l'on va applique à notre objet\n    accX +=  frict.x;\n    accY +=  frict.y;\n\n    // déplacement : l'objet va être attiré par la souris \n    var dir = pos.sub(target); // on obtient le vecteur de déplacement : différence entre la position et la cible\n    var d = dir.mag(); // on calcul sa magnitude : la distance  qui sépare les deux points du vecteur\n    dir.normalize();\n    dir.mult(-1);\n    dir.div(1/d*d) // on fait en sorte que la force appliquée dépende de l'inverse du carré de la distance\n    dir.div(force) // on multiplie par la force souhaitée\n    // on ajoute cela à l'accélération\n    accX = accX+ dir.x;\n    accY = accY+ dir.y;\n    \n    // on ajoute l'accélération à la vitesse\n    speedX = speedX + accX\n    speedY = speedY + accY\n    \n    // on ajoute la vitesse à la position\n    posX = posX + speedX\n    posY = posY + speedY\n    \n    // on vérifie les collisions\n    if (posX \u003c 0 || posX \u003e windowWidth) speedX = speedX * (-1) \n    if (posY \u003c 0 || posY \u003e windowHeight) speedY = speedY * (-1)\n    \n    // on dessine notre cercle\n    ellipse(posX, posY, 20, 20);\n}\n```\n\nPour implémenter un comportement de répulsion, il suffit de remplacer :\n```javascript\ndir.mult(-1);\n```\npar :\n```javascript\ndir.mult(1);\n```\n\nAprès une petite remise en forme du code en utilisant une fonction pour l'attraction et une fonction pour la répulsion, ainsi qu'une légère interaction utilisateur pour passer d'un mode à l'autre on obtient le programme suivant :\n\n```javascript\n\nvar posX, posY // stocker la position de notre objet\nvar speedX, speedY // stocker sa vitesse\nvar friction = 0.05 // un force de friction pour faire ralentir les objets (résistance de l'air)\nvar force = 10 // une force d'attraction ou de répulsion en fonction du mode choisi\nvar attraction = true // choix du mode true =\u003e la souris attire la balle , false =\u003e la souris repousse la balle\n\nfunction setup() {\n    createCanvas(windowWidth, windowHeight); \n    background(100); \n    \n    posX = windowWidth/2\n    speedX = random(0.5,2)*cos(random(TWO_PI))\n    \n    posY = windowHeight/2\n    speedY = random(0.5,2)*sin(random(TWO_PI))\n    \n    textSize(14)\n    textAlign(CENTER, BOTTOM)\n} \n\nfunction draw() {\n    text(\"press ' a ' to attract the ball and ' r ' to repulse it\",windowWidth/2,windowHeight - 5)\n    \n    // on utilise des vecteur pour stocker les positions, vitesses, cibles, cela facilite l'appel des fonctions de calcul\n    var vtarget = createVector(mouseX,mouseY)// un vecteur qui représente les coordonnées de notre cible.\n    var vpos = createVector(posX, posY) // un vecteur qui represente notre position\n    \n    // en fonction du mode choi","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fb2renger%2Fintroduction_p5js","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fb2renger%2Fintroduction_p5js","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fb2renger%2Fintroduction_p5js/lists"}