Laptop camera turns on automatically when page opens

I have this code turns camera on once the page is opened. Is there a way where I can open the page, but have to click a button to turn the camera on, rather than the camera automatically opening?

I appreciate your help.

<style>
    #video {
  border: 1px solid black;
  box-shadow: 2px 2px 3px black;
  width: 320px;
  height: 240px;
}

#photo {
  border: 1px solid black;
  box-shadow: 2px 2px 3px black;
  width: 320px;
  height: 240px;
}

#canvas {
  display: none;
}

.camera {
  width: 340px;
  display: inline-block;
}

.output {
  width: 340px;
  display: inline-block;
  vertical-align: top;
}

#startbutton {
  display: block;
  position: relative;
  margin-left: auto;
  margin-right: auto;
  bottom: 32px;
  background-color: rgb(0 150 0 / 50%);
  border: 1px solid rgb(255 255 255 / 70%);
  box-shadow: 0px 0px 1px 2px rgb(0 0 0 / 20%);
  font-size: 14px;
  font-family: "Lucida Grande", "Arial", sans-serif;
  color: rgb(255 255 255 / 100%);
}

.contentarea {
  font-size: 16px;
  font-family: "Lucida Grande", "Arial", sans-serif;
  width: 760px;
}
</style>

<script>
    (() => {
  // The width and height of the captured photo. We will set the
  // width to the value defined here, but the height will be
  // calculated based on the aspect ratio of the input stream.

  const width = 320; // We will scale the photo width to this
  let height = 0; // This will be computed based on the input stream

  // |streaming| indicates whether or not we're currently streaming
  // video from the camera. Obviously, we start at false.

  let streaming = false;

  // The various HTML elements we need to configure or control. These
  // will be set by the startup() function.

  let video = null;
  let canvas = null;
  let photo = null;
  let startbutton = null;

  function showViewLiveResultButton() {
    if (window.self !== window.top) {
      // Ensure that if our document is in a frame, we get the user
      // to first open it in its own tab or window. Otherwise, it
      // won't be able to request permission for camera access.
      document.querySelector(".contentarea").remove();
      const button = document.createElement("button");
      button.textContent = "View live result of the example code above";
      document.body.append(button);
      button.addEventListener("click", () => window.open(location.href));
      return true;
    }
    return false;
  }

  function startup() {
    if (showViewLiveResultButton()) {
      return;
    }
    video = document.getElementById("video");
    canvas = document.getElementById("canvas");
    photo = document.getElementById("photo");
    startbutton = document.getElementById("startbutton");

    navigator.mediaDevices
      .getUserMedia({ video: true, audio: false })
      .then((stream) => {
        video.srcObject = stream;
        video.play();
      })
      .catch((err) => {
        console.error(`An error occurred: ${err}`);
      });

    video.addEventListener(
      "canplay",
      (ev) => {
        if (!streaming) {
          height = video.videoHeight / (video.videoWidth / width);

          // Firefox currently has a bug where the height can't be read from
          // the video, so we will make assumptions if this happens.

          if (isNaN(height)) {
            height = width / (4 / 3);
          }

          video.setAttribute("width", width);
          video.setAttribute("height", height);
          canvas.setAttribute("width", width);
          canvas.setAttribute("height", height);
          streaming = true;
        }
      },
      false,
    );

    startbutton.addEventListener(
      "click",
      (ev) => {
        takepicture();
        ev.preventDefault();
      },
      false,
    );

    clearphoto();
  }

  // Fill the photo with an indication that none has been
  // captured.

  function clearphoto() {
    const context = canvas.getContext("2d");
    context.fillStyle = "#AAA";
    context.fillRect(0, 0, canvas.width, canvas.height);

    const data = canvas.toDataURL("image/png");
    photo.setAttribute("src", data);
  }

  // Capture a photo by fetching the current contents of the video
  // and drawing it into a canvas, then converting that to a PNG
  // format data URL. By drawing it on an offscreen canvas and then
  // drawing that to the screen, we can change its size and/or apply
  // other changes before drawing it.

  function takepicture() {
    const context = canvas.getContext("2d");
    if (width && height) {
      canvas.width = width;
      canvas.height = height;
      context.drawImage(video, 0, 0, width, height);

      const data = canvas.toDataURL("image/png");
      photo.setAttribute("src", data);
    } else {
      clearphoto();
    }
  }

  // Set up our event listener to run the startup process
  // once loading is complete.
  window.addEventListener("load", startup, false);
})();
</script>

<div class="contentarea">

  <div class="camera">
    <video id="video">Video stream not available.</video>
    <button id="startbutton">Take photo</button>
  </div>
  <canvas id="canvas"> </canvas>
  <div class="output">
    <img id="photo" alt="The screen capture will appear in this box." />
  </div>
  
</div>

make it… not a load event?

Add a button to your html

<button id='start'>Start Camera</button>

Change this in your JS

window.addEventListener("load", startup, false);

To

document
  .querySelector('#start')
  .addEventListener('click', (ev) => {
    // remove the button once clicked
    ev.target.remove();
    startup();
  });

So now it fires up on a click event. That maybe a starting point.

Thanks for your reply. I have this and it doesn’t start the camera when I click on the button I added
I tried removing brackets etc to no success.

Thanks

  document
  .querySelector('#start')
  .addEventListener('click', (ev) => {
    // remove the button once clicked
    ev.target.remove();
    startup();
  });
})();
</script>

You need to add the id = “start” to your button

Did you add the button to your html, like I suggested?

I did do a quick test before posting and it worked for me.

I already had added that and it wouldn’t work.

This is what I have and it doesn’t work. Perhaps I misplaced something:

  // Set up our event listener to run the startup process
  // once loading is complete.
  document
  .querySelector('#start')
  .addEventListener('click', (ev) => {
    // remove the button once clicked
    ev.target.remove();
    startup();
  });
})();
</script>

<div class="contentarea">

  <div class="camera">
    <video id="video">Video stream not available.</video>
    <button id="startbutton">Take photo</button>
      <button id="start">Start Camera</button>
  </div>
  <canvas id="canvas"> </canvas>
  <div class="output">
    <img id="photo" alt="The screen capture will appear in this box." />
  </div>
  
</div>

You first need to add the element to the DOM and after that you can add the eventhandler not other way around …

2 Likes

I ran the following code in vscode with live server

HTML

<!DOCTYPE html>
<html lang='en'>
<head>
  <meta charset='UTF-8'>
  <meta name='viewport' content='width=device-width, initial-scale=1.0'>
  <title>Document</title>
  <link rel='stylesheet' href='css/camera.css'>
</head>
<body>
  <div class="contentarea">

    <div class="camera">
      <video id="video">Video stream not available.</video>
      <button id="startbutton">Take photo</button>
    </div>
    <canvas id="canvas"> </canvas>
    <div class="output">
      <img id="photo" alt="The screen capture will appear in this box." />
    </div>

  </div>
  <button id='start'>Start Camera</button>
  <script src='js/camera.js'></script>
</body>
</html>

CSS

#video {
  border: 1px solid black;
  box-shadow: 2px 2px 3px black;
  width: 320px;
  height: 240px;
}

#photo {
  border: 1px solid black;
  box-shadow: 2px 2px 3px black;
  width: 320px;
  height: 240px;
}

#canvas {
  display: none;
}

.camera {
  width: 340px;
  display: inline-block;
}

.output {
  width: 340px;
  display: inline-block;
  vertical-align: top;
}

#startbutton {
  display: block;
  position: relative;
  margin-left: auto;
  margin-right: auto;
  bottom: 32px;
  background-color: rgb(0 150 0 / 50%);
  border: 1px solid rgb(255 255 255 / 70%);
  box-shadow: 0px 0px 1px 2px rgb(0 0 0 / 20%);
  font-size: 14px;
  font-family: "Lucida Grande", "Arial", sans-serif;
  color: rgb(255 255 255 / 100%);
}

.contentarea {
  font-size: 16px;
  font-family: "Lucida Grande", "Arial", sans-serif;
  width: 760px;
}

Javascript

(() => {
  // The width and height of the captured photo. We will set the
  // width to the value defined here, but the height will be
  // calculated based on the aspect ratio of the input stream.

  const width = 320; // We will scale the photo width to this
  let height = 0; // This will be computed based on the input stream

  // |streaming| indicates whether or not we're currently streaming
  // video from the camera. Obviously, we start at false.

  let streaming = false;

  // The various HTML elements we need to configure or control. These
  // will be set by the startup() function.

  let video = null;
  let canvas = null;
  let photo = null;
  let startbutton = null;

  function showViewLiveResultButton() {
    if (window.self !== window.top) {
      // Ensure that if our document is in a frame, we get the user
      // to first open it in its own tab or window. Otherwise, it
      // won't be able to request permission for camera access.
      document.querySelector('.contentarea').remove();
      const button = document.createElement('button');
      button.textContent = 'View live result of the example code above';
      document.body.append(button);
      button.addEventListener('click', () => window.open(location.href));
      return true;
    }
    return false;
  }

  function startup() {
    if (showViewLiveResultButton()) {
      return;
    }
    video = document.getElementById('video');
    canvas = document.getElementById('canvas');
    photo = document.getElementById('photo');
    startbutton = document.getElementById('startbutton');

    navigator.mediaDevices
      .getUserMedia({ video: true, audio: false })
      .then((stream) => {
        video.srcObject = stream;
        video.play();
      })
      .catch((err) => {
        console.error(`An error occurred: ${err}`);
      });

    video.addEventListener(
      'canplay',
      (ev) => {
        if (!streaming) {
          height = video.videoHeight / (video.videoWidth / width);

          // Firefox currently has a bug where the height can't be read from
          // the video, so we will make assumptions if this happens.

          if (Number.isNaN(height)) {
            height = width / (4 / 3);
          }

          video.setAttribute('width', width);
          video.setAttribute('height', height);
          canvas.setAttribute('width', width);
          canvas.setAttribute('height', height);
          streaming = true;
        }
      },
      false,
    );

    startbutton.addEventListener(
      'click',
      (ev) => {
        takepicture();
        ev.preventDefault();
      },
      false,
    );

    clearphoto();
  }

  // Fill the photo with an indication that none has been
  // captured.

  function clearphoto() {
    const context = canvas.getContext('2d');
    context.fillStyle = '#AAA';
    context.fillRect(0, 0, canvas.width, canvas.height);

    const data = canvas.toDataURL('image/png');
    photo.setAttribute('src', data);
  }

  // Capture a photo by fetching the current contents of the video
  // and drawing it into a canvas, then converting that to a PNG
  // format data URL. By drawing it on an offscreen canvas and then
  // drawing that to the screen, we can change its size and/or apply
  // other changes before drawing it.

  function takepicture() {
    const context = canvas.getContext('2d');
    if (width && height) {
      canvas.width = width;
      canvas.height = height;
      context.drawImage(video, 0, 0, width, height);

      const data = canvas.toDataURL('image/png');
      photo.setAttribute('src', data);
    } else {
      clearphoto();
    }
  }

  // Set up our event listener to run the startup process
  // once loading is complete.
  document
    .querySelector('#start')
    .addEventListener('click', (ev) => {
      // remove the button once clicked
      ev.target.remove();
      startup();
    });
})();

It worked fine. As Thallius has pointed out, you are running the script before the dom content has loaded.

In mine I am loading the script at the bottom of the body e.g. after the page content has loaded.

An alternative is to wrap your js with an eventListener for ‘DOMContentLoaded’ e.g.

// wait for dom content to load then execute what's inside
window.addEventListener('DOMContentLoaded', () => {
  // The width and height of the captured photo. We will set the
  // width to the value defined here, but the height will be
  // calculated based on the aspect ratio of the input stream.

  const width = 320; // We will scale the photo width to this
  let height = 0; // This will be computed based on the input stream

  // ... rest of code here

  // Set up our event listener to run the startup process
  // once start button is clicked
  document
    .querySelector('#start')
    .addEventListener('click', (ev) => {
      // remove the button once clicked
      ev.target.remove();
      startup();
    });
})
1 Like

Thank you for that. I have it working and see what you did.

Do you believe that this code should work (and current) in all browsers, OS, and mobile?

Thank you again and I appreciate your efforts in making this work for me.

If I recall correctly from our other threads, you support Internet Explorer, don’t you? (or did I get that wrong)

Hi James, good to hear from you. I haven’t supported IE for probably 2 years now, even though most of my coding would work with IE. My experience with my users is that 99%, if not 100% don’t use IE.

Good to hear :slight_smile:

In that case, I cannot immediately see anything that would stop the code that @rpg_digital posted working in modern browsers.

However…

If you really want to be sure, what you need to do is check the support of each method on site like Can I Use.

Here are the results for navigator.mediaDevices:

As you can see, support is good, but outliers like QQ Browser and Baidu Browser offer no support. This is likely no big deal for you, though.

3 Likes

Thank you for that information as it’s very useful and I will use it in the future. I very much appreciate it.

Take care!

startbutton.addEventListener( ““click””, (ev) => { takepicture(); // Here the takepicture() function is called only after the button is clicked ev.preventDefault(); }, false, ); This code leaves the camera inactive until the user presses a button. Once the button is pressed, the takepicture() function will be called and the camera will work.