簡體   English   中英

如何渲染數以萬計的元素?

[英]How can I render tens of thousands of elements?

在你 go 之前說我瘋了,相信我,我知道。 我不會選擇渲染速度快、加載速度快或燈塔得分高的網站。 我只是想讓它工作。

我有一些 javascript 可以拾取圖像的所有像素 colors。 使用這個 function,我創建了一個 1px x 1px 的 div 元素,並將背景顏色設置為相同坐標的像素顏色。 然后坐標用於設置頂部和左側的值。 我的代碼按照它所說的去做。

這是我的問題,我的圖像是 700 像素 x 387 像素。 如果您進行數學計算,則可以計算出 270,900 個 html 元素。 Chrome,根本不是為這種瘋狂而構建的。 我想看看這項工作,我想以某種方式“手動”創建一個帶有 div 元素的圖像。 當我嘗試這樣做時,我的 cpu 會達到最大值,而且我確信我最終會用完 ram。

如果我只嘗試數百或數千個像素,一切都會正常工作,但如果再嘗試,那么 chrome 就會死掉。 我不確定它是否在瀏覽器中計算可能是我的問題,或者 chrome 是否無法顯示這么多元素,或兩者兼而有之。 我想我可以在我的服務器上使用 python 和 append 對 html 進行相同的數學運算,但是 chrome 可能無法顯示它。

顯然,這不是很重要,只是好玩。 我認為社區也將享受挑戰。

這里計算 100 個像素:

 onload = e => { function componentToHex(c) { var hex = c.toString(16); return hex.length == 1? "0" + hex: hex; } function rgbToHex(r, g, b) { return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); } function img(x, y) { var img = document.getElementById('my-image'); var canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height); var pixelData = canvas.getContext('2d').getImageData(x, y, 1, 1).data; return rgbToHex(pixelData[0], pixelData[1], pixelData[2]); } //x = 700 y = 387 for (var x = 0; x < 10; x++) { for (var y = 0; y < 10; y++) { document.body.insertAdjacentHTML("beforeend", "<div style='top:" + y + "px; left:" + x + "px;background:" + img(x, y) + ";' />"); } } };
 div { position: absolute; width: 1px; height: 1px; }
 <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fb/New_born_Frisian_red_white_calf.jpg/640px-New_born_Frisian_red_white_calf.jpg" id="my-image" crossorigin="anonymous">

這里正在計算 2500px(仍然有效,需要一段時間)

 onload = e => { function componentToHex(c) { var hex = c.toString(16); return hex.length == 1? "0" + hex: hex; } function rgbToHex(r, g, b) { return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); } function img(x, y) { var img = document.getElementById('my-image'); var canvas = document.createElement('canvas'); canvas.width = img.width; canvas.height = img.height; canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height); var pixelData = canvas.getContext('2d').getImageData(x, y, 1, 1).data; return rgbToHex(pixelData[0], pixelData[1], pixelData[2]); } //x = 700 y = 387 for (var x = 0; x < 50; x++) { for (var y = 0; y < 50; y++) { document.body.insertAdjacentHTML("beforeend", "<div style='top:" + y + "px; left:" + x + "px;background:" + img(x, y) + ";' />"); } } };
 div { position: absolute; width: 1px; height: 1px; }
 <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/f/fb/New_born_Frisian_red_white_calf.jpg/640px-New_born_Frisian_red_white_calf.jpg" id="my-image" crossorigin="anonymous">

干杯,艾薩克。

目前,您正在為每個像素執行以下操作

  • 創建 canvas
  • 獲取上下文並繪制到圖像
  • 獲取上下文並獲取一個像素的像素數據
  • 創建一個 DIV
  • 將其添加到 DOM

現在,讓我們簡化一下

以下可以完成一次

  • 創建 canvas
  • 獲取上下文
  • 使用上下文繪制圖像
  • 使用上下文獲取圖像數據
  • 創建一個空字符串

現在,對於每個像素

  • 獲取像素數據
  • 將 div 的 html 添加到字符串

最后,就一次

  • 將帶有所有 div 的字符串添加到 DOM

就像是:

const componentToHex = c => c.toString(16).padStart(2, '0');
const rgbToHex = (r, g, b) => `#${componentToHex(r)}${componentToHex(g)}${componentToHex(b)}`;
const img = document.getElementById('my-image');
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
const w = canvas.width = img.width;
const h = canvas.height = img.height;
context.drawImage(img, 0, 0, img.width, img.height);
const imageData = context.getImageData(0, 0, w, h).data;
const pixel = (x, y) => {
    const index = (w * y + x) * 4;
    return rgbToHex(imageData[index], imageData[index + 1], imageData[index + 2]);
}
const df = document.createDocumentFragment();
for (let y = 0; y < img.height; y++) {
    for (let x = 0; x < img.width; x++) {
        const div = df.appendChild(document.createElement('div'));
        div.style.top = y + "px";
        div.style.left = x + "px";
        div.style.backgroundColor = pixel(x, y);
    }
}
document.body.appendChild(df);

注意:現在可能不是這種情況,但是這樣的循環在 function 內可能會更快地工作 - 通常全局上下文中的循環會更慢

因此,您可以將上面的整個代碼包裝在

(() => {
    // the code from above
})();

並再次看到顯着改善 - 不確定,過去幾年曾經是這種情況

更改為使用document fragment進一步提高 25% 的速度
現在在 firefox 中需要 1.4 秒以獲得 640x480 圖像,在 chrome 中需要 2.3 秒 - 這並沒有真正看到使用insertAdjacentHTML與文檔片段之間的巨大差異

還有一點需要注意。 在 Firefox 中,頁面變得遲緩,在 chrome 中,對於 640x480,沒有這樣的問題

暫無
暫無

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

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