components/pages/Teleop.vue

<template>
  <!-- Teleop Page -->
  <b-jumbotron
    id="teleop-layout"
    :fluid="true"
    :container-fluid="true"
    class="h-100 "
    bg-variant="light">
    <!-- Row -->
    <b-row class="h-100">
      <!-- Camera column -->
      <b-col
        lg="8"
        md="7"
        sm="6"
        class="mh-100">
        <!-- Camera Container -->
        <div class="h-100 w-100 m-auto position-relative">
          <!-- Camera -->
          <video-box
            :show="showCamera"
            video-id="camera-stream" />
        </div>
      </b-col>
      <!-- Map and joystick column -->
      <b-col
        lg="4"
        md="5"
        sm="6"
        class="mh-100">
        <!-- Map row -->
        <b-row class="h-50 w-100 position-relative m-0">
          <!-- Map container -->
          <div class="h-100 w-100 m-auto position-relative">
            <!-- Map -->
            <video-box
              :show="showMap"
              video-id="map-stream" />
          </div>
        </b-row>
        <!-- Joystick Switch -->
        <div
          class="position-absolute"
          style="top:55%;right:25px;z-index:10;">
          <toggle-button
            :value="enableJoystick"
            :color="switchColor"
            :sync="true"
            :labels="true"
            :disabled="disableJoystick"
            @change="enableJoystick = $event.value" />
        </div>
        <!-- Joystick Row -->
        <b-row
          id="joystick-row"
          class="position-relative h-50 m-auto p-4">
          <!-- Joystick Outer -->
          <div
            class="position-relative m-auto"
            :style="joystickStyle">
            <!-- Joystick Inner-->
            <div
              class="position-absolute h-100 w-100 border
              border-secondary rounded-circle shadow-sb"
              style="top:0;left:0;">
              <!-- Joystick -->
              <joystick
                :enable="enableJoystick"
                :absolute-max-x="1"
                :absolute-max-y="1"
                :bus="bus" />
            </div>
          </div>
        </b-row>
      </b-col>
    </b-row>
  </b-jumbotron>
</template>


<script>
/**
 * Component used as a page for teleoperation of the robot. It manages the layout of
 * its components and communicate with its parent component through a bus given in props. The
 * components used in this page are 2 VideoBox and 1 Joystick. This component have the following
 * dependency : VideoBox.vue Component, Joystick.vue Component and Bootstrap-Vue for styling.
 *
 *
 * @module Teleop
 * @vue-prop {Vue} bus - Vue bus use to emit event to other components.
 * @vue-prop {Vue} Router - Vue bus use to routing emit event to parent.
 * @vue-event {} destroyed - Event indicating the component has been destroyed.
 * @vue-event {} mounted - Event indicating the component has been mounted.
 * @vue-data {boolean} showCamera - Enable or disable the camera display.
 * @vue-data {boolean} showMap - Enable or disable the map display.
 * @vue-data {boolean} enableJoystick - Enable or disable the joystick ability to send data.
 */

/** Disabled comment documentation
 * Might use those eventually by forking jsdoc-vue-js so it can manage the author
 * and version tag correctly
 * @author Edouard Legare <edouard.legare@usherbrooke.ca>
 * @version 1.0.0
 */

import { ToggleButton } from 'vue-js-toggle-button';
import Vue from 'vue';

import VideoBox from '../widget/VideoBox';
import Joystick from '../widget/Joystick';

export default {
  name: 'teleop-page',
  components: {
    VideoBox,
    Joystick,
    ToggleButton,
  },
  props: {
    bus: {
      type: Vue,
      required: true,
    },
    router: {
      type: Vue,
      required: true,
    },
  },
  data() {
    return {
      showCamera: true,
      showMap: true,
      enableJoystick: false,
      disableJoystick: true,
      joystickStyle: {
        width: '100%',
        'padding-top': '100%',
        height: 0,
      },
      switchColor: {
        checked: '#00A759',
        unchecked: '#808080',
        disabled: '#E8E8E8',
      },
    };
  },
  /**
   * Lifecycle Hook - mounted
   *
   * @method
   * @listens mount(el)
   */
  mounted() {
    console.log('Teleop have been mounted');
    this.bus.$on('on-joystick-state-changed', this.changeJoystickState);
    this.router.$emit('mounted');

    this.$nextTick(() => {
      window.addEventListener('resize', this.setJoystickStyle);
    });

    this.setJoystickStyle();
  },
  /**
   * Lifecycle Hook - destroyed
   *
   * @method
   * @listens destroyed(el)
   */
  destroyed() {
    console.log('Teleop have been destroyed');
    this.router.$emit('destroyed');

    window.removeEventListener('resize', this.setJoystickStyle);
  },
  methods: {
    /**
     * Callback used to change the state of the joystick
     * @method
     * @param {boolean} state - Request of the joystick state
     * @listens on-joystick-state-changed
     */
    changeJoystickState(state) {
      if (state === 'enable') {
        this.disableJoystick = false;
      } else {
        this.enableJoystick = false;
        this.disableJoystick = true;
      }
    },
    setJoystickStyle() {
      let ratio = 1;
      const e = document.getElementById('joystick-row');
      if (e) {
        ratio = ((e.clientHeight / e.clientWidth) < 1)
          ? `${(((e.clientHeight / e.clientWidth) * 100) - 5)}%` : '95%';
        this.joystickStyle = {
          width: ratio,
          'padding-top': ratio,
          height: 0,

        };
      }
    },
  },
};
</script>

<style>
</style>