Après avoir réfléchi... j'ai décidé de répondre à ma propre question. Un an et demi plus tard. C'était vraiment une aventure avec les idées de plusieurs utilisateurs utiles, et je vous remercie tous ! Celle-ci est pour l'équipe ! Bien que ce ne soit pas nécessairement la réponse que je cherchais. Parce que si ce que James Khoury dit est vrai, alors il n'y a pas de véritables maths hexagonales en javascript, je dois utiliser des décimales, cette double conversion est nécessaire. Si nous faisons cette hypothèse, alors c'est probablement le moyen le plus rapide que j'ai vu (ou auquel je peux penser) pour éclaircir (ajouter du blanc) ou assombrir (ajouter du noir) une couleur RBG arbitraire en pourcentage. Cela tient également compte des problèmes mentionnés par Cool Acid dans sa réponse à cette question (il remplit les 0). Mais cette version appelle toString
une seule fois. Cela tient également compte du dépassement des limites (0 et 255 seront appliqués comme limites).
Mais attention, la couleur saisie doit comporter EXACTEMENT 7 caractères, comme par exemple #08a35c
. (ou 6 si vous utilisez la version supérieure)
Merci à Pablo pour l'inspiration et l'idée d'utiliser le pourcentage. Pour cela, je garderai le même nom de fonction ! lol ! Cependant, celle-ci est différente, car elle normalise le pourcentage à 255 et ajoute donc la même quantité à chaque couleur (plus de blanc). Si vous passez 100 pour percent
cela rendra votre couleur blanche pure. Si vous passez 0 pour percent
il ne se passera rien. Si vous passez en 1 pour percent
il ajoutera 3 teintes à toutes les couleurs (2,55 teintes par 1%, arrondi). Vous passez donc réellement dans un pourcentage de blanc (ou de noir, utilisez le négatif). Cette version vous permet donc d'éclaircir le rouge pur (FF0000), par exemple.
J'ai également utilisé des éléments de la réponse de Keith Mashinter à cette question : Comment convertir des décimales en hexadécimales en JavaScript ?
J'ai supprimé certaines parenthèses, apparemment inutiles. (comme dans la déclaration ternaire double et dans l'artisanat B) Je ne sais pas si cela va perturber la précédence des opérateurs dans certains environnements. Le test est bon dans FireFox.
function shadeColor1(color, percent) {
var num = parseInt(color,16),
amt = Math.round(2.55 * percent),
R = (num >> 16) + amt,
G = (num >> 8 & 0x00FF) + amt,
B = (num & 0x0000FF) + amt;
return (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);
}
Ou, si vous voulez qu'il gère le "#" :
function shadeColor1(color, percent) {
var num = parseInt(color.slice(1),16), amt = Math.round(2.55 * percent), R = (num >> 16) + amt, G = (num >> 8 & 0x00FF) + amt, B = (num & 0x0000FF) + amt;
return "#" + (0x1000000 + (R<255?R<1?0:R:255)*0x10000 + (G<255?G<1?0:G:255)*0x100 + (B<255?B<1?0:B:255)).toString(16).slice(1);
}
Comment cela se passe-t-il pour deux lignes de code ?
EDIT : Correction de la gaffe de l'échange B<->G. Merci svachalek !
-- UPDATE - Version 2 avec Blending --
Un peu plus d'un an plus tard, à nouveau, et ça continue. Mais cette fois, je pense que c'est fini. Je note les problèmes mentionnés à propos de la non-utilisation de HSL pour éclaircir correctement la couleur. Il existe une technique qui élimine la plupart de ces imprécisions sans avoir à convertir en HSL. Le problème principal est qu'un canal de couleur sera complètement saturé avant le reste de la couleur. Ce qui provoque un décalage de la teinte après ce point. J'ai trouvé ces questions ici , ici et ici ce qui m'a mis sur la voie. Le message de Mark Ransom m'a montré la différence, et Le message de Keith m'a montré le chemin. Le Lerp est le sauveur. C'est la même chose que de mélanger les couleurs, donc j'ai créé un blendColors
également la fonction.
Donc, sans plus attendre :
function shadeColor2(color, percent) {
var f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF;
return "#"+(0x1000000+(Math.round((t-R)*p)+R)*0x10000+(Math.round((t-G)*p)+G)*0x100+(Math.round((t-B)*p)+B)).toString(16).slice(1);
}
function blendColors(c0, c1, p) {
var f=parseInt(c0.slice(1),16),t=parseInt(c1.slice(1),16),R1=f>>16,G1=f>>8&0x00FF,B1=f&0x0000FF,R2=t>>16,G2=t>>8&0x00FF,B2=t&0x0000FF;
return "#"+(0x1000000+(Math.round((R2-R1)*p)+R1)*0x10000+(Math.round((G2-G1)*p)+G1)*0x100+(Math.round((B2-B1)*p)+B1)).toString(16).slice(1);
}
Il n'y a pas de contrôle d'erreur, donc les valeurs hors limites transmises provoqueront des résultats inattendus. De plus, la couleur saisie doit comporter EXACTEMENT 7 caractères, par exemple #08a35c
. Mais tous les autres avantages sont toujours là, comme le plafonnement de la plage de sortie (sorties 00-FF), le remplissage (0A), les poignées, etc. #
et utilisable sur des couleurs unies, comme #FF0000
.
Cette nouvelle version de shadeColor prend un flottant pour son deuxième paramètre. Pour shadeColor2
la plage valable pour le deuxième paramètre (pourcentage) est la suivante -1.0
à 1.0
.
Et pour blendColors
la plage valable pour le troisième paramètre (pourcentage) est la suivante 0.0
à 1.0
Les négatifs ne sont pas autorisés ici.
Cette nouvelle version ne prend plus un pourcentage de blanc pur, comme l'ancienne version. Elle prend en compte un pourcentage de la DISTANCE entre la couleur donnée et le blanc pur. Dans l'ancienne version, il était facile de saturer la couleur, et par conséquent, de nombreuses couleurs étaient calculées en blanc pur en utilisant un pourcentage important. Avec la nouvelle version, le calcul du blanc pur n'est effectué que si vous indiquez 1.0
ou du noir pur, utilisez -1.0
.
Appel à blendColors(color, "#FFFFFF", 0.5)
est la même chose que shadeColor2(color,0.5)
. Ainsi que, blendColors(color,"#000000", 0.5)
est la même chose que shadeColor2(color,-0.5)
. Juste un peu plus lentement.
shadeColor2
est plus lent que shadeColor1
mais pas de manière significative. (Attends, c'est une déclaration contradictoire !)
La précision obtenue peut être vue ici :
-- Version RGB --
function shadeRGBColor(color, percent) {
var f=color.split(","),t=percent<0?0:255,p=percent<0?percent*-1:percent,R=parseInt(f[0].slice(4)),G=parseInt(f[1]),B=parseInt(f[2]);
return "rgb("+(Math.round((t-R)*p)+R)+","+(Math.round((t-G)*p)+G)+","+(Math.round((t-B)*p)+B)+")";
}
function blendRGBColors(c0, c1, p) {
var f=c0.split(","),t=c1.split(","),R=parseInt(f[0].slice(4)),G=parseInt(f[1]),B=parseInt(f[2]);
return "rgb("+(Math.round((parseInt(t[0].slice(4))-R)*p)+R)+","+(Math.round((parseInt(t[1])-G)*p)+G)+","+(Math.round((parseInt(t[2])-B)*p)+B)+")";
}
Utilisations :
var color1 = "rbg(63,131,163)";
var lighter-color = shadeRGBColor(color1, 0.5); // rgb(159,193,209)
var darker-color = shadeRGBColor(color1, -0.25); // rgb(47,98,122)
var color2 = "rbg(244,128,0)";
var blend1 = blendRGBColors(color1, color2, 0.75); // rgb(199,129,41)
var blend2 = blendRGBColors(color2, color1, 0.62); // rgb(132,130,101)
-- Version Uni --
function shade(color, percent){
if (color.length > 7 ) return shadeRGBColor(color,percent);
else return shadeColor2(color,percent);
}
function blend(color1, color2, percent){
if (color1.length > 7) return blendRGBColors(color1,color2,percent);
else return blendColors(color1,color2,percent);
}
Utilisation :
var color1 = shade("rbg(63,131,163)", 0.5);
var color2 = shade("#3f83a3", 0.5);
var color3 = blend("rbg(63,131,163)", "rbg(244,128,0)", 0.5);
var color4 = blend("#3f83a3", "#f48000" 0.5);
PT
1 votes
Si vous n'obtenez pas les résultats escomptés en modifiant les couleurs, je vous suggère de vous pencher sur l'espace couleur LAB, qui est plus proche de la vision humaine. De nombreux langages disposent de bibliothèques pour la conversion. D'après mon expérience, les nuances d'orange en particulier peuvent poser problème lors de l'assombrissement ou de l'éclaircissement.
0 votes
Très bon point. Cependant, le but principal de cette question était de trouver, premièrement, la formule la plus rapide et la plus petite taille... et deuxièmement, sa précision. C'est pourquoi je ne me suis pas occupé de la conversion en HSL ou autre. Ici, la vitesse et la taille sont plus importantes. Mais, comme vous pouvez le voir avec ma version 2 de la formule. L'utilisation du LERP pour nuancer donnera des oranges agréables dans toute la gamme de nuances. Jetez un coup d'œil au nuancier ci-dessous et dites-moi si cette gamme de nuances n'est pas assez proche de la réalité.
0 votes
Je me suis un peu embrouillé avec la structure ici, mais vous avez raison, les niveaux d'orange pour shadeColor1 semblent être très bons.
0 votes
Lol, tu veux dire shadeColor2. Je suppose que la structure dont vous parlez est la disposition générale de la réponse elle-même ? Des conseils pour être plus clair ?
0 votes
Non, shadeColor2 ne tient pas compte du changement de teinte que subit normalement l'orange. Voici une capture d'écran montrant comment l'orange se comporte dans (CIE)LAB imgur.com/oHSPWCO . Quant à la structure, c'est peut-être la longueur de la réponse acceptée qui m'a dérouté.
0 votes
Oh, ok, maintenant c'est une clef ! J'ai été amené à croire que ce changement de teinte était une mauvaise chose, comme vous le voyez sur mon nuancier ci-dessous, il passe au rouge pur avec un assombrissement de seulement 60%, en utilisant shadeColor1. Le message de Mark m'a donné cette idée. Je fais ça imgur en utilisant le sélecteur de couleurs d'Adobe Illustrator, il n'y a pas de LAB. Mais regardez les oranges dans la boîte rouge que j'ai dessinée. shadeColor2 suit à peu près cette colonne.
0 votes
Comme vous pouvez le voir dans mon imgur cela crée des oranges de la même teinte qui sont juste plus foncées. C'est probablement ce à quoi les gens pensent quand ils veulent une version plus foncée d'une couleur, je suppose. Lorsque je glisse vers le bas sur le sélecteur de couleurs d'Illustrator, si je regarde les couleurs HSB, cela diminue simplement le B (luminosité). La teinte ne change jamais dans ce grand carré du sélecteur de couleurs, seulement la saturation et la luminosité. La teinte est la colonne la plus mince.
0 votes
Dernière réflexion, regardez ça MinutePhysics vidéo. Ça ressemble vraiment à un problème similaire, peut-être pas. Je ne suis pas sûr de la solution. Parce qu'un changement de la teinte semble être un problème, parce qu'une orange plus foncée... pour la plupart des gens... devrait toujours être orange... et non rouge... Je suppose.
10 votes
Il y a juste un problème dans la fonction avec # ci-dessus, c'est qu'elle ne crée pas les zéros de tête si le code hexagonal final commence par des zéros. Par exemple, si le code hexadécimal est #00a6b7, il sera affiché comme #a6b7, ce qui ne fonctionnera pas si vous l'utilisez comme css. Vous pouvez corriger cela en remplaçant la ligne de retour par ceci : var string = "000000" + (g | (b << 8) | (r << 16)).toString(16) ; return (usePound ? "#" :"") + string.substr(string.length-6) ;
0 votes
@RafaelLevy - Oui, cette question a été traitée. Veuillez consulter la réponse acceptée à cette question ci-dessous pour une version de la fonction qui corrige de nombreux problèmes que la fonction ci-dessus a dans la question originale.
0 votes
Algorithme simple de hsl2rgb stackoverflow.com/a/54014428/860099
0 votes
@KamilKieczewski - oui, cela semble simple. Merci ! Mais l'autre problème principal avec HSL est la double conversion. Une conversion en HSL juste pour augmenter/baisser le L, puis de HSL en RGB. Ce qui semble beaucoup plus lent, je suppose. Surtout que si la couleur d'entrée était HEX, il y aurait deux conversions supplémentaires de HEX à RGB et retour. Mais je ne sais pas. Cette version devait se concentrer sur la vitesse et la taille en premier lieu, la précision en second lieu. Et les nouvelles versions de cette fonction suivront de près l'ombrage des couleurs tel qu'on le voit dans les produits Adobe, comme on le voit ici (dans la boîte rouge) : imgur.com/tmEAfau
0 votes
Vous avez été copié-collé par Chris Coyier 2 ans après votre message ? Méchant Chris ! css-tricks.com/snippets/javascript/lighten-darken-color
0 votes
@martinedwards - Yup ! Faites défiler jusqu'en bas des commentaires sur l'article de Coyier pour lire ma réponse.
0 votes
Si je veux une couleur plus foncée, comment puis-je l'ajuster de disons 40%, et si je veux une couleur plus claire comment puis-je l'ajuster de 40% dans l'autre sens ?
0 votes
@chovy - Hé, vérifiez la réponse acceptée ci-dessous pour une bonne solution et des exemples d'utilisation. Mais il semble que vous voulez de l'ombrage donc, en utilisant la solution ci-dessous, votre réponse serait quelque chose comme
pSBC ( -0.4, color );
pour foncer et ensuitepSBC ( 0.4, color );
pour alléger.