Lorsqu’on conçoit des éléments visuels animés il peut être intéressant de superposer des éléments graphiques animés individuellement. Les GRAPHICS sont des canavas virtuels, ils peuvent être affichés à l’écran ou pas. Ils peuvent apparaître comme un élément qui est devant un autre, ou faire l’objet d’une transformation (rotation, translation, ….) sans que le reste du canevas soit altéré. Ils fonctionnent un peu comme des calques. des feuilles de papier virtuelles. On peut avoir plusieurs « graphics » ou calques dans le même projet.
Dans cette brique j’explore la création de 6 objets GRAPHIC, tous placés sur un canevas blanc qui fait la taille de l’écran :
Le script complet, qui réutilise la fonction ajustImage(txt, ratio) définie dans dans l’article « p5.js Brique 1 : un canevas « responsive » n’a pas été modifiée. Elle sert à calculer la taille du premier rectangle gris, le GRAPHIC graf.
/****************************************************************
https://editor.p5js.org/Anne-Laure/sketches/I4K--pRHH
Dessiner des polygones à l'intérieur d'un rectangle qui s'ajustent à la taille du rectangle
Suite de https://editor.p5js.org/Anne-Laure/sketches/isSlIPoVn
****************************************************************/
// les caractéristiques du rectangle de base
var grafSize;
var grafPos;
var ratio = 16 / 9; // ratio du rectangle w = ratio * h
var graf ; // le GRAPHICS qui va porter tout
var offsetY = 50 ; // l'espace en hauteur dédié à autre chose
var drawLoop = true ; // arrêter la boucle draw
var polyG = [] ; // le rectangle et les 4 polygones
function setup() {
createCanvas(windowWidth, windowHeight);
grafSize = createVector(0, 0);
grafPos = createVector(0, 0);
}
function draw() {
if( drawLoop) {
background( 255) ;
/*** initialiser les GRAPHICS, calculer les tailles ***/
grafSize = ajustImage("sz", ratio);
graf = createGraphics(grafSize.x, grafSize.y + offsetY );
for (let i = 0; i <5; i++) {
// renderer les formes
polyG[i] = createGraphics(grafSize.x, grafSize.y );
}
grafPos = ajustImage("ps", ratio);
/*** créer les GRAPHICS ***/
// graf est le renderer principal, celui qui sera sauvegardé
graf.background( 220 ) ;
/* créer les formes polyG[i] */
// i = 0 un simple rectangle blanc
polyG[0].fill( 255 ) ;
polyG[0].rect(0,0,graf.width, graf.height) ;
// i = 1 à 4 des polygones plus compliqués
let ep = grafSize.x/20 ; // espace autour des rectangles
let w = grafSize.x/2 - 3 * ep/2 ;
let h = grafSize.y/2 - 3 * ep/2;
polyG[1].fill( 255, 0, 0 ) ;
polyG[1].rect(ep,ep,w, h) ;
polyG[2].fill( 0, 255, 0 ) ;
polyG[2].rect(w+2*ep,ep,w, h) ;
polyG[3].fill( 0, 0, 255 ) ;
polyG[3].rect(w+2*ep,h+2*ep,w,h) ;
polyG[4].fill( 155, 55, 0 ) ;
polyG[4].rect(ep,h+2*ep,w, h) ;
for (let i = 0; i < 5; i++) {
// afficher les polygones dans graf
graf.image( polyG[i], 0, 0) ;
}
// graf.stroke(0) ;
graf.fill(0) ;
graf.textSize(offsetY/3) ;
graf.text("Et voilà !", 10, grafSize.y + 25 ) ;
graf.ellipse(grafSize.x/8, grafSize.y/4, 20, 20 ) ;
image( graf, grafPos.x, grafPos.y ) ;
drawLoop = false ;
}
}
function ajustImage(txt, ratio) {
// RAPPEL ratio = 3/4 ; // ratio du rectangle que je veux dessiner w= 3 --> h = 4
let coeff = 0.95; // on veut que l'image ne représente que 95% du plus petit côté du canevas
let OffH = height - offsetY ; // laisser place pour texte)
let CanR = width / OffH;
print(txt, " Canevas W/H ", CanR);
let maxSize = createVector(0, 0);
let gPos = createVector(0, 0);
if (CanR >= 1) {
// la largeur est supérieure à la hauteur. C'est la hauteur qui nous limite
if ( OffH * coeff * ratio >= width * coeff ) {
// il faut que la hauteur soit réduite malgré tout
maxSize.y = width * coeff / ratio ;
} else {
// il faut que la largeur ne dépasse pas la largeur moins la bordure prévue
maxSize.y = OffH * coeff ;
}
maxSize.x = maxSize.y * ratio ;
} else {
// la hauteur est supérieure à la largeur. C'est la largeur qui nous limite
/* maxSize.x est le plus petit de
- la largeur du canevas * le coefficient d'occupation (pour avoir une bordure)
- la hauteur du dessin qui doit quand même respecter le ratio initial sans dépasser la hauteur du canevas
*/
if ( width * coeff / ratio >= OffH * coeff ) {
// il faut que la largeur soit réduite malgré tout
maxSize.x = OffH * coeff * ratio ;
} else {
// il faut que la largeur ne dépasse pas la largeur moins la bordure prévue
maxSize.x = width * coeff ;
}
maxSize.y = maxSize.x / ratio ;
}
maxSize.x = int(maxSize.x);
maxSize.y = int(maxSize.y);
gPos.x = (width - maxSize.x) / 2;
gPos.y = (OffH - maxSize.y) / 2;
if (txt == "sz") {
print(txt, "l canvas, l size, h canvas, h size ", width, maxSize.x, OffH, maxSize.y);
return maxSize;
} else if (txt == "ps") {
print(txt, "x, y totx toty", gPos.x, gPos.y, maxSize.x + 2 * gPos.x, maxSize.y + 2 * gPos.y);
return gPos;
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
// redessiner avec draw()
drawLoop = true ;
}
Et maintenant ?
Et voilà nous avons une deuxième brique ! Les autres briques sont et seront publiées dans cette même série, p5.js mes "briques" de connaissance. La prochaine étape sera de faire des polygones plus compliqués avec certains GRAPHIC. A suivre !
Pour mieux apprendre à coder des travaux numériques avec la librairie p5.js (processing en javascript), j’ai décidé de construire des briques successives. Aujourd’hui, la première brique, c’est d’être capable d’ajuster la taille du canevas en instantané à la taille de la fenêtre. C’est comme si on avait un canevas « responsive », allusion aux sites internet qui s’ajustent aux écrans utilisés.
Pour valider cette brique, j’ai décidé de dessiner un rectangle de rapport 16/9 qui occupe au maximum 95% de la dimensions la plus faible de l’écran. Ce rectangle doit donc respecter les règles suivantes :
son ratio largeur sur hauteur est en permanence de 16/9 : lorsque la largeur fait 16 la hauteur fait 9 ;
si la fenêtre est plus large que haute alors la hauteur du rectangle fait 95% de la hauteur de la fenêtre (et donc la largeur du rectangle représente 16/9 de cette hauteur) ;
si la fenêtre est plus haute que large alors la largeur du rectangle fait 95% de la largeur de la fenêtre (et donc la hauteur du rectangle représente 9/16 de cette largeur) ;
/****************************************************************
https://editor.p5js.org/Anne-Laure/sketches/isSlIPoVn
Dessiner un rectangle qui prend 95% de la hauteur ou largeur d'écran et se centre
****************************************************************/
var grafSize;
var grafPos;
var ratio = 16 / 9; // ratio du rectangle que je veux dessiner w = ratio * h
var drawLoop = true ; // arrêter la boucle draw
function setup() {
createCanvas(windowWidth, windowHeight);
colorMode(HSB, 360, 100, 100, 100);
grafSize = createVector(0, 0);
grafPos = createVector(0, 0);
}
function draw() {
if( drawLoop) {
background(95) ;
let col = random(100) ; // couleur
grafSize = ajustImage("sz", ratio);
grafPos = ajustImage("ps", ratio);
fill( col, 80, 80, 100 ) ;
rect(grafPos.x, grafPos.y, grafSize.x, grafSize.y);
drawLoop = false ;
}
}
function ajustImage(txt, ratio) {
// RAPPEL ratio = 3/4 ; // ratio du rectangle que je veux dessiner w= 3 --> h = 4
let coeff = 0.95; // on veut que l'image ne représente que 95% du plus petit côté du canevas
let CanR = width / height;
print(txt, " Canevas W/H ", CanR);
let maxSize = createVector(0, 0);
let gPos = createVector(0, 0);
if (CanR >= 1) {
// la largeur est supérieure à la hauteur. C'est la hauteur qui nous limite
if ( height * coeff * ratio >= width * coeff ) {
// il faut que la hauteur soit réduite malgré tout
maxSize.y = width * coeff / ratio ;
} else {
// il faut que la largeur ne dépasse pas la largeur moins la bordure prévue
maxSize.y = height * coeff ;
}
maxSize.x = maxSize.y * ratio ;
} else {
// la hauteur est supérieure à la largeur. C'est la largeur qui nous limite
/* maxSize.x est le plus petit de
- la largeur du canevas * le coefficient d'occupation (pour avoir une bordure)
- la hauteur du dessin qui doit quand même respecter le ratio initial sans dépasser la hauteur du canevas
*/
if ( width * coeff / ratio >= height * coeff ) {
// il faut que la largeur soit réduite malgré tout
maxSize.x = height * coeff * ratio ;
} else {
// il faut que la largeur ne dépasse pas la largeur moins la bordure prévue
maxSize.x = width * coeff ;
}
maxSize.y = maxSize.x / ratio ;
}
maxSize.x = int(maxSize.x);
maxSize.y = int(maxSize.y);
gPos.x = (width - maxSize.x) / 2;
gPos.y = (height - maxSize.y) / 2;
if (txt == "sz") {
print(txt, "l canvas, l size, h canvas, h size ", width, maxSize.x, height, maxSize.y);
return maxSize;
} else if (txt == "ps") {
print(txt, "x, y totx toty", gPos.x, gPos.y, maxSize.x + 2 * gPos.x, maxSize.y + 2 * gPos.y);
return gPos;
}
}
function windowResized() {
resizeCanvas(windowWidth, windowHeight);
// redessiner avec draw()
drawLoop = true ;
}
Dans le sketch ci-dessus, il y a deux fonctions intéressantes :
function windowResized() qui est une fonction p5.js qui s’exécute automatiquement dès que l’on modifie la taille de la fenêtre active. A l’intérieur j’indique qu’il faut retailler le canevas à la taille de la fenêtre et que la variable drawLoop est repassée à true. Ca signifie que la fonction draw redessinera le contenu du canevas.
function ajustImage(txt, ratio) que j’ai créée pour calculer la taille du rectangle contenant l’image à afficher. C’est cette fonction qui fait que le rectangle affiché a des dimensions qui respectent les règles exposées.
Mes Raspberry Pi sont « headless », c’est à dire sans écran, clavier et souris dédiés. Je m’y connecte en SSH à partir de mon PC (Windows) par le réseau local. Jusqu’à présent, je n’ai pas eu besoin de l’interface graphique et j’étais contente de la ligne de commande Linux, qui m’a permis d’apprendre énormément.
Mais maintenant je voudrais utiliser un Raspberry Pi pour des projets d’art numérique. Il va donc falloir que ce soit le Pi lui même, en autonomie, qui gère l’affichage sur un écran. J’avais exploré une solution avec VNC voici quelques années mais je ne m’en suis jamais vraiment servie. Et en lisant un article externe sur node.js, « Beginner’s Guide to Installing Node.js on a Raspberry Pi« , j’ai vu cette solution pour accéder à l’interface graphique du Pi de manière HeadLess. C’est celle solution que je teste et que je présente ici.
La situation initiale
J’ai un Raspberry Pi B3+ connecté « headless » par cable ethernet et en wifi sur mon réseau locale. Je l’ai préparé comme je l’expliquedans les articles suivants :
Le Raspberry Pi contient RealVNC depuis plusieurs années maintenant. Il ne m’enthousiasmait pas et semble ne pas être optimal pour des fonctionnements headless. Je vais donc installer tightVNC comme recommandé dans « Beginner’s Guide to Installing Node.js on a Raspberry Pi« .
Désactivation de VNC avec Raspi-config
J’ai désactivé VNC pour l’utilisateur al dans Raspi-config : choix 5 interfacing Options puis P3 Enable / disable VNC avec réponse NO (I don’t want it enabled). VNC est désactivé.
Installation de tightVNC et xRDP
Je me perds dans les protocoles de contrôle des sessions distantes. Ici nous allons installer tightVNC, un serveur VNC (Virtual Network Computing) auquel on se connecte avec une “connexion Bureau à distance” utilisant le protocole RDP (Remote Desktop Protocol) géré par xRDP, serveur RDP.
J’installe le serveur tightvnc avec la commande apt install -y tightvncserver. Seulement après j’installe le serveur xRDP avec la commande apt install -y xrdp.
En principe RealVNC qui était installés sur le Pi a été supprimé.
Accès à partir de la machine Windows
Dans notre machine Windows, nous pouvons accéder au Pi par son « hostname » puisque Samba a été installé et paramétré sur le Pi. Donc dans la machine Windows, je tape sur la touche Windows et je cherche « connexion Bureau à distance » (dans les accessoires windows). cliquer dessus.
Indiquer le nom du Pi (son hostname) dans la boîte de dialogue puis cliquer sur connexion
Pour se connecter au bureau à distance d’un Raspberry Pi – etape 1
Ensuite, on accepte de ne pas vérifier l’identité de l’ordinateur distant.
Pour se connecter au bureau à distance d’un Raspberry Pi – etape 2Pour se connecter au bureau à distance d’un Raspberry Pi – etape 3
Aller dans l’onglet Display et régler sur plein écran si nécessaire. Cliquer sur Connexion
Et enfin, on est dans le bureau du Raspberry Pi et on indique le nom d’utilisateur et le mot de passe de l’utilisateur Raspberry Pi qui se connecte.
Identification de l’utilisateur Raspberry Pi. A ce stade la fenêtre du bureau distant est générée par le Pi.
Et ça y est, je suis connectée à distance à mon Raspberry Pi en mode graphique !
Mon bureau à distance sur un Raspberry Pi !
Et maintenant j’enregistre dans ma machine Windows la connexion Bureau à distance sur le bureau Windows sous le nom Pi PI-ArtNum-01.rdp. Maintenant je double clique dessus, l’indique mon nom d’utilisateur et mon mot de passe et ça y est.
Et maintenant ?
Que vais-je bien pouvoir faire de ça ? Je ne sais pas encore !
Si vous avez des idées, partagez-les avec nous en commentaires.
Un Raspberry Pi sous Raspbian n’existe pas sur un reseau pour un ordinateur Windows, sauf en tant qu’adresse IP.
Par exemple un appareil « PI-ArtNum-01 » sous Raspbian connecté au réseau local avec l’adresse IP 192.168.1.114 sera visible en tapant ping 192.168.1.114 dans l’invite de commande Windows mais pas ping PI-ArtNum-01. Du moins pas tant qu’on aura pas installé samba sur le Pi et défini le workgroup comme indiqué dans cet article « Mise en service d’un Raspberry Pi« .
Et même lorsque Windows trouvera le pi par son « hostname », il n’y aura pas moyen d’échanger des fichiers tant qu’on n’aura pas défini un espace partagé avec Samba. C’est ce que nous allons faire dans cet article.
Qu’est-ce que Samba ?
Samba permet le partage de fichiers sur un réseau local. Il facilite le réglage des droits d’accès selon cet article de linuxConfig.org, en anglais qui sera intéressant pour aller plus loin.
l’état initial
Mon Raspberry Pi (un Pi 3 B+) est connecté à mon réseau local. Il porte le nom (hostname défini avec Raspi-config) « ArtNum-01 ». Samba a été installé en même temps que d’autres éléments de notre Pi puisque j’ai suivi mon tutoriel « Mise en service d’un Raspberry« . A ce stade, si je tape \\PI-ArtNum-01 dans l’explorateur Windows, le Pi apparaît dans les éléments réseau. Par contre il est « vide » pour Windows
Pas possible d’accéder au contenu du Pi à partir de l’explorateur Windows
Définir un répertoire partagé avec Samba
Pour définir un espace partagé avec Samba sur le Pi, on va éditer /etc/samba/smb.conf et y copier et coller (shift + inser avec l’éditeur MC) tout en bas le contenu qui suit :
Raspbian va redémarrer automatiquement Samba lorsqu’on sauvegarde le fichier de configuration.
Ensuite dans l’invite de commande du Raspberry Pi, on va créer un utilisateur et un mot de passe pour ce répertoire partagé.
smbpasswd -a al
On tape deux fois le mot de passe choisi. On le note soigneusement !
Sur une machine Windows du même réseau local, je vois maintenant le répertoire PiShare de PI-ArtNum-01. Si je double-clique dessus, Windows me demande le nom d’utilisateur et le mot de passe. Si vous les renseignez, vous avez maintenant accès (deux fois bizarrement) aux fichiers du Raspberry Pi :
Accès au répertoire partagé ( le même sous ses deux noms…)
Si je le souhaite, je peux également « connecter un lecteur réseau », ce qui revient à disposer du répertoire partagé sur une machine Windows comme s’il était sur un disque Windows
Je clique à droite sur Réseau dans la liste des répertoires de l’explorateur Windows et je choisis « connecter un lecteur réseau » (en anglais c’est « Map network drive » qui est probablement plus juste)
Dans la fenêtre qui s’ouvre je choisis d’affecter la lettre M au répertoire partagé de ce Pi (\\PI-ArtNum-01\PiShare).
connecter un répertoire partagé d’un Raspberry Pi comme un lecteur réseau
Et voilà ce PiShare apparaît comme un répertoire local.
Par contre comme je me suis déjà connectée en donnant le mot de passe, Windows ne me demande pas de fournir mon nom d’utilisateur et mon mot de passe. Lorsque je redémarre windows et que je recommence cette connexion :
saisie du nom d’utilisateur et du mot de passe d’un répertoire partagé par Samba
Et maintenant ?
Je vais pouvoir facilement placer des scripts p5.js pour des projets d’art numérique sur ce Pi.
Je veux installer node.js sur un Raspberry Pi car je voudrais disposer d’un serveur capable de diffuser des travaux d’art numérique (qui utilisent du javascript et la bibliothèque p5.js). C’est aussi une installation qui me servira à tester différents capteurs connectés à un Raspberry Pi pour des projets de domotique. J’en parlerai dans les prochains articles de cette série, .
Dans cet article je vais me concentrer sur l’installation de node.js. Je parlerai plus tard d’expériences que je réaliserai ensuite en art numérique ou domotique.
Préparer un Raspberry Pi avec Raspbian
Je dispose d’un Raspberry Pi 3 B+ qui fonctionnait sous Raspbian Stretch lite. J’y ai installé Raspbian Buster « with desktop and recommanded software ». C’est possible sous réserve d’avoir une carte SD de 8 Go au moins (avec 4Go, la carte est occupée à 85% dès l’installation de Raspbian).
L’installation a été réalisée sur la base de mon article « Mise en service d’un Raspberry Pi« . Le Pi est connecté en ethernet mais dispose aussi d’une connexion wifi. Son nom est Pi-ArtNum-01.
Qu’est-ce que node.js (et npm)
Je ne suis pas une experte, ce que je dis doit être pris avec des pincettes ! Ma source principale a été cette page de OpenClassRoom et aussi cet article, beaucoup plus concret mais en anglais. Node.js est un moyen de faire du JavaScript en dehors du navigateur, par exemple pour générer des pages web. Node.js est open source et compatible avec la plupart des plateforme.
et node.js est inséparable de npm le système de gestion de paquets de node.js. Ce que je comprends c’est que c’est le système qui gère les « extensions » de node.js.
et NodeRed ???
Pour savoir à quoi sert nodered, voir cet article de projetdiy.fr. nodeRED est une application reposant sur Node.js qui permet de programmer graphiquement des composants dans un environnement Web (source cet article de blog.ippon.fr). Pour l’instant nous ne nous y intéresserons pas, même s’il est déjà installé sur notre Raspberry Pi (essayez de taper node-red -v dans l’invite de commande).
Installation d’une version récente de node.js
Je vais avoir besoin des dernières versions de node.js et npm. Commençons par déterminer si j’ai ces programmes et dans quelle version avec les commandes node -v et npm -v.
Le dézipper puis le placer dans le répertoire home/al/ Hello_P5_drawing_2020_04_12_07_55_16 avec filezilla. Et maintenant regardons quel est son chemin exact sur le Pi :
cd /home/al
cd p5jsFiles
cd Hello_P5_drawing_2020_04_12_07_55_16
ls
Nota si j’étais entrée comme al, cd ~ ou seulement cd m’enverrait directmeent sur /home/al
Maintenant lancer le serveur http avec http-server, en étant dans le répertoire du script précédent
Dans un navigateur internet je peux en principe accéder au serveur avec l’une des trois adresses HTTP proposées. Dans mon cas je suis en accès distant (SSH) et la première adresse ne fonctionne pas. Par contre les deux autres adresses sont celles du Pi (en connexion ethernet et en connexion wifi). Si je tape http://192.168.1.100:8080, j’ai un message d’erreur d’abord et lorsque je recommence, mon canevas apparaît à l’écran du navigateur tandis que divers message apparaissent dans la console pi !
Le canevas d’un script p5.js apparaît dans mon navigateur. La console vers le Pi affiche plein de messages !
Et si je bouge ma souris dans le canevas, le script Hello P5 drawing fonctionne !
Je bouge la souris sur mon écran d’ordinateur et le Raspberry Pi donne l’ordre de tracer des traits en fonction de mes mouvements !
Donc ca y est j’ai réussi à servir des fichiers p5.js sur mon pi.
Autres utilisations possibles de node.js sur mon raspberry pi
Si je veux disposer de plusieurs serveurs (plusieurs nodes ou processus), il va falloir trouver un système qui permet de lancer simultanément des serveurs http sur plusieurs ports distincts. C’est ce que font les auteurs des articles suivants :
Je ne sais pas encore ce que je veux faire. Mon souhait est de pouvoir brancher un Pi à une télévision et le laisser tout seul pour exposer des travaux numériques. Et ensuite, je pourrai y connecter des capteurs divers pour que les scripts interagissent avec les visiteurs ou le contexte. A suivre donc dans la série !
Commentaires récents