Search code examples
javascripthtmlaugmented-realitygetusermedia

HTML5 + 2 JS Scripts only working separately - camera and local file input


I am trying to combine two js scripts to allow a local jpeg to be viewed locally in browser on top of the camera feed with 80% opacity to make an AR tracing web app.

With the following code, it displays the webcam feed correctly but it doesn't display the uploaded overlaying the camera feed. I am trying to keep the code as simple as possible. The scripts work okay when using only one or the other, but not both at the same time.

Image viewer overlay JS:

$("input").change(function(e) {
     for (var i = 0; i < e.originalEvent.srcElement.files.length; i++) {
        var file = e.originalEvent.srcElement.files[i];
        var img = document.createElement("img");
        var reader = new FileReader();
        reader.onloadend = function() {
             img.src = reader.result;
        }
        reader.readAsDataURL(file);
        $("input").after(img);
    }
});

Cam feed JS:

var constraints = { audio: false, video: { width: 300, height: 300 } };
navigator.mediaDevices.getUserMedia(constraints)
.then(function(mediaStream) {
  var video = document.querySelector('video');
  video.srcObject = mediaStream;
  video.onloadedmetadata = function(e) {
    video.play();
  };
})
.catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.

HTML:

<html>
<head>
<style>
img { opacity: 80%
}
</style>
<script src="camfeed.js"></script>
<script src="overlay.js"></script>
</head>
<body>
<video id="vid"></video>
<input type="file" accept="image"></input>
</body>
</html>

UPDATE: I made some modifications of the code following suggestions. No fix but I get error message in console Uncaught TypeError: Cannot read property 'addEventListener' of null at window.onload (overlay.js:7).

Here's the current HTML:

<html>
<head>
<style>
  .overlay {
    position: absolute;
  left: 0px;
  top: 0px;
    opacity: 25%; 
      z-index: -1;
  }
  img {
    position: absolute;
  left: 0px;
  top: 0px;
    opacity: 25%; 
      z-image: -1;
    }
    video {
    position: absolute;
  left: 0px;
  top: 0px;
    height: 720;
    width: 1280;
        z-index:-2;
    }
    input {
        z-index: 1;
    }
</style>
</head>
<body>
<video id="vid"></video>
<div id="overlay"></div>
<input type="file" id=fileInput" accept="image" value="pick a pic"></input>
<script src="camfeed.js"></script>
<script src="overlay.js"></script>                                   
</body>
</html>

Here's the current overlay.js:

window.onload = function() {

        var fileInput = document.getElementById('fileInput');
        var fileDisplayArea = document.getElementById('overlay');


        fileInput.addEventListener('change', function(e) {
            var file = fileInput.files[0];
            var imageType = /image.*/;

            if (file.type.match(imageType)) {
                var reader = new FileReader();

                reader.onload = function(e) {
                    fileDisplayArea.innerHTML = "";

                    var img = new Image();
                    img.src = reader.result;

                    fileDisplayArea.appendChild(img);
                }

                reader.readAsDataURL(file); 
            } else {
                fileDisplayArea.innerHTML = "File not supported!"
            }
        });

}

Here's the current camfeed.js (working):

// Prefer camera resolution nearest to 1280x720.
var constraints = { audio: false, video: { width: 1280, height: 720, facingMode: "environment" }};
navigator.mediaDevices.getUserMedia(constraints).then(function(mediaStream) {
  var video = document.querySelector('video');
  video.srcObject = mediaStream;
  video.onloadedmetadata = function(e) {
    video.play();
  };
})
.catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.

Solution

  • I got it working. The cause of the issue seems to be that I didn't include the following jquery script code in index.html console error log show that it couldn't interpret the dollar sign ($)in the javascript scripts without jquery:

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    

    Here's the fully functional code:

    index.html:

    <html>
    <head>
    <style>
      .overlay {
        position: absolute;
      left: 0px;
      top: 0px;
        opacity: 25%; 
          z-index: -1;
      }
      img {
        position: absolute;
      left: 0px;
      top: 0px;
        opacity: 25%; 
          z-index: -1;
        }
        video {
        position: absolute;
      left: 0px;
      top: 0px;
        height: auto;
        width: 100%;
            z-index:-2;
        }
        input {
            z-index: 1;
        }
    </style>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    </head>
    <body>
    <video id="vid"></video>
    <input class="joint" type='file' id="imgInp" />
    <img style="width:100%" id="blah" src="#" alt="image display error" />
    <script src="camfeed.js"></script>
    <script src="overlay.js"></script>                                   
    </body>
    </html>
    

    overlay.js:

    function readURL(input) {
    
        if (input.files && input.files[0]) {
            var reader = new FileReader();
    
            reader.onload = function (e) {
                $('#blah').attr('src', e.target.result);
            }
    
            reader.readAsDataURL(input.files[0]);
        }
    }
    
    $("#imgInp").change(function(){
        readURL(this);
    });
    

    camfeed.js:

    // Prefer camera resolution nearest to 1280x720.
    var constraints = { audio: false, video: { width: 1280, height: 720, facingMode: "environment" }};
    navigator.mediaDevices.getUserMedia(constraints).then(function(mediaStream) {
      var video = document.querySelector('video');
      video.srcObject = mediaStream;
      video.onloadedmetadata = function(e) {
        video.play();
      };
    })
    .catch(function(err) { console.log(err.name + ": " + err.message); }); // always check for errors at the end.
    

    The end result is a helpful AR web app for tracing photos. Thanks for the tips.