Bonjour à tous,
Je vous propose de partager ce widget qui permet d’afficher une valeur numérique avec un formatage graphique différent suivant des valeurs limites de test.
Exemple :
afficher en vert une valeur entre 20 et 30°C, en bleu si < 20 et en rouge si >30°C
J’ai ajouté quelques effets pour attirer l’oeil…
Les effets, les limites et bien d’autres éléments comme la police sont paramétrables…
A vous de jouer avec si cela vous intéresse
un exemple avec des sur une valeur entre -100 et 100 et des limites de test entre -50 et 50.
Je prend toutes les remarques, corrections, optimisations etc…
<!--
Maj: 17/02/2025
_GenericValueDisplay
@Silkarion avec l'aide de @noodom pour l'ajout des polices :)
Version 1.0 : Création
-->
<template>
<div>*************************************</div>
<div>Ce widget permet de gérer l'affichage d'un numérique dans une tuile </div>
<div>suivant 3 états associés à 2 limites (basse et haute) </div>
<div></div>
<div>Min/---State0---/ValueMinTest/---State1---/ValueMaxTest/---State2---/max</div>
<div></div>
<div>Pour ne pas activer une des limite, ne pas la renseigner...</div>
<div>Affiche jusque 2 décimales après la virgule</div>
<div></div>
<div>** Parametres de forme **</div>
<div>SizeWidth : largeur du widget en px (défaut : 100px)</div>
<div>SizeHeight : hauteur du widget en px (défaut : 30px)</div>
<div>Radius1 : arrondi 1 en px ou % (défaut : 50%)</div>
<div>Radius2 : arrondi 2 en px ou % (défaut : Radius1)</div>
<div>Radius3 : arrondi 2 en px ou % (défaut : Radius1)</div>
<div>Radius4 : arrondi 2 en px ou % (défaut : Radius1)</div>
<div>NoBorder : 1 > suppression de la bordure (défaut : 0)</div>
<div></div>
<div>** Parametres de test **</div>
<div>ValueMinTest : valeur de sanction basse (defaut #min#)</div>
<div>ValueMaxTest : valeur de sanction haute (defaut #max#)</div>
<div>Si #min# ou #max# non renseigné ni le paramètre de test, le test associé n'est pas actif, </div>
<div></div>
<div>** Parametres de texte **</div>
<div>FontRatio : ratio de la taille du texte</div>
<div>UnitRatio : ratio de la taille des unités versus texte (defaut : 1.0)</div>
<div>FontName : fonte du libellé (`fonte`, `fonte.ttf`, `data/fonts/fonte.ttf`)</div>
<div>FontColorState0 : Couleur du texte pour le state 0 (default : contrasté si couleur format #xxxxxx ; blanc sinon)</div>
<div>FontColorState1 : Couleur du texte pour le state 1 (default : contrasté si couleur format #xxxxxx ; blanc sinon)</div>
<div>FontColorState2 : Couleur du texte pour le state 2 (default : contrasté si couleur format #xxxxxx ; blanc sinon)</div>
<div></div>
<div>** Parametres de couleur **</div>
<div>Color1State0 : Couleur du fond pour le state 0 (default : red)</div>
<div>Color1State1 : Couleur du fond pour le state 1 (default : green)</div>
<div>Color1State2 : Couleur du fond pour le state 2 (default : red)</div>
<div>Color2State0 : Couleur du dégradé pour le state 0 (default : black)</div>
<div>Color2State1 : Couleur du dégradé pour le state 1 (default : black)</div>
<div>Color2State2 : Couleur du dégradé pour le state 2 (default : black)</div>
<div>ColorRotation : rotation en degres du dégradé de couleur (défaut : 0deg)</div>
<div>Tips: #00000000 pour un fond transparent!</div>
<div></div>
<div>** Parametres d'effet **</div>
<div>Effect0 : Effet pour le state 0 (default : 0)</div>
<div>Effect1 : Effet pour le state 1 (default : 0)</div>
<div>Effect2 : Effet pour le state 2 (default : 0)</div>
<div> effet = 0 >> pas d'effets</div>
<div> effet = 1 >> souffle </div>
<div> effet = 2 >> zoom </div>
<div> effet = 3 >> clignottement </div>
<div> effet = 4 >> vibrations </div>
<div> effet = 5 >> sonnerie </div>
<div></div>
</template>
<div class="cmd cmd-widget tooltips #history#" data-type="info" data-subtype="numeric" data-cmd_id="#id#" data-cmd_uid="#uid#" data-version="#version#" data-eqLogic_id="#eqLogic_id#">
<div class="title #hide_name#">
<div class="cmdName">#name_display#</div>
</div>
<div id="data_display#uid#" class="content-lg">
<div id="value_content#uid#">
<div id="data_value#uid#"></div>
<div id="data_unit#uid#">#unite#</div>
<div id="value_border#uid#"></div>
</div>
</div>
<div class="cmdStats #hide_history#">
<span title='{{Min}}' class='tooltips'>#minHistoryValue#</span>|<span title='{{Moyenne}}' class='tooltips'>#averageHistoryValue#</span>|<span title='{{Max}}' class='tooltips'>#maxHistoryValue#</span> <i class="#tendance#"></i>
</div>
<span class="timeCmd label label-default" data-type="info"></span>
<script>
jeedom.cmd.update['#id#'] = function(_options){
function getRandomColor#id#() {
return `#${Math.floor(Math.random() * 16777215).toString(16).padStart(6, '0')}`;
}
function getContrastingTextColor#id#(bgColor) {
// Convertit la couleur hex en RGB
const r = parseInt(bgColor.substring(1, 3), 16);
const g = parseInt(bgColor.substring(3, 5), 16);
const b = parseInt(bgColor.substring(5, 7), 16);
const brightness = (r * 299 + g * 587 + b * 114) / 1000;
return brightness > 128 ? "black" : "white";
}
var bgColor#id# = getRandomColor#id#();
var textColor#id# = getContrastingTextColor#id#(bgColor#id#);
function sendJeedomCommand#id#(cmdId) {
jeedom.cmd.execute({id: cmdId});
}
function getJsonFilePath(fileName, extension) {
const basePath = "data/fonts/";
if (!fileName.includes(".")) {
fileName += `.${extension}`;
}
const ext = fileName.split('.').pop().toLowerCase();
if (ext !== `${extension}`) {
throw new Error("Seuls les fichiers ttf sont acceptés.");
}
if (!fileName.includes("/")) {
fileName = basePath + fileName;
}
return fileName;
}
function loadCustomFont(fontPath) {
const filePath = getJsonFilePath(fontPath, 'ttf');
let fontName = filePath.split(/[/\\]/).pop();
fontName = fontName.split('.').slice(0, -1).join('.');
let styleTag = document.getElementById("style#id#");
styleTag.innerHTML += `
@font-face {
font-family: '${fontName}';
src: url('${filePath}') format('truetype');
font-weight: normal;
font-style: normal;
}
`;
document.documentElement.style.setProperty("--tile-label-font-family#id#", `'${fontName}'`);
}
var cmd = $('.cmd[data-cmd_id=#id#]');
var val#uid# = is_float(parseFloat(_options.display_value)) ? parseFloat(_options.display_value).toFixed(2) : parseInt(_options.display_value);
var sizeWidth#uid# = ('#SizeWidth#' != '#'+'SizeWidth#') ? "#SizeWidth#" : "100px";
if (sizeWidth#uid# != '') {
document.documentElement.style.setProperty('--element-sizeWidth#uid#', sizeWidth#uid#);
} else {
document.documentElement.style.setProperty('--element-sizeWidth#uid#', "100px");
}
var sizeHeight#uid# = ('#SizeHeight#' != '#'+'SizeHeight#') ? "#SizeHeight#" : "30px";
if (sizeHeight#uid# != '') {
document.documentElement.style.setProperty('--element-sizeHeight#uid#', sizeHeight#uid#);
} else {
document.documentElement.style.setProperty('--element-sizeHeight#uid#', "30px");
}
var radius1#uid# = ('#Radius1#' != '#'+'Radius1#') ? "#Radius1#" : "15px";
if (radius1#uid# != '') {
document.documentElement.style.setProperty('--radius1#uid#', radius1#uid#);
} else {
document.documentElement.style.setProperty('--radius1#uid#', "15px");
}
var radius2#uid# = ('#Radius2#' != '#'+'Radius2#') ? "#Radius2#" : radius1#uid#;
if (radius2#uid# != '') {
document.documentElement.style.setProperty('--radius2#uid#', radius2#uid#);
} else {
document.documentElement.style.setProperty('--radius2#uid#', radius1#uid#);
}
var radius3#uid# = ('#Radius3#' != '#'+'Radius3#') ? "#Radius3#" : radius1#uid#;
if (radius3#uid# != '') {
document.documentElement.style.setProperty('--radius3#uid#', radius3#uid#);
} else {
document.documentElement.style.setProperty('--radius3#uid#', radius1#uid#);
}
var radius4#uid# = ('#Radius4#' != '#'+'Radius4#') ? "#Radius4#" : radius1#uid#;
if (radius4#uid# != '') {
document.documentElement.style.setProperty('--radius4#uid#', radius4#uid#);
} else {
document.documentElement.style.setProperty('--radius4#uid#', radius1#uid#);
}
//Récupération des valeurs min max de l'item
const ValMin#uid# = ('#minValue#id#' !='#'+'minValue#id#') ? parseFloat('#minValue#id#') : val#uid#;
const ValMax#uid# = ('#maxValue#id#' !='#'+'maxValue#id#') ? parseFloat('#maxValue#id#') : val#uid#;
//Définition des min max de test
var ValueMinTest#uid# = (is_numeric('#ValueMinTest#')) ? parseFloat('#ValueMinTest#') : ValMin#uid#;
var ValueMaxTest#uid# = (is_numeric('#ValueMaxTest#')) ? parseFloat('#ValueMaxTest#') : ValMax#uid#;
var fontRatio#uid# = (is_numeric('#FontRatio#')) ? parseFloat('#FontRatio#') : 1.0;
document.documentElement.style.setProperty('--fontRatio#uid#', fontRatio#uid#);
var unitRatio#uid# = (is_numeric('#UnitRatio#')) ? parseFloat('#UnitRatio#') : 1.0;
document.documentElement.style.setProperty('--unitRatio#uid#', unitRatio#uid#);
var color1State0#uid# = ('#Color1State0#' != '#'+'Color1State0#') ? "#Color1State0#" : "red";
if (color1State0#uid# != '') {
document.documentElement.style.setProperty('--color1State0#uid#', color1State0#uid#);
} else {
document.documentElement.style.setProperty('--color1State0#uid#', "red");
}
var color2State0#uid# = ('#Color2State0#' != '#'+'Color2State0#') ? "#Color2State0#" : color1State0#uid#;
if (color2State0#uid# != '') {
document.documentElement.style.setProperty('--color2State0#uid#', color2State0#uid#);
} else {
document.documentElement.style.setProperty('--color2State0#uid#', color1State0#uid#);
}
var fontColorState0#uid# = ('#FontColorState0#' != '#'+'FontColorState0#') ? "#FontColorState0#" : getContrastingTextColor#id#(color1State0#uid#);
if (fontColorState0#uid# != '') {
document.documentElement.style.setProperty('--fontColorState0#uid#', fontColorState0#uid#);
} else {
document.documentElement.style.setProperty('--fontColorState0#uid#', getContrastingTextColor#id#(color1State0#uid#));
}
var color1State1#uid# = ('#Color1State1#' != '#'+'Color1State1#') ? "#Color1State1#" : "green";
if (color1State1#uid# != '') {
document.documentElement.style.setProperty('--color1State1#uid#', color1State1#uid#);
} else {
document.documentElement.style.setProperty('--color1State1#uid#', "green");
}
var color1State2#uid# = ('#Color1State2#' != '#'+'Color1State2#') ? "#Color1State2#" : "red";
if (color1State2#uid# != '') {
document.documentElement.style.setProperty('--color1State2#uid#', color1State2#uid#);
} else {
document.documentElement.style.setProperty('--color1State2#uid#', "red");
color1State2#uid# = "red";
}
var color2State1#uid# = ('#Color2State1#' != '#'+'Color2State1#') ? "#Color2State1#" : color1State1#uid#;
if (color2State1#uid# != '') {
document.documentElement.style.setProperty('--color2State1#uid#', color2State1#uid#);
} else {
document.documentElement.style.setProperty('--color2State1#uid#', color1State1#uid#);
}
var color2State2#uid# = ('#Color2State2#' != '#'+'Color2State2#') ? "#Color2State2#" : color1State2#uid#;
if (color2State2#uid# != '') {
document.documentElement.style.setProperty('--color2State2#uid#', color2State2#uid#);
} else {
document.documentElement.style.setProperty('--color2State2#uid#', color1State2#uid#);
}
var colorRotation#uid# = ('#ColorRotation#' != '#'+'ColorRotation#') ? "#ColorRotation#" : "0deg";
if (colorRotation#uid# != '') {
document.documentElement.style.setProperty('--colorRotation#uid#', colorRotation#uid#);
} else {
document.documentElement.style.setProperty('--colorRotation#uid#', "0deg");
}
var fontName#uid# = ('#FontName#' != '#'+'FontName#') ? "#FontName#" : '';
if (fontName#uid# != '') {
loadCustomFont(fontName#uid#);
}
var fontColorState1#uid# = ('#FontColorState1#' != '#'+'FontColorState1#') ? "#FontColorState1#" : getContrastingTextColor#id#(color1State1#uid#);
if (fontColorState1#uid# != '') {
document.documentElement.style.setProperty('--fontColorState1#uid#', fontColorState1#uid#);
} else {
document.documentElement.style.setProperty('--fontColorState1#uid#', getContrastingTextColor#id#(color1State1#uid#));
}
var fontColorState2#uid# = ('#FontColorState2#' != '#'+'FontColorState2#') ? "#FontColorState2#" : getContrastingTextColor#id#(color1State2#uid#);
if (fontColorState2#uid# != '') {
document.documentElement.style.setProperty('--fontColorState2#uid#', fontColorState2#uid#);
} else {
document.documentElement.style.setProperty('--fontColorState2#uid#', getContrastingTextColor#id#(color1State2#uid#));
}
var effect0#uid# = ('#Effect0#' !='#'+'Effect0#') ? parseInt("#Effect0#") :0;
var effect1#uid# = ('#Effect1#' !='#'+'Effect1#') ? parseInt("#Effect1#") :0;
var effect2#uid# = ('#Effect2#' !='#'+'Effect2#') ? parseInt("#Effect2#") :0;
var effectSpeed0#uid# = ('#EffectSpeed0#' != '#'+'EffectSpeed0#') ? "#EffectSpeed0#" : '1s';
if (effectSpeed0#uid# == '') {effectSpeed0#uid# = '1s';}
var effectSpeed1#uid# = ('#EffectSpeed1#' != '#'+'EffectSpeed1#') ? "#EffectSpeed1#" : effectSpeed0#uid#;
if (effectSpeed1#uid# == '') {effectSpeed1#uid# = effectSpeed0#uid#;}
var effectSpeed2#uid# = ('#EffectSpeed2#' != '#'+'EffectSpeed2#') ? "#EffectSpeed2#" : effectSpeed0#uid#;
if (effectSpeed2#uid# == '') {effectSpeed2#uid# = effectSpeed0#uid#;}
var noBorder#uid# = ('#NoBorder#' !='#'+'NoBorder#') ? parseInt("#NoBorder#") :0;
if (noBorder#uid# == '') {noBorder#uid# = 0;}
if (noBorder#uid# == 0) {
document.documentElement.style.setProperty('--border-Color1#uid#', "4px");
document.documentElement.style.setProperty('--border-Color2#uid#', "2px");
}
else {
document.documentElement.style.setProperty('--border-Color1#uid#', "0px");
document.documentElement.style.setProperty('--border-Color2#uid#', "0px");
}
if ( val#uid# < ValueMinTest#uid#){
document.documentElement.style.setProperty('--fontColor#uid#', 'var(--fontColorState0#uid#)');
document.documentElement.style.setProperty('--color1#uid#', 'var(--color1State0#uid#)');
document.documentElement.style.setProperty('--color2#uid#', 'var(--color2State0#uid#)');
if (effect0#uid#==0) { cmd.find('#value_content#uid#').css('animation', 'none');}
else if (effect0#uid#==1) { cmd.find('#value_content#uid#').css('animation', 'glow#id# ' + effectSpeed0#uid# + ' infinite alternate');}
else if (effect0#uid#==2) { cmd.find('#value_content#uid#').css('animation', 'scale#id# ' + effectSpeed0#uid# + ' infinite alternate');}
else if (effect0#uid#==3) { cmd.find('#value_content#uid#').css('animation', 'blinker#id# ' + effectSpeed0#uid# + ' infinite alternate');}
else if (effect0#uid#==4) { cmd.find('#value_content#uid#').css('animation', 'vibrate#id# ' + effectSpeed0#uid# + ' infinite alternate');}
else if (effect0#uid#==5) { cmd.find('#value_content#uid#').css('animation', 'ring#id# ' + effectSpeed0#uid# + ' infinite');}
} else if (val#uid# > ValueMaxTest#uid#){
document.documentElement.style.setProperty('--fontColor#uid#', 'var(--fontColorState2#uid#)');
document.documentElement.style.setProperty('--color1#uid#', 'var(--color1State2#uid#)');
document.documentElement.style.setProperty('--color2#uid#', 'var(--color2State2#uid#)');
if (effect2#uid#==0) { cmd.find('#value_content#uid#').css('animation', 'none');}
else if (effect2#uid#==1) { cmd.find('#value_content#uid#').css('animation', 'glow#id# ' + effectSpeed2#uid# + ' infinite alternate');}
else if (effect2#uid#==2) { cmd.find('#value_content#uid#').css('animation', 'scale#id# ' + effectSpeed2#uid# + ' infinite alternate');}
else if (effect2#uid#==3) { cmd.find('#value_content#uid#').css('animation', 'blinker#id# ' + effectSpeed2#uid# + ' infinite alternate');}
else if (effect2#uid#==4) { cmd.find('#value_content#uid#').css('animation', 'vibrate#id# ' + effectSpeed2#uid# + ' infinite alternate');}
else if (effect2#uid#==5) { cmd.find('#value_content#uid#').css('animation', 'ring#id# ' + effectSpeed2#uid# + ' infinite');}
} else{
document.documentElement.style.setProperty('--fontColor#uid#', 'var(--fontColorState1#uid#)');
document.documentElement.style.setProperty('--color1#uid#', 'var(--color1State1#uid#)');
document.documentElement.style.setProperty('--color2#uid#', 'var(--color2State1#uid#)');
cmd.find('#value_content#uid#').css('animation', 'none');
if (effect1#uid#==0) { cmd.find('#value_content#uid#').css('animation', 'none');}
else if (effect1#uid#==1) { cmd.find('#value_content#uid#').css('animation', 'glow#id# ' + effectSpeed1#uid# + ' infinite alternate');}
else if (effect1#uid#==2) { cmd.find('#value_content#uid#').css('animation', 'scale#id# ' + effectSpeed1#uid# + ' infinite alternate');}
else if (effect1#uid#==3) { cmd.find('#value_content#uid#').css('animation', 'blinker#id# ' + effectSpeed1#uid# + ' infinite alternate');}
else if (effect1#uid#==4) { cmd.find('#value_content#uid#').css('animation', 'vibrate#id# ' + effectSpeed1#uid# + ' infinite alternate');}
else if (effect1#uid#==5) { cmd.find('#value_content#uid#').css('animation', 'ring#id# ' + effectSpeed1#uid# + ' infinite');}
}
cmd.find('#data_value#uid#').css('animation', 'rotate#id# ' + effectSpeed1#uid# + ' infinite alternate');
cmd.find('#data_value#uid#').text(val#uid#);
//*************************
cmd.attr('title','{{Date de valeur}} : '+_options.valueDate+'<br/>{{Date de collecte}} : '+_options.collectDate+'<br/>{{Valeur}} : '+_options.display_value+'#unite#');
if ('#time#' == 'duree') {
jeedom.cmd.displayDuration(_options.valueDate,cmd.find('.timeCmd'));
}
else if ('#time#' == 'date') {
let week = ['dim.', 'lun.', 'mar.', 'mer.', 'jeu.', 'ven.', 'sam.'];
let date = new Date(_options.valueDate.replace(' ', 'T'));
let t = _options.valueDate.split(/[- :]/);
let format = week[date.getDay()]+" "+t[2]+"/"+t[1];
let time = "à "+t[3]+":"+t[4];
cmd.find('.timeCmd').html(format+'<br>'+time);
}
else if ('#time#' == 'heure') {
let date = new Date(_options.valueDate.replace(' ', 'T'));
let t = _options.valueDate.split(/[- :]/);
let time = "à "+t[3]+":"+t[4]+":"+t[5];
cmd.find('.timeCmd').html(time);
}
}
jeedom.cmd.update['#id#']({display_value:'#state#',valueDate:'#valueDate#',collectDate:'#collectDate#',alertLevel:'#alertLevel#'});
</script>
<style id="style#id#">
@-webkit-keyframes glow#id# {
from { box-shadow: 0 0 10px -5px var(--color1#uid#) ; !important}
to { box-shadow: 0 0 10px 5px var(--color1#uid#) ;!important }
}
@-webkit-keyframes scale#id# {
from { transform: scale(1);}
to { transform: scale(1.2);}
}
@-webkit-keyframes blinker#id# {
from { opacity: 1.0 ;!important }
to { opacity: 0.25 ;!important }
}
@-webkit-keyframes vibrate#id# {
0% {transform: translate(0);!important}
10% {transform: translate(-1px, -1px);!important}
20% {transform: translate(1px, -1px);!important}
30% {transform: translate(-1px, 1px);!important}
40% {transform: translate(1px, 1px);!important}
50% {transform: translate(-1px, -1px);!important}
60% {transform: translate(1px, -1px);!important}
70% {transform: translate(-1px, 1px);!important}
80% {transform: translate(-1px, -1px);!important}
90% {transform: translate(1px, -1px);!important}
100% {transform: translate(0);!important}
}
@-webkit-keyframes ring#id# {
0% { transform: rotate(0deg); }
10% { transform: rotate(5deg); }
20% { transform: rotate(-5deg); }
30% { transform: rotate(5deg);}
40% { transform: rotate(-5deg); }
50% { transform: rotate(5deg); }
60% { transform: rotate(-5deg); }
70% { transform: rotate(5deg);}
80% { transform: rotate(-5deg); }
90% { transform: rotate(0deg); }
100% { transform: rotate(0deg); }
}
:root {
--element-sizeWidth#uid#: "100px";
--tile-label-font-family#id#: "Arial, sans-serif";
}
#data_value#uid#{
/*position:absolute;*/
font-size: calc(100% * (var(--fontRatio#uid#))/(1)) !important;
color: var(--fontColor#uid#) !important;
text-shadow: 1px 1px 1px #6b6b6b;
font-family: var(--tile-label-font-family#id#);
}
#data_unit#uid# {
position:relative;
left: 2px;
z-index:2;
font-size: calc(100% * var(--fontRatio#uid#) * var(--unitRatio#uid#)) !important;
color: var(--fontColor#uid#) !important;
text-shadow: 1px 1px 1px #6b6b6b;
font-family: var(--tile-label-font-family#id#);
}
#value_content#uid#{
/* content */
position:absolute;
width: calc(var(--element-sizeWidth#uid#)) !important;
height: calc(var(--element-sizeHeight#uid#)) !important;
border-radius: calc(var(--radius1#uid#)*1) var(--radius2#uid#) var(--radius3#uid#) var(--radius4#uid#) !important;
background: linear-gradient(var(--colorRotation#uid#), var(--color2#uid#), var(--color1#uid#)) !important;
/* border: 4px solid #767B91 !important;*/
border: var(--border-Color1#uid#) solid #767B91 !important;
display: inline-flex;
align-items: center;
justify-content: center;
}
#value_border#uid# {
/* content */
position:absolute;
width: calc(var(--element-sizeWidth#uid#)) !important;
height: calc(var(--element-sizeHeight#uid#)) !important;
border-radius: calc(var(--radius1#uid#)*1) var(--radius2#uid#) var(--radius3#uid#) var(--radius4#uid#) !important;
/*border: 2px solid #666F84 !important;*/
border: var(--border-Color2#uid#) solid #666F84 !important;
/* z-index:2;*/
/* font-size: calc(100% * (var(--fontRatio#uid#))/(1)) !important;*/
}
#data_display#uid# {
/* Container */
position:relative;
color:#F0F0F0;
width: calc(var(--element-sizeWidth#uid#)) !important;
height: calc(var(--element-sizeHeight#uid#)) !important;
}
</style>
</div>