序二(09/11/1)
近来看了Dean的“Convert any colour value to hex in MSIE”,终于解决了根据关键字获取颜色rgb值的问题。顺便把程序也重新整理一番,并使用了最近整理的工具库。
序一(09/03/11)
很久没写blog,太忙了。没什么时间写复杂的东西,重新把颜色渐变效果写一遍。关于颜色的效果一般就两个,颜色梯度变化和颜色动态渐变,前者在ie中一般用滤镜实现。
效果预览
颜色梯度变化演示: "; }).join(""); } GradsSet("green"); 简单的颜色拾取器(点击修改梯度演示颜色): 颜色渐变菜单: CropperTweenSliderResizeDragTooltips 点击随机颜色渐变: 点击随机颜色渐变
程序说明
【ColorGrads颜色梯度】
程序ColorGrads的作用是根据颜色集合和渐变级数生成颜色梯度集合。渐变级数的意思是分多少步完成渐变。
网页设计中的颜色是用RGB色彩模式呈现的。在这个模式中每种颜色可以用三个代表红(r)、绿(g)、蓝(b)的颜色值(0到255)来表示。
从w3c的Colors部分看到标准中颜色的表示形式包括:关键字形式:em { color: red }RGB形式:em { color: #f00 }em { color: #ff0000 }em { color: rgb(255, 0, 0) }em { color: rgb(100%, 0%, 0%) }以上都是表示同一种颜色(红色)。关键字形式就是用关键字代表颜色值。而RGB形式,前两种用的比较多,都是一个"#"后面带16进制表示的颜色值,第三种是用十进制的颜色值,第四种是实际值跟255的百分比形式。
各个浏览器对各种颜色表示形式的获取并不相同:
"color: red"形式: ieoperaffchrome/safaristyleredred#ff0000redcurrentStylered"red" getComputedStyle #ff0000rgb(255, 0, 0)rgb(255, 0, 0)"color: #ff0000"/"color: #f00"形式: ieoperaffchrome/safaristyle#ff0000/#f00#ff0000rgb(255, 0, 0)rgb(255, 0, 0)currentStyle#ff0000/#f00#ff0000 getComputedStyle #ff0000rgb(255, 0, 0)rgb(255, 0, 0)"color: rgb(255, 0, 0)"/"color: rgb(100%, 0%, 0%)"形式: ieoperaffchrome/safaristylergb(255,0,0)#ff0000rgb(255, 0, 0)rgb(255, 0, 0)currentStylergb(255,0,0)#ff0000 getComputedStyle #ff0000rgb(255, 0, 0)rgb(255, 0, 0)基本上得到的值还是按标准的形式显示的,只是有些会自动转换形式。不过ie的rgb形式跟ff/chrome/safari的不同,数值之间并没有空格。要特别注意的是opera用currentStyle获取关键字形式得到的颜色值是带双引号的,十分奇怪,要尽量避免使用。
要获取两种颜色的渐变梯度,先要把颜色转化成能用来计算的数值。GetColor和GetData程序就是用来把符合w3c标准表示的颜色值转化成组合该颜色的红(r)、绿(g)、蓝(b)的颜色数值。RGB形式的值本身就已经带了rgb的具体数值,只要用正则把值提取出来再转化就可以了。这个过程在GetData中进行:
Code function GetData(color) { var re = RegExp; if (/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.test(color)) { //#rrggbb return $$A.map([ re.$1, re.$2, re.$3 ], function(x){ return parseInt(x, 16); }); } else if (/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(color)) { //#rgb return $$A.map([ re.$1, re.$2, re.$3 ], function(x){ return parseInt(x + x, 16); }); } else if (/^rgb\((.*),(.*),(.*)\)$/i.test(color)) { //rgb(n,n,n) or rgb(n%,n%,n%) return $$A.map([ re.$1, re.$2, re.$3 ], function(x){ return x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x | 0; }); }}注意#rrggbb/#rgb形式得到的是16进制的数值字符,把parseInt的第二个参数设为16就可以指定用16进制来处理字符串转换。对于rgb(n,n,n)/rgb(n%,n%,n%)的形式,直接取得数值,如果有%就根据百分比计算对应数值就行了。使用这种形式设置颜色时也要注意,ie6和ie7允许数字百分比混用,其他不可以(包括ie8);ie6和ie7可以用空格或逗号分隔数值,其他必须用逗号(包括ie8);当然我们使用时也应该是按照w3c的标准来设置了。ps:那个DHTML 手册上写的 EM { color: rgb 1.0 0.0 0.0 } 是不能用的,不要被误导了。
如果是关键字形式那就要另外想方法了,可以用一个字典对象来匹配颜色值,但这样程序会变得很庞大。ps:可以到这里看所有颜色名对应的数值。近来dean发表了“Convert any colour value to hex in MSIE”,终于解决了这个难题。其中的关键是利用queryCommandValue("ForeColor")来获取颜色值(或许做过编辑器的会比较熟悉)。queryCommandValue的作用是返回document、range或current selection对于给定命令的当前值。而ForeColor命令是设置或获取文本时的前景色。
具体的做法是先创建一个textarea:
if ( ! frag) { frag = document.createElement( " textarea " ); frag.style.display = " none " ; document.body.insertBefore(frag, document.body.childNodes[ 0 ]);};ps:由于ie的document.body.appendChild()导致IE已终止操作bug,所以要用insertBefore。
然后设置color为要取值的颜色:
try { frag.style.color = color; } catch (e) { return [ 0 , 0 , 0 ]; }ps:在ie如果设置错误的颜色值会报错,所以这里用try...catch来保证能返回值。
能使用queryCommandValue方法的对象包括document、range和current selection。用createTextRange就可以建立一个range:
color = frag.createTextRange().queryCommandValue( " ForeColor " );createTextRange可以用在Body,Button,Input和TextArea。dean是用createPopup().document.body的,好处是不用插入元素到dom。但createPopup是ie的方法,而TextArea还可以用于getComputedStyle,后面会用到。
这样得到的颜色值是一个数值,这个数字跟颜色的关系是这样的:例如红色的16进制rgb是ff0000,先转成bgr,即0000ff,然后转成10进制,得到255。同样粉红色pink是FFC0CB,转成bgr是CBC0FF,10进制是13353215。ps:使用时要注意,跟一般不同,queryCommandValue("ForeColor")得到的颜色是bgr排列的。
要得到rgb的值可以把转换过程倒过来获取,不过参考dean的文章有更巧妙的方法:
ret = [ color & 0x0000ff , (color & 0x00ff00 ) >>> 8 , (color & 0xff0000 ) >>> 16 ];先用与操作(&)把对应位的数值取出来,再用右移运算符(>>>)把数值移到正确的位置上。
例如粉红色FFC0CB要取得绿(g)的颜色值,用与操作(&)取得对应值,FFC0CB & 0x00ff00得到C000,然后右移8个数位得到C0(16进制的一位相当于二进制的4位),即192。
其他支持document.defaultView的可以直接用getComputedStyle获取color。从上面各个浏览器获取颜色值的结果可知获取的值都是RGB形式的值,所以可以直接用GetData转换:
ret = GetData(document.defaultView.getComputedStyle(frag, null ).color);注意除了ff,如果元素没有插入dom,用getComputedStyle是获取不了color的,所以元素创建时要顺便插入到body中。
在GetStep用GetColor获得颜色值之后,再根据step就可以获得步长了:
var colors = [], start = GetColor(start), end = GetColor(end), stepR = (end[ 0 ] - start[ 0 ]) / step, stepG = (end[ 1 ] - start[ 1 ]) / step, stepB = (end[ 2 ] - start[ 2 ]) / step;再根据步长生成集合:
for ( var i = 0 , r = start[ 0 ], g = start[ 1 ], b = start[ 2 ]; i < step; i ++ ){ colors[i] = [r, g, b]; r += stepR; g += stepG; b += stepB;}colors[i] = end;正确的颜色值是在0到255之间的,而且是不带小数的,需要修正一下:
return $$A.map(colors, function (x){ return $$A.map(x, function (x){ return Math.min(Math.max( 0 , Math.floor(x)), 255 );});});
程序支持设置多个颜色的连续变换:
for ( var i = 0 , n = len - 1 ; i < n; i ++ ){ var steps = GetStep( colors[i], colors[i + 1 ], step ); i < n - 1 && steps.pop(); ret = ret.concat(steps);}要注意的是要去掉各次变换之间重复的颜色组合(steps.pop())。
【ColorTrans颜色渐变】
有了颜色梯度集合,只需要设个定时器把颜色集合的元素依次显示就是一个渐变效果了。这个渐变有两种效果:颜色渐入(transIn)和颜色渐出(transOut)。原理就是通过改变_index集合索引属性,渐入时逐渐变大,渐出时逐渐变小:
Code transIn: function() { this.stop(); this._index++; this._set(); if(this._index < this._colors.length - 1){ this._timer = setTimeout($$F.bind( this.transIn, this ), this.speed); } }, transOut: function() { this.stop(); this._index--; this._set(); if(this._index > 0){ this._timer = setTimeout($$F.bind( this.transOut, this ), this.speed); } },在_set设置样式程序中修改样式:
var color = this ._colors[Math.min(Math.max( 0 , this ._index), this ._colors.length - 1 )]; this ._elem.style[ this .style] = " rgb( " + color.join( " , " ) + " ) " ;其中style属性是要修改的样式属性名,例如颜色是"color",背景色是"backgroundColor"。
由于颜色集合是根据开始颜色、结束颜色和步数生成的,所以如果要修改这些属性必须重新生成过集合。reset程序就是用来重新生成集合的,同时索引也会设回0:
this ._options = options = $$.extend( this ._options, options || {}); this ._colors = ColorGrads( [options.from, options.to], options.step ); this ._index = 0 ;程序初始化的时候也会reset一次:
this .reset({ from: this .options.from || $$D.getStyle( this ._elem, this .style), to: this .options.to, step: Math.abs( this .options.step)});如果没有自定义from颜色的话会自动获取当前颜色。
使用技巧
链接标签a的伪类的颜色暂时没有办法直接用dom来修改(除非改class)。所以在颜色渐变菜单中用了个小技巧,把a的内容和跳转换到td的innerHTML和onclick上实现:
var a = x.getElementsByTagName( " a " )[ 0 ], href = a.href, txt = a.innerHTML;x.onclick = function (){ location.href = href; }x.innerHTML = txt;这样就可以实现效果的同时保持可访问性。
在测试过程中还发现一个数组的问题,运行alert([,,].length),在ie会返回3,其他会返回2。在mozilla的Array_Literals部分查到:If you include a trailing comma at the end of the list of elements, the comma is ignored. 即如果数组字面量元素集合的最后是逗号,逗号会被忽略掉。
使用说明
ColorGrads的第一个参数是颜色集合,第二个参数是渐变级数。
ColorTrans只要一个参数,要实现渐变的对象,可设置以下属性:from: "",//开始颜色to: "#000",//结束颜色step: 20,//渐变级数speed: 20,//渐变速度style: "color"//设置属性(Scripting属性)from默认是空值,方便判断自动获取。其中from、to和step在实例化后要修改的话需要用reset来设置。具体使用请参考实例。
程序代码
ColorGrads部分:
Code var ColorGrads = (function(){ //获取颜色梯度数据 function GetStep(start, end, step) { var colors = [], start = GetColor(start), end = GetColor(end), stepR = (end[0] - start[0]) / step, stepG = (end[1] - start[1]) / step, stepB = (end[2] - start[2]) / step; //生成颜色集合 for(var i = 0, r = start[0], g = start[1], b = start[2]; i < step; i++){ colors[i] = [r, g, b]; r += stepR; g += stepG; b += stepB; } colors[i] = end; //修正颜色值 return $$A.map(colors, function(x){ return $$A.map(x, function(x){ return Math.min(Math.max(0, Math.floor(x)), 255); });}); } //获取颜色数据 var frag; function GetColor(color) { var ret = GetData(color); if (ret === undefined) { if (!frag) { frag = document.createElement("textarea"); frag.style.display = "none"; document.body.insertBefore(frag, document.body.childNodes[0]); }; try { frag.style.color = color; } catch(e) { return [0, 0, 0]; }//ie opera if (document.defaultView) { //opera #rrggbb ret = GetData(document.defaultView.getComputedStyle(frag, null).color); } else { color = frag.createTextRange().queryCommandValue("ForeColor"); ret = [ color & 0x0000ff, (color & 0x00ff00) >>> 8, (color & 0xff0000) >>> 16 ]; } } return ret; } //获取颜色数组 function GetData(color) { var re = RegExp; if (/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i.test(color)) { //#rrggbb return $$A.map([ re.$1, re.$2, re.$3 ], function(x){ return parseInt(x, 16); }); } else if (/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i.test(color)) { //#rgb return $$A.map([ re.$1, re.$2, re.$3 ], function(x){ return parseInt(x + x, 16); }); } else if (/^rgb\((.*),(.*),(.*)\)$/i.test(color)) { //rgb(n,n,n) or rgb(n%,n%,n%) return $$A.map([ re.$1, re.$2, re.$3 ], function(x){ return x.indexOf("%") > 0 ? parseFloat(x, 10) * 2.55 : x | 0; }); } } return function(colors, step){ var ret = [], len = colors.length; if ( step === undefined ) { step = 20; } if ( len == 1 ) { ret = GetStep( colors[0], colors[0], step ); } else if ( len > 1 ) { for(var i = 0, n = len - 1; i < n; i++){ var steps = GetStep( colors[i], colors[i+1], step ); i < n - 1 && steps.pop(); ret = ret.concat(steps); } } return ret; }})();
ColorTrans部分:
Code var ColorTrans = function(elem, options){ this._elem = $$(elem); this._timer = null;//定时器 this._index = 0;//索引 this._colors = [];//颜色集合 this._options = {};//参数对象 this._setOptions(options); this.speed = Math.abs(this.options.speed); this.style = this.options.style; this.reset({ from: this.options.from || $$D.getStyle(this._elem, this.style), to: this.options.to, step: Math.abs(this.options.step) }); this._set();};ColorTrans.prototype = { //设置默认属性 _setOptions: function(options) { this.options = {//默认值 from: "",//开始颜色(默认空值方便自动获取) to: "#000",//结束颜色 step: 20,//渐变级数 speed: 20,//渐变速度 style: "color"//设置属性(Scripting属性) }; $$.extend(this.options, options || {}); }, //重设颜色集合 reset: function(options) { //根据参数设置属性 this._options = options = $$.extend( this._options, options || {} ); //获取颜色集合 this._colors = ColorGrads( [ options.from, options.to ], options.step ); this._index = 0; }, //颜色渐入 transIn: function() { this.stop(); this._index++; this._set(); if(this._index < this._colors.length - 1){ this._timer = setTimeout($$F.bind( this.transIn, this ), this.speed); } }, //颜色渐出 transOut: function() { this.stop(); this._index--; this._set(); if(this._index > 0){ this._timer = setTimeout($$F.bind( this.transOut, this ), this.speed); } }, //颜色设置 _set: function() { var color = this._colors[Math.min(Math.max(0, this._index), this._colors.length - 1)]; this._elem.style[this.style] = "rgb(" + color.join(",") + ")"; }, //停止 stop: function() { clearTimeout(this._timer); }};
下载完整实例
转载于:https://www.cnblogs.com/cloudgamer/archive/2009/03/11/color.html
相关资源:数据结构—成绩单生成器