Несколько разных фонов на веб-странице - PullRequest
0 голосов
/ 19 октября 2018

У меня есть миллионы фотографий, которые я хочу отобразить в виде мозаики / установить в качестве фона веб-страницы в виде сетки одновременно.Как я могу добиться этого, используя javascript, jquery или любую веб-технологию без сбоя или замедления работы браузера?

Что я пробовал:

  1. Предназначен для динамического создания миллионов пролетов и установки каждогокартинка в качестве фона участка: он замедляет работу компьютера, когда он достигает 60 000 участков.
  2. Пытался использовать Div / Tables, даже хуже по производительности, чем диапазон.
  3. Поскольку изображения могут быть созданыДинамически используя javascript, я решил нарисовать каждую картинку на холсте и нарисовать как можно больше холстов, но все же очень медленно.

Ответы [ 2 ]

0 голосов
/ 19 октября 2018

Согласно вашему третьему пункту, изображения могут быть созданы динамически с использованием javascript .

Итак, давайте возьмем вашу первую идею, просто нарисовав ее на холсте,но вместо того, чтобы генерировать много холстов, создайте один, на котором мы будем рисовать полную сетку.

Вместо того, чтобы хранить каждое изображение в виде пикселей, мы просто сохраним то, что необходимо для его фактического создания.В итоге это будет просто набор координат, и, если повезет, мы сможем сохранить его в объектах с достаточно схожими формами, чтобы движки js могли оптимизировать его наилучшим образом.

Все, что нам нужно сделать, это вычислить, сколько из этих картинок может появиться на нашем экране, поместить их в сетку и отобразить только те, которые действительно видимы.(Поскольку маловероятно, что вы когда-либо сможете визуализировать все эти изображения одновременно).

(function() {

  const pic_width = 150;
  const pic_height = 75;
  const padding = 10;
  const colors = Array.from({
    length: 150
  }, _ => '#' + Math.random().toString(16).substr(2, 6));


  // This offscreen canvas is only used to avoid clipping the main one
  // It is shared by all instances of Pic
  const pic_drawer = Object.assign(document.createElement('canvas'), {
    width: pic_width,
    height: pic_height
  }).getContext('2d');
  pic_drawer.textAlign = 'center';
  pic_drawer.textBaseline = 'hanging';


  /* 
    Our Picture class.
    Holds only some coords in memory
    Redraws itself from scratch every time
  */
  class Pic {
    constructor(index) {
      this.id = index;
      const max_rad = 25;
      const min_rad = 3;
      // just hold some coords of points
      this.points = Array.from({
        length: Math.random() * 20 + 5
      }, _ => ({
        color: colors[(Math.random() * colors.length) | 0],
        x: Math.random() * pic_width,
        y: Math.random() * pic_height,
        r: (Math.random() * (max_rad - min_rad)) + min_rad
      }));
    }
    draw(ctx) {
      // render all our points on the small canvas so the clipping is easy done
      const pts = this.points;
      pic_drawer.clearRect(0, 0, pic_width, pic_height);
      pic_drawer.beginPath();
      pic_drawer.fillStyle = pts[0].color;
      for (let pt of pts) {
        if (pic_drawer.fillStyle !== pt.color) {
          pic_drawer.fill();
          pic_drawer.fillStyle = pt.color;
          pic_drawer.beginPath();
        }
        pic_drawer.moveTo(pt.x + pt.r, pt.y);
        pic_drawer.arc(pt.x, pt.y, pt.r, 0, Math.PI * 2);
      }
      pic_drawer.fillText(this.id, pic_width / 2, pic_height / 2);
      // draw back on main context
      ctx.drawImage(pic_drawer.canvas, 0, 0);
    }
  }

  /*
    The Grid instance will hold all our Pics
    It will get responsible for the main canvas' size and scroll
    And for the disposition of all our Pics and their rendering
    Exposes a *dirty*  flag so the outside anim loop can know when it needs update
  */
  class Grid {
    constructor() {

      this.dirty = true;

      this.scrollTop = 0;
      this.pics = [];

      this.canvas = document.createElement('canvas');
      this.ctx = this.canvas.getContext('2d');

      window.addEventListener('resize', this.resize.bind(this), {
        passive: true
      });
      // ToDo: implement touch events...
      this.canvas.addEventListener('wheel', e => {
        e.preventDefault();
        this.scrollTop += e.deltaY;
        if (this.scrollTop < 0) this.scrollTop = 0;
        this.dirty = true;
      }, {
//        passive: true // (disabled for SO's iframe)
      })

      this.resize();


    }
    resize() {
      this.width = this.canvas.width = innerWidth;
      this.height = this.canvas.height = innerHeight;
      this.dirty = true;
    }
    update() {
      // update only the grid info

      // number of columns that can fit in screen
      this.columns = Math.floor(this.width / (pic_width + padding * 2));
      // number of rows (ceil + 1 to get partial previous and next ones too)
      this.rows = Math.ceil(this.height / (pic_height + padding * 2)) + 1;

      const floating_row_index = this.scrollTop / (pic_height + padding * 2);
      const first_row_index = Math.floor(floating_row_index);

      // the index of the first Pic that will get drawn
      this.first_visible_pic = first_row_index * this.columns;

      // floating scroll
      this.y_offset = (first_row_index - floating_row_index) * (pic_height + padding * 2);
      // center
      this.x_offset = (this.width - (this.columns * (pic_width + padding * 2))) / 2;

    }
    draw() {
      const ctx = this.ctx;
      // clear
      ctx.setTransform(1, 0, 0, 1, 0, 0);
      ctx.clearRect(0, 0, this.width, this.height);
      // iterate through our cells
      for (let y = 0; y < this.rows; y++) {
        for (let x = 0; x < this.columns; x++) {
          // get the Pic at given index
          const index = (y * this.columns + x) + this.first_visible_pic;
          // in case it doesn't exist yet, create it
          if (!this.pics[index]) {
            this.pics[index] = new Pic(index);
          }
          // move our context at cell's coords
          ctx.setTransform(
            1, 0, 0,
            1,
            x * (pic_width + padding * 2) + padding + this.x_offset,
            y * (pic_height + padding * 2) + padding + this.y_offset
          );
          // draw our Pic
          this.pics[index].draw(ctx);
          // border...
          ctx.strokeRect(0, 0, pic_width, pic_height);
        }
      }
    }
  }


  const grid = new Grid();
  document.body.append(grid.canvas);

  function anim() {
    // only if it has changed
    if (grid.dirty) {
      grid.update(); // update the grid
      grid.draw(); // draw it
      grid.dirty = false; // clean the flag
    }
    requestAnimationFrame(anim); // check again at next screen refresh
  }
  anim();

})();
:root,body,canvas{margin:0;padding:0;line-height:0}
0 голосов
/ 19 октября 2018

Вам действительно нужно показывать 60 000 снимков за один раз, потому что я не могу представить, что кто-нибудь сможет увидеть ВСЕ 60 000 снимков одновременно.

Я бы сделал следующее:

1 - сгенерировать макет сетки / диапазона для фона 5 * 5 (или столько изображений, которые вы хотите показать одновременно);

2 - создать папку на сервере со всеми изображениями, которые можно использовать, с числовыми увеличивающимися именами файлов, такими как "0.png" "1.png" "2.png" "3.png" и т. д.

3 - ЕСЛИ вам не нужно менять картинки, пока пользовательглядя на страницу, и вы будете менять картинки только тогда, когда пользователь (повторно) загружает страницу, вы можете написать на сервере код, который генерирует случайное число в диапазоне от 0 до макс. номеров файлов (-1).добавьте «.png» за этим номером и установите этот файл в качестве фона диапазона.

3 - Если вы хотите, чтобы изображения менялись, пока пользователь смотрит на страницу, вам нужно написать код javascriptкоторый сгенерирует случайное число в диапазоне от 0 до максимального номера файла (-1).Добавьте к нему «.png» и измените фон пролета на это имя файла.теперь повторяйте эту функцию каждые x секунд.

это предотвратит создание 60 000 промежутков, что определенно замедлит работу браузера.Также вы не связаны ни с тем, ни с другим.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...