Эффективный метод изменения изображения, отображаемого на <img>? - PullRequest
4 голосов
/ 05 апреля 2019

В JavaScript у меня есть ссылка на элемент DOM <img>.Мне нужно изменить изображение, отображаемое <img> изнутри javascript.

До сих пор я пробовал это, меняя атрибут image.src на URL нового изображения.Это сработало, но проблема все еще остается: мне нужно, чтобы изображение менялось много раз в секунду, а изменение атрибута src заставляет браузер выполнить новый запрос GET для изображения (которое уже кэшировано), в результате чегонагрузка на веб-сервер, так как будут сотни одновременных клиентов.

Мое текущее (неэффективное) решение сделано так:

let image = document.querySelector("img");

setInterval(function(){
    image.src = getNextImageURL();//this causes a GET request
}, 10);

function getNextImageURL() {
   /*...implementation...*/
}
<img>

Я ищу более эффективный способ изменения изображения, который не вызывает ненужных HTTP-запросов.

Ответы [ 2 ]

3 голосов
/ 05 апреля 2019

Я думаю, вам нужно кодировать по-другому ...

если вы хотите уменьшить количество запросов, вам следует объединить все изображения в одном листе спрайта. этот трюк использует так много игровых анимаций. Но вам нужно поменять тег <img/> на другой тег, например <div></div>

Идея в том, что у нас есть одно изображение, и мы просто меняем область просмотра на то, что хотим

образец Для спрайтового листа

enter image description here

let element = document.querySelector("div");
let i = 1
setInterval(function(){
    element.style.backgroundPosition= getNextImagePostion(i++);//this will change the posion
}, 100);

function getNextImagePostion(nextPos) {
   /*...implementation...*/

   // this just for try
   //  6 is the number of images in sheet
   // 20 is the height for one segment in sheet
   var posX = 100*(nextPos%6);

  // first is position on x and latter is position on y
   return "-"+posX+"px 0px ";
}
.image {
    width: 100px; /*  width of single image*/
    height: 100px; /*height of single image*/
    background-image: url(https://picsum.photos/500/100?image=8) /*path to your sprite sheet*/
}
<div class="image">
</div>
2 голосов
/ 05 апреля 2019

Если идея спрайт-листа не работает (например, потому что у вас большие изображения), тогда используйте canvas .

. Вам просто нужно предварительно загрузить все ваши изображения, сохранить ихв массиве, а затем нарисуйте их один за другим на своем холсте:

const urls = new Array(35).fill(0).map((v, i) =>
  'https://picsum.photos/500/500?image=' + i
 );
// load all the images
const loadImg = Promise.all(
  urls.map(url => 
    new Promise((res, rej) => {
      // each url will have its own <img>
      const img = new Image();
      img.onload = e => res(img);
      img.onerror = rej;
      img.src = url;
    })
  )
);
// when they're all loaded
loadImg.then(imgs => {
  // prepare the canvas
  const canvas = document.getElementById('canvas');
  // set its size
  canvas.width = canvas.height = 500;
  // get the drawing context
  const ctx = canvas.getContext('2d');

  let i = 0;
  // start the animation
  anim();

  function anim() {
    // do it again at next screen refresh (~16ms on a 60Hz monitor)
    requestAnimationFrame(anim);
    // increment our index
    i = (i + 1) % imgs.length;
    // draw the required image
    ctx.drawImage(imgs[i], 0, 0);
  }
})
.catch(console.error);
<canvas id="canvas"></canvas>

А если вы хотите контроль времени:

const urls = new Array(35).fill(0).map((v, i) =>
  'https://picsum.photos/500/500?image=' + i
 );
// load all the images
const loadImg = Promise.all(
  urls.map(url => 
    new Promise((res, rej) => {
      // each url will have its own <img>
      const img = new Image();
      img.onload = e => res(img);
      img.onerror = rej;
      img.src = url;
    })
  )
);
// when they're all loaded
loadImg.then(imgs => {
  // prepare the canvas
  const canvas = document.getElementById('canvas');
  // set its size
  canvas.width = canvas.height = 500;
  // get the drawing context
  const ctx = canvas.getContext('2d');

  const duration = 100; // the number of ms each image should last
  let i = 0;
  let lastTime = performance.now();

  // start the animation
  requestAnimationFrame(anim);

  // rAF passes a timestamp
  function anim(time) {
    // do it again at next screen refresh (~16ms on a 60Hz monitor)
    requestAnimationFrame(anim);

    const timeDiff = time - lastTime;
    if(timeDiff < duration) { // duration has not yet elapsed
      return;
    }
    // update lastTime
    lastTime = time - (timeDiff - duration);
    // increment our index
    i = (i + 1) % (imgs.length);
    // draw the required image
    ctx.drawImage(imgs[i], 0, 0);
  }
})
.catch(console.error);
<canvas id="canvas"></canvas>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...