2011-11-05 53 views
10

Tôi đang sử dụng mã sau để lướt một hình ảnh trên lớp trên cùng của trang web nhưng hơi lúng túng, cho các đường thẳng đứng vệt xuống hình ảnh đặc biệt khi trên nội dung có nhiều phần tử lồng nhau . Đây là trường hợp ngay cả khi đường viền được đặt thành 0. Bất kỳ đề xuất nào cho một phương pháp mượt mà hơn để lướt hình ảnh bằng JS/CSS?Các kỹ thuật cho hoạt ảnh hình ảnh mượt mà hơn với JS/CSS

border=4; 
pps=250; // speed of glide (pixels per second) 
skip=2; // e.g. if set to 10 will skip 9 in 10 pixels 
refresh=3; // how often looks to see if move needed in milliseconds 

elem = document.createElement("img"); 
elem.id = 'img_id'; 
elem.style.zIndex="2000"; 
elem.style.position="fixed"; 
elem.style.top=0; 
elem.style.left=0; 
elem.src='http://farm7.static.flickr.com/6095/6301314495_69e6d9eb5c_m.jpg'; 
elem.style.border=border+'px solid black'; 
elem.style.cursor='pointer'; 
document.body.insertBefore(elem,null); 

pos_start = -250; 
pos_current = pos_start; 
pos_finish = 20000; 

var timer = new Date().getTime(); 
move(); 

function move() 
{ 
    var elapsed = new Date().getTime() - timer; 
    var pos_new = Math.floor((pos_start+pps*elapsed/1000)/skip)*skip; 

    if (pos_new != pos_current) 
    { 
    if (pos_new>pos_finish) 
     pos_new=pos_finish; 

    $("#img_id").css('left', pos_new); 
    if (pos_new==pos_finish) 
     return; 

    pos_current = pos_new; 
    } 

    t = setTimeout("move()", refresh); 
} 
+3

Hãy thử sử dụng jQuery. Nó thường trơn tru hơn và dễ hơn rất nhiều so với những gì bạn đang làm bây giờ. – RobinJ

+8

@RobinJ No. Đây không phải là một câu hỏi jQuery, câu trả lời là không sử dụng jQuery. Đây là một câu hỏi tuyệt vời bởi vì hiểu được quirks hoạt hình không được hiểu rõ. – Incognito

+1

Tôi đang bắt đầu kết luận không có cách nào để lướt một hình ảnh như thế này ở 250pps mà không có một số vệt. Nhân tiện, nếu ai đó làm bất kỳ hoạt hình nào như thế này trong tương lai, tôi khuyên bạn nên sử dụng thư viện JS này: http://fx.inetcat.com/ nó không giải quyết được vấn đề trên nhưng nó vẫn cực kỳ hữu ích. –

Trả lời

9

Tôi không có giải pháp chắc chắn sẽ ngăn các đường thẳng đứng xuất hiện.
Tuy nhiên, tôi có một số mẹo để cải thiện mã của bạn để tăng hiệu suất và bạn có thể có khả năng các dòng biến mất.

  1. cache các yếu tố hình ảnh bên ngoài của chức năng di chuyển của bạn:

    var image = $("#img_id")[0];

    Trong code của bạn, không có lý do gì để truy vấn ID hình ảnh so với DOM mỗi 3 mili giây. Công cụ chọn của jQuery, Sizzle có rất nhiều công việc¹.

  2. Không sử dụng jQuery CSS chức năng:

    image.style.left = pos_new;

    Thiết lập một đối tượng sở hữu là nhanh hơn so với một lời gọi hàm. Trong trường hợp của hàm jQuery css, có ít nhất hai lệnh gọi hàm (một đến css và một trong số bên trong css).

  3. Sử dụng khoảng thời gian thay vì thời gian chờ:

    setInterval(move, refresh);

    tôi sẽ xem xét một khoảng thời gian cho một lần hình ảnh động Tôi muốn trở thành như suôn sẻ càng tốt

    setTimeout or setInterval?


Một tùy chọn khác cho hoạt ảnh mượt mà hơn là sử dụng hiệu ứng chuyển tiếp hoặc hoạt ảnh CSS. Một giới thiệu tuyệt vời và so sánh có thể được tìm thấy trong CSS Animations and JavaScript bởi John Resig bảng

Trình duyệt hỗ trợ: http://caniuse.com/#search=transition

thư viện Một JavaScript mà tôi tìm thấy làm CSS animation qua JavaScript rất dễ dàng là morpheus.


¹ Dưới mui xe, đây là mã nó đi qua mỗi 3 mili giây để tìm hình ảnh của bạn:

Trong một trình duyệt hỗ trợ querySelectorAll:

Sizzle = function(query, context, extra, seed) { 
    context = context || document; 

    // Only use querySelectorAll on non-XML documents 
    // (ID selectors don't work in non-HTML documents) 
    if (!seed && !Sizzle.isXML(context)) { 
     // See if we find a selector to speed up 
     var match = /^(\w+$)|^\.([\w\-]+$)|^#([\w\-]+$)/.exec(query); 

     if (match && (context.nodeType === 1 || context.nodeType === 9)) { 
      // Speed-up: Sizzle("TAG") 
      if (match[1]) { 
       return makeArray(context.getElementsByTagName(query), extra); 

      // Speed-up: Sizzle(".CLASS") 
      } else if (match[2] && Expr.find.CLASS && context.getElementsByClassName) { 
       return makeArray(context.getElementsByClassName(match[2]), extra); 
      } 
     } 

     if (context.nodeType === 9) { 
      // Speed-up: Sizzle("body") 
      // The body element only exists once, optimize finding it 
      if (query === "body" && context.body) { 
       return makeArray([ context.body ], extra); 

      // Speed-up: Sizzle("#ID") 
      } else if (match && match[3]) { 
       var elem = context.getElementById(match[3]); 

       // Check parentNode to catch when Blackberry 4.6 returns 
       // nodes that are no longer in the document #6963 
       if (elem && elem.parentNode) { 
        // Handle the case where IE and Opera return items 
        // by name instead of ID 
        if (elem.id === match[3]) { 
         return makeArray([ elem ], extra); 
        } 

       } else { 
        return makeArray([], extra); 
       } 
      } 

      try { 
       return makeArray(context.querySelectorAll(query), extra); 
      } catch(qsaError) {} 

     // qSA works strangely on Element-rooted queries 
     // We can work around this by specifying an extra ID on the root 
     // and working up from there (Thanks to Andrew Dupont for the technique) 
     // IE 8 doesn't work on object elements 
     } else if (context.nodeType === 1 && context.nodeName.toLowerCase() !== "object") { 
      var oldContext = context, 
       old = context.getAttribute("id"), 
       nid = old || id, 
       hasParent = context.parentNode, 
       relativeHierarchySelector = /^\s*[+~]/.test(query); 

      if (!old) { 
       context.setAttribute("id", nid); 
      } else { 
       nid = nid.replace(/'/g, "\\$&"); 
      } 
      if (relativeHierarchySelector && hasParent) { 
       context = context.parentNode; 
      } 

      try { 
       if (!relativeHierarchySelector || hasParent) { 
        return makeArray(context.querySelectorAll("[id='" + nid + "'] " + query), extra); 
       } 

      } catch(pseudoError) { 
      } finally { 
       if (!old) { 
        oldContext.removeAttribute("id"); 
       } 
      } 
     } 
    } 

    return oldSizzle(query, context, extra, seed); 
}; 

Và một trình duyệt điều đó không 't:

var Sizzle = function(selector, context, results, seed) { 
    results = results || []; 
    context = context || document; 

    var origContext = context; 

    if (context.nodeType !== 1 && context.nodeType !== 9) { 
     return []; 
    } 

    if (!selector || typeof selector !== "string") { 
     return results; 
    } 

    var m, set, checkSet, extra, ret, cur, pop, i, 
     prune = true, 
     contextXML = Sizzle.isXML(context), 
     parts = [], 
     soFar = selector; 

    // Reset the position of the chunker regexp (start from head) 
    do { 
     chunker.exec(""); 
     m = chunker.exec(soFar); 

     if (m) { 
      soFar = m[3]; 

      parts.push(m[1]); 

      if (m[2]) { 
       extra = m[3]; 
       break; 
      } 
     } 
    } while (m); 

    if (parts.length > 1 && origPOS.exec(selector)) { 

     if (parts.length === 2 && Expr.relative[ parts[0] ]) { 
      set = posProcess(parts[0] + parts[1], context, seed); 

     } else { 
      set = Expr.relative[ parts[0] ] ? 
       [ context ] : 
       Sizzle(parts.shift(), context); 

      while (parts.length) { 
       selector = parts.shift(); 

       if (Expr.relative[ selector ]) { 
        selector += parts.shift(); 
       } 

       set = posProcess(selector, set, seed); 
      } 
     } 

    } else { 
     // Take a shortcut and set the context if the root selector is an ID 
     // (but not if it'll be faster if the inner selector is an ID) 
     if (!seed && parts.length > 1 && context.nodeType === 9 && !contextXML && 
       Expr.match.ID.test(parts[0]) && !Expr.match.ID.test(parts[parts.length - 1])) { 

      ret = Sizzle.find(parts.shift(), context, contextXML); 
      context = ret.expr ? 
       Sizzle.filter(ret.expr, ret.set)[0] : 
       ret.set[0]; 
     } 

     if (context) { 
      ret = seed ? 
       { expr: parts.pop(), set: makeArray(seed) } : 
       Sizzle.find(parts.pop(), parts.length === 1 && (parts[0] === "~" || parts[0] === "+") && context.parentNode ? context.parentNode : context, contextXML); 

      set = ret.expr ? 
       Sizzle.filter(ret.expr, ret.set) : 
       ret.set; 

      if (parts.length > 0) { 
       checkSet = makeArray(set); 

      } else { 
       prune = false; 
      } 

      while (parts.length) { 
       cur = parts.pop(); 
       pop = cur; 

       if (!Expr.relative[ cur ]) { 
        cur = ""; 
       } else { 
        pop = parts.pop(); 
       } 

       if (pop == null) { 
        pop = context; 
       } 

       Expr.relative[ cur ](checkSet, pop, contextXML); 
      } 

     } else { 
      checkSet = parts = []; 
     } 
    } 

    if (!checkSet) { 
     checkSet = set; 
    } 

    if (!checkSet) { 
     Sizzle.error(cur || selector); 
    } 

    if (toString.call(checkSet) === "[object Array]") { 
     if (!prune) { 
      results.push.apply(results, checkSet); 

     } else if (context && context.nodeType === 1) { 
      for (i = 0; checkSet[i] != null; i++) { 
       if (checkSet[i] && (checkSet[i] === true || checkSet[i].nodeType === 1 && Sizzle.contains(context, checkSet[i]))) { 
        results.push(set[i]); 
       } 
      } 

     } else { 
      for (i = 0; checkSet[i] != null; i++) { 
       if (checkSet[i] && checkSet[i].nodeType === 1) { 
        results.push(set[i]); 
       } 
      } 
     } 

    } else { 
     makeArray(checkSet, results); 
    } 

    if (extra) { 
     Sizzle(extra, origContext, results, seed); 
     Sizzle.uniqueSort(results); 
    } 

    return results; 
}; 
+1

Bạn nhận được tiền thưởng vì câu trả lời của bạn giải thích một số vấn đề lớn mà mọi người gặp phải, chẳng hạn như mã được tối ưu hóa kém, cũng như liên kết với một số tài nguyên. Những người khác có câu trả lời tuyệt vời như kasimir và ExpExc.Mọi người nên đọc câu trả lời của Nhà ngôn ngữ học máy tính khi anh ấy trả về một tính năng hiếm khi được sử dụng (và có phần mới) có thể được sử dụng để thực sự giúp luồng hình ảnh động trở nên độc đáo. – Incognito

+0

Cảm ơn rất nhiều! Tôi đồng ý rằng có những câu trả lời tuyệt vời khác (mà tôi đã upvoted). – DADU

+0

Không phải là nó không chính xác, nhưng những thứ được chỉ ra ở đây không thực sự liên quan đến hiệu suất hoạt hình. Chi phí truy vấn một phần tử bằng ID hoặc sử dụng jQuery để đặt thuộc tính kiểu là không đáng kể trong trường hợp này, trong phạm vi 0-1ms. Hầu hết các trình duyệt sẽ rơi vào đường dẫn mã 'querySelectorAll'. –

3

Tôi đã chụp ảnh này với một vài ý tưởng. Tôi không bao giờ có thể làm cho hình ảnh động trở nên cực kỳ trơn tru, cũng như tôi chưa bao giờ trải nghiệm bất kỳ đường thẳng đứng nào, vì vậy tôi không chắc liệu nó có cải thiện hay không. Tuy nhiên, chức năng dưới đây có một vài ý tưởng chìa khóa vào tài khoản đó có ý nghĩa với tôi:

  • Giữ nguyên tố này ra khỏi DOM với một container <div> cho các hình ảnh động. Sự tham gia của DOM trong các bản sao lại khiến cho nó dài hơn nhiều so với hình ảnh lớp phủ cơ bản.

  • Giữ càng nhiều chất béo càng tốt khỏi chức năng move. Nhìn thấy như chức năng này sẽ được gọi là một số lượng lớn, kịch bản ít hơn có để chạy, thì tốt hơn. Điều này bao gồm cuộc gọi jQuery để thay đổi vị trí phần tử.

  • Chỉ làm mới càng nhiều càng cần thiết. Tôi thiết lập khoảng thời gian làm mới ở đây đến 121 Hz, nhưng đó là một đầu cuối tuyệt đối cho một màn hình 60Hz. Tôi có thể đề nghị 61 hoặc ít hơn, tùy thuộc vào những gì cần thiết.

  • Chỉ đặt giá trị cho đối tượng kiểu phần tử nếu cần. Các chức năng trong câu hỏi đã làm điều này, nhưng một lần nữa nó là một điều tốt để ghi nhớ, bởi vì trong một số động cơ chỉ đơn giản là truy cập vào setter trong một đối tượng phong cách sẽ buộc một repaint.

  • Điều tôi muốn thử là sử dụng hình ảnh làm nền của phần tử, vì vậy bạn chỉ có thể tập lệnh thay đổi thuộc tính CSS background-position thay vì thay đổi vị trí phần tử. Điều này có nghĩa là sự tham gia của DOM bị mất trong các bản sao được kích hoạt bởi hoạt ảnh, nếu có thể.

Và chức năng, để thử nghiệm của bạn, với một kết thúc khá không cần thiết:

var border = 4; 
var pps = 250; 
var skip = 2; 
var refresh = 1000/121; // 2 * refresh rate + 1 
var image = new Image(); 
image.src = 'http://farm7.static.flickr.com/6095/6301314495_69e6d9eb5c_m.jpg'; 
// Move img (Image()) from x1,y1 to x2,y2 
var moveImage = function (img, x1, y1, x2, y2) { 
     x_min = (x1 > x2) ? x2 : x1; 
     y_min = (y1 > y2) ? y2 : y1; 
     x_max = (x1 > x2) ? x1 : x2; 
     y_max = (y1 > y2) ? y1 : y2; 
     var div = document.createElement('div'); 
     div.id = 'animationDiv'; 
     div.style.zIndex = '2000'; 
     div.style.position = 'fixed'; 
     div.style.top = y_min; 
     div.style.left = x_min; 
     div.style.width = x_max + img.width + 'px'; 
     div.style.height = y_max + img.height + 'px'; 
     div.style.background = 'none'; 
     document.body.insertBefore(div, null); 
     elem = document.createElement('img'); 
     elem.id = 'img_id'; 
     elem.style.position = 'relative'; 
     elem.style.top = 0; 
     elem.style.left = 0; 
     elem.src = img.src; 
     elem.style.border = border + 'px solid black'; 
     elem.style.cursor = 'pointer'; 

     var theta = Math.atan2((y2 - y1), (x2 - x1)); 
     (function() { 
      div.insertBefore(elem, null); 
      var stop = function() { 
        clearInterval(interval); 
        elem.style.left = x2 - x1; 
        elem.style.top = y2 - y1; 
       }; 
      var startTime = +new Date().getTime(); 
      var xpmsa = pps * Math.cos(theta)/(1000 * skip); // per milli adjusted 
      var ypmsa = pps * Math.sin(theta)/(1000 * skip); 

      var interval = setInterval(function() { 
       var t = +new Date().getTime() - startTime; 
       var x = (Math.floor(t * xpmsa) * skip); 
       var y = (Math.floor(t * ypmsa) * skip); 
       if (parseInt(elem.style.left) === x && 
        parseInt(elem.style.top) === y) return; 
       elem.style.left = x + 'px'; 
       elem.style.top = y + 'px'; 
       if (x > x_max || x < x_min || y > y_max || y < y_min) stop(); 
      }, refresh); 
      console.log(xpmsa, ypmsa, elem, div, interval); 
     })(); 

    }; 
4

Có rất nhiều cách nhỏ để tinh chỉnh bạn mã để chạy mượt mà hơi ... Sử dụng một vòng lặp thông tin phản hồi để tối ưu hóa kích thước và độ trễ của bước, hãy tìm các bước thậm chí không làm tròn lên hoặc xuống gây ra các bước nhảy nhỏ theo các khoảng thời gian đều đặn, v.v.

Nhưng API bí mật bạn đang tìm kiếm (và được nhiều người sử dụng các thư viện bạn đang tránh) là requestAnimationFrame. Hiện tại, tính năng này không được chuẩn hóa, do đó, mỗi trình duyệt đều có triển khai tiền tố (webkitRequestAnimationFrame, mozRequestAnimationFrom, v.v.)

Thay vì tái giải thích cách nó giúp giảm/ngăn chặn các vấn đề nó bị rách và vsync, tôi sẽ chỉ cho bạn những bài báo đó:

http://robert.ocallahan.org/2010/08/mozrequestanimationframe_14.html

+0

+1 cho requestAnimationFrame, nhưng nó chỉ là một phần của tổng vấn đề. – Incognito

+0

Đúng, nhưng nó giải quyết các vấn đề lập lịch và thời gian. Các hạng mục còn lại chính là (a) tính toán trước càng nhiều càng tốt (b) sử dụng vị trí nền thay vì di chuyển một phần tử dom khi có thể. Tối ưu hóa setInterval vs setTimeout là không có thật. Và tuyến tính nới lỏng làm cho các lỗi làm tròn và jitter đáng chú ý nhất - tốt nhất là có một số (de) tăng tốc đang diễn ra. –

+0

requestAnimationFrame trong thực tế không dẫn đến hoạt ảnh mượt mà hơn, nó chỉ tránh các chu kỳ lãng phí khi bạn không tập trung vào trang. http://www.phoboslab.org/log/2011/08/are-we-fast-yet –

3

Đối với hoàn cảnh của bạn, bạn nên xem xét các nội dung sau để làm cho hình ảnh động mượt mà:

  1. khoảng cách giữa các bước hoạt hình (giá trị refresh của bạn) nên dài đủ cho trình duyệt xử lý (mã JavaScript, rendering). Theo kinh nghiệm của tôi, nó phải là 10 đến 20 mili giây.

  2. Tại sao bạn thực hiện nhiều vị trí hình ảnh của skip? Đặt giá trị skip càng nhỏ càng tốt (1) có thể làm cho hoạt ảnh mượt mà hơn.

  3. Tránh làm cho trình duyệt bị hỏng nếu có thể (reflow vs repaint).

  4. Sử dụng phương pháp nới lỏng thích hợp thay vì tuyến tính (như trong mã của bạn) có thể làm cho hình ảnh động đẹp hơn (tầm nhìn của con người, không kỹ thuật)

  5. đang Optimize JavaScript cho mỗi bước hoạt hình. Đây không phải là vấn đề trong hoạt hình đơn giản như bạn, nhưng bạn có thể cải thiện một cái gì đó như: sử dụng setInterval thay vì setTimeout, bộ nhớ cache hình ảnh đối tượng để truy cập nhanh chóng, sử dụng mã JS mẹ đẻ để thay đổi vị trí hình ảnh

Hope những sự giúp đỡ.

3

Câu hỏi của bạn thực sự có vẻ là về công cụ hiển thị trình duyệt và khả năng của chúng. Như bạn đã nhận thấy, có những hạn chế về tốc độ trình duyệt có thể hiển thị hoạt ảnh. Nếu bạn đạt đến giới hạn này, bạn sẽ thấy hành vi của jitter hoặc 'unsmooth' khác. Đôi khi hiển thị lỗi, như không làm sạch các phần của hoạt ảnh hoặc các bộ phận tranh giành.
Quay lại những ngày xa xưa, bất kỳ hình thức hoạt hình phong nha nào cũng hầu như không thể. Trong thời gian, mọi thứ trở nên tốt hơn, nhưng tôi vẫn nhớ sử dụng những hình ảnh nhỏ nhất có thể để giữ cho trình đơn gấp/mở dễ thương của tôi hoạt động suôn sẻ. Tất nhiên, những ngày này chúng tôi đã có hiển thị phần cứng tăng tốc trình duyệt, vì vậy bạn có thể thực hiện nhiều hoạt ảnh cùng một lúc và không cần phải lo lắng nhiều về hoạt ảnh chậm.
Nhưng tôi đã làm lại một số hoạt ảnh mà tôi đã sử dụng, bởi vì iPad (1) của tôi có vẻ khá chậm vẽ một số trong số đó. Giống như cuộn một số lớn div đã khá bị thay đổi. Vì vậy, về cơ bản, tôi bắt đầu để điều chỉnh mọi thứ xuống:

  • Sử dụng hình ảnh động đơn giản thay vì phức tạp, và: không có hình ảnh động kết hợp (như cuộn phai)
  • Giảm số html-yếu tố bên trong đối tượng hoạt hình
  • làm cho đối tượng hoạt hình nhỏ hơn
  • Preload càng nhiều càng tốt
  • Tạo không gian cho đối tượng hoạt hình (nếu có thể, trong trường hợp trượt hoặc di chuyển phương tiện di chuyển một toàn bộ rất nhiều yếu tố khác)

Điều này đã hoạt động sau một số lần thử và lỗi. Những gì bạn cần lưu ý là javascript chỉ thay đổi các thuộc tính css của các phần tử html. Trình duyệt vẽ lại những gì JS nói với anh ta.Vì vậy, càng có nhiều nó nói với anh ta, nó nặng hơn, và dựng hình rơi xuống phía sau.
Nhìn vào hiệu suất, nó chia nhỏ thành ba thành phần: CPU, GPU và cập nhật màn hình. Mỗi công cụ trình duyệt hoạt động khác nhau, do đó hiệu suất cũng có thể khác nhau. Một cái nhìn thú vị về cách thức hoạt động của nó, xuất phát từ những người trong nhóm IE 10, kỹ lưỡng hơn tôi có thể là: http://blogs.msdn.com/b/ie/archive/2011/04/26/understanding-differences-in-hardware-acceleration-through-paintball.aspx

3

Hoạt ảnh Javascript luôn hơi hốt hoảng vì bộ hẹn giờ không chính xác lắm. Bạn có thể nhận peformance tốt hơn một chút bằng cách sử dụng một vài thủ thuật:

  • Enable hardware acceleration: img { -webkit-transform: translateZ(0) };
  • Sử dụng setInterval, nó có thể dẫn đến hình ảnh động mượt mà quá, mặc dù sự thay đổi thường là không đáng kể
  • Đặt tốc độ làm tươi của bạn để 1000/60 (60pfs) - đó là giới hạn màn hình và bộ hẹn giờ không bao giờ dưới 4ms

IE9 + dường như giải quyết vấn đề này bằng cách làm cho hoạt ảnh mượt mà hơn, nhưng tôi sẽ không tính vào các trình duyệt khác làm điều đó bất cứ lúc nào sớm. Tương lai là trong quá trình chuyển đổi CSS.

Trong CSS, bạn có thể sử dụng này:

img { 
    -webkit-transition:2s all linear; 
    -moz-transition:2s all linear; 
     -ms-transition:2s all linear; 
      transition:2s all linear; 
} 

Nhưng kể từ thời gian hoạt hình của bạn phụ thuộc vào vị trí đích để đạt được một tốc độ không đổi, bạn có thể thao tác các giá trị thông qua JS:

var img = document.createElement('img') 

document.body.appendChild(img) 

var styles = { 
     zIndex : '2000' 
    , position : 'absolute' 
    , top  : '0px' 
    , left  : '0px' 
    , border : '4px solid black' 
    , cursor : 'pointer' 
} 

Object.keys(styles).forEach(function(key){ 
    img.style[key] = styles[key] 
}) 

var prefixes = ['webkit', 'Moz', 'O', 'ms', ''] 
    , speed = 250 
    , endPosition = 2000 
    , transition = Math.floor(endPosition/speed)+'s all linear' 

prefixes.forEach(function(prefix){ 
    img.style[prefix+(prefix ? 'T' : 't')+'ransition'] = transition 
}) 

img.onload = function(){ 
    img.style.left = endPosition+'px' // starts the animation 
} 

img.src = 'http://farm7.static.flickr.com/6095/6301314495_69e6d9eb5c_m.jpg' 

(còn lại một vài đường dẫn mã trình duyệt chéo cho ngắn gọn - onload, forEach, Object.keys)

0

Hãy thử tận dụng lợi thế của phép biến đổi css và tính năng khung yêu cầu.

Xem thư viện TweenLite:

http://www.greensock.com/v12/

Các vấn đề liên quan