DEV Community

Dita Rahma P.
Dita Rahma P.

Posted on

Make a Camera App in Web (Part 1): Accessing the webcam

Last year I have a project that requires me to access device webcam using JavaScript. Since I can't find any good webcam library on Github that builds with Vue, then I decide to try to make it with JavaScript getUserMedia().

The problem with this method is, Internet Explorer doesn't support this, and in Safari, the compatibility is still unknown, both on mobile and desktop. It may be okay for IE because what on earth people still using that slow-problematic browser? But Safari is used by so many people and it may be a problem if you are a good developer who wants the best for the users. Well, it doesn't mean that I am a bad developer (or maybe I am!) for still using it despite the unknown compatibility with Safari. It just that we really need this feature back then. And maybe you are too.

So here it is, the low-key webcam feature that I build past year. You can open it directly on CodePen to run it to prevent any error message.

Before we get started, in the CodePen above I use Vue.js and Bulma for the styling.

The first thing that we want is a button. This button will act as a toggle to open and close the camera div also to turn it on/off so your camera won't active all the time (for the sake of privacy).

<div class="camera-button">
  <button type="button" class="button is-rounded" :class="{ 'is-primary' : !isCameraOpen, 'is-danger' : isCameraOpen}" @click="toggleCamera">
    <span v-if="!isCameraOpen">Open Camera</span>
    <span v-else>Close Camera</span>
  </button>
</div>
Enter fullscreen mode Exit fullscreen mode

I put the class condition there. is-primary is active when the camera is closed, and is-danger gonna replace is-primary when the camera is open. These classes are not only to give the button some colors but also to better describe what the button does. And now, take a look at the JavaScript.

data() {
  return {
    isCameraOpen: false
  }
},

methods: {
  toggleCamera() {
    this.isCameraOpen = !this.isCameraOpen;
  }
}
Enter fullscreen mode Exit fullscreen mode

The toggleCamera() would act as a switch to change isCameraOpen condition. The default value of isCameraOpen is false, and when the true value assigned through the button click, which gonna call toggleCamera(), the webcam will be activated.

Then we need a box which will display the camera. We're going to add <video></video> as a streaming media which will show up when isCameraOpen is true.

<div v-if="isCameraOpen" class="camera-box">  
  <video ref="camera" :width="450" :height="337.5" autoplay></video>
</div>
Enter fullscreen mode Exit fullscreen mode

A little warning here, on the mobile web, the camera would appear vertically, unlike in desktop. So you might want to tweak the width and height a little bit if you want it to be seamlessly responsive.

And then the most important part; creating a method that initiates media input permission which produces a MediaStream with tracks containing the requested types of media.

createCameraElement() {
  const constraints = (window.constraints = {
    audio: false,
    video: true
  });


  navigator.mediaDevices
    .getUserMedia(constraints)
    .then(stream => {
      this.$refs.camera.srcObject = stream;
    })
    .catch(error => {
      alert("May the browser didn't support or there is some errors.");
  });
}
Enter fullscreen mode Exit fullscreen mode

constraints is a parameter describing the media types requested. Since we just want a camera that can only capture an image and not video streaming, so we just going to set the audio permission to false.

Then we call the mediaDevices.getUserMedia with the constraints as a parameter. From this call, we received a stream that going to be assigned to the <video></video> element we created before.

Inside constraints parameter, you also can specify where the camera is facing (you may want to use the back-facing camera on mobile). To require the rear camera, you can put this instead

const constraints = (window.constraints = {
  audio: false,
  video: {
    facingMode: {
      exact: "environment"
    }
  }
});
Enter fullscreen mode Exit fullscreen mode

We're going to call that method when the user clicks the open button. But since the open and close button is the same, we're going to prevent it to be called when the user clicks the close button. So we also have to modify the toggleCamera() a little bit like this.

toggleCamera() {
  if(this.isCameraOpen) {
    this.isCameraOpen = false;
  } else {
    this.isCameraOpen = true;
    this.createCameraElement();
  }
}
Enter fullscreen mode Exit fullscreen mode

There is still a problem though. We already managed to open the camera, and when we close it, it doesn't call the createCameraElement() again. But, the camera indicator on your laptop is still on! That makes the close button didn't do anything except just "hiding" the camera div. What we're going to do next is to really stop the camera from streaming.

stopCameraStream() {
  let tracks = this.$refs.camera.srcObject.getTracks();

  tracks.forEach(track => {
    track.stop();
  });
}
Enter fullscreen mode Exit fullscreen mode

The method above is going to catch the tracks on the camera element and then stop it. To make it works, let's put it into the close button.

toggleCamera() {
  if(this.isCameraOpen) {
    this.isCameraOpen = false;
    this.stopCameraStream();
  } else {
    this.isCameraOpen = true;
    this.createCameraElement();
  }
}
Enter fullscreen mode Exit fullscreen mode

That's it! We successfully access the webcam and put the stream inside an HTML tag. The next step is we want to capture the stream and download it as an image. But I'm going to make it in part two of this article.

Top comments (6)

Collapse
 
shahrozahmd profile image
Shahroz Ahmed

Did u use vue?

Collapse
 
ditarahma08 profile image
Dita Rahma P. • Edited

Yes

Collapse
 
shahrozahmd profile image
Shahroz Ahmed

okay. Thank You

Collapse
 
dcruz1990 profile image
Dennis Quesada Cruz

What about a input element instead of a video, how to close it? im just taking photos but i want to shut down camera after component gets unmounted.

Collapse
 
pieterjanse profile image
Pieter Janse

When i take a photo the quality is very bad and the foto get stretched is there any option to give the photo size or something like that?

Collapse
 
ditarahma08 profile image
Dita Rahma P.

I think the photo quality produced is depending on the device camera quality itself. Desktop camera tends to have low quality, try to check in on mobile. And make sure to provide the canvas size the exact same as the video size, also put the same size when calls drawImage function so it doesn't stretched (it's on the chapter two).