JavaScript不断改变SVG元素的颜色 - 闪烁

时间:2016-06-17 03:42:45

标签: javascript css

我有一个元素,我正在用计时器改变它的颜色:

r = 0.05;
delta = 0.05;
function changecol(){
  if (r < 0.05 || r > 0.95) delta = delta * (-1);
  r += delta;
  col = '#'+(Math.floor(r*255)).toString(16)+(Math.floor(r*255)).toString(16)+(Math.floor(r*255)).toString(16);
  svg_elem.style.fill = col;
  setTimeout("changecol()", 50);
}

因此颜色从白色变为黑色并返回,r*255将其保持在00和FF之间,一切顺利,但当它变为黑色时,它会闪烁到白色并开始基本上升。我在计算中错过了一些错误吗?

这是一个带有演示的jFiddle:https://jsfiddle.net/b4f58bz2/

5 个答案:

答案 0 :(得分:2)

我在你的jsfiddle上运行了一个console.debug,我发现(Math.floor(r*255)).toString(16)当它闪烁时的结果是&#39; C&#39;在十六进制中,就在&#39; 0&#39;之前。问题在于,当翻译成css颜色时,#ccc等于#cccccc,这是一种非常浅的颜色,而不是一种深色。如果长度小于2,则必须使用前导0填充(Math.floor(r*255)).toString(16)的结果,如:

color = (Math.floor(r*255)).toString(16);
if (color.length < 2) {
  color = "0" + color;
}

然后只做:

col = '#' + color + color + color;

我希望这能让你走上正轨。

答案 1 :(得分:1)

这需要一点点。

问题是你转换为toString(16),你没有考虑你的十六进制代码太短的可能性。

 R = hex.length == 1 ? "0" + hex : hex;

请参阅:

r = 0.05;
delta = 0.05;

function changecol() {
  if (r < 0.05 || r > 0.95) delta = delta * (-1);
  r += delta;
  hex = (Math.floor(r * 255)).toString(16);
  R = hex.length == 1 ? "0" + hex : hex;
  col = '#' + R + R + R;

  document.getElementById('test').style.backgroundColor = col;

  setTimeout("changecol()", 300);
}
document.addEventListener('DOMContentLoaded', changecol, false);
<div id="test">
  ADFASDF
</div>
<div id="test1">
  ADFASDF
</div>

答案 2 :(得分:1)

另一张海报已经提到了编码小值时的错误,因此#0C0C0C编码为#CCC,实际上代表#CCCCCC

除此之外,你的代码还有一些不好的做法。

首先:使用局部变量!有些可能是“需要的”全球性的,但col例如没有任何理由可以全球化。那只是环境污染。

下一步:将函数传递给setTimeout,而不是必须解析的字符串。

setTimeout(changecol, 50);

它更快,更清洁,可以封装,可以缩小,......只有好处。

然后,通过一个小技巧,你可以重写你的颜色编码更好:

var c = 255 * r;
var col = "#" + (0x1000000 | c << 16 | c << 8 | c).toString(16).substr(1);

0x1000000是填充,因此值总是超过6位,然后是三个颜色通道(r,g,b)。

此值转换为十六进制值,填充前面有一个1,然后由substr(1)删除。因此,我们总是有6个十六进制数字,每个颜色通道2个,不用担心前导零和东西。

位操作也会删除c可能包含的所有小数位。

并且不要使用body-onload来启动这个东西。如果你真的需要,使用jQuery($(changecol))或搜索DOMContentLoaded实现,...或者只是将脚本放在正文的末尾,因此知道在解析完所有html之后执行该脚本,并且建造了dom。

但是imo。我们可以做得更好。我们可以将这个东西作为时间的函数,而不是递增和递减值,并给它一个5%的填充,这样你就不会越过边界,...

var startTime = Date.now();
var speed = 255 / 1000;   //255 shades of gray / 1000ms

//this means every 2 seconds this animation completes 
//a full cycle from black to white to black again.
//or you slow the speed down to `2*255 / 30000` for example
//1cycle per 30seconds

function changecol(){
    //first we calculate the passed time since the start (in ms) 
    //and then we multiply it by the speed by wich the value should change
    //the amount of color-steps per ms
    var t = (Date.now() - startTime) * speed;

    //now we get the fraction of 256 wich defines the shade
    /*
        var c = Math.floor(t % 256);
    */
    //since we're dealing with powers of 2 we can use a bit-mask to extract just 
    //the last 8 bit of the value and do basically the same, including the Math.floor()
    var c = t & 0xFF;

    //every other interval we have to change the direction, so that we fade back from white to black
    //and don't start over from 0 to 255 (black to white)
    /*
        var interval = Math.floor(t / 256);  //get the interval
        if(interval % 2 === 1)               //check wether it's odd
            c = 255 - c;  //revert the direction
    */
    //but again we can do easyer by simply checking the 9th bit. 
    //if it's a 1, this is an odd interval. the 9th bit equals 0x100 (256).
    if(t & 0x100) //mask only the 9th bit. returns either 256 (wich is true) or 0 (false)
        c = 0xFF - c;  //revert the direction

    var col = "#" + (0x1000000 | c << 16 | c << 8 | c).toString(16).substr(1);
    test.style.color = col;

    //using animation-frames to stay in sync with the rest of animation in the browser.
    requestAnimationFrame(changecol);
}
changecol();  //start this thing, don't use body-onload

答案 3 :(得分:1)

要从黑色变为白色,您可以简单地使用HSL的亮度部分,其饱和度为0%,将其作为颜色参数:

setTimeout()替换requestAnimationFrame()也可以使动画更顺畅,因为它会同步到监视器vblank更新。通过将delta减少到大约一半来弥补。

使用div

的示例

var l = 5;
var delta = 2.5;

(function changecol() {
  if (l < 5 || l > 95) delta = -delta;
  l += delta;
  d.style.backgroundColor = "hsl(0,0%," + l + "%)";
  requestAnimationFrame(changecol);
})();
<div id=d>Ping-pong fade</div>

答案 4 :(得分:0)

你可以做这样的事情,这样你就不必尝试找出正确的十六进制代码。

var whatColor = true;
fadeColor = function() {

  var color = whatColor ? 'white' : 'black';
  $('svg circle').css({fill: color});
  whatColor = !whatColor;
  setTimeout(function() {
    fadeColor();
  }, 1000);
  
}
fadeColor();
svg circle {
  -webkit-transition: fill 1s;
  transition: fill 1s;
  fill: black;
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<svg class="mySVG" height="100" width="100">
  <circle cx="50" cy="50" r="40" stroke="black" stroke-width="3"  />
</svg>