【问题标题】:Same JavaScript function producing different results when manually called vs through an HTML button click手动调用与单击 HTML 按钮时,相同的 JavaScript 函数会产生不同的结果
【发布时间】:2016-10-21 22:55:03
【问题描述】:

我一直试图理解为什么我的代码中的同一个 JavaScript 函数在函数内部调用而不是通过 HTML 按钮单击调用时会产生不同的结果。

基本上,我正在尝试使用杜克大学的Simple Image 库上传图像并将其转换为灰度。然后这些图像显示在两个 <canvas> 元素上。

这是我的代码(很抱歉没有制作小提琴,因为我正在使用的库不能包含在其中。这是我的codepen 的链接)-

HTML -

<script src="http://www.dukelearntoprogram.com/course1/common/js/image/SimpleImage.js"></script>
<h1>Upload and Display an Image</h1>
<canvas id="canvas"></canvas>
<canvas id="canvas2"></canvas>
<p>Filename:
<input type="file" multiple="false" accept="image/*" id="fileInput" onchange="upload()">
</p>
<p><input type="button" value="Make Grayscale" onclick="makeGray()"></p>

CSS -

html {
  margin: 10px;
}

h1 {
  font-family: helvetica;
}

canvas {
  width: 500px;
  height: 250px;
  border-style: solid;
}

#textInput {
  font-size: 20px;
}

JavaScript -

var img;

function upload() {
  img = new SimpleImage(fileInput);
  var canvas = document.getElementById("canvas");

  img.drawTo(canvas);
}

function makeGray() {
  for(var pixel of img.values()) {
    var avg = (pixel.getRed() + pixel.getGreen() + pixel.getBlue())/3;
    pixel.setRed(avg);
    pixel.setGreen(avg);
    pixel.setBlue(avg);
  }
  var canvas = document.getElementById("canvas2");

  img.drawTo(canvas);
}

这很有效,因为我可以单击Make Grayscale 按钮并在将灰度图像上传到第一个画布后将其显示在第二个画布上。但是,当我去掉 Make Grayscale 按钮并在 upload() 函数内调用 makeGray() 函数时,它不会发布灰度图像,而是将普通图像发布到第二个画布上。

我不确定为什么会这样,因为控制台上没有错误。任何有关这方面的信息都会很棒。谢谢!

【问题讨论】:

    标签: javascript html canvas


    【解决方案1】:

    等到图片加载完毕

    当前答案不正确。虽然它会起作用,但这只是运气,如果图像加载时间超过 1000 毫秒,它会失败。 需要等待图像加载才能绘制它,你无法猜测多久这需要。

    由于文档错误导致库错误。

    不幸的是,您使用的库的文档非常少。通过源代码,可以在加载图像时调用 onload 回调,但我无法确定它是哪个参数,因为没有命名参数。它使用的 FileReader 对象也不会暴露给您以覆盖 onload 事件。

    你有两个选择。

    • 知道什么是用于创建 SimpleImage 的 onload 回调参数,并提供一个在加载图像时调用的函数。
    • 使用已知信息并在可以使用图像时轮询该信息以进行锻炼。

    第二个选项

    Lib 内部 cmets 说,当图像准备好时,然后img.imageData !== null,所以你能做的最好的就是轮询图像并等待它准备好渲染。

    函数轮询SimpleImage对象img等待img.imageData !== null,然后调用函数callback。轮询间隔为 pollTime,如果未提供,则默认为 250ms

    function pollImage(img,callback,pollTime){
        function isReady(){
            if(img.dataURL === null){ // not ready
                setTimeout(isReady,pollTime); // try again soon
            }else{
                callback(); // yes loaded call the callback
            }
        }
        if(img === null || img === undefined){
            throw new ReferenceError("No image object given!");
        }
        if(typeof callback !== "function"){
            throw new ReferenceError("No callback function given!");
        }
    
        pollTime = pollTime === undefined ? 250 : pollTime; // default to 1/4 second
        setTimeout(isReady,0); // Start as soon as possible
    
    }
    

    然后您将代码更改为

    function upload() {
      img = new SimpleImage(fileInput);
      pollImage(
          img,
          function(){  // callback function that is run when image is ready
              var canvas = document.getElementById("canvas");
              makeGray();
          },
          200
      );
    }  
    

    第三个选项。

    就我个人而言,我发现一个宣传主题 (x) 教学但将核心概念隐藏在文档稀少的界面后面的网站对任何人都没有任何好处。不要使用 SimpleImage。学习直接使用 DOM,它有很好的文档,而且使用起来非常简单,当出现不可避免的并发症时不会让您猜测。

    【讨论】:

    • 优秀而详细的答案!非常感谢!我正在学习他们的课程,因为他们有练习可以让我练习我所学的理论。我肯定会尝试在不使用他们的库的情况下实现这一点。
    猜你喜欢
    • 2015-06-18
    • 2017-10-07
    • 2010-09-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多