范围滑块控制画布需要更好的图片加载和预览图像(?)

时间:2017-11-07 08:25:57

标签: javascript jquery canvas

我对javascript和编码一般都缺乏经验,所以我从以下和其他地方看过的一些例子中拼凑了下面的代码。代码完成了我现在想要的90%,但我想知道如何在移动滑块之前显示数组“videoFrames”中的第一个图像,就像现在一样,画布在页面加载时是空白的。第二件事是,它似乎不是在页面加载时加载图像,我错了吗?如何改进/合并到此代码中?

<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="400" height="225" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
    </canvas>
<br>
<input id="my-input" type="range" min="1" max="50" value="0" />
numbers

3 个答案:

答案 0 :(得分:2)

我的某些图片上有404,但我会尝试触发输入。

你确实可以立即画画

Loading an image onto a canvas with javaScript

而不是等待输入,但它将与触发它一样等待,因为画布必须在绘制之前存在

以下是触发的方法 - 注意:如果图像很大,当你触发它时,第一张图像的预加载可能还没有完成

var canvas = document.getElementById("myCanvas");
var width = 1920;
var height = 1080;

var totalImages = 50;
var videoFrames = [];
for (var i = 1; i <= totalImages; i++) {
  var img = new Image;
  var videoFrameUrl = 'https://the-faction.squarespace.com/assets/chalet-lightmix-01/Chalet-V06_LM_' + i + '.jpg';
  img.src = videoFrameUrl;
  videoFrames.push(img);
}

$("#my-input").on("input", function(event) {
  var currentImage = videoFrames[event.target.value - 1];
  console.log("val",currentImage)
  var ctx = canvas.getContext("2d");
  ctx.drawImage(currentImage, 0, 0, canvas.width, canvas.height);
}).trigger("input");
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="400" height="225" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
    </canvas>
<br>
<input id="my-input" type="range" min="1" max="50" value="0" />

可能效果更好的版本

var canvas,ctx;
$(function() {
  canvas=$("#myCanvas")[0];
  ctx = canvas.getContext("2d");
  $("#my-input").on("input", function(event) {
    var currentImage = videoFrames[this.value];
    ctx.drawImage(currentImage, 0, 0, canvas.width, canvas.height);
  })

  var totalImages = 50;
  var videoFrames = [];
  for (var i = 1; i <= totalImages; i++) {
    videoFrames[i] = new Image();
    if (i === 1) {
      videoFrames[i].onload = function() {
        console.log("loaded")
        $("#my-input").trigger("input");
      }
    }
    videoFrames[i].src = 'https://the-faction.squarespace.com/assets/chalet-lightmix-01/Chalet-V06_LM_' + i + '.jpg';
  }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="400" height="225" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
    </canvas>
<br>
<input id="my-input" type="range" min="1" max="50" value="1" />

答案 1 :(得分:0)

您似乎想要的是图像预加载器。

处理图片时的基本规则是在加载之前,您无法对其进行任何操作。

你可以实现所有类型的图像预加载器,这取决于你的规则,这是一个当第一个图像加载时所有图像加载了另一个图像时将触发回调的图像预加载器,这将删除那些图像预加载器堆栈:

&#13;
&#13;
function preload(imgURLs, onalldone, onfirstdone){
  var loaded = 0;
  function onsingleload(){
    if(++loaded >= imgURLs.length){
      onalldone(stack);
    }
  }
  function onerror(evt){
    // remove the image from the stack
    stack.splice(stack.indexOf(evt.target), 1);
    onsingleload();
  }
  var stack = imgURLs.map(function(url, i){
    var img = new Image();
    if(!i && typeof onfirstdone === 'function'){
      img.addEventListener('load', onfirstdone);
    }
    img.src = url;
    img.onload = onsingleload;
    img.onerror = onerror;
    return img;
  });
  return stack;
}

// now your code
var canvas = document.getElementById("myCanvas");
var width = 1920;
var height = 1080;

var totalImages = 25;
var videoFrames = [];
for (var i = 1; i <= totalImages; i++) {
  videoFrames.push('https://the-faction.squarespace.com/assets/chalet-lightmix-01/Chalet-V06_LM_' + i + '.jpg');
}

videoFrames = preload(videoFrames, 
// when all images have loaded
function onfullyloaded(loadedImages){
  $("#my-input").attr({
    max: loadedImages.length - 1, // some errors ?
    disabled: false // now we can enable the range
    });
},
// when the first of the stack has loaded
function onfirstimageloaded(event){
    var ctx = canvas.getContext("2d");
    ctx.drawImage(event.target, 0, 0, canvas.width, canvas.height);
  });

$("#my-input").on("input", function(event){
  var currentImage = videoFrames[event.target.value];
  var ctx = canvas.getContext("2d");
  ctx.drawImage(currentImage, 0, 0, canvas.width, canvas.height);
  })
&#13;
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<canvas id="myCanvas" width="400" height="225" style="border:1px solid #d3d3d3;">
    Your browser does not support the HTML5 canvas tag.
</canvas>
<br>
<input id="my-input" type="range" min="0" max="50" value="0" disabled/>
&#13;
&#13;
&#13;

答案 2 :(得分:0)

哇50张高清图像,大概是0.4Gig的RAM。也许你应该考虑将它全部压缩成视频。

无论如何都不能一次性加载所有图像,请尽快启动第一个着陆图像。使用image onload事件,一旦准备就将其呈现给画布。

然后加载每个第8个图像,这样你至少可以伪造动画,人们不会等待50个图像加载,所以尽早给他们一些东西。当每个第8张图像都已加载时,请获取其间的图像。

在加载并移动滑块时,使用画布在您拥有的图像之间淡入淡出。

以下示例仅使用6张图片。但是它适用于任意数量的图像(如果动画需要它)但是你需要分步加载它们,每次都加载它们,然后加载它们,依此类推,直到所有图像都加载完毕。如果移动滑块,则等待它们之间的淡入淡出。

const ctx = canvas.getContext("2d");


const imagesIdx = [1,10,20,30,40,50];
const images = [];
imagesIdx.forEach((idx,i) => {
    const img = new Image;
    img.src = "https://the-faction.squarespace.com/assets/chalet-lightmix-01/Chalet-V06_LM_" + idx + ".jpg";
    if (i === 0) { img.onload = loadedFirst }
    images.push(img);
});

function loadedFirst(){

    ctx.drawImage(images[0],0,0,canvas.width, canvas.height);
    slider.addEventListener("mousemove",sliderMove);
}
var sliderValOld;
function sliderMove(){
    if(slider.value !== sliderValOld){
      var imageA = (Number(slider.value) / (Number(slider.max) / images.length)) | 0;
      if(imageA >= images.length){
          imageA -= 1;
      }
      var imageB = imageA + 1;

      while(!images[imageA].complete){ imageA -= 1 }
      while(imageB < images.length && !images[imageB].complete) { imageB += 1 }
      ctx.globalAlpha = 1;
      ctx.drawImage(images[imageA],0,0,canvas.width, canvas.height);
      if(imageB < images.length){
        var rng = Number(slider.max) / images.length;
        var a = imageA * rng;
        var b = imageB * rng;
        ctx.globalAlpha = (Number(slider.value) - a) / (b - a);
        ctx.drawImage(images[imageB],0,0,canvas.width, canvas.height);
      }
    }
    sliderValOld = slider.value;
}
<input id="slider" type="range" min="0" max="600" value="0" /><br>
<canvas id="canvas" width="400" height="225" style="border:1px solid #d3d3d3;">
  </canvas>