1/25/2009

Choix automatique de la couleur d'un texte en fonction de sa couleur d'arrière plan

Ou en terme plus technique, comment créer un algorithme qui retourne un foregroundColor adéquate en fonction d'un backgroundColor variable.

Dans le cadre de mon stage @ Zlio Nantes, j'ai eu besoin de créer un algorithme qui, à partir de n'importe quelle couleur d'arrières plans, serait capable de définir si la couleur du texte (blanc ou noir) afin que ce dernier soit toujours visible.

Postulat : Pour la démonstration, nous prendrons un vert foncé comme couleur d'arrière plan

#155147 = rgb(21, 81, 71); //RGB (Red, Blue, Green) ou RVB (Rouge, Vert, Bleu)

 

Méthode rapide

La première idée qui pourrait vous venir à l'esprit serait d' additionner les composantes RVB :

21+81+71 = 173

Or, au maximum il est possible d'obtenir une somme de

255+255+255 = 765

Donc il suffirait donc de regarder si la somme des composantes et supérieur ou inférieur à 382,5 (765/2) pour savoir s'il faut mettre le texte en blanc (donc plus clair) ou en noir (plus foncé). Ce qui pourrait donner cet algorithme :

var couleurRGB = [21,81,71];

Si couleurRGB[0]+couleurRGB[1]+couleurRGB[2] > 382 Alors
     //#FFFFFF
Sinon
     //#000000
FinSi

En réalité cet approche est fausse. D'ailleurs en utilisant la couleur de l'exemple, l'algorithme nous propose d'utiliser du noir. Voici le résultat :

En testant on constate que le texte n'est clairement pas visible et que le blanc aurait été un meilleur choix.

 

En baissant la valeur seuil à 170 notre algorithme retourne une couleur correcte (blanc) pour notre exemple, mais qu'en est-il pour ces autres couleurs ? rgb(4, 1, 31), rgb(9, 23, 9), rgb(29, 50, 3), rgb(27, 15, 27). La somme de leurs composantes ne dépasse pas 170 et pourtant la proposition est fausse, notre algorithme propose du noir.

Pour corriger cela nous pourrions baisser la valeur seuil. Lors de mes tests j'ai réussi à obtenir de très bon résultat avec une valeur seuil à 86 mais il reste encore une infinité de cas où notre algorithme propose une couleur erronée.

A ce stade, 2 possibilités. Soit nous complexifions notre algorithme en étudiant chacune des composants les une après les autres et en réalisant un savant mélange de test,... Soit nous passons à la méthode fiable.

 

Méthode fiable

La méthode fiable consiste à convertir le format de gestion de couleur de RGB vers HSL (Hue, Saturation, Lightness) soit TSL (Teinte, Saturation, Lumière) en français. C'est la composante lumière qui nous intéresse :

La lumière est la luminosité (depuis 0 % qui correspond au noir jusqu'à 100 %, luminosité maximale permise par le support, le blanc dans le cas des écrans).

Une fois la conversion effectuée ils nous suffira de définir si la composante "L" est supérieur ou inférieur à 50% et d'en déduire la couleur à appliquer en premier plan. Notre algorithme devient donc :

var couleurRGB = [21,81,71];
var couleurHSL = RGBtoHSL(couleurRGB);

Si couleurHSL[2] > 0.5 Alors //0.5 = 50% 
     //#000000
Sinon
     //#FFFFFF
FinSi 

Et voila ! Cette méthode est légèrement plus lente en calcul processeur car elle nécessite une conversion supplémentaire mais elle est 100% fiable.

[MAJ] La démo est disponible en ligne ici, elle intègre le code javascript fonctionnel des deux algorithmes ainsi qu'un script de test pour comparer automatiquement leurs valeurs de retour.

1/12/2009

Débugger avec Firebug sous Firefox en testant en parallèle avec IE, Opera et Chrome

Si vous développez et débuggez votre application sous Firefox et utilisez les méthodes de l’objet console de Firebug, tel que :

console.debug(maVariable);
console.info('Hello World :', monApplication.version);
console.log('Logged in');

Il vous est alors impossible de tester votre code en parallèle sous Internet Explorer, Opera et Chrome[1] sans voir apparaitre un de ces messages :

/* IE */
Erreur : 'console' est indéfini

/* Opera */
Error:
name: ReferenceError
message: Statement on line 437: Undefined variable: console

/* Chrome (v1.x.xxx.x) */
Uncaught TypeError: Object #<a console="console"> has no method 'debug'

 

Commençons donc par un petit rappel sur les moyens de débug offert par ces différents navigateurs :

 

Internet Explorer

Il n’existe pas de console en natif qui propose les mêmes fonctionnalités que celles offertes par Firebug. Cependant des plugins tel que DebugBar devraient permettre cela.

 

Opera

Opera possède sa propre méthode postError() mais son utilisation est limitée car elle n’affiche pas le contenu des objets

opera.postError([1,2,3,4,5]);//Affiche: 1,2,3,4,5
opera.postError('Mon tableau',[1,2,3,4,5]);//Affiche: Mon tableau,1,2,3,4,5
opera.postError({maPropriete: 'Hello', maMethode : function(){return 'World';}});//Affiche: [object Object]

Google Chrome

Dans ses dernières versions (testé sous 2.0.156.1) Chrome supporte partiellement, via sa Console Javascript (Ctrl+Maj+J) les méthodes suivantes :

console.debug();
console.info();
console.log();

Partiellement car il est actuellement impossible de passer plusieurs objets/tableaux via un seul appel

monTableau = [1,2,3,4,5,6];
monObjet = {maPropriete : 'Hello', maMethode : function(){return 'World';}};
console.debug(monTableau,monObjet);//Affiche: [1, 2, 3, 4, 5, 6] Object
console.debug(monObjet);//Affiche le contenu de l'objet monObjet

La solution

Voici un bout de code (snippet) à placer avant tout appel aux méthodes console.debug, console.info et console.log.

//On créé l’objet console s’il n’existe pas (sous d’autre navigateur que Firebox & Chrome)
if(typeof console !== 'object')
     console = {};
if((typeof console.debug) !== 'function')//On pourrait aussi vérifier pour console.info et console.log
{
     if(typeof opera === 'object')//On redirige les appels vers opera.postError();
         console = {debug : function(){return opera.postError(arguments);}, info : function(){this.debug('[INFO] ',arguments);}, log :
function(){this.debug('[LOG] ',arguments);}};
     else//Ne rien afficher sur les autres navigateurs
         console = {debug : function(){return true;},info : function(){return true;}, log : function(){return true;}};
}

Il vous est maintenant possible de tester (voir même de debugger si vous êtes sous Chrome et/ou Opera) votre application sans vous soucier de supprimer les lignes de debug pour Firebug. Je vous conseille toutefois de placer ce bout de code dans l’événement DomReady afin d’éviter tout problème de chargement.

DomReady avec jQuery :

$(document).ready(function(){ /* bout de code à copier ici */ });

DomReady avec MooTools:

window.addEvent('domready', function() { /* bout de code à copier ici */ });

[1] Versions 1.x.xxx.x de Chrome

1/03/2009

Savoir si les librairies JavaScript jQuery, Prototype, Mootools, YUI et DOJO sont présentes sur une page web

Voici plusieurs bouts de code qui vous permettrons de savoir si tel ou tel libraire est présente (mais pas forcément initialisées) dans une page web. Très utile lorsque vous devez réaliser un script reposant sur l'une de ces librairies, il vous est alors possible d'éviter de ré-inclure la librairie. Pour cela il suffit d'utiliser un bootstrap (Facebook appelle cela un bootloader).

bootstrap : petit programme d'amorçage qui permet d'en lancer un plus gros. (Wikipedia)

 

JQuery :

var JQuery_estPresent = (typeof jQuery != "undefined")?true:false;

Prototype :

var Prototype_estPresent = (typeof Prototype != "undefined")?true:false;

Mootools :

var MooTools_estPresent = (typeof MooTools != "undefined")?true:false;

YUI :

var YahooUI_estPresent = (typeof YAHOO != "undefined")?true:false;

Dojo :

var Dojo_estPresent = (typeof dojo != "undefined")?true:false;

 

Exemple d'utilisation via un BootStrap depuis une page web

var hasJQuery = (typeof jQuery != "undefined")?true:false;//retourne un booléen selon la présence de jQuery sur la page
var scrpt = document.createElement('script');
scrpt.src = 'http://monsite.com/script/monscript.js.php?' + (hasJQuery?'besoinDeJquery=true':'');//préparation de l'URL
document.body.appendChild(scrpt);//ajout du script

Le fichier monscript.js.php se chargera d'inclure ou non la librairie jQuery en fonction de la variable besoinDeJquery.

 

De nombreuses autres utilisations de ces informations sont bien entendu possible.

« »
 
 
Made with on a hot august night.
http://bit.ly/1II1u5L