Widgets simple et double jauges circulaires

Voici 2 widgets développés ce week-end en s’inspirant de @sartog et d’autres. Tout d’abord, voici une jauge circulaire dont les couleurs varient en fonction de la valeur. Il n’y a pas de fond, le widget est transparent:
image

Les valeurs min, max et unités sont celles indiquées dans la commande info/numeric.
Voici le code, fichier du type cmd.info.numeric.TOneCircle.html (version du 09 fevrier 2022):

<div class="cmd cmd-widget" data-type="info" data-subtype="numeric" data-template="default" data-cmd_id="#id#" data-cmd_uid="#uid#" data-version="#version#" data-eqLogic_id="#eqLogic_id#">
	<div class="title #hide_name#">
      	<span class="cmdName">#name_display#</span>
  	</div>
  	<div class="jauge#id#">
      	<div class="grille-valeur-unite#id#">
      		<span class="ligne"></span>
      	</div>
  	</div>
  	<template>
      <div>scale : 1 facteur de dimensionnement</div>
  	</template>
  	<script>
    	jeedom.cmd.update['#id#'] = function(_options){
      
      		// Initialisation des variables.
      		//
      		// Pour l'utilisation des "Paramètres optionnels widget" :
      		//    scale : taille du widget. 1 = 100%, inférieur à 1 on réduit la taille et supérieur à 1 on augmente la taille.
      		//

      		// Initialisation des constantes.
      		const scale = (is_numeric('#scale#')) ? parseFloat('#scale#') : 1;

      		// Initialisation des variables.
      		var valeur = _options.display_value;
      		var cmd = $('.cmd[data-cmd_id=#id#]');
          	var colorProgress;
          	var colorBgProgress;
          	var canvas;
          	var ratio = (valeur - #minValue#) / (#maxValue# - #minValue#);
          
          	// On ajuste les couleurs en fonction de valeur1
          	if (valeur < 15) {
              	colorProgress = "rgb(70,130,180)";		/* SteelBlue */
              	colorBgProgress = "rgb(175,238,238)";	/* PaleTurquoise */
            } else if (valeur < 18) {
              	colorProgress = "rgb(64,224,208)";		/* Turquoise */
              	colorBgProgress = "rgb(175,238,238)";	/* PaleTurquoise */
            } else if (valeur < 20) {
              	colorProgress = "rgb(20,205,50)";		/* LimeGreen */			
              	colorBgProgress = "rgb(152,251,152)";	/* PaleGreen */
            } else if (valeur < 23) {
              	colorProgress = "rgb(46,139,87)";		/* SeaGreen */
              	colorBgProgress = "rgb(152,251,152)";	/* PaleGreen */
            } else if (valeur < 28) {
              	colorProgress = "rgb(255,165,0)";		/* Orange */
              	colorBgProgress = "rgb(255,218,185)";	/* PeachPuff */
            } else if (valeur < 30) {
              	colorProgress = "rgb(255,99,71)";		/* Tomato */
              	colorBgProgress = "rgb(255,218,185)";	/* PeachPuff */
            } else if (valeur < 35) {
              	colorProgress = "rgb(255,0,0)";		/* Red */
              	colorBgProgress = "rgb(255,160,122)";	/* LightSalmon */
            } else {
              	colorProgress = "rgb(220,20,60)";		/* Crimson */
              	colorBgProgress = "rgb(255,160,122)";	/* LightSalmon */
            }

          	// On crée un canvas dans la div et on récupère son contexte
          	cmd.find('div.jauge#id# canvas').remove();
          	canvas = $('<canvas width="100px" height="100px"></canvas>');
          	cmd.find('div.jauge#id#').append(canvas);
			var ctx = canvas[0].getContext('2d');
          
          	/* On dessine le cercle en background */          	
            ctx.beginPath();
          	ctx.arc(50,50,44,0,2*Math.PI);
          	ctx.lineWidth = 8;
          	ctx.strokeStyle = colorBgProgress;
            ctx.stroke();
			ctx.closePath();
          
            // On dessine le cercle de la progression en fonction de valeur
            ctx.beginPath();
          	ctx.arc(50,50,44,-1/2 * Math.PI,ratio * 2*Math.PI - 1/2 * Math.PI);
          	ctx.lineWidth = 8;
          	ctx.strokeStyle = colorProgress;
            ctx.stroke();
			ctx.closePath();
          		                    
          	// On affiche la valeur avec son unité
          	cmd.find('.ligne').html(valeur + '<sup>' + '#unite#' + '</sup>');
          
      		// Scale.
      		cmd.find('div.jauge#id#').css('transform', 'scale(' + scale + ')');
    	}
    	jeedom.cmd.update['#id#']({display_value:'#state#'});
	</script>
	<style>
		div.jauge#id# {
  			margin: 0;
  			padding: 0;
  			width: 100px;
  			height: 100px;
  			position: relative;
  		}
  		div.jauge#id# canvas {
    		position: absolute;
    		top: 0; left: 0; right: 0; bottom: 0;
  		}
  		div.grille-valeur-unite#id# {
  			display: grid;
  			position : absolute;
  			top : 40px;
      		left: 10px;
  			height : 20px;
  			width : 80px;;
  			font-size: 18px;
  			font-weight: bold;
  			grid-template-columns : 100%;
  			grid-template-rows : auto;
		}
  		span.ligne {
      		grid-column: 1;
      		grid-row: 1;
      		align-self: center;
      		color: rgb(105,105,105);
  		}
	</style>
</div>

Pour paramétrer les ranges de valeurs et les couleurs, il suffit de personnaliser la série de 'if else if '.
Le seul paramètre optionnel est ‹ scale › qui détermine la taille du widget (par défaut 100x100px).

Deuxième widget, une double jauge qui fonctionne sur le même principe avec les couleurs qui changent en fonction de 2 valeurs. Exemple avec température et humidité :
image

Ce widget virtuel de type info/autre contient les 2 commandes à utiliser, séparées par une virgule, exemple :

Les paramètres optionnels sont nombreux car il faut indiquer: min, max et unité pour les 2 valeurs:
minValeur1, maxValeur1 et uniteValeur1 puis minValeur2, maxValeur2 et uniteValeur2:
image

Le paramètre scale donne un ratio de dimension, par défaut 1=100x100px.
Voici le code, à placer dans un fichier du type cmd.info.string.THTwoCircles.html (version du 09 février 2022):

<div class="cmd cmd-widget" data-type="info" data-subtype="string" data-template="default" data-cmd_id="#id#" data-cmd_uid="#uid#" data-version="#version#" data-eqLogic_id="#eqLogic_id#">
	<div class="title #hide_name#">
      <span class="cmdName">#name_display#</span>
  	</div>	
  	<div class="jauge#id#">
      	<div class="grille-valeur-unite#id#">
      		<span class="ligne1"></span>
      		<span class="ligne2"></span>
      	</div>
  	</div>
  	<template>
      <div>minValeur1 : 10 valeur minimum pour la jauge externe</div>
      <div>maxValeur1 : 40 valeur maximum pour la jauge externe</div>
      <div>uniteValeur1 : °C unité pour la première valeur</div>
      <div>minValeur2 : 0 valeur minimum pour la jauge interne</div>
      <div>maxValeur2 : 100 valeur maximum pour la jauge interne</div>
      <div>uniteValeur2 : % unité pour la deuxième valeur</div>
      <div>scale : 1 facteur de dimensionnement</div>
  	</template>
  	<script>
    	jeedom.cmd.update['#id#'] = function(_options){
      
      		// Initialisation des variables.
      		//
      		// Pour l'utilisation des "Paramètres optionnels widget" (conseillé), il faut impérativement utiliser ces libélés :
      		//    minValeur1 : la valeur minimal sur laquelle sera basée le calcul de pourcentage.
      		//    maxValeur1 : la valeur maximal sur laquelle sera basée le calcul de pourcentage. 
      		//    minValeur2 : idem que #minValeur1
      		//    maxValeur2 : idem que #maxValeur1
      		//    uniteValeur1 : L'unité qui sera affichée à côté de la 1ère valeur.
      		//    uniteValeur2 : L'unité qui sera affichée à côté de la 2nde valeur.
      		//    scale : taille du widget. 1 = 100%, inférieur à 1 on réduit la taille et supérieur à 1 on augmente la taille.
      		//

      		// Initialisation des constantes.
      		const minValeur1 = (is_numeric('#minValeur1#')) ? parseFloat('#minValeur1#') : 10;
      		const maxValeur1 = (is_numeric('#maxValeur1#')) ? parseFloat('#maxValeur1#') : 40;
      		const minValeur2 = (is_numeric('#minValeur2#')) ? parseFloat('#minValeur2#') : 0;
      		const maxValeur2 = (is_numeric('#maxValeur2#')) ? parseFloat('#maxValeur2#') : 100;
      		const uniteValeur1 = ('#uniteValeur1#' != '#' + 'uniteValeur1' + '#') ? '#uniteValeur1#' : '°C';
      		const uniteValeur2 = ('#uniteValeur2#' != '#' + 'uniteValeur2' + '#') ? '#uniteValeur2#' : '%';
      		const scale = (is_numeric('#scale#')) ? parseFloat('#scale#') : 1;

      		// Initialisation des variables.
      		var valeur = _options.display_value.split(',');
      		var cmd = $('.cmd[data-cmd_id=#id#]');
			var valeur1 = valeur[0];
          	var valeur2 = valeur[1];
          	var colorProgress1;
          	var colorBgProgress1;
          	var colorProgress2;
          	var colorBgProgress2;
          	var canvas;
          	var ratio1 = (valeur1 - minValeur1) / (maxValeur1 - minValeur1);
          	var ratio2 = (valeur2 - minValeur2) / (maxValeur2 - minValeur2);
          
          	// On ajuste les couleurs en fonction de valeur1
          	if (valeur1 < 15) {
              	colorProgress1 = "rgb(70,130,180)";		/* SteelBlue */
              	colorBgProgress1 = "rgb(175,238,238)";	/* PaleTurquoise */
            } else if (valeur1 < 18) {
              	colorProgress1 = "rgb(64,224,208)";		/* Turquoise */
              	colorBgProgress1 = "rgb(175,238,238)";	/* PaleTurquoise */
            } else if (valeur1 < 20) {
              	colorProgress1 = "rgb(20,205,50)";		/* LimeGreen */			
              	colorBgProgress1 = "rgb(152,251,152)";	/* PaleGreen */
            } else if (valeur1 < 23) {
              	colorProgress1 = "rgb(46,139,87)";		/* SeaGreen */
              	colorBgProgress1 = "rgb(152,251,152)";	/* PaleGreen */
            } else if (valeur1 < 28) {
              	colorProgress1 = "rgb(255,165,0)";		/* Orange */
              	colorBgProgress1 = "rgb(255,218,185)";	/* PeachPuff */
            } else if (valeur1 < 30) {
              	colorProgress1 = "rgb(255,99,71)";		/* Tomato */
              	colorBgProgress1 = "rgb(255,218,185)";	/* PeachPuff */
            } else if (valeur1 < 35) {
              	colorProgress1 = "rgb(255,0,0)";		/* Red */
              	colorBgProgress1 = "rgb(255,160,122)";	/* LightSalmon */
            } else {
              	colorProgress1 = "rgb(220,20,60)";		/* Crimson */
              	colorBgProgress1 = "rgb(255,160,122)";	/* LightSalmon */
            }

            // On ajuste les couleurs en fonction de valeur2
          	if (valeur2 < 40) {
              	colorProgress2 = "rgb(255,215,0)";		/* Gold */
              	colorBgProgress2 = "rgb(255,250,205)";	/* LemonChiffon */
            } else if (valeur2 < 60) {
              	colorProgress2 = "rgb(46,139,87)";		/* SeaGreen */
              	colorBgProgress2 = "rgb(152,251,152)";	/* PaleGreen */
            } else if (valeur2 < 75) {
              	colorProgress2 = "rgb(70,130,180)";		/* SteelBlue */
              	colorBgProgress2 = "rgb(175,238,238)";	/* PaleTurquoise */
            } else if (valeur2 < 90) {
              	colorProgress2 = "rgb(255,99,71)";		/* Tomato */
              	colorBgProgress2 = "rgb(255,218,185)";	/* PeachPuff */
            } else {
              	colorProgress2 = "rgb(255,0,0)";		/* Red */
              	colorBgProgress2 = "rgb(255,160,122)";	/* LightSalmon */
            }

          	// On crée un canvas dans la div et on récupère son contexte
          	cmd.find('div.jauge#id# canvas').remove();
          	canvas = $('<canvas width="100px" height="100px"></canvas>');
          	cmd.find('div.jauge#id#').append(canvas);
			var ctx = canvas[0].getContext('2d');
          
          	/* On dessine le cercle extérieur en background */          	
            ctx.beginPath();
          	ctx.arc(50,50,44,0,2*Math.PI);
          	ctx.lineWidth = 8;
          	ctx.strokeStyle = colorBgProgress1;
            ctx.stroke();
			ctx.closePath();
          
            // On dessine le cercle extérieur de la progression en fonction de valeur1 
            ctx.beginPath();
          	ctx.arc(50,50,44,-1/2 * Math.PI,ratio1 * 2*Math.PI - 1/2 * Math.PI);
          	ctx.lineWidth = 8;
          	ctx.strokeStyle = colorProgress1;
            ctx.stroke();
			ctx.closePath();
          		
          	// On dessine le cercle en background 
            ctx.beginPath();
          	ctx.arc(50,50,34,0,2*Math.PI);
          	ctx.lineWidth = 8;
          	ctx.strokeStyle = colorBgProgress2;
            ctx.stroke();
			ctx.closePath();
          
            // On dessine le cercle de la progression en fonction de valeur2 
            ctx.beginPath();
          	ctx.arc(50,50,34,-1/2 * Math.PI,ratio2 * 2*Math.PI - 1/2 * Math.PI);
          	ctx.lineWidth = 8;
          	ctx.strokeStyle = colorProgress2;
            ctx.stroke();
          	ctx.closePath();
          
          	// On ajoute un trait horizontal de séparation des valeurs
          	ctx.beginPath();
          	ctx.lineWidth = 1;
          	ctx.setLineDash([4,2]);
          	ctx.strokeStyle = "rgb(112,128,144)";
          	ctx.moveTo(22,50);
          	ctx.lineTo(80,50);
          	ctx.stroke();
          	ctx.closePath();
          
          	// On affiche les 2 valeurs avec leurs unités
          	cmd.find('.ligne1').html(valeur1 + '<sup>' + uniteValeur1 + '</sup>');
          	cmd.find('.ligne2').html(valeur2 + '<sup>' + uniteValeur2 + '</sup>');
          
      		// Scale.
      		cmd.find('div.jauge#id#').css('transform', 'scale(' + scale + ')');
    	}
    	jeedom.cmd.update['#id#']({display_value:'#state#'});
	</script>
	<style>
		div.jauge#id# {
  			margin: 0;
  			padding: 0;
  			width: 100px;
  			height: 100px;
  			position: relative;
  		}
  		div.jauge#id# canvas {
    		position: absolute;
    		top: 0; left: 0; right: 0; bottom: 0;
  		}
  		div.grille-valeur-unite#id# {
  			display: grid;
  			position : absolute;
  			top : 25px;
      		left: 25px;
  			height : 50px;
  			width : 50px;;
  			font-size: 14px;
  			font-weight: bold;
  			grid-template-columns : 100%;
  			grid-template-rows : auto;
		}
  		span.ligne1 {
      		grid-column: 1;
      		grid-row: 1;
      		align-self: center;
      		color: rgb(105,105,105);
  		}
		span.ligne2 {
      		grid-column: 1;
      		grid-row: 2;
      		align-self: center;
      		color: rgb(105,105,105);
  		}
	</style>
</div>

cdt

3 « J'aime »

Hello,

Merci pour le partage
Rajoute la balise template pour connaitre tes variables à rajouter c’est dans la doc https://doc.jeedom.com/fr_FR/dev/core4.2

Cordialement
Shun84

Ok je modifie les codes.
cdt

Bonsoir merci pour le partage.

Bien vu la solution du design des cercles via JS plutôt que CSS.
Beaucoup plus rapide à écrire et beaucoup plus simple à corriger que la gestion des polygon dans CSS.

Bonjour, j’ai ajouté ce matin un appel à ...remove() pour ne plus empiler les canvas dans la div. Il y a donc une version corrigée (en tête de ce post), désolé.
cdt

Bonjour,
Super sympa, merci pour le travail et partage.
Une question, même si la case afficher le nom est coché on n’a rien. Je veux l’utiliser dans un virtuel ou j’ai regroupé plusieurs capteurs maison, dans mon cas sans nom c’est pas lisible car je n’ai pas la pièce.

Possibilité soit d’afficher le nom jeedom soit de le gérer en paramètre optionnel ?
Bien cordialement

Ok je vais regarder cette histoire de nom.

Bonjour, j’ai ajouté les div+class « standardisé jeedom » pour afficher le nom de la commande. La mise à jour est disponible en tête de ce fil.
cdt

Bonjour @phil38 ,
j’ai du loupé un truc, je n’ai qu’un demi cercle, noir et blanc.
r3vs7y0wdV

Le code fourni tu l’as mis dans html/data/customTemplates/dashboard
Dans les paramètres de la commande T° tu dois sélectionner dans affichage du widget un truc du genre TOneCircle ou THTwoCircles en fonction du code que tu as choisis et sauvegarder