Créez un sélecteur de couleur en jQuery
Posé ici le lundi 06 juillet 2009 à 23:25 par
Pour faire évoluer markItUp! dans sa version 2.0 (sortie officielle décembre 2039), j'ai voulu remplacer la très archaïque palette de couleurs que proposait la version 1.1 par une palette digne de ce nom.
Plutôt content du résultat final, je me suis dit qu'il serait intéressant de proposer cette palette dans un plugin jQuery indépendant. Ce n'est pas que ce plugin soit d'un grand intérêt - il doit en existe de bien meilleurs - mais il peut en découler un tutoriel que j'espère intéressant. Le voici.
MISE A JOUR le Jeudi 9 Juillet 2009 :
Quelques modifications ont été apportées pour aller dans le sens d'intéressants commentaires.
Ce que je veux
Ne pouvant demander à mes utilisateurs de connaitre par cœur la table des couleurs web hexadécimales, je veux proposer un moyen simple de sélectionner une valeur de couleur tout en laissant aux plus spécialistes la possibilité de taper directement cette valeur. Je proposerai donc l'affichage d'une palette de couleurs dites websafe lorsque le curseur de l'utilisateur entrera dans le champ de saisi. Un clic sur une couleur remplira automatiquement ce champ.
La logique
Le plugin est constitué de deux fichiers, le plugin lui-même jquery.mycolorpicker.js et sa feuille de style nommée jquery.mycolorpicker.css. Voici la version intégrale du code agrémentée de quelques commentaires succins. Une explication plus en détail fera suite.
jquery.mycolorpicker.js
/**
* Créez un sélecteur de couleur en jQuery
* par Jay Salvat - http://blog.jaysalvat.com/
*/
(function($) {
$.fn.myColorPicker = function() {
return this.each(function(){
var $$ = $(this);
var x = $$.offset().left;
var y = $$.offset().top + $$.outerHeight(true);
// Lorsque le curseur entre dans le champ de saisi
$$.focus(function() {
buildColorPicker();
});
// Fonction de création de la palette
function buildColorPicker() {
// On supprime d'éventuelles autres palettes déjà ouvertes
removeColorPicker();
// On construit le Html de la palette
var values = ['00', '33', '66', '99', 'CC', 'FF'];
var content = '';
content += '<div id="myColorPicker">';
content += '<ul>';
for(r = 0; r < 6; r++) {
for(g = 0; g < 6; g++) {
for(b = 0; b < 6; b++) {
color = '#' + values[r] + values[g] + values[b];
content += '<li><a rel="'+ color +'" style="background:'+ color +'" ¬
… title="'+ color +'"></a></li>';
}
}
}
content += '</ul>';
content += '<a class="close">Fermer</a>';
content += '</div>';
// On la place dans la page aux coordonnées du textfield
$(content).css({
position:'absolute',
left:x,
top:y,
backgroundColor:$$.val()
}).appendTo('body');
// Au survol d'une couleur, on change le fond de la palette
$('#myColorPicker a').hover(function() {
$('#myColorPicker').css('backgroundColor', $(this).attr('rel') );
}, function() {
$('#myColorPicker').css('backgroundColor', $$.val() );
});
// Lorsqu'une couleur est cliqué, on affiche la valeur dans le textfield
$('#myColorPicker a').not('.close').click(function() {
$$.val( $(this).attr('rel') );
removeColorPicker();
return false;
});
// Au survol d'une couleur, on change le fond
$('#myColorPicker a').mouseover(function() {
$('#myColorPicker').css('backgroundColor', $(this).attr('rel') );
});
// On supprime la palette si le lien "Fermer" est cliqué
$('#myColorPicker a.close').click(function() {
removeColorPicker();
return false;
});
}
// Fonction de suppression de la palette
function removeColorPicker() {
$('#myColorPicker').remove();
}
});
};
})(jQuery);
Dissection du code
Je reviens sur les points les plus intéressants.
(function($) {
$.fn.myColorPicker = function() {
// ...
};
})(jQuery);
Un plugin jQuery se commence ainsi. Je passe rapidement sur cette partie, ce n'est pas le premier plugin jQuery développé sur ce blog. Plus d'informations dans cet article.
return this.each(function(){
var $$ = $(this);
var x = $$.offset().left;
var y = $$.offset().top + $$.outerHeight(true);
//...
});
Le plugin sera appliqué à chaque élément précisé lors de son appel, théoriquement ici des textfields. Pour plus de simplicité j'ai pour usage de garder l'élément courant $(this) dans une variable $$. J'en profite pour garder les coordonnées top et left du textfield pour positionner la palette plus tard.
$$.focus(function() {
buildColorPicker();
});
J'écoute l'événement focus sur le champ de saisi courant $$. Ainsi dès que l'utilisateur entrera dans le champ de saisi la fonction buildColorPicker() se lancera.
function buildColorPicker() {
// ...
var values = ['00', '33', '66', '99', 'CC', 'FF'];
var content = '';
content += '<div id="myColorPicker">';
content += '<ul>';
for(r = 0; r < 6; r++) {
for(g = 0; g < 6; g++) {
for(b = 0; b < 6; b++) {
color = '#' + values[r] + values[g] + values[b];
content += '<li><a rel="'+ color +'" style="background:'+ color +'" ¬
… title="'+ color +'"></a></li>';
}
}
}
content += '</ul>';
content += '<a class="close">Fermer</a>';
content += '</div>';
// ...
}
La fonction buildColorPicker construit la palette de couleurs. 3 boucles imbriquées (une pour le rouge, une pour le vert, une pour le bleu) empilent les liens avec les informations de couleur dans une variable content. Les liens générés ressemblent à ça :
<li><a rel="#FF9900" style="background:#FF9900" title="#FF9900"></a></li>
Le tout est rangé dans une liste non-ordonnée ul et li ancrée dans un div nommé #myColorPicker qui me servira à identifier la palette. Je n'ai pas oublié d'ajouté un lien pour fermer plus tard la palette.
$(content).css({
position:'absolute',
left:x,
top:y,
backgroundColor:$$.val()
}).appendTo('body');
Un élément est créé à partir du code HTML contenu dans la variable content et greffé au body, puis placé aux coordonnées x et y du champ de saisi précédemment stockés. Si le champ contient déjà une valeur, on l'applique à la palette pour qu'elle soit prévisualisée.
$('#myColorPicker a').hover(function() {
$('#myColorPicker').css('backgroundColor', $(this).attr('rel') );
, function() {
$('#myColorPicker').css('backgroundColor', $$.val() );
});
Maintenant que tout est en place, on ajoute les différents comportements. Pour que l'utilisateur puisse se faire une meilleure opinion de la couleur à choisir, on change le backgroundColor de la palette entière lorsqu'une couleur est survolée. On remet comme c'était lorsqu'elle ne l'est plus.
$('#myColorPicker a').not('.close').click(function() {
$$.val( $(this).attr('rel') );
removeColorPicker();
return false;
});
Lorsqu'un lien autre que le bouton Fermer (.close) est cliqué, la valeur de l'attribut rel est récupérée par $(this).attr('rel')) est appliquée dans le champ de saisi. Enfin, on supprime la palette de la page grâce à la fonction removeColorPicker() à venir.
$('#myColorPicker a.close').click(function() {
removeColorPicker();
return false;
});
Le lien .close appellera aussi la fonction removeColorPicker() qui détruira la palette :
function removeColorPicker() {
$('#myColorPicker').remove();
}
L'esthétique
Jusqu'à présent, la liste de liens affichée par le plugin est loin de ressembler à une palette de couleur. Nous y remédions grâce à la feuille de style ci-dessous.
jquery.mycolorpicker.css
#myColorPicker {
background-color:#000;
border:1px solid #000;
margin:-1px;
width:390px;
}
#myColorPicker ul {
width:360px;
margin-right:30px;
}
#myColorPicker * {
margin:0; padding:0;
}
#myColorPicker a {
cursor:pointer;
display:block;
width:10px; height:10px;
}
#myColorPicker li {
float:left;
list-style:none;
}
#myColorPicker a.close {
background:transparent url(images/close.png) center center;
position:absolute;
text-indent:-5000px;
top:-10px; right:-10px;
width:20px; height:20px;
}
On peut aussi s'amuser à améliorer le champ de saisi avec un petit icône.
.myColorPicker {
background:transparent url(images/palette.png) no-repeat 99% center;
padding-right:20px;
}
Et voici les images utilisées.
Images utilisées
Usage
Comme pour tout plugin jQuery, la librairie doit être incluse, puis le plugin en question et sa feuille de style.
<link rel="stylesheet" type="text/css" href="jquery.mycolorpicker.css" /> <script type="text/javascript" src="jquery.js"></script> <script type="text/javascript" src="jquery.mycolorpicker.js"></script>
Il suffit ensuite d'appliquer notre nouveau plugin aux éléments de la page voulus. Dans l'exemple suivant, on l'applique aux inputs portant la classe .myColorPicker :
<script type="text/javascript">
$(function() {
$('input.myColorPicker').myColorPicker();
});
</script>
Ainsi, tout input de ce type :
<input class="myColorPicker" type="text" />
se transformera en un joli sélecteur de couleurs.
Conclusion
Voilà ! Tout y est. Un fichier zip comprenant la totalité des éléments est disponible en téléchargement.
MISE A JOUR le Jeudi 9 Juillet 2009 :
MISE A JOUR le Jeudi 9 Juillet 2009 : Cet article a été mis a jour.
Ce contenu est mis à disposition selon les termes de la licence Creative Commons 2.0 France : Paternité, Pas d'Utilisation Commerciale, Partage des Conditions Initiales à l'Identique.
Context
Thématiques :
Trackbacks
0 trackback



Commentaires
16 commentaires
Je commente juste le début, c'est la seule chose qui m'ai marqué depuis le flux rss :
version 2.0 (sortie officielle décembre 2039) ?
Héhé ... avec ça, on peut espérer une super nouvelle version :o)
Avec un peu plus de sérieux, je vais lire l'article avec plaisir, comme d'habitude et je reviendrais peut être commenter. Et avec autant de sérieux, une version 2.0 est prévue dans un vrai avenir moins éloigné ?
PS : c'est volontaire d'avoir réduit le flux RSS depuis quelques semaines à son strict minimum ?
1. Par Emmanuel le mardi 07 juillet 2009 à 02:56
@Emmanuel,
2039 est un peu exagéré, je pense avoir 10 ans d'avance en travaillant bien.
Blague mise à part, famille, boulot, blog, me prennent un temps fou et me laisse peu de place pour remettre le nez dans le code de markItUp!.
J'avais bien avancé sur la 1.2 mais finalement, ça ne ressemblait qu'à une suite de patches mal intégrés. Cette version m'aurait demandé de toute façon de refaire les exemples et une grande partie de la doc et du site web.
Quitte à faire tout se travail, je préfère prendre le temps et développer directement la 2.0 avec tout se qu'il faut dedans et bien ordonné. Seulement ça prend beaucoup beaucoup de temps.
Pour le flux, il est comme d'habitude non ? TItre et intro.
2. Par Jay Salvat le mardi 07 juillet 2009 à 09:23
Bonjour,
J'ai repéré une faute de frappe dans la ligne suivante :
content += '<li><a rel="'+ color +' style="background:'+ color +'" title="'+ color +'"></a></li>';
La double-quote de l'attribut rel n'est pas refermé, on retrouve d'ailleurs l'erreur lors de la dissection du code :
<li><a rel="#FF9900' style="background:#FF9900" title="#FF9900"></a></li>
rel est ouvert par une double-quote et fermé par une simple-quote.
En tout cas, c'est toujours un plaisir de lire tes articles.
3. Par Stéphane Bareau le mardi 07 juillet 2009 à 10:22
Intéressante cette palette.
Je n'ai pas regardé précisément le code mais à l'usage j'ai une petite remarque : le fait de cliquer sur la croix fait disparaître la couleur dans le input.
Cela pose le problème suivant : on est obligé de laisser sa palette ouverte ou de sélectionner une couleur.
Mais quid de celui qui veut entrer la couleur à la main ou de celui qui a déjà sélectionné une couleur et qui voulait juste ouvrir la palette pour regarder si une autre couleur n'aurait pas été mieux ?
Je précise que je suis avec FF3.5.
4. Par Stan le mardi 07 juillet 2009 à 10:23
@ Stéphane Bareau
Merci ! C'est corrigé.
@ Stan
Tu as entièrement raison. C'était un bug. C'est corrigé également.
5. Par Jay Salvat le mardi 07 juillet 2009 à 11:48
Sans vouloir abuser, je pense qu'il serait également assez naturel pour l'utilisateur de pouvoir fermer la fenêtre en appuyant sur Echap ou lorsqu'il clic ailleurs dans la page.
Mais bon ... pas obligé de le faire, je suis un chieur :)
6. Par Stan le mardi 07 juillet 2009 à 13:20
Pendant que j'y suis il serait aussi sans doute intéressant d'avoir un petit carré de couleur à côté l'input qui permet de voir instantanément la couleur correspondant au code.
Car autant là on peut facilement obtenir le code à partir de la couleur, autant pour obtenir la couleur à partir du code ... le problème reste entier, l'utilisateur ne parlant pas couramment "code couleur" ne saura pas à quelle couleur correspond le code sélectionné.
7. Par Stan le mercredi 08 juillet 2009 à 10:56
@Stan,
Non tu n'es pas un chieur, ces options seraient parfaites pour une release finale. Comme d'habitude sur ce blog, c'est ébauche sur une idée et non un produit fini. A chacun de se l'approprier et d'en faire ce qu'il veut selon ces besoins :)
Je reste volontairement "straight to the point" sur les tutoriels sinon on arrive vite à ce que je ne veux pas : des articles interminables. Je trouve déjà les miens trop longs.
Si je fais un jour une release publique de ce plugin, soit sûr qu'il inclura toutes ces options.
8. Par Jay Salvat le mercredi 08 juillet 2009 à 15:32
Je m'en doutais un peu, comme pour le plugin de chat.
Mais j'aime bien écrire mes idées ça pourrait aider certains qui liront :)
9. Par Stan le mercredi 08 juillet 2009 à 16:04
@Jay : J'en suis conscient que c'est un gros travail. Et ce n'est pas moi qui te dirait quand tu dois produire quoi que ce soit. On a tous une vie en dehors du web (quoi que :o) )
Pour le flux RSS, je me mélange peut être les pinceaux ... à force d'avoir des dizaines de posts à parcourir tous les jours, je me trompe peut etre. Il me semblait que passé un temps, il y avait le post complet. Rien de grave !
10. Par Emmanuel le jeudi 09 juillet 2009 à 13:25
J'ai apporté quelques modifications en deux lignes.
- J'utilise maintenant .not('.close') pour éviter le conflit entre les liens couleurs et le lien du bouton 'Fermer'. Cela évite que le champs de saisie soit remis à zéro lorsque la palette est fermée.
- Si une valeur est déjà entrée dans le champ de saisie, le fond de la palette s'affiche de cette couleur, permettant ainsi de prévisualiser n'importe quelle couleur.entrée.
11. Par Jay Salvat le jeudi 09 juillet 2009 à 14:05
Bravo :)
En étant tatillon (toujours pour une version release, pas pour une démo), je dirais qu'il faudrait également éviter que le survol du bouton de fermeture mette l'aperçu de la couleur en noir.
12. Par Stan le vendredi 10 juillet 2009 à 10:57
Mince j'ai cliqué sur "Envoyer" un peu tôt.
Je voulais aussi rajouter qu'il faudrait réduire de 1 la taille du champ de saisie (passer de 8 à 7).
Car pour le moment on peut mettre #FF00FF0 ce qui n'est pas une couleur valide. Cependant, il y a peut être une excellente raison qui m'échappe à avoir 8 mais dans ce cas là il faut m'expliquer pour que je sois moins bête :)
13. Par Stan le vendredi 10 juillet 2009 à 11:01
Y a vraiment des killer apps sur terre.
Bravo !
14. Par ZeNerzhul le mercredi 05 août 2009 à 17:36
pour ma part j'ai pensé qu'il serait plus sympathique de voir la couleur choisie dans le champ après la fermeture du selecteur.
Voici la modification apporté au code de jquery.mycolorpicker.js
// Lorsqu'une couleur est cliqué, on affiche la valeur dans
// le textfield
$( '#myColorPicker a' ).not( '.close' ).click(
function()
{
var color = $( this ).attr( 'rel' );
var r = color.substr( 1, 2 );
var g = color.substr( 3, 2 );
var b = color.substr( 5, 2 );
$$.val( color );
$$.css( 'background-color', color );
if( ( parseInt( r, 16 ) * 0.3 ) + ( parseInt( g, 16 ) * 0.59 ) + ( parseInt( b, 16 ) * 0.11 ) > 128 )
{
$$.css( 'color', 'black' );
}
else
{
$$.css( 'color', 'white' );
}
removeColorPicker();
return false;
} );
15. Par ZeNerzhul le mercredi 05 août 2009 à 17:38
Merci de cet ajout ZeNerzhul !
16. Par Jay Salvat le mercredi 05 août 2009 à 19:02