簡體   English   中英

JavaScript不斷改變SVG元素的顏色-閃爍

[英]JavaScript continiously changing colour of SVG element - flickers

我有一個元素,並且正在使用計時器更改其顏色:

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/

我在您的jsfiddle上運行了一個console.debug,我發現(Math.floor(r*255)).toString(16)閃爍時的結果是十六進制的“ C”,就在“ 0”之前。 問題在於,當轉換為CSS顏色時,它是: #ccc等於#cccccc ,這是一種非常淺的顏色而不是深色。 如果(Math.floor(r*255)).toString(16)的長度小於2,則必須在其前加上0。

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

然后做:

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

我希望這能使您走上正確的道路。

這花了一點時間。

問題是您對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> 

另一個張貼者已經提到過您在編碼小值時的錯誤,例如,將#0C0C0C編碼為#CCC wich,實際上代表#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)。

該值被轉換為十六進制值,該值在填充之前位於其前面,然后被substr(1)刪除。 因此,我們總是精確地有6個十六進制數字,每個顏色通道2個,而不必擔心前導零和填充。

而且位運算還去除了c可能具有的所有小數位。

並且不要使用body-onload來開始這個事情。 如果確實需要,請使用jQuery($(changecol))或搜索DOMContentLoaded-implementation,...或只是將腳本放在正文的末尾,並因此知道在解析所有html之后執行該腳本,並且圓頂建成。


但是,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

要從黑色變為白色,您只需使用飽和度為0%的HSL的“亮度”部分,並將其作為顏色參數即可:

setTimeout()替換為requestAnimationFrame()還將使動畫更加平滑,因為這將同步到監視器vblank更新。 只需通過將增量減少到一半來進行補償即可。

使用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> 

您可以改為執行類似的操作,這樣就不必嘗試找出正確的十六進制代碼。

 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> 

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM