Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Saturday, July 9, 2022

How to call parent window function from child window in javascript

In this tutorial, we will learn how to call the parent window function from the child window in javascript.

In some cases, we need to open the child browser window as a modal or dialog. For example, if need to handle and load the redirect URL in a single-page application.

While using third-party services providers for e.g PayPal we are supposed to get the redirect URL to load the payment page for security reasons. In this case, we will load that redirect URL in the child window as a modal and the user will proceed with the payment securely. Once the payment is done we need to notify the parent window or our single-page application that the payment got succeeded or pass some token. In this case, we need to call the parent window function from the child window.

Let's look into the example, where we are passing token from the child window to the parent function.

Here, while opening the child window we will register the function in the document interface that represents any web page loaded in the browser and serves as an entry point into the web page's content

document.responseToken = function (token){
          // manuplate the token
        }

Now let's add the calling function from the child window.

window.opener.document.responseToken(token);
        window.close();

Here, we are using window.opener The Window interface's opener property returns a reference to the window that opened the window i.e parent window. So we can get the responseToken function that we registered previously. This will pass the token to the reference or parent window. After that window.close() will close the child dialog window.

Share:

Thursday, January 13, 2022

How to use share functionality using web share API in VueJs application

In this tutorial, we are going to implement the web share functionality using Web Share API.

Web Share API is not supported for all browsers. We can see the supported browser for this API from caniuse.


Please follow the tutorial for sharing on social media platforms.

The Web Share API provides a mechanism for sharing links, text, files, and other content utilizing the sharing mechanisms of the underlying operating system. Note that this API only can be used over the secure connection HTTPS.

Sharing Links and Text Description

Let's create a sample vue component called Share.vue and add the following HTML inside the template which contains a simple button to allow users for sharing.

<div class="share" v-if="isSupported">
    <button class="button" @click="webShare">Share</button>
</div>
.button {
  background-color: #4CAF50;
  border: none;
  color: white;
  padding: 15px 32px;
  text-align: center;
  text-decoration: none;
  display: inline-block;
  font-size: 16px;
  margin: 4px 2px;
  cursor: pointer;
}

Here, if the browser supports the API, we are rendering the share button to allow the user to share. If not then we are hiding the button. Now, let's add the data and method used

created() {
    this.isSupport();
  },
  data () {
    return {
      isSupported : false,
      url : "https://caniuse.com/web-share",
      title:"Web API Share",
      description: "Web API Sharing"
    }
  },
  methods: {
    isSupport() {
      if (navigator.share) {
        this.isSupported = true;
      }
    },
    webShare() {
      let self = this;
      navigator.share({
        title: self.title,
        text: self.description,
        url: self.url
      })
    }
  }
}

webShare function allows the user to share link and title and description on different applications of OS.

Sharing Files

webShare() {
      let self = this;
      fetch("file_url").then(function (response) {
        return response.blob()
      }).then(function (blob) {
        let file = new File([blob], "picture.jpg", {type: 'image/jpeg'});
        let filesArray = [file];
        if (navigator.canShare && navigator.canShare({files: filesArray})) {
          navigator.share({
            title: self.title,
            text: self.description,
            files: filesArray,
            url: self.url
          });
        }
      });
    }

If we want to share the file, first load the file and test whether the file can be sharable or not, if it is sharable then it will be shared over the available supported application of OS.

The overall implementation looks as below:

<template>
    <div class="share" v-if="isSupported">
        <button class="button" @click="webShare">Share</button>
    </div>
</template>

<script>
    export default {
        name: "Share",
        created() {
            this.isSupport();
        },
        data () {
            return {
                isSupported : false,
                url : "https://www.360learntocode.com/2022/01/how-to-implement-social-media-share.html",
                title:"Web API Share",
                description: "Web API Sharing"
            }
        },
        methods: {
            isSupport() {
                if (navigator.share) {
                    this.isSupported = true;
                }
            },
            webShare() {
                let self = this;
                navigator.share({
                    title: self.title,
                    text: self.description,
                    url: self.url
                })
            }
        }
    }
</script>

<style scoped>
    .button {
        background-color: #4CAF50;
        border: none;
        color: white;
        padding: 15px 32px;
        text-align: center;
        text-decoration: none;
        display: inline-block;
        font-size: 16px;
        margin: 4px 2px;
        cursor: pointer;
    }
</style>
Share:

Sunday, January 9, 2022

Create UTC count down timer in VueJs

In this tutorial, we are going to learn how to create a UTC countdown timer in VueJs. We are UTC time to manipulate the countdown timer so that every user from different locations can see the same countdown.

Let's create a component called CountDownTimer.vue

Now, let's add some HTML and CSS for the countdown timer in the template.

<div v-if="displayCountDown">
    <h2 class="text-animation" v-if="isLive">Sale is now LIVE</h2>
    <div v-else>
        <h2 class="text-animation">Sale starts in:</h2>
        <section>
            <section class="timer">
                <div>
                    <section>
                        <p>{{ days }}</p>
                        <p>
                            <small>Days</small>
                        </p>
                    </section>
                    <span>:</span>
                    <section>
                        <p>{{ hours }}</p>
                        <p>
                            <small>Hours</small>
                        </p>
                    </section>
                    <span>:</span>
                    <section>
                        <p>{{ minutes }}</p>
                        <p>
                            <small>Minutes</small>
                        </p>
                    </section>
                    <span>:</span>
                    <section>
                        <p>{{ seconds }}</p>
                        <p>
                            <small>Seconds</small>
                        </p>
                    </section>
                </div>
            </section>
        </section>
    </div>
</div>
<style scoped>
    .timer {
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .timer div:first-child {
        border: 1px solid white;
        border-radius: 3px;
        display: grid;
        grid-template-columns: repeat(7, 1fr);
        text-align: center;
        margin-bottom: 1em;
        padding: 1em 1em 0 1em;
    }

    section p:first-child,
    .timer div:last-child span {
        display: contents;
    }

    @media screen and (max-width: 480px) {
        .timer div:last-child {
            margin-left: 2em;
            margin-right: 2em;
        }
    }

    .text-animation {
        animation: color-change 5s infinite;
        font-weight: 400;
    }

    @keyframes color-change {
        0% {
            color: #00FFA3;
        }
        25% {
            color: yellow;
        }
        50% {
            color: #DC1FFF;
        }
        75% {
            color: #F1A945;
        }
        100% {
            color: #00FFA3;
        }
    }
</style>

Add the data used inside the template

data() {
    return {
      days: 0,
      hours: 0,
      minutes: 0,
      seconds: 0,
      isLive: false,
      displayCountDown: false
    }
  },

Create a function called startTimer where we are going to add the timmer logic.

methods: {
    startTimer() {
      const countdownDate = new Date("January 11, 2022 7:59:00").getTime(); // always use UTC time
      let self = this;
      let interval = setInterval(() => {
        const now = new Date();
        let nowUTC = new Date(
            now.getUTCFullYear(),
            now.getUTCMonth(),
            now.getUTCDate(),
            now.getUTCHours(),
            now.getUTCMinutes(),
            now.getUTCSeconds()
        ).getTime();
        const distance = countdownDate - nowUTC;
        const days = Math.floor(distance / (1000 * 60 * 60 * 24));
        const hours = Math.floor(
            (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
        );
        const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
        const seconds = Math.floor((distance % (1000 * 60)) / 1000);
        if (distance <= 0) {
          self.isLive = true;
          clearInterval(interval);
        } else {
          self.days = days;
          self.hours = hours;
          self.minutes = minutes;
          self.seconds = seconds;
        }
        self.displayCountDown = true;
      }, 1000);
    }
  }

Here, first, create the UTC time when the action will happen i.e for e.g the time when the sale starts. Make sure that the time needs to be UTC time.

const countdownDate = new Date("January 11, 2022 7:59:00").getTime(); // always use UTC time

After that, we are using setInterval() method which repeatedly calls a function or executes a code snippet inside it, with a fixed time delay between each call.

Note there we are using 1000 ms time so that the countdown will refresh in every second.

Let's look into the below code

 const now = new Date();
        let nowUTC = new Date(
            now.getUTCFullYear(),
            now.getUTCMonth(),
            now.getUTCDate(),
            now.getUTCHours(),
            now.getUTCMinutes(),
            now.getUTCSeconds()
        ).getTime();

We are getting the current data which gives the current location browser data. We have to convert this to UTC current date. So the user from a different location can see the same countdown

After that, we are calculating distance which will show the countdown is expired or not and days, hours, minutes, and seconds.

If the countdown is expired then we are clearing the setInterval and hiding the countdown and showing some desired text

Start the countdown timer. For this, simply call the startTimer function from created hook.

created() {
    this.startTimer();
  },

The demo output for this example looks like below:


The overall code implementation looks as below:

<template>
    <div v-if="displayCountDown">
        <h2 class="text-animation" v-if="isLive">Sale is now LIVE</h2>
        <div v-else>
            <h2 class="text-animation">Sale starts in:</h2>
            <section>
                <section class="timer">
                    <div>
                        <section>
                            <p>{{ days }}</p>
                            <p>
                                <small>Days</small>
                            </p>
                        </section>
                        <span>:</span>
                        <section>
                            <p>{{ hours }}</p>
                            <p>
                                <small>Hours</small>
                            </p>
                        </section>
                        <span>:</span>
                        <section>
                            <p>{{ minutes }}</p>
                            <p>
                                <small>Minutes</small>
                            </p>
                        </section>
                        <span>:</span>
                        <section>
                            <p>{{ seconds }}</p>
                            <p>
                                <small>Seconds</small>
                            </p>
                        </section>
                    </div>
                </section>
            </section>
        </div>
    </div>
</template>

<script>
    export default {
        name: "CountDownTimer",
        created() {
            this.startTimer();
        },
        data() {
            return {
                days: 0,
                hours: 0,
                minutes: 0,
                seconds: 0,
                isLive: false,
                displayCountDown: false
            }
        },
        methods: {
            startTimer() {
                const countdownDate = new Date("January 11, 2022 7:59:00").getTime();
                let self = this;
                let interval = setInterval(() => {
                    const now = new Date();
                    let nowUTC = new Date(
                        now.getUTCFullYear(),
                        now.getUTCMonth(),
                        now.getUTCDate(),
                        now.getUTCHours(),
                        now.getUTCMinutes(),
                        now.getUTCSeconds()
                    ).getTime();
                    const distance = countdownDate - nowUTC;
                    const days = Math.floor(distance / (1000 * 60 * 60 * 24));
                    const hours = Math.floor(
                        (distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60)
                    );
                    const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
                    const seconds = Math.floor((distance % (1000 * 60)) / 1000);
                    if (distance <= 0) {
                        self.isLive = true;
                        clearInterval(interval);
                    } else {
                        self.days = days;
                        self.hours = hours;
                        self.minutes = minutes;
                        self.seconds = seconds;
                    }
                    self.displayCountDown = true;
                }, 1000);
            }
        }
    }
</script>

<style scoped>
    .timer {
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .timer div:first-child {
        border: 1px solid white;
        border-radius: 3px;
        display: grid;
        grid-template-columns: repeat(7, 1fr);
        text-align: center;
        margin-bottom: 1em;
        padding: 1em 1em 0 1em;
    }

    section p:first-child,
    .timer div:last-child span {
        display: contents;
    }

    @media screen and (max-width: 480px) {
        .timer div:last-child {
            margin-left: 2em;
            margin-right: 2em;
        }
    }

    .text-animation {
        animation: color-change 5s infinite;
        font-weight: 400;
    }

    @keyframes color-change {
        0% {
            color: #00FFA3;
        }
        25% {
            color: yellow;
        }
        50% {
            color: #DC1FFF;
        }
        75% {
            color: #F1A945;
        }
        100% {
            color: #00FFA3;
        }
    }
</style>
Share:

Friday, December 11, 2020

How to Implement Webcam in VueJs Application

In this tutorial, we are going to implement a webcam in the Vuejs application.


Generally, what it does is:

  1. Stream the video from the webcam
  2. Capture photo from the streaming video
  3. Preview the captured photo
  4. Convert it into the file to send to the server
The overall implementation looks as below:




1. Create a sample Vuejs application.

Open the terminal or command prompt and create the application.

vue create vue-camera
  

Select the default option or can select manually, where you can have a choice to set up.
cd vue-camera
yarn serve

2. Create a Vuejs webcam component



Now, let's create a component called Camera.vue.  
<div class="camera-box">
    <div style="display: flex; justify-content: center;">
        <img style="height: 25px;" v-if="isCameraOpen"
             src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"
             class="button-img camera-shoot" @click="capture"/>
        <div class="camera-button">
            <button type="button" class="button is-rounded cam-button"
                    style="margin-left: 40%; background-color: white; border: 0px;"
                    @click="toggleCamera"
            >
        <span v-if="!isCameraOpen"><img style="height: 25px;" class="button-img"
                                        src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"></span>
                <span v-else><img style="height: 25px;" class="button-img"
                                  src="https://img.icons8.com/material-outlined/50/000000/cancel.png"></span>
            </button>
        </div>
    </div>
    <div style="height: 200px">
        <div v-if="isCameraOpen" class="camera-canvas">
            <video ref="camera" :width="canvasWidth" :height="canvasHeight" autoplay></video>
            <canvas v-show="false" id="photoTaken" ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
        </div>
    </div>
</div>
Let's set the data used.
export default {
  name: "Camera",
  components: {
  },
  data() {
    return {
      isCameraOpen: false,
      canvasHeight:200,
      canvasWidth:190,
      items: [],
    }
  },
  }
<style scoped>
.camera-box {
  border: 1px dashed #d6d6d6;
  border-radius: 4px;
  padding: 2px;
  width: 80%;
  min-height: 300px;
}

</style>





The HTML file used will show the camera image button to capture the photo. Here, we are using canvas height and width for the photo size. You can always adjust the different size photo by adjusting canvas height and width.

Let's use the different functions used in HTML.
toggleCamera() {
      if (this.isCameraOpen) {
        this.isCameraOpen = false;
        this.stopCameraStream();
      } else {
        this.isCameraOpen = true;
        this.startCameraStream();
      }
    },
This function simply toggles the camera to capture the photo. And start streaming the video. Let's implement the function used inside this toggleCamer().
startCameraStream() {
      const constraints = (window.constraints = {
        audio: false,
        video: true
      });
      navigator.mediaDevices
          .getUserMedia(constraints)
          .then(stream => {
            this.$refs.camera.srcObject = stream;
          }).catch(error => {
        alert("Browser doesn't support or there is some errors." + error);
      });
    },
The above function will start the camera by using the navigator mediaDevices interface which will access to the connected media input device, in our case its camera. And asign the streaming to canvas dom element to show the video. Here we are setting the constraints as audio is false because we don't need the audio to capture the photo.
stopCameraStream() {
      let tracks = this.$refs.camera.srcObject.getTracks();
      tracks.forEach(track => {
        track.stop();
      });
    },
The above function will simply stop the camera by stopping the sequence of track in streaming.
capture() {
      const FLASH_TIMEOUT = 50;
      let self = this;
      setTimeout(() => {
        const context = self.$refs.canvas.getContext('2d');
        context.drawImage(self.$refs.camera, 0, 0, self.canvasWidth, self.canvasHeight);
        const dataUrl = self.$refs.canvas.toDataURL("image/jpeg")
            .replace("image/jpeg", "image/octet-stream");
        self.addToPhotoGallery(dataUrl);
        self.uploadPhoto(dataUrl);
        self.isCameraOpen = false;
        self.stopCameraStream();
      }, FLASH_TIMEOUT);
    },
When a user clicks the camera button, then it will take the video streaming dom context and captured the 2d photo with the given width and height. We are using the setTimeout because video streaming will take some time to stream.




Let's implement the self.addToPhotoGallery() used in the above function. This is to preview the captured photo. For this, we are using the "vue-picture-swipe" library. So first let's add this to our application.

For yarn package manager:

yarn add vue-picture-swipe

For npm package manager:

npm install --save vue-picture-swipe

Import the library in our application:

import VuePictureSwipe from 'vue-picture-swipe';
Register the component:

components: {
    VuePictureSwipe
  },
Use in the template:

<vue-picture-swipe :items="items"></vue-picture-swipe>

addToPhotoGallery(dataURI) {
      this.items.push(
          {
            src: dataURI,
            thumbnail: dataURI,
            w: this.canvasWidth,
            h: this.canvasHeight,
            alt: '' // optional alt attribute for thumbnail image
          }
      )
    },
This will preview the captured pictures.

Finally, using self.uploadPhoto() we can upload the captured picture to the server.

uploadPhoto(dataURL){
      let uniquePictureName = this.generateCapturePhotoName();
      let capturedPhotoFile = this.dataURLtoFile(dataURL, uniquePictureName+'.jpg')
      let formData = new FormData()
      formData.append('file', capturedPhotoFile)
      // Upload api
      // axios.post('http://your-url-upload', formData).then(response => {
      //   console.log(response)
      // })
    },
    generateCapturePhotoName(){
      return  Math.random().toString(36).substring(2, 15)
    },
    dataURLtoFile(dataURL, filename) {
      let arr = dataURL.split(','),
          mime = arr[0].match(/:(.*?);/)[1],
          bstr = atob(arr[1]),
          n = bstr.length,
          u8arr = new Uint8Array(n);

      while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
      }
      return new File([u8arr], filename, {type: mime});
    },




generateCapturePhotoName() will generate the unique name for each captured picture, and to send to the server, first we are converting the dataUrl value to file using dataURLtoFile()

The overall implementation of the component Camera.vue looks like as below:

<template>
    <div class="camera-box">
        <div style="display: flex; justify-content: center;">
            <img style="height: 25px;" v-if="isCameraOpen"
                 src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"
                 class="button-img camera-shoot" @click="capture"/>
            <div class="camera-button">
                <button type="button" class="button is-rounded cam-button"
                        style="margin-left: 40%; background-color: white; border: 0px;"
                        @click="toggleCamera"
                >
        <span v-if="!isCameraOpen"><img style="height: 25px;" class="button-img"
                                        src="https://img.icons8.com/material-outlined/50/000000/camera--v2.png"></span>
                    <span v-else><img style="height: 25px;" class="button-img"
                                      src="https://img.icons8.com/material-outlined/50/000000/cancel.png"></span>
                </button>
            </div>
        </div>
        <div style="height: 200px">
            <div v-if="isCameraOpen" class="camera-canvas">
                <video ref="camera" :width="canvasWidth" :height="canvasHeight" autoplay></video>
                <canvas v-show="false" id="photoTaken" ref="canvas" :width="canvasWidth" :height="canvasHeight"></canvas>
            </div>
        </div>
        <vue-picture-swipe :items="items"></vue-picture-swipe>
    </div>
</template>

<script>
    import VuePictureSwipe from 'vue-picture-swipe';

    export default {
        name: "Camera",
        components: {
            VuePictureSwipe
        },
        data() {
            return {
                isCameraOpen: false,
                canvasHeight:200,
                canvasWidth:190,
                items: [],
            }
        },
        methods: {
            toggleCamera() {
                if (this.isCameraOpen) {
                    this.isCameraOpen = false;
                    this.stopCameraStream();
                } else {
                    this.isCameraOpen = true;
                    this.startCameraStream();
                }
            },
            startCameraStream() {
                const constraints = (window.constraints = {
                    audio: false,
                    video: true
                });
                navigator.mediaDevices
                    .getUserMedia(constraints)
                    .then(stream => {
                        this.$refs.camera.srcObject = stream;
                    }).catch(error => {
                    alert("Browser doesn't support or there is some errors." + error);
                });
            },

            stopCameraStream() {
                let tracks = this.$refs.camera.srcObject.getTracks();
                tracks.forEach(track => {
                    track.stop();
                });
            },

            capture() {
                const FLASH_TIMEOUT = 50;
                let self = this;
                setTimeout(() => {
                    const context = self.$refs.canvas.getContext('2d');
                    context.drawImage(self.$refs.camera, 0, 0, self.canvasWidth, self.canvasHeight);
                    const dataUrl = self.$refs.canvas.toDataURL("image/jpeg")
                        .replace("image/jpeg", "image/octet-stream");
                    self.addToPhotoGallery(dataUrl);
                    self.uploadPhoto(dataUrl);
                    self.isCameraOpen = false;
                    self.stopCameraStream();
                }, FLASH_TIMEOUT);
            },

            addToPhotoGallery(dataURI) {
                this.items.push(
                    {
                        src: dataURI,
                        thumbnail: dataURI,
                        w: this.canvasWidth,
                        h: this.canvasHeight,
                        alt: 'some numbers on a grey background' // optional alt attribute for thumbnail image
                    }
                )
            },
            uploadPhoto(dataURL){
                let uniquePictureName = this.generateCapturePhotoName();
                let capturedPhotoFile = this.dataURLtoFile(dataURL, uniquePictureName+'.jpg')
                let formData = new FormData()
                formData.append('file', capturedPhotoFile)
                // Upload image api
                // axios.post('http://your-url-upload', formData).then(response => {
                //   console.log(response)
                // })
            },

            generateCapturePhotoName(){
                return  Math.random().toString(36).substring(2, 15)
            },

            dataURLtoFile(dataURL, filename) {
                let arr = dataURL.split(','),
                    mime = arr[0].match(/:(.*?);/)[1],
                    bstr = atob(arr[1]),
                    n = bstr.length,
                    u8arr = new Uint8Array(n);

                while (n--) {
                    u8arr[n] = bstr.charCodeAt(n);
                }
                return new File([u8arr], filename, {type: mime});
            },
        }
    }
</script>

<style scoped>
    .camera-box {
        border: 1px dashed #d6d6d6;
        border-radius: 4px;
        padding: 2px;
        width: 80%;
        min-height: 300px;
    }

</style>



Share: