# How to Use a Web API

This tutorial explains how to use the [MediaDevices API ](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices)to capture pictures using the device camera in a sample application.

## Electron TODO app

### Creating the app

First of all, let's create the application with a Monaca template. From the Monaca dashboard, go to **Create New Project → Sample Applications**. Then choose **Electron TODO App** from the template list, fill in the `Project Name` and `Description` and click **Create Project**.

<div align="center"><img src="https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MgErdSqJo4WJT2K32M0%2F-MgF8hIbQP7ceOylGCkN%2Fimage.png?alt=media&#x26;token=fee6a00c-32b9-4828-a9cf-1550f0b94deb" alt=""></div>

### Application features

This sample application allows users to create and manage a to do list. The user can add pictures by uploading an existing picture or taking a picture. The list is saved in the local storage.

{% hint style="info" %}
This tutorial focuses on explaining how we use the MediaCapture API to take pictures using the built-in camera.
{% endhint %}

Once you open the application, it displays the items saved in the local storage.

![Application dashboard](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MgF8y1WcGExhEwDH9c9%2F-MgIkA0pcLHykwguITrh%2Fimage.png?alt=media\&token=e4c87c4a-6467-4e5c-8957-77d5888f97af)

To create a new item, click the **+ new** button on the top right corner of the screen. A new modal dialog will open. You can input a description to the text field and upload an existing picture with the :frame\_photo: button or take a new picture by clicking the :camera: button.

![Add a new item](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MgF8y1WcGExhEwDH9c9%2F-MgIkIY-GFZAOzfga75n%2Fimage.png?alt=media\&token=32af91ca-b47c-489b-b834-7d261853b3ba)

Once the :camera: button is clicked, another modal dialog with the camera view opens. If you press `capture`, it will capture a photo and save it.

![ Taking a picture using the laptop camera](https://3091308003-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-MfWe1U2tFctp8FkP9W8%2F-MgF8y1WcGExhEwDH9c9%2F-MgIkQBWPZANQEDMpQDO%2Fimage.png?alt=media\&token=b1ce304d-268b-4520-ae80-3871ae3ee7c1)

## HTML explanation

### Camera modal

The following code snippet is the camera modal. This modal opens when the `camera` button is clicked. It has 3 buttons - `rotate`, `capture` , and `cancel`. The `rotate` button is only visible if the device supports flipping between the `front` and `rear` cameras. The `video-container` element is used to stream pictures from the built-in camera.

```markup
<div class="modal fade" id="camera-modal" tabindex="-1" data-backdrop="static" role="dialog" aria-labelledby="camera-modal-label" aria-hidden="true">
    <div class="modal-dialog modal-dialog-centered" role="document">
        <div class="modal-content">
            <div class="camera-header-modal"></div>
            <div class="camera-modal-body modal-body text-center">
                <video id="video-container" class="camera-preview" autoplay></video>
            </div>
            <a id="cordova-camera-cancel" class="btn enabled camera-close-btn" data-dismiss="modal"><i class="fa fa-times"></i> cancel</a>
            <a id="rotate-camera" class="btn enabled camera-rotate-btn"><i class="fa fa-sync"></i> Rotate</a>
            <a id="camera-capture" class="btn enabled camera-capture-btn" data-dismiss="modal"><i class="fa fa-camera"></i> Capture</a>
        </div>
    </div>
</div>
```

## JavaScript explanation

### Global variable declaration

Let's go quickly through some of the most important variables used in the camera feature:

* `isFrontCamera` is used to toggle between front and rear camera.
* `FRONT_CAMERA` is used to store the front camera value of the mediaDevices API’s [facingModeEnum.](https://w3c.github.io/mediacapture-main/#dom-videofacingmodeenum)
* `REAR_CAMERA` is used to store the rear camera value of the mediaDevices API’s facingModeEnum.

```javascript
let isFrontCamera;
const FRONT_CAMERA = 'user';
const REAR_CAMERA = 'environment';
const videoContainer = document.getElementById('video-container');
const btnOpenCameraModal = document.getElementById('open-camera-modal');
const btnRotateCamera = document.getElementById('rotate-camera');
...
```

### Checking if the mediaDevices API is supported

The following code snippet is to check whether the mediaDevices API is supported and to display the `rotate` button if the device is Android and use the `rear` camera as default.

```javascript
function initialize() {
  // Check if getUserMedia is supported on the device
  if (!hasMediaDevicesApi()) {
    btnOpenCameraModal.hidden = true;
  }
  if (isAndroidOS()) {
    // use rear camera for android
    btnRotateCamera.hidden = false;
    isFrontCamera = false;
  } else {
    // use front camera for browser/electron
    btnRotateCamera.hidden = true;
    isFrontCamera = true;
  }
  ...
}

function hasMediaDevicesApi() {
  return !!(navigator.mediaDevices &&
    navigator.mediaDevices.getUserMedia);
}
```

### Turning the camera on/off

We will use the function `getUserMedia()` to ask the user for the permission to use the media input that forms the `MediaStream`. The stream can contain video (such as camera, video recording device, screen sharing service, etc), audio, or other media. For more details, please refer to the [official document](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices). The syntax is as following:

```javascript
var promise = navigator.mediaDevices.getUserMedia(constraints);
```

The function returns a [promise ](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)and accepts a [MediaStreamConstraints ](https://developer.mozilla.org/en-US/docs/Web/API/MediaStreamConstraints)object as a parameter.

In the following code snippet, we specify the width and height of the `video` element to be exactly `250` pixels and set the camera facing mode based on the provided argument. Once the camera device is connected, the [Media Stream](https://developer.mozilla.org/en-US/docs/Web/API/MediaStream) object is returned and assigned to the `video` element.

```javascript
function turnOnCamera(frontCamera) {
  const facingModeOption = frontCamera ? FRONT_CAMERA : REAR_CAMERA;
  const constraints = {
    video: {
      width: {
        exact: 250
      },
      height: {
        exact: 250
      },
      facingMode: facingModeOption
    }
  };
  // Access to the camera and turn it own
  navigator.mediaDevices.getUserMedia(constraints)
    .then(handleSuccess)
    .catch(handleError);

  function handleSuccess(stream) {
    videoContainer.srcObject = stream;
  }

  function handleError(error) {
    alert('Could not get user media API' + JSON.stringify(error));
  }
}
```

To turn off the camera, we need to stop all the sources associated with the video stream.

```javascript
function turnOfCamera() {
  if (videoContainer && videoContainer.srcObject) {
    videoContainer.srcObject.getTracks().forEach(function(track) {
      track.stop();
    });
    videoContainer.srcObject = null;
  }
}
```

The function below flips the camera between the front and rear view.

```javascript
function rotateCamera(e) {
  isFrontCamera = !isFrontCamera;
  turnOfCamera();
  turnOnCamera(isFrontCamera);
}
```

### Capturing a photo

To capture a photo of the video stream, we first create a `canvas` element whose width and height are the same as the `video` element. Then, we stop the stream and convert the last capture of it to image format.

```javascript
function takePicture(e) {
  const canvas = document.createElement('canvas');
  // Saving current image
  canvas.width = videoContainer.videoWidth;
  canvas.height = videoContainer.videoHeight;
  canvas.getContext('2d').drawImage(videoContainer, 0, 0);
  // If the video source Object is set, stop all tracks
  if (videoContainer.srcObject) {
    videoContainer.srcObject.getTracks().forEach(function(track) {
      track.stop();
      try {
        // Other browsers will fall back to image/png
        todoItemImage.src = canvas.toDataURL('image/webp');
      } catch (error) {
        alert('Could not get the picture.' + JSON.stringify(error));
      }
    });
  }
}
```

See Also:

* [Building for Electron](https://en.docs.monaca.io/products_guide/monaca_ide/build/electron)
