你可曾在某些站点上见过某一词组或是句子呈一种颜色到另一种颜色的渐变显示?--注意,是字符而不是图形。假如你见过,一定会疑惑是没有使用一些特效程序才能实现这种直接在页面上输出的颜色渐变效果。那么在这一节内容中,我们将学习到javascript中的一些先进的功能,而使之成为现实。
我们首先需要学习一下相关的前提知识,假如你对以下几个部分:“颜色是如何工作的”“十六进制配色系统”“十六进制的表示法”有所知晓的话,可以跳过不看。
颜色是如何工作的
你可能知道,显示器是通过像素(pixel)来显示每一件事物的,在屏幕上有很多你看不到的小点,它们由红、绿、蓝三种颜色色组成。事实上,这些颜色也是色谱中的主要组成颜色。我们平时所看到的任何颜色都是由红绿蓝三原色不同调配而组成的。为了使每一个像素呈现颜色,我们可以通过不断调整红绿蓝三色的强度对比来形成各种色彩。比如,可以让所有的像素呈现为黑色、或白色,或其中一部分为蓝色。
十六进制配色系统
十六位进制是16位系统的基础,然而,我们一向使用的是十位进制系统,这一点对你来说意味着什么?这意味着将多出六个数字要你来处理。在每一个数字系统中你可以看到。在十位制系统中,我们使用数字0-9来书写所有的数字。在十六进制数中,我们使用数字0-F。在这里,A=10(十进制),B=11, C=12, D=13, E=14,F=15。那么我们怎样来使用这个陌生的系统进行计算呢?其计算方法与十进制实际上是一样的。
十进制数值: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20...
对应以上数值用十六进制表示即:0 1 2 3 4 5 6 7 8 9 A B C D E F 10 11 12 13 14...
十六进制数的表示法
十六进制数表示法和十进制数是一样的,虽然你可能没有意识到。在十进制数中,所有的数值均可以10为基础来表示,即使我们并不真的想这样做。
例如,十进制数值16345:
1 x 104 + 6 x 103 + 3 x 102 + 4 x 101 + 5 x 100 = 16345
以此类推,以上数值转换成十六进制数为3FD9(别忘了F=15,D=13),我们可以用以下的表达式来表示:
3 x 163 + F x 162 + D x 161 + 9 x 160 = 3FD9
令人惊讶!所以当你对十六进制有了一个全局概念以后,你会认识到在十进制和十六进制或其他进制数之间其实并没有什么大的差别,计算机的创造者决定了使用十六进制作为标准的计算机语言,尽管计算机本身的运行是使用二进制系统,这个我们将在稍后介绍。假如你曾接触过某些低级语言,你就会认识到十六进制更易于读取,因为它允许用更少的数字来表示较大的十进制数值。在本课中不再介绍如何实现十进制和十六进制数之间的相互转换,因为你必须要使用一个计算器才能进行顺利的转换,并要认识到十六进制倒底划什么,而在本课的范围中并不需要碰到这些。
十六进制数在像素中的实现
在大多数的程序语言中,甚至HTML,都使用到RGB色彩模式,其利用红、绿、蓝三种颜色组合成某种颜色组成一个像素点。一个RGB色彩,在我们的认识中,是3个字节(byte),每一个字节是RGB色彩中的一个组成部分。注意1 byte = 8 bits,而RGB色彩是24位色彩系统,每一位单独的字节代表十进制数0-255中的某一个值,用十六进制表示就是0-FF。在HTML中,你可以看到象这样的标签,< font color="#FF0000" >,那么这个值在RGB色彩中就代表了红色。注意它用六位数字来表示,RGB色彩不可以用超过六位数字的长度来表示,因为它只有三个字节。在RGB色彩中,“#FF12AC”,第一第二个数字“FF”,该像素表示为为纯红色,这是最高数了,因为在字节中没有再超过FF的数值了;接下来的两个数字“12”,表现为某种很亮的绿色,这个数值相当的低,最后两位数字“AC”,在该像素中表现为很强亮度的蓝色,这个数值比较高。最后,这个像素的组合色彩显示为粉红色。
请注意绝大多数的编程语言,包括javascript,十六进制必须用“0x”来表示,这可以使计算机不至于把十进制和十六进制混淆起来。因此早先在javascript中使用RGB色彩时,上面的数值应写成0xFF12AC,举个例子,我们可以在javascript中定义背景颜色为那种粉红色:
document.bgColor = 0xFF12AC;
使用RGB色彩的红、绿、蓝各自的256种深浅变化来组合调变颜色,我们可以实现16万种色彩!
色彩渐变
现在我们明白了色彩和像素是如何来工作的,我们就要说上正题,倒底字符的渐变怎么来实现呢?
渐变是指两种不同的颜色,分别作为起始色和终结色,找出它们需要多少步色彩增量变化才可从起始颜色变成最终颜色。它可用以下公式来表示:
(secondcolor - firstcolor) / number_of_steps;
“secondcolor”即指最终指定颜色,“firstcolor”就是起始的颜色。变量“number_of_steps”指所要渐变字符的长度,我们用这个变量来确定像素中的每个字符有多少增量变化,如果我们能知道字符间增量的话,下面这行语句就是我们所需要的:
(secondcolor - firstcolor) / string.length;
开始渐变
虽然上面的概念很简单,但我们需要把它用到实际中去。我们需要在由红、绿、蓝所组成的各种颜色中实现渐变,如果我们仅仅只是减去红和蓝并使用某些数值来划分它们,那么色彩渐变是不会正确的依照色谱的物理原理来工作的。我们需要某种漂亮的过渡结果。那么,我们必须从RGB颜色中分开红、绿、蓝三种原色,并单独的对某一种主色调进行计算。
你可能会疑惑你倒底怎么去做这件事!这中间包含了一种更先进的方法-位屏蔽。位屏蔽将艺术化的取走我们不再需要的某些色块
计算机里的所有信息都以二进制方式存储,这意味着你能使用的数字仅仅是0或1。(对于电气工程师来说,1表示高电压而0表示低电压,但这里仅需了解到计算机是用二进制进行操作的)所以十进制数20,十六进制数0x14,转化为二进制数即是10100。和十六进制及十进制一样,我们用相应的方法来计算二进制数,因此数值0-10用以下二进制来表示:
0, 1, 10, 11, 100, 101, 110, 111, 1000, 1001, 1010
二进制1010可用以下算式来换算成十进制数值:
1 x 23 + 0 x 22 + 1 x 21 + 0 x 20 = 10
javascript、c,以及所有真正的编程语言都允许你除去不需要的bit(比特,二进制计数)。
介绍三种基本的逻辑操作,and(&)、or(|)和xor(^)。下面是它们的逻辑计算方式:
现有二进制数11101011,要除去最前面的三个高位1,只需进行以下操作:
反过来,如果是要把二进制数00001011前面三个低位0转换成高位1,只需如此操作:
了解位移位
在我们能够完全分离RGB色彩的颜色组合之前,我们还需了解一个关键的问题-位移位。照字面意义看来“位移位”就是指把bit往右或是往左移动。在javascript中,用字符“ > >”表示右移位,字符“< < ”表示左移位。注意这些操作数必须是32位操作,移位后出现的空位用0补上。以下是一些在二进制中的位移位。
在二进制数中 移位操作
红色(Red)
在这个部分,我们将举0xAABBCC为例。首先,我们需要得到三原色的红色部分。最纯的红色应为0xFF0000,那是在高位的两个数值,我们必须去掉数值中的“BBCC”,我们并不使用位屏蔽的方法来得到红色,而采用移动操作把“BBCC”去掉。后者可使用右移位操作来完成。然而在本课中,有一个很容易忽略的小错觉,我们不能使用简单的把0xFF0000右移四位,因为这不是一种算术方法。
0xFF0000 > > 4 = 0x0FF000
这是因为移位操作是进行单独的比特(bit)移位,而一个字节中有八个bits,所以在上例中仅仅移了0xFF0000半个字节,而我们是需要移两个字节,或16个比特,所以正确的方法应为:
0xAABBCC > > 16 = 0xAA
绿色(Green)
在三原色中找出绿色,在这里我们需要同时使用到上面所学的屏蔽及移位操作的知识。在三原色中,中间的两位数字是表示绿色,那么如何来得到它?我们知道AND操作是操作数中有一个0结果即为0,我们可以这样来做:
0xAABBCC & 0x00FF00 = 0x00BB00
然而这个数值似乎太大了,我们还必须向右移位1个字节:
(0xAABBCC & 0x00FF00) > > 8 = 0xBB
蓝色(Blue)
在RGB中得到蓝色,我们仅需去掉前面两个字节,可以这么做:
0xAABBCC & 0x0000FF = 0xCC
24位色彩渐变公式
当把三原色从RGB色彩中分离出来以后,我们必须计算RGB中每一部分相差多少色彩增量值。计算公式如下:
RedStep = (endRed - startRed) / string.length
GreenStep = (endGreen - startGreen) / string.length
BlueStep = (endBlue - startBlue) / string.length
应用到真正的字符上去
最后,我们可以来讨论真正的字符串的渐变过程了。我们的方法是从初始颜色开始,每一个邻近的字母都发生一些RGB组色变化,我们通过javascript,让字母渐变在HTML页显示出来。代码这样写:
for (var index = 0; index < string.length;index++)
document.write("< font color=' ",color, " ' >", string.charAt(index), "< /font >");
为了让它工作起来,必须每次都变换色彩数值,我们得在HTML语法的色彩数值之前加上一个标记#。
十进制转换到十六进制
在我们开始转换RGB到十六进制以前,我们已经学过如何分离三原色,在这里我们必须得重温一下。用位屏蔽的OR操作以及简单的左移位可以实现这个任务,让所有的比特出现在它应该的地方:
var merged = (red < < 16) | (green < < 8) | blue;
这里要稍微补充一下。从十六进制转换到十进制的方法,是把原始数值除以16,保存其余值,继续除以16,直至它比16小。下面这个函数返回的是字符串而不是数值,javascript会自动把数值转换为十进制,那对我们来说是无意义的。不要担心无法理解这些代码,重要的是你要理解十六进制数是如何来描述RGB色彩的。
var h="0123456789ABCDEF";
function hex(c) {
var temp = "";
var hexStr = "";
var remainder, i;
// divide c by 16 each time
for( ; c != 0; c > >= 4) {
remainder = c % 16;
hexStr += h.charAt(remainder);
}
// only thing with a conversion is that it does it backwards
// so this makes it right
// you could have also used recursion but that
// would have been more complicated
for(i=5 ; i >= 0; i--)
temp += hexStr.charAt(i);
// return the converted hex number
return temp;
}