iT邦幫忙

0

marquee去抖動

如題 marquee在滾動時文字會有些微抖動
不知道該如何解決這問題 可能跟我內容會動態變動有關

html

<table>
<tr>
<td class=title>下一首:</td>
<td><marquee scrollamount=25><div id=req class=next></div></marquee></td>
</tr>
</table>

js

function next_call()
{
	$.getJSON("data/complex.json",
		function(b)
		{
			request_json=b.requestlist;
			request_length=request_json.length;
			currenttrack_json=b.currenttrack;
			currenttrack_length=currenttrack_json.length;
			currenttrack_html="";
			request_html="";
			for(q=0;q<1;q++)
			{
				var time_r=currenttrack_json[q].time_remaining_seconds;
				var min=Math.floor(time_r/60);
				if(min<10)
				{
					min="0"+min;
				}
				var sec=Math.floor(time_r%60);
				if(sec<10)
				{
					sec="0"+sec;
				}
				request_html+='歌手:'+request_json[q].artist+"&nbsp&nbsp&nbsp";
				request_html+="歌名:"+request_json[q].title+"&nbsp&nbsp&nbsp";
				request_html+='專輯:'+request_json[q].album+"&nbsp&nbsp&nbsp";
				request_html+="時間:"+request_json[q].length+"&nbsp&nbsp&nbsp";
				currenttrack_html+="離下首播放還剩:"+min+"分"+sec+"秒";
			}
			request_html+="";
			currenttrack_html+="";
			$("#req").html(request_html+currenttrack_html);
		}
	)
}
看更多先前的討論...收起先前的討論...
淺水員 iT邦新手 5 級 ‧ 2018-12-07 23:51:34 檢舉
何謂抖動呢?
scrollamount=25 是指每次移動25個像素吧,你說的是這個嗎?
淺水員 iT邦新手 5 級 ‧ 2018-12-07 23:56:24 檢舉
另外也許可以考慮用CSS動畫處理
不是scrollamount 就是移動時文字感覺會有些微抖動 我還是綠個影片八
不行 錄出來的全是抖動的 你還是直接到該網站上看吧
http://ac1011.hopto.org:4095/next.html

就是文字不定時的會抖動個一 兩下
淺水員 iT邦新手 5 級 ‧ 2018-12-08 10:19:34 檢舉
我發現在 Firfox 只會一直閃...
我用chrome看是偶而會抖動個一兩下而已
firefox的問題解決了 加個width就好了
淺水員 iT邦新手 5 級 ‧ 2018-12-08 11:42:44 檢舉
預先問看看,我大概晚上才有時間想:
如果在臨界狀況,像是A跑到中間就要換B了,這時候打算怎麼做?
1. 直接清除A,讓B從右邊跑出來
2. 等A跑到左邊結束後,B再跑出來(這要考慮A的倒數秒數變成負值)
3. 直接把 A 換成 B(如果A跟B長度不同,要用哪邊對齊?"左,右,中")
4. A淡出B從右邊跑出來(這個好像比較複雜些)
以目前狀況來說是3吧

1 個回答

0
淺水員
iT邦新手 5 級 ‧ 2018-12-09 17:05:58

先說原因
根據我的觀察,是 marquee 在處理長度時,根據的是一開始從左邊跑出來的長度
即使中途變更內文,他還是當作原先的長度處理。

因此,當中途改變時:

  1. 由短變長,實際上原本舊的長度已經跑到結尾了,但視覺上後來更新的資料比較長(看起來還沒跑完),所以感覺會突然跳到右側重新開始。
  2. 由長變短,原本多出來長度的部分看起來是空白,此時可能會感覺到等待一小段空白才會從右側再跑出來。

至於解決辦法, marquee 原本設計並沒有考慮到內文變更,所以最偷懶的方法是想辦法讓訊息的 width 一樣。
如果要做比較精細的控制,看是用 javascript 動畫,或是 svg+SMIL,或是CSS動畫。後兩者可能需要配合 javascript 來改變屬性。


另外,我個人是覺得不需要 0.5秒 送一次 ajax 啦。
用 timer 每秒更新一次就好,當時間變成 0 之後再送 ajax。
如果希望時間準確些,可以再配合每幾秒(例如15秒)校正一次就好。

淺水員 iT邦新手 5 級 ‧ 2018-12-10 12:08:54 檢舉

用 CSS 動畫做的範例

index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>marquee</title>
    <style>
        #myCssMarque{
            width:300px;
            position:relative;
            border:1px solid;
            overflow:hidden;
        }
    </style>
    <script src="CssMarque.js" type="text/javascript"></script>
</head>
<body>
    <div id="myCssMarque"></div>
    <button id="testL">長</button>
    <button id="testS">短</button>
    <button id="testP">短(不重設動畫)</button>
    
    <script type="text/javascript">
        var t=new CssMarquee("myCssMarque",150);
        t.setText("123");

        document.getElementById("testL").addEventListener("click",function(){
            t.setText("12345678901234567890");
        });
        document.getElementById("testS").addEventListener("click",function(){
            t.setText("123");
        });
        document.getElementById("testP").addEventListener("click",function(){
            t.setText("321",true);
        });	
    </script>
</body>
</html>

CssMarquee.js

function CssMarquee(tagId,speed)
{
    this.st=0; //0為沒在跑,1為正在跑
    this.speed=speed; //速度,每秒幾像素
    //容器相關資訊
    this.tagId=tagId;
    this.container=document.getElementById(tagId);
    this.container.innerHTML="";
    this.leftBorder=parseInt(getComputedStyle(this.container)["border-left-width"],10); //容器的 border
    
    //建立 span (內部真正在跑的區域)
    this.span=document.createElement("span");
    this.container.appendChild(this.span);
    this.span.textContent="marquee"; //這隨便給的初值
    
    //建立 style (放置動畫 keyframe 參數)
    this.myCss=document.createElement("style");
    document.body.appendChild(this.myCss);
    
    //設定動畫結束的 callback (用來重新下一輪動畫)
    this.span.addEventListener('animationend',CssMarquee.prototype.onAniEnd.bind(this));
}
CssMarquee.prototype.setText=function(text,lenUnchange)
{
    //當 lenUnchange 為 true 時,直接變更 textContent 即可
    //例如變更倒數計時的時間,如果每次都重新設定動畫會卡卡的
    //這時就可以用這功能(把第2個參數設為 true)
    if(lenUnchange && this.st==1){
        this.span.textContent=text;
        return;
    }
    
    var rect0=this.span.getBoundingClientRect(); //span 原先的矩形
    this.span.textContent=text;
    this.span.setAttribute("style","\
        position:relative;\
        left:100%;\
    "); //先清除動畫,以重新設定
    
    var rect1=this.span.getBoundingClientRect(); //span 變更後的矩形
    var rect2=this.container.getBoundingClientRect(); //容器的矩形
    var total_t;
    
    if(this.st==0){ //已經跑完了
        total_t=(rect2.width+rect1.width)/this.speed;
        this.myCss.innerHTML="\
            @keyframes ani_"+this.tagId+"{\
                0%{left:"+rect2.width+"px}\
                100%{left:-"+rect1.width+"px}\
            }\
        ";
    } else { //正在跑	
        total_t=(rect0.left-rect2.left-this.leftBorder+rect1.width)/this.speed;
        this.myCss.innerHTML="\
            @keyframes ani_"+this.tagId+"{\
                0%{left:"+(rect0.left-rect2.left-this.leftBorder)+"px}\
                100%{left:-"+rect1.width+"px}\
            }\
        ";
    }
    this.span.setAttribute("style","\
        position:relative;\
        left:100%;\
        animation-name:ani_"+this.tagId+";\
        animation-timing-function:linear;\
        animation-duration:"+total_t+"s;\
    ");
    this.st=1;
}
CssMarquee.prototype.onAniEnd=function()
{
    this.st=0;
    this.setText(this.span.textContent);
}

感覺好像文字還是有些微抖動 這應該是marquee本身的問題吧 不過還是感謝大大提供的方法 不過文字會跳到最右側之前的版本確實有 改天把ajax導入這個新版的marquee裡看看

我要發表回答

立即登入回答