[英]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更新。 只需通過將增量減少到一半來進行補償即可。
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.