Categories
Vue 3 Projects

Add an Audio Player with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a video player with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create audio-player

and select all the default options to create the project.

Create the Audio Player

We can create the audio player by writing:

<template>
  <input
    type="range"
    min="0"
    max="100"
    step="1"
    v-model="seekValue"
    @change="onSeek"
  />
  <audio
    src="https://file-examples-com.github.io/uploads/2017/11/file_example_MP3_700KB.mp3"
    ref="audioPlayer"
    @timeupdate="onPlaying"
  >
    Your browser does not support the
    <code>audio</code> element.
  </audio>
  <p>{{ currentTime }}</p>
  <div>
    <button @click="play">play</button>
    <button @click="pause">pause</button>
    <button @click="stop">stop</button>
    <button @click="setSpeed(0.5)">0.5x</button>
    <button @click="setSpeed(1)">1x</button>
    <button @click="setSpeed(1.5)">1.5x</button>
    <button @click="setSpeed(2)">2x</button>
  </div>
</template>

<script>
export default {
  name: "App",
  data() {
    return {
      currentTime: 0,
      seekValue: 0,
    };
  },
  methods: {
    play() {
      this.$refs.audioPlayer.play();
    },
    pause() {
      this.$refs.audioPlayer.pause();
    },
    stop() {
      const { audioPlayer } = this.$refs;
      audioPlayer.pause();
      audioPlayer.currentTime = 0;
    },
    setSpeed(speed) {
      this.$refs.audioPlayer.playbackRate = speed;
    },
    onPlaying() {
      const { audioPlayer } = this.$refs;
      if (!audioPlayer) {
        return;
      }
      this.currentTime = audioPlayer.currentTime;
      this.seekValue = (audioPlayer.currentTime / audioPlayer.duration) * 100;
    },
    onSeek() {
      const { audioPlayer } = this.$refs;
      const seekto = audioPlayer.duration * (this.seekValue / 100);
      audioPlayer.currentTime = seekto;
    },
  },
};
</script>

We have a range input that we can slide around to change the seekValue ,

We bound it to seekValue with v-model .

Also, we attach a change event handler to the input that changes the currentTime of the audio element to seek the audio.

The audio element has the audio we want to play.

We listen to the timeUpdate event so we can get the current time.

We assign a ref to it so we can manipulate it later.

Below that, we display the currentTime .

And then we have a few buttons to let us play, pause, stop, and change the speed of the audio.

Below the template, we have the data method with the currentTime and seekValue reactive properties returned.

The play method gets the audio player element from the ref and call play to play the audio.

The pause method gets the audio player element from the ref and call pause to pause the audio.

The stop method pauses the audio and set the currentTime to 0 to reset the audio playback back to the beginning.

setSpeed lets us set the speed by changing the playbackRate property.

The onPlaying method is called when the timeUpdate event is emitted.

We set the this.currentTime reactive property to the currentTime property of the audioPlayer .

Also, we update the seekValue so that it’s in sync with the currentTime .

This will update the range slider to be in sync with the currentTime .

Finally, we have the onSeek method that’s run when the change event is emitted by the range input, which is done when we’re done moving the slider.

We get the seekValue reactive property and to compute the seekTo value by multiplying that by the duration and dividing by 100.

Then we set that to the currentTime to change the current time.

Conclusion

We can add an audio player with Vue 3 and JavaScript.

Categories
Vue 3 Projects

Add a Video Player with Vue 3 and JavaScript

Vue 3 is the latest version of the easy to use Vue JavaScript framework that lets us create front end apps.

In this article, we’ll look at how to create a video player with Vue 3 and JavaScript.

Create the Project

We can create the Vue project with Vue CLI.

To install it, we run:

npm install -g @vue/cli

with NPM or:

yarn global add @vue/cli

with Yarn.

Then we run:

vue create video-player

and select all the default options to create the project.

Create the Video Player

We can create the video player by writing:

<template>
  <video width="320" height="240" ref="videoPlayer">
    <source
      src="https://www.learningcontainer.com/wp-content/uploads/2020/05/sample-mp4-file.mp4"
      type="video/mp4"
    />
    Your browser does not support the video tag.
  </video>
  <div>
    <button @click="play">play</button>
    <button @click="pause">pause</button>
    <button @click="stop">stop</button>
    <button @click="setSpeed(0.5)">0.5x</button>
    <button @click="setSpeed(1)">1x</button>
    <button @click="setSpeed(1.5)">1.5x</button>
    <button @click="setSpeed(2)">2x</button>
  </div>
</template>

<script>
export default {
  name: "App",
  methods: {
    play() {
      this.$refs.videoPlayer.play();
    },
    pause() {
      this.$refs.videoPlayer.pause();
    },
    stop() {
      const { videoPlayer } = this.$refs;
      videoPlayer.pause();
      videoPlayer.currentTime = 0;
    },
    setSpeed(speed) {
      this.$refs.videoPlayer.playbackRate = speed;
    },
  },
};
</script>

We have the video element with a ref assigned to it.

width and height sets the dimensions of the video.

The source element has the video source.

We set it to the URL to an MP4 clip that we want to play.

Below that, we add buttons to let us play, pause, and stop the video.

We also have buttons that let us change the playback speed.

Then below that, we add some methods that are called when we click on buttons.

The play method lets us play the video by getting the videoPlayer ref with this.$refs.videoPlayer and calling the play method on the returned video element.

The pause method is similar. We get the videoPlayer ref which has the element and call pause on it to pause the video.

A video element has no method to stop a video. But we can implement that by pausing it and resetting the currentTime to 0.

To set the speed of the video, we can set the playbackRate property.

0.5 is half the normal speed.

And anything above 1 is faster than normal speed.

Conclusion

We can add a video player easily into our web app with Vue 3 and JavaScript.

Categories
JavaScript

Add Charts to Our JavaScript App with Anychart

Anychart is an easy to use library that lets us add chart into our JavaScript web app.

In this article, we’ll look at how to create basic charts with Anychart.

Create Our First Chart

We can create our first chart by adding the script tag to add the Anychart library:

<script src="https://cdn.anychart.com/releases/8.9.0/js/anychart-base.min.js" type="text/javascript"></script>

Then we add a container element for the chart:

<div id="container" style="width: 500px; height: 400px;"></div>

We set the id which we’ll use later.

Then to create a pie chart, we write:

anychart.onDocumentLoad(() => {
   const chart = anychart.pie();
   chart.data([
     ["apple", 5],
     ["orange", 2],
     ["grape", 2],
   ]);
   chart.title("Most popular fruits");
   chart.container("container");
   chart.draw();
 });

We create a pie chart with anychart.pie() .

Then we call chart.data to add our data in an array.

chart.title sets the chart title.

chart.container sets the ID of the container to render the chart in.

chart.draw draws the chart.

Load Data from XML

We can load data from XML.

For instance, we can write the following HTML:

<div id="container" style="width: 500px; height: 400px;"></div>

And the following JavaScript code:

const xmlString = `
<xml>
 <chart type="pie" >
  <data>
   <point name="apple" value="1222"/>
   <point name="orange" value="2431"/>
   <point name="grape" value="3624"/>
  </data>
 </chart>
</xml>
`

anychart.onDocumentLoad(() => {
  const chart = anychart.fromXml(xmlString);
  chart.title("Most popular fruits");
  chart.container("container");
  chart.draw();
});

to add a pie chart that renders the given XML string.

We have the chart tag with the type attribute set to 'pie' .

The data tag has the point elements which have the data.

name has the keys and value has the value.

Load Data from JSON

To load data from JSON objects, we can use the anychart.fromJSON method.

We keep the same HTML as before, and we write the following JavaScript:

const json = {
  "chart": {
    "type": "pie",
    "data": [
      ["apple", 1222],
      ["orange", 2431],
      ["grape", 3624],
    ]
  }
};

anychart.onDocumentLoad(() => {
  const chart = anychart.fromJson(json);
  chart.title("Most popular fruits");
  chart.container("container");
  chart.draw();
});

We have the json object with the chart property that has the chart data.

type has the chart type to render.

data has an array of key-value arrays with the data.

Load Data from CSV

We can load chart data from CSV with the chart.title method.

For instance, we can write:

const csvString = `
  2009-02-06,6764n
  2009-02-07,7056n
  2009-02-08,7180n
`

anychart.onDocumentLoad(() => {
  const chart = anychart.area();
  chart.area(csvString);
  chart.title("Profit growth");
  chart.container("container");
  chart.draw();
});

We have the csvString variable that has a string with the CSV columns.

The first is the x-axis values.

The 2nd column is the y-axis values.

Then we pass csvString to chart.area to use csvString ‘s data to render our area chart.

Conclusion

We can render charts from various data sources easily with Anychart.

Categories
Vue

Developing Vue Apps with Class-Based Components — Type Annotations

If we prefer to use classes, we can use the class-based components API that comes with Vue.

In this article, we’ll look at how to developing Vue apps with class-based components.

TypeScript Autocomplete for External Hooks

We can add autocomplete for external hooks within our class-based components written in TypeScript.

For instance, we can write:

vue-router-hook-types.ts

import Vue from "vue";
import { Route, RawLocation } from "vue-router";

declare module "vue/types/vue" {
  interface Vue {
    beforeRouteEnter?(
      to: Route,
      from: Route,
      next: (to?: RawLocation | false | ((vm: Vue) => void)) => void
    ): void;

    beforeRouteLeave?(
      to: Route,
      from: Route,
      next: (to?: RawLocation | false | ((vm: Vue) => void)) => void
    ): void;

    beforeRouteUpdate?(
      to: Route,
      from: Route,
      next: (to?: RawLocation | false | ((vm: Vue) => void)) => void
    ): void;
  }
}

main.ts

import Vue from "vue";
import App from "./App.vue";
import Foo from "./views/Foo.vue";
import Bar from "./views/Bar.vue";
import VueRouter from "vue-router";
import "./vue-router-hook-types";
Vue.config.productionTip = false;
const routes = [
  { path: "/foo", component: Foo },
  { path: "/bar", component: Bar }
];
const router = new VueRouter({
  routes
});
Vue.use(VueRouter);
new Vue({
  router,
  render: (h) => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <router-link to="/foo">Foo</router-link>
    <router-link to="/bar">Bar</router-link>
    <router-view></router-view>
  </div>
</template>
<script>
export default {
  name: "App",
};
</script>

views/Bar.vue

<template>
  <div>bar</div>
</template>
<script>
import Vue from "vue";
import Component from "vue-class-component";
Component.registerHooks([
  "beforeRouteEnter",
  "beforeRouteLeave",
  "beforeRouteUpdate",
]);
@Component
export default class Foo extends Vue {
  beforeRouteEnter(to, from, next) {
    console.log("beforeRouteEnter");
    next();
  }
  beforeRouteUpdate(to, from, next) {
    console.log("beforeRouteUpdate");
    next();
  }
  beforeRouteLeave(to, from, next) {
    console.log("beforeRouteLeave");
    next();
  }
}
</script>

views/Foo.vue

<template>
  <div>foo</div>
</template>
<script>
import Vue from "vue";
import Component from "vue-class-component";
import "vue-class-component/hooks";

Component.registerHooks([
  "beforeRouteEnter",
  "beforeRouteLeave",
  "beforeRouteUpdate",
]);
@Component
export default class Foo extends Vue {
  beforeRouteEnter(to, from, next) {
    console.log("beforeRouteEnter");
    next();
  }
  beforeRouteUpdate(to, from, next) {
    console.log("beforeRouteUpdate");
    next();
  }
  beforeRouteLeave(to, from, next) {
    console.log("beforeRouteLeave");
    next();
  }
}
</script>

We have the vue-router-hook-types.ts with the type definitions for the Vue Router hooks.

In main.ts , we have:

import "./vue-router-hook-types";

to import the type definitions.

Then in the Foo.vue and Bar.vue components, we can see the beforeRouteEnter, beforeRouteUpdate, and beforeRouteLeave hooks in the autocomplete menu when we’re typing them into the component class code.

We can also annotate types of methods in our code.

For instance, we can write:

<template>
  <div>
    <button @click="increment">increment</button>
    <p>{{ count }}</p>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component(({
  watch: {
    count(val: number) {
      this.log(val)
    }
  }
})
export default class HelloWorld extends Vue {
  count: number = 0

  log(val: number): void {
    console.log(val)
  }

  increment(){
    this.count++
  }
}
</script>

We have the log method that returns void and takes a val parameter with type number ,

We use that in the count watcher which is defined in the argument we pass into Component .

This way, we won’t have to worry about passing parameters with data types we don’t expect.

And the same applies to return types of methods.

Conclusion

We can annotate data types easily with TypeScript to avoid making mistakes in our Vue class-based components.

Categories
Vue

Developing Vue Apps with Class-Based Components — TypeScript, Superclasses, Hooks, and Mixins

If we prefer to use classes, we can use the class-based components API that comes with Vue.

In this article, we’ll look at how to developing Vue apps with class-based components.

TypeScript, Superclasses, and Mixins

We can add props and inherit superclass components with the mixins method in our Vue TypeScript project.

For instance, we can write:

<template>
  <div>
    <p>{{ message }}</p>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component, { mixins } from "vue-class-component";

const GreetingProps = Vue.extend({
  props: {
    name: String,
  },
});

@Component
class Super extends Vue {
  lastName = "smith";
}

@Component
export default class HelloWorld extends mixins(GreetingProps, Super) {
  get message(): string {
    return `Hello, ${this.name} ${this.lastName}`;
  }
}
</script>

We create the Super component class with the 1astName property.

And we have the GreetProps class that we create with the Vue.extend method so we can accept props in a way that’s acceptable by TypeScript.

Then we call the mixins method with the GreetProps and Super methods so we can inherit from both classes.

We inherit from both classes, so this.name is 'james' and this.lastName is 'smith' .

We can define properties with type definitions.

For instance, we can write:

<template>
  <div>
    <p v-for="p of persons" :key="p">{{ p.firstName }} {{ p.lastName }}</p>
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

interface Person {
  firstName: string;
  lastName: string;
}

@Component
export default class HelloWorld extends Vue {
  persons!: Person[] = [
    { firstName: "james", lastName: "smith" },
    { firstName: "jane", lastName: "doe" },
  ];
}
</script>

We create the Person interface and use that for defining the type of the persons class property.

The ! means the class property isn’t nullable.

Now if the persons array entries have extra properties, we’ll get an error from the TypeScript compiler.

Refs and TypeScript

To define and assign refs with TypeScript class-based Vue components, we write:

<template>
  <div>
    <input ref="input" />
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component
export default class HelloWorld extends Vue {
  $refs!: {
    input: HTMLInputElement;
  };

  mounted() {
    this.$refs.input.focus();
  }
}
</script>

We have to set the type for each $refs property we assign.

input is an HTML input element, so we set it to the HTMLInputElement type.

Then we call call focus on it to focus it.

With the type annotation added, we get autocomplete when we type in the code in the mounted hook.

Hooks Autocomplete

To add autocomplete for hooks, we write:

main.ts

import Vue from "vue";
import App from "./App.vue";
import "vue-class-component/hooks";
Vue.config.productionTip = false;

new Vue({
  render: (h) => h(App)
}).$mount("#app");

App.vue

<template>
  <div id="app">
    <HelloWorld />
  </div>
</template>

<script lang='ts'>
import HelloWorld from "./components/HelloWorld.vue";

export default {
  name: "App",
  components: {
    HelloWorld,
  },
};
</script>

components/HelloWorld.vue

<template>
  <div>
    {{ message }}
  </div>
</template>

<script lang="ts">
import Vue from "vue";
import Component from "vue-class-component";

@Component
export default class HelloWorld extends Vue {
  data() {
    return {
      message: "hello world",
    };
  }
}
</script>

Once we add:

import "vue-class-component/hooks";

in main.ts , we get autocomplete when we type in data in the HelloWorld component.

Conclusion

We can add hooks autocomplete, mixins and superclass inheritance, and refs type annotation within our Vue class-based components written in TypeScript.