HTML5 Canvas so với SVG so với div


476

Cách tiếp cận tốt nhất để tạo ra các yếu tố một cách nhanh chóng và có thể di chuyển chúng xung quanh là gì? Ví dụ: giả sử tôi muốn tạo một hình chữ nhật, hình tròn và đa giác rồi chọn các đối tượng đó và di chuyển chúng xung quanh.

Tôi hiểu rằng HTML5 cung cấp ba yếu tố có thể thực hiện điều này: svg , canvasdiv . Đối với những gì tôi muốn làm, một trong những yếu tố đó sẽ cung cấp hiệu suất tốt nhất?

Để so sánh các cách tiếp cận này, tôi đã nghĩ đến việc tạo ra ba trang web giống hệt nhau mà mỗi trang có một tiêu đề, chân trang, widget và nội dung văn bản trong đó. Các widget trong trang đầu tiên sẽ được tạo hoàn toàn với canvasphần tử, phần thứ hai hoàn toàn với svgphần tử và phần thứ ba với divphần tử đơn giản , HTML và CSS.


13
Bạn có thể thấy điều này thú vị: Suy nghĩ khi nào nên sử dụng Canvas và SVG .
robertc

1
Đối với những người mới làm quen với chuyên đề này, video này bao gồm cả SVG và Canvas và các chi tiết khác về cách tích hợp trên html5.
Paulo Bueno

12
Câu trả lời ngắn: Canvas là cho MS Paint vì SVG là MS Powerpoint. Canvas là raster, SVG là véc tơ.
GetFree

2
Bạn đọc thân mến: lấy tất cả các so sánh và tuyên bố ở đây với một hạt muối và nhìn vào ngày của các bài viết và bình luận. Thời đại đã thay đổi và sẽ thay đổi. Hiệu suất tương đối và thậm chí các tùy chọn bạn có sẽ thay đổi. Ví dụ, hầu hết các câu trả lời được viết khi không có WebGL, đây chắc chắn là một giải pháp thay thế - nó cũng sẽ bị lỗi thời trong một vài năm nữa, nhưng cho đến ngày hôm nay, nó có thể rất phù hợp.
Sebastian

@Sebastian mà bạn muốn giới thiệu ngày hôm nay? nếu được cung cấp kích thước cơ sở (ví dụ: 1280x800) và nếu bạn sẵn sàng chia tỷ lệ các phần tử theo cách thủ công trong mã hoặc sử dụng tỷ lệ phần trăm mọi lúc, thì SVG có lợi thế gì khi sử dụng DIV không?
Crashalot

Câu trả lời:


563

Câu trả lời ngắn gọn:

SVG sẽ dễ dàng hơn cho bạn, vì lựa chọn và di chuyển nó xung quanh đã được tích hợp sẵn. Các đối tượng SVG là các đối tượng DOM, vì vậy chúng có các trình xử lý "nhấp chuột", v.v.

DIV vẫn ổn nhưng cồng kềnh và có hiệu suất khủng khiếp khi tải với số lượng lớn.

Canvas có hiệu suất tốt nhất, nhưng bạn phải tự thực hiện tất cả các khái niệm về trạng thái được quản lý (lựa chọn đối tượng, v.v.) hoặc sử dụng thư viện.


Câu trả lời dài:

HTML5 Canvas chỉ đơn giản là một bề mặt vẽ cho bản đồ bit. Bạn thiết lập để vẽ (Nói với màu sắc và độ dày đường kẻ), vẽ thứ đó và sau đó Canvas không biết gì về điều đó: Nó không biết nó ở đâu hoặc bạn vừa vẽ gì, đó là chỉ pixel. Nếu bạn muốn vẽ hình chữ nhật và để chúng di chuyển xung quanh hoặc có thể lựa chọn thì bạn phải mã hóa tất cả những thứ đó từ đầu, bao gồm cả mã để nhớ rằng bạn đã vẽ chúng.

Mặt khác, SVG phải duy trì các tham chiếu đến từng đối tượng mà nó hiển thị. Mỗi phần tử SVG / VML bạn tạo là một phần tử thực trong DOM. Theo mặc định, điều này cho phép bạn theo dõi tốt hơn các yếu tố bạn tạo và giúp xử lý các sự kiện như sự kiện chuột theo mặc định dễ dàng hơn, nhưng nó chậm đi đáng kể khi có một số lượng lớn đối tượng

Các tham chiếu DOMG DOM đó có nghĩa là một số công việc cần thiết để xử lý những thứ bạn vẽ được thực hiện cho bạn. Và SVG nhanh hơn khi kết xuất các đối tượng thực sự lớn , nhưng chậm hơn khi kết xuất nhiều đối tượng.

Một trò chơi có thể sẽ nhanh hơn trong Canvas. Một chương trình bản đồ khổng lồ có lẽ sẽ nhanh hơn trong SVG. Nếu bạn muốn sử dụng Canvas, tôi có một số hướng dẫn về cách đưa các đối tượng có thể di chuyển lên và chạy ở đây .

Canvas sẽ tốt hơn cho những thứ nhanh hơn và thao tác bitmap nặng (như hoạt hình), nhưng sẽ mất nhiều mã hơn nếu bạn muốn có nhiều tương tác.

Tôi đã chạy một loạt các số trên bản vẽ do HTML DIV tạo ra so với bản vẽ được tạo bởi Canvas. Tôi có thể tạo một bài đăng lớn về lợi ích của mỗi loại, nhưng tôi sẽ đưa ra một số kết quả có liên quan trong các thử nghiệm của mình để xem xét cho ứng dụng cụ thể của bạn:

Tôi đã tạo các trang thử nghiệm Canvas và HTML DIV, cả hai đều có các "nút" có thể di chuyển được. Các nút canvas là các đối tượng tôi đã tạo và theo dõi trong Javascript. Các nút HTML là Divs di động.

Tôi đã thêm 100.000 nút vào mỗi hai bài kiểm tra của mình. Họ thực hiện khá khác nhau:

Tab kiểm tra HTML mất quá nhiều thời gian để tải (được hẹn giờ ở mức dưới 5 phút, chrome yêu cầu giết trang lần đầu tiên). Trình quản lý tác vụ của Chrome cho biết tab đó đang chiếm tới 168 MB. Nó chiếm tới 12-13% thời gian CPU khi tôi nhìn vào nó, 0% khi tôi không nhìn.

Tab Canvas được tải trong một giây và chiếm 30MB. Nó cũng chiếm 13% thời gian của CPU mọi lúc, bất kể người ta có nhìn vào nó hay không. (Chỉnh sửa 2013: Họ hầu như đã sửa nó)

Việc kéo trên trang HTML mượt mà hơn, được thiết kế mong đợi, vì thiết lập hiện tại là vẽ lại MỌI THỨ cứ sau 30 mili giây trong thử nghiệm Canvas. Có rất nhiều tối ưu hóa cần có cho Canvas cho việc này. (vô hiệu hóa canvas là dễ nhất, cũng là các vùng cắt, vẽ lại có chọn lọc, v.v. chỉ phụ thuộc vào mức độ bạn cảm thấy muốn thực hiện)

Không còn nghi ngờ gì nữa, bạn có thể khiến Canvas trở nên nhanh hơn khi thao tác đối tượng như các div trong bài kiểm tra đơn giản đó, và tất nhiên là nhanh hơn rất nhiều trong thời gian tải. Vẽ / tải nhanh hơn trong Canvas và cũng có nhiều chỗ để tối ưu hóa hơn (nghĩa là loại trừ những thứ ngoài màn hình rất dễ dàng).

Phần kết luận:

  • SVG có lẽ tốt hơn cho các ứng dụng và ứng dụng có ít mục (dưới 1000? Phụ thuộc thực sự)
  • Canvas tốt hơn cho hàng ngàn đối tượng và thao tác cẩn thận, nhưng cần nhiều mã hơn (hoặc thư viện) để đưa nó lên khỏi mặt đất.
  • Các Diva HTML rất cục mịch và không mở rộng quy mô, việc tạo một vòng tròn chỉ có thể thực hiện được với các góc tròn, tạo ra các hình dạng phức tạp là có thể nhưng liên quan đến hàng trăm div nhỏ trên pixel. Sự điên rồ xảy ra.

4
Các Bánh thư viện là một ví dụ về làm đối tượng di chuyển và hình ảnh động với các đối tượng trên một canvas
SiggyF

Sai: P div có thể mở rộng quy mô nếu trình duyệt đang sử dụng công cụ CSS được tăng tốc hw, css art khác biệt và bên cạnh Canvas và SVG là lựa chọn thích hợp ở đây, CSS art / div art chỉ là khi bạn không cần làm quá mức chỉ là một lớp phủ nhỏ: P
ShrekOverflow

Liên quan đến các DIV, nếu bạn muốn tạo các vòng tròn / hình dạng đặc biệt và sẽ không thay đổi khóa học hình ảnh / sprite của nó, bạn chỉ có thể tạo một PNG và sử dụng nó như background-image... Mặc dù bạn có thể làm những điều tương tự trong SVG / Canvas
luiges90

4
Nếu bạn đang tạo một trò chơi bản đồ tương tác thì sao? : p
Anthony

Điều này đã được tạo bằng cách sử dụng các biến đổi DIV và CSS 3D (không lồng nhau), vì vậy tôi nói rằng các DIV không chậm chút nào: youtube.com/watch?v=fzBC20B5dsk
Erik Kaplun 6/12/2016

39

Để thêm vào điều này, tôi đã làm một ứng dụng sơ đồ và ban đầu bắt đầu với canvas. Sơ đồ bao gồm nhiều nút và chúng có thể trở nên khá lớn. Người dùng có thể kéo các yếu tố trong sơ đồ xung quanh.

Những gì tôi tìm thấy là trên máy Mac của tôi, đối với những hình ảnh rất lớn, SVG là vượt trội. Tôi có MacBook Pro 2013 13 "Retina và nó chạy fiddle bên dưới khá tốt. Hình ảnh là 6000x6000 pixel và có 1000 đối tượng. Một cấu trúc tương tự trong canvas không thể làm động cho tôi khi người dùng đang kéo các vật thể xung quanh trong biểu đồ.

Trên màn hình hiện đại, bạn cũng phải tính đến các độ phân giải khác nhau và ở đây, SVG cung cấp cho bạn tất cả những điều này miễn phí.

Fiddle: http://jsfiddle.net/knutsi/PUcr8/16/

Toàn màn hình: http://jsfiddle.net/knutsi/PUcr8/16/embedded/result/

var wiggle_factor = 0.0;
nodes = [];

// create svg:
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('style', 'border: 1px solid black');
svg.setAttribute('width', '6000');
svg.setAttribute('height', '6000');

svg.setAttributeNS("http://www.w3.org/2000/xmlns/", "xmlns:xlink",
    "http://www.w3.org/1999/xlink");

document.body.appendChild(svg);


function makeNode(wiggle) {
    var node = document.createElementNS("http://www.w3.org/2000/svg", "g");
    var node_x = (Math.random() * 6000);
    var node_y = (Math.random() * 6000);
    node.setAttribute("transform", "translate(" + node_x + ", " + node_y +")");

    // circle:
    var circ = document.createElementNS("http://www.w3.org/2000/svg", "circle");
    circ.setAttribute( "id","cir")
    circ.setAttribute( "cx", 0 + "px")
    circ.setAttribute( "cy", 0 + "px")
    circ.setAttribute( "r","100px");
    circ.setAttribute('fill', 'red');
    circ.setAttribute('pointer-events', 'inherit')

    // text:
    var text = document.createElementNS("http://www.w3.org/2000/svg", "text");
    text.textContent = "This is a test! ÅÆØ";

    node.appendChild(circ);
    node.appendChild(text);

    node.x = node_x;
    node.y = node_y;

    if(wiggle)
        nodes.push(node)
    return node;
}

// populate with 1000 nodes:
for(var i = 0; i < 1000; i++) {
    var node = makeNode(true);
    svg.appendChild(node);
}

// make one mapped to mouse:
var bnode = makeNode(false);
svg.appendChild(bnode);

document.body.onmousemove=function(event){
    bnode.setAttribute("transform","translate(" +
        (event.clientX + window.pageXOffset) + ", " +
        (event.clientY + window.pageYOffset) +")");
};

setInterval(function() {
    wiggle_factor += 1/60;
    nodes.forEach(function(node) {

        node.setAttribute("transform", "translate(" 
                          + (Math.sin(wiggle_factor) * 200 + node.x) 
                          + ", " 
                          + (Math.sin(wiggle_factor) * 200 + node.y) 
                          + ")");        
    })
},1000/60);

2
Chúng tôi cũng đã giải quyết SVG, sau khi cố gắng hết sức để Canvas hoạt động cho chúng tôi. Chúng tôi có một sơ đồ rất lớn và cho đến nay, SVG là hiệu quả nhất, cộng với việc tự động mở rộng trên màn hình võng mạc là một phần thưởng lớn.
Fijjit

knut và @Fijjit bạn có cân nhắc sử dụng DIV thay vì SVG không? nếu được cung cấp kích thước cơ sở (ví dụ: 1280x800), bạn không thể tự điều chỉnh tỷ lệ DIV sao cho chúng trông sắc nét như SVG? Cảm ơn bạn đã giúp đỡ!
Crashalot

24

Biết được sự khác biệt giữa SVG và Canvas sẽ hữu ích trong việc chọn đúng.

Tranh sơn dầu

SVG

  • Nghị quyết độc lập
  • Hỗ trợ xử lý sự kiện
  • Phù hợp nhất cho các ứng dụng có khu vực kết xuất lớn (Google Maps)
  • Kết xuất chậm nếu phức tạp (mọi thứ sử dụng DOM nhiều sẽ chậm)
  • Không phù hợp với ứng dụng trò chơi

8
Tại sao mọi người nói Canvas phụ thuộc vào độ phân giải? tôi hiểu rằng một khi bitmap đã được hiển thị, nó không có tỷ lệ độc đáo. nhưng bạn có thể vẽ lại thay đổi kích thước độ phân giải, vậy độ phân giải đó không độc lập như thế nào?
Alex Bollbach

@AlexBollbach - Canvas phụ thuộc vào độ phân giải, bởi vì bạn cần tính đến (phụ thuộc) vào độ phân giải để có kết quả tốt. Với SVG, bạn không quan tâm đến độ phân giải. Chúc may mắn với việc có được các dòng không bị lởm chởm trên máy in 2400DPI và kết xuất dựa trên Canvas. Không có vấn đề với SVG.
Sebastian

18

Tôi đồng ý với kết luận của Simon Sarris:

Tôi đã so sánh một số hình ảnh trực quan trong Protovis (SVG) với Treatmentjs (Canvas) hiển thị> 2000 điểm và processjs nhanh hơn nhiều so với protovis.

Xử lý các sự kiện với SVG tất nhiên dễ dàng hơn nhiều vì bạn có thể gắn chúng vào các đối tượng. Trong Canvas, bạn phải thực hiện thủ công (kiểm tra vị trí chuột, v.v.) nhưng để tương tác đơn giản thì không nên khó.

Ngoài ra còn có thư viện dojo.gfx của bộ công cụ dojo. Nó cung cấp một lớp trừu tượng và bạn có thể chỉ định trình kết xuất (SVG, Canvas, Silverlight). Đó cũng có thể là một lựa chọn khả thi mặc dù tôi không biết lớp trừu tượng bổ sung thêm bao nhiêu nhưng nó giúp dễ dàng mã hóa các tương tác và hoạt hình và không thể kết xuất.

Dưới đây là một số điểm chuẩn thú vị:


17

Chỉ cần 2 xu của tôi về tùy chọn divs.

Nổi tiếng / Nổi tiếng và SamsaraJS (và có thể cả những người khác) sử dụng các div không lồng nhau được định vị tuyệt đối (với nội dung HTML / CSS không tầm thường), kết hợp với matrix2d / matrix3d ​​để định vị và chuyển đổi 2D / 3D và đạt được 60FPS ổn định trên phần cứng di động vừa phải , vì vậy tôi cho rằng divs là một lựa chọn chậm.

Có rất nhiều bản ghi màn hình trên Youtube và các nơi khác, các nội dung 2D / 3D hiệu suất cao đang chạy trong trình duyệt với mọi thứ đều là phần tử DOM mà bạn có thể Kiểm tra phần tử trên, ở 60FPS (trộn với WebGL cho các hiệu ứng nhất định, nhưng không phải cho phần chính của kết xuất).


14

Mặc dù vẫn còn một số sự thật đối với hầu hết các câu trả lời ở trên, tôi nghĩ rằng chúng xứng đáng được cập nhật:

Trong những năm qua, hiệu suất của SVG đã được cải thiện rất nhiều và hiện tại có các chuyển đổi và hoạt ảnh CSS được tăng tốc phần cứng cho SVG hoàn toàn không phụ thuộc vào hiệu suất JavaScript. Tất nhiên, hiệu suất JavaScript cũng được cải thiện và với hiệu suất của Canvas, nhưng không nhiều như SVG đã được cải thiện. Ngoài ra, có một "đứa trẻ mới" trên khối có sẵn trong hầu hết các trình duyệt hiện nay và đó là WebGL . Để sử dụng cùng một từ mà Simon đã sử dụng ở trên: Nó đánh bại cả hai tay Canvas và SVG . Tuy nhiên, điều này không có nghĩa là nó phải là công nghệ tiên tiến, vì nó là một con thú để làm việc và nó chỉ nhanh hơn trong các trường hợp sử dụng rất cụ thể.

IMHO cho hầu hết các trường hợp sử dụng hiện nay, SVG cho tỷ lệ hiệu năng / khả năng sử dụng tốt nhất. Hình ảnh cần phải thực sự phức tạp (liên quan đến số lượng phần tử) và thực sự đơn giản cùng một lúc (trên mỗi phần tử) để Canvas và thậm chí nhiều hơn để WebGL thực sự tỏa sáng.

Trong câu trả lời này cho một câu hỏi tương tự tôi đang cung cấp thêm chi tiết, tại sao tôi nghĩ rằng sự kết hợp của cả ba công nghệ đôi khi là lựa chọn tốt nhất mà bạn có.


Người dùng Unix nên lưu ý rằng việc tăng tốc phần cứng bị tắt theo mặc định trên cả Firefox và Chromium, vẫn đúng vào giữa năm 2019.
NVRM

@NVRM - đây là về tăng tốc phần cứng của CSS và SVG, không phải về giải mã video. AFAIK trước đây đã có sẵn trong nhiều năm: Kiểm tra đầu ra của chrome: // gpu
Sebastian

layers.acceleration.force-enabledtrong Firefox không phải là về giải mã video. Đó là một thực tế nổi tiếng. Khi thực hiện các vòng lặp bằng requestAnimationFrame là một cấp độ khác, cho phép nhiều lần lặp lại. Không phải về video cả.
NVRM

@NVRM - bạn có thể cung cấp liên kết đến các lỗi FF và Chromium cho các sự cố GPU này trên Linux không? Cũng lưu ý rằng bằng cách "tăng tốc phần cứng", tôi không chỉ đề cập đến khả năng tăng tốc GPU, mà còn cả kết hợp và hoạt ảnh đa luồng, ví dụ như tải các spinners tiếp tục quay trong khi không chạy JavaScript hoặc trong khi JS đang được thực thi. Điều này là không thể đối với Canvas và liên quan đến "JavaScript" thuần túy, nó thực sự là một loại tăng tốc phần cứng (đa luồng) chắc chắn có sẵn trong Chrome và FF trên tất cả các nền tảng. Cảm ơn!
Sebastian

1
Để tổng hợp tình huống hiện tại: Hoạt động với tôi trên Chrome và Chromium. Trên Linux. Năm 2019. Trên tất cả các trường hợp tôi đã thử nghiệm mà không có cấu hình đặc biệt. Firefox / Mozilla đang làm việc trên Linux cho Linux , tuy nhiên, quá trình kết xuất không phải là điều gì mới đối với FF, và sẽ luôn hoạt động tốt hơn với SVG, CSS, v.v. so với Canvas.
Sebastian

13

Đối với mục đích của bạn, tôi khuyên bạn nên sử dụng SVG, vì bạn nhận được các sự kiện DOM, như xử lý chuột, bao gồm kéo và thả, bạn không phải thực hiện vẽ lại của riêng mình và bạn không phải theo dõi trạng thái đối tượng của bạn. Sử dụng Canvas khi bạn phải thực hiện thao tác hình ảnh bitmap và sử dụng div thông thường khi bạn muốn thao tác các công cụ được tạo trong HTML. Về hiệu suất, bạn sẽ thấy rằng các trình duyệt hiện đại hiện đang tăng tốc cả ba, nhưng bức tranh đó đã nhận được sự chú ý nhiều nhất cho đến nay. Mặt khác, việc bạn viết javascript tốt đến mức nào để đạt hiệu suất cao nhất với canvas, vì vậy tôi vẫn khuyên bạn nên sử dụng SVG.


1
Trên thực tế, sử dụng HTML đơn giản là hiệu quả nhất khi kết hợp với hình ảnh CSS.
Raynos

16
@Raynos: Nguồn?
Janus Troelsen

3

Trong khi googling tôi tìm thấy một lời giải thích tốt về việc sử dụng và nén SVGCanvas tại http://teropa.info/blog/2016/12/12/graphics-in-angular-2.html

Hy vọng nó giúp:

  • SVG, giống như HTML, sử dụng kết xuất được giữ lại : Khi chúng tôi muốn vẽ một hình chữ nhật trên màn hình, chúng tôi khai báo sử dụng một phần tử trong DOM của chúng tôi. Trình duyệt sau đó sẽ vẽ một hình chữ nhật, nhưng nó cũng sẽ tạo ra một đối tượng SVGRectEuity trong bộ nhớ đại diện cho hình chữ nhật. Đối tượng này là một cái gì đó dính xung quanh để chúng ta thao tác - nó được giữ lại. Chúng ta có thể chỉ định các vị trí và kích cỡ khác nhau cho nó theo thời gian. Chúng tôi cũng có thể đính kèm người nghe sự kiện để làm cho nó tương tác.
  • Canvas sử dụng kết xuất ngay lập tức : Khi chúng ta vẽ một hình chữ nhật , trình duyệt sẽ ngay lập tức hiển thị một hình chữ nhật trên màn hình, nhưng sẽ không bao giờ có bất kỳ "đối tượng hình chữ nhật" nào đại diện cho nó. Chỉ có một loạt các pixel trong bộ đệm canvas. Chúng ta không thể di chuyển hình chữ nhật. Chúng ta chỉ có thể vẽ một hình chữ nhật khác. Chúng tôi không thể phản hồi các nhấp chuột hoặc các sự kiện khác trên hình chữ nhật. Chúng tôi chỉ có thể trả lời các sự kiện trên toàn bộ khung vẽ .

Vì vậy, canvas là một API hạn chế, mức độ thấp hơn so với SVG. Nhưng có một điểm bất cập, đó là với canvas bạn có thể làm được nhiều hơn với cùng một lượng tài nguyên. Bởi vì trình duyệt không phải tạo và duy trì biểu đồ đối tượng trong bộ nhớ của tất cả những thứ chúng ta đã vẽ, nên nó cần ít bộ nhớ và tài nguyên tính toán hơn để vẽ cùng một cảnh trực quan. Nếu bạn có một hình ảnh trực quan rất lớn và phức tạp để vẽ, Canvas có thể là vé của bạn.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.