Top 10 Our favourite Games made with Vue.js

Top 10 Our favourite Games made with Vue.js .Designing a 2D game for a 2D screen is pretty simple to us .The objective in Minesweeper is to find and mark all the mines hidden under the grey squares .Chessboard vue component to load positions, create positions and see threats.

1. Perspective Vue

Designing a 2D game for a 2D screen is pretty simple to us. But it comes to design a 3D environment for a 2D computer screen we tend to adopt game engines thinking that's a lot of complex math we can't handle. Though there's no denying the reliability of game engines, some features of the 3D environment can be implemented with really simple mathematics we learnt at school. This repository is intented to demonstrate that.

Perspective drawing is a drawing technique used to illustrate dimension through a flat surface. This is how we see a flat surface image and perceive a 3D environment in our brain depending on the position and sizes of the objects drawn. So if we can do the math to calculate how large or small the object needs to be drawn depending on how far it is from the screen, that's all we need to have a 3D layout.

2. Vue 8 Puzzle

An itty-bitty slide puzzle game made as Vue.js component.

Images/Videos for source

3.Vue Minesweeper

The objective in Minesweeper is to find and mark all the mines hidden under the grey squares, in the shortest time possible. This is done by clicking on the squares to open them. Each square will have one of the following:

1. A mine, and if you click on it you'll lose the game.
2. A number, which tells you how many of its adjacent squares have mines in them.
3. Nothing. In this case you know that none of the adjacent squares have mines, and they will be automatically opened as well.

It is guaranteed that the first square you open won't contain a mine, so you can start by clicking any square. Often you'll hit on an empty square on the first try and then you'll open up a few adjacent squares as well, which makes it easier to continue. Then it's basically just looking at the numbers shown, and figuring out where the mines are.

4.Vue Chessboard

Chessboard vue component to load positions, create positions and see threats.

• It uses chess.js for chess movements and validations
• It uses chessground for chessboard UI chessground

5.VueSwing

A Vue.js wrapper for Swing. Swing is a swipeable cards interface. The swipe-left/swipe-right for yes/no input. As seen in apps like Jelly and Tinder, and many others.

6.Tic-Tac-Toe web app created with Animate and Vue.js

Classic game with a modern look. Fully responsive Tic-Tac-Toe web app created with HTML, CSS, Animate.css, Bootstrap, JavaScript and Vue.js.

7.Vue-2048

2048 is a single-player sliding block puzzle game designed by Italian web developer Gabriele Cirulli. The game's objective is to slide numbered tiles on a grid to combine them to create a tile with the number 2048. However, one can continue to play the game after reaching the goal, creating tiles with larger numbers.

8.Tic Tac Toe with Vue.js

A little experiment in Collab Mode. Built together with @JonasKuiler to explain some basic Vue.js stuff

View Demo

9.Vue.js Go Game

Go game is an abstract strategy board game for two players, in which the aim is to surround more territory than the opponent.

10. Vue Tetris

The game has seven types of bricks: I (vertical), J, L, O (square), S, T, Z. We see each block of bricks made up of 4 small squares put together. We can treat these blocks as rectangles of different sizes.

The other shapes created by rotating these basic blocks are 90 degrees, 180 degrees and 270 degrees, respectively.

A random sequence of Tetriminos falls onto the playing field (a rectangular vertical axis, called a "good" or "matrix").

11.Vue Defuse

An implementation of the classical minesweeper game in vue.js.

Demo: https://connexo.de/defuse/
View on GitHub

12.Vue Minesweeper

Examples: https://codepen.io/disjfa/pen/axdmob
View on GitHub

13.JavaScript Guessing Game

You know there are too many JavaScript libraries when there is a game for it

React, Flux, Angular, Aurelia, TypeScript, Flow, oh my! By trying to make things simpler, I have created this game to stay on top of JavaScript in 2017.

Contributing

• Add a new object of a JavaScript tool to /static/logos.json JSON file.
• Add 100x100 .png image to /static/logos/ directory with the tool's name in lowercase as the file's name.
• Create a pull request :)

Examples: https://javascript-game.firebaseapp.com/#/
View on GitHub

How to build Vue.js JWT Authentication with Vuex and Vue Router

In this tutorial, we’re gonna build a Vue.js with Vuex and Vue Router Application that supports JWT Authentication

In this tutorial, we’re gonna build a Vue.js with Vuex and Vue Router Application that supports JWT Authentication. I will show you:

• JWT Authentication Flow for User Signup & User Login
• Project Structure for Vue.js Authentication with Vuex & Vue Router
• How to define Vuex Authentication module
• Creating Vue Authentication Components with Vuex Store & VeeValidate
• Vue Components for accessing protected Resources

Let’s explore together.

Contents

Overview of Vue JWT Authentication example

We will build a Vue application in that:

• There are Login/Logout, Signup pages.
• Form data will be validated by front-end before being sent to back-end.
• Depending on User’s roles (admin, moderator, user), Navigation Bar changes its items automatically.

– Signup Page:

Demo

This is full Vue JWT Authentication App demo (with form validation, check signup username/email duplicates, test authorization with 3 roles: Admin, Moderator, User). In the video, we use Spring Boot for back-end REST APIs.

Flow for User Registration and User Login

For JWT Authentication, we’re gonna call 2 endpoints:

• POST `api/auth/signup` for User Registration
• POST `api/auth/signin` for User Login

You can take a look at following flow to have an overview of Requests and Responses Vue Client will make or receive.

Vue Client must add a JWT to HTTP Authorization Header before sending request to protected resources.

Vue App Component Diagram with Vuex & Vue Router

Now look at the diagram below.

– The `App` component is a container with `Router`. It gets app state from Vuex `store/auth`. Then the navbar now can display based on the state. `App` component also passes state to its child components.

`Login` & `Register` components have form for submission data (with support of `vee-validate`). We call Vuex store `dispatch()` function to make login/register actions.

– Our Vuex actions call `auth.service` methods which use `axios` to make HTTP requests. We also store or get JWT from Browser Local Storage inside these methods.

`Home` component is public for all visitor.

`Profile` component get `user` data from its parent component and display user information.

`BoardUser`, `BoardModerator`, `BoardAdmin` components will be displayed by Vuex state `user.roles`. In these components, we use `user.service` to get protected resources from API.

`user.service` uses `auth-header()` helper function to add JWT to HTTP Authorization header. `auth-header()` returns an object containing the JWT of the currently logged in user from Local Storage.

Technology

We will use these modules:

• vue: 2.6.10
• vue-router: 3.0.3
• vuex: 3.0.1
• axios: 0.19.0
• vee-validate: 2.2.15
• bootstrap: 4.3.1
• vue-fontawesome: 0.1.7
Project Structure

This is folders & files structure for our Vue application:

With the explaination in diagram above, you can understand the project structure easily.

Setup Vue App modules

Run following command to install neccessary modules:

``````npm install vue-router
npm install vuex
npm install [email protected]
npm install axios
npm install bootstrap jquery popper.js
npm install @fortawesome/fontawesome-svg-core @fortawesome/free-solid-svg-icons @fortawesome/vue-fontawesome

``````

After the installation is done, you can check `dependencies` in package.json file.

``````"dependencies": {
"@fortawesome/fontawesome-svg-core": "^1.2.25",
"@fortawesome/free-solid-svg-icons": "^5.11.2",
"@fortawesome/vue-fontawesome": "^0.1.7",
"axios": "^0.19.0",
"bootstrap": "^4.3.1",
"core-js": "^2.6.5",
"jquery": "^3.4.1",
"popper.js": "^1.15.0",
"vee-validate": "^2.2.15",
"vue": "^2.6.10",
"vue-router": "^3.0.3",
"vuex": "^3.0.1"
},

``````

``````import Vue from 'vue';
import App from './App.vue';
import { router } from './router';
import store from './store';
import 'bootstrap';
import 'bootstrap/dist/css/bootstrap.min.css';
import VeeValidate from 'vee-validate';
import { library } from '@fortawesome/fontawesome-svg-core';
import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome';
import {
faHome,
faUser,
faUserPlus,
faSignInAlt,
faSignOutAlt
} from '@fortawesome/free-solid-svg-icons';

Vue.config.productionTip = false;

Vue.use(VeeValidate);
Vue.component('font-awesome-icon', FontAwesomeIcon);

new Vue({
router,
store,
render: h => h(App)
}).\$mount('#app');

``````

You can see that we import and apply in `Vue` object:
`store` for Vuex (implemented later in src/store)
`router` for Vue Router (implemented later in src/router.js)
`bootstrap` with CSS
`vee-validate`
`vue-fontawesome` for icons (used later in `nav`)

Create Services

We create two services in src/services folder:

services

auth.service.js (Authentication service)

user.service.js (Data service)

Authentication service

The service provides three important methods with the help of axios for HTTP requests & reponses:

• `login()`: POST {username, password} & save `JWT` to Local Storage
• `logout()`: remove `JWT` from Local Storage
• `register()`: POST {username, email, password}
``````import axios from 'axios';

const API_URL = 'http://localhost:8080/api/auth/';

class AuthService {
return axios
.post(API_URL + 'signin', {
})
.then(this.handleResponse)
.then(response => {
if (response.data.accessToken) {
localStorage.setItem('user', JSON.stringify(response.data));
}

return response.data;
});
}

logout() {
localStorage.removeItem('user');
}

register(user) {
return axios.post(API_URL + 'signup', {
email: user.email,
});
}

handleResponse(response) {
if (response.status === 401) {
this.logout();

const error = response.data && response.data.message;
return Promise.reject(error);
}

return Promise.resolve(response);
}
}

export default new AuthService();

``````

If `login` request returns 401 status (Unauthorized), that means, JWT was expired or no longer valid, we will logout the user (remove JWT from Local Storage).

Data service

We also have methods for retrieving data from server. In the case we access protected resources, the HTTP request needs Authorization header.

Let’s create a helper function called `authHeader()` inside auth-header.js:

``````export default function authHeader() {
let user = JSON.parse(localStorage.getItem('user'));

if (user && user.accessToken) {
return { Authorization: 'Bearer ' + user.accessToken };
} else {
return {};
}
}

``````

It checks Local Storage for `user` item.
If there is a logged in `user` with `accessToken` (JWT), return HTTP Authorization header. Otherwise, return an empty object.

Now we define a service for accessing data in user.service.js:

``````import axios from 'axios';

const API_URL = 'http://localhost:8080/api/test/';

class UserService {
getPublicContent() {
return axios.get(API_URL + 'all');
}

getUserBoard() {
}

getModeratorBoard() {
}

}
}

export default new UserService();

``````

You can see that we add a HTTP header with the help of `authHeader()` function when requesting authorized resource.

Define Vuex Authentication module

We put Vuex module for authentication in src/store folder.

store

auth.module.js (authentication module)

index.js (Vuex Store that contains also modules)

Now open index.js file, import `auth.module` to main Vuex Store here.

``````import Vue from 'vue';
import Vuex from 'vuex';

import { auth } from './auth.module';

Vue.use(Vuex);

export default new Vuex.Store({
modules: {
auth
}
});

``````

Then we start to define Vuex Authentication module that contains:

• state: { status, user }
• actions: { login, logout, register }

We use `AuthService` which is defined above to make authentication requests.

auth.module.js

``````import AuthService from '../services/auth.service';

const user = JSON.parse(localStorage.getItem('user'));
const initialState = user
? { status: { loggedIn: true }, user }
: { status: {}, user: null };

export const auth = {
namespaced: true,
state: initialState,
actions: {
user => {
return Promise.resolve(user);
},
error => {
return Promise.reject(error.response.data);
}
);
},
logout({ commit }) {
AuthService.logout();
commit('logout');
},
register({ commit }, user) {
return AuthService.register(user).then(
response => {
commit('registerSuccess');
return Promise.resolve(response.data);
},
error => {
commit('registerFailure');
return Promise.reject(error.response.data);
}
);
}
},
mutations: {
state.status = { loggedIn: true };
state.user = user;
},
state.status = {};
state.user = null;
},
logout(state) {
state.status = {};
state.user = null;
},
registerSuccess(state) {
state.status = {};
},
registerFailure(state) {
state.status = {};
}
}
};

``````

You can find more details about Vuex at Vuex Guide.

Create Vue Authentication Components

Define User model

To make code clear and easy to read, we define the `User` model first.
Under src/models folder, create user.js like this.

``````export default class User {
this.email = email;
}
}

``````

Let’s continue with Authentication Components.
Instead of using axios or `AuthService` directly, these Components should work with Vuex Store:
– getting status with `this.\$store.state.auth`
– making request by dispatching an action: `this.\$store.dispatch()`

views

Register.vue

Profile.vue

In src/views folder, create Login.vue file with following code:

``````<template>
<div class="col-md-12">
<div class="card card-container">
<img
id="profile-img"
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
class="profile-img-card"
/>
<div class="form-group">
<input
type="text"
class="form-control"
v-validate="'required'"
/>
<div
</div>
<div class="form-group">
<input
class="form-control"
v-validate="'required'"
/>
<div
</div>
<div class="form-group">
</button>
</div>
<div class="form-group">
</div>
</form>
</div>
</div>
</template>

<script>
import User from '../models/user';

export default {
computed: {
loggedIn() {
return this.\$store.state.auth.status.loggedIn;
}
},
data() {
return {
user: new User('', ''),
message: ''
};
},
mounted() {
if (this.loggedIn) {
this.\$router.push('/profile');
}
},
methods: {
this.\$validator.validateAll();

if (this.errors.any()) {
return;
}

() => {
this.\$router.push('/profile');
},
error => {
this.message = error.message;
}
);
}
}
}
};
</script>

<style scoped>
label {
display: block;
margin-top: 10px;
}

.card-container.card {
max-width: 350px !important;
}

.card {
background-color: #f7f7f7;
margin: 0 auto 25px;
margin-top: 50px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}

.profile-img-card {
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
}
</style>

``````

This page has a Form with `username` & `password`. We use [VeeValidate 2.x](http://<a href=) to validate input before submitting the form. If there is an invalid field, we show the error message.

We check user logged in status using Vuex Store: `this.\$store.state.auth.status.loggedIn`. If the status is `true`, we use Vue Router to direct user to Profile Page:

``````created() {
if (this.loggedIn) {
this.\$router.push('/profile');
}
},

``````

In the `handleLogin()` function, we dispatch `'auth/login'` Action to Vuex Store. If the login is successful, go to Profile Page, otherwise, show error message.

Vue Register Page

For form validation, we have some more details:

• `username`: required|min:3|max:20
• `email`: required|email|max:50
• `password`: required|min:6|max:40

For form submission, we dispatch `'auth/register'` Vuex Action.

src/views/Register.vue

``````<template>
<div class="col-md-12">
<div class="card card-container">
<img
id="profile-img"
src="//ssl.gstatic.com/accounts/ui/avatar_2x.png"
class="profile-img-card"
/>
<form name="form" @submit.prevent="handleRegister">
<div v-if="!successful">
<div class="form-group">
<input
type="text"
class="form-control"
v-validate="'required|min:3|max:20'"
/>
<div
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
class="form-control"
name="email"
v-model="user.email"
v-validate="'required|email|max:50'"
/>
<div
v-if="submitted && errors.has('email')"
>{{errors.first('email')}}</div>
</div>
<div class="form-group">
<input
class="form-control"
v-validate="'required|min:6|max:40'"
/>
<div
</div>
<div class="form-group">
</div>
</div>
</form>

<div
v-if="message"
>{{message}}</div>
</div>
</div>
</template>

<script>
import User from '../models/user';

export default {
name: 'register',
computed: {
loggedIn() {
return this.\$store.state.auth.status.loggedIn;
}
},
data() {
return {
user: new User('', '', ''),
submitted: false,
successful: false,
message: ''
};
},
mounted() {
if (this.loggedIn) {
this.\$router.push('/profile');
}
},
methods: {
handleRegister() {
this.message = '';
this.submitted = true;
this.\$validator.validate().then(valid => {
if (valid) {
this.\$store.dispatch('auth/register', this.user).then(
data => {
this.message = data.message;
this.successful = true;
},
error => {
this.message = error.message;
this.successful = false;
}
);
}
});
}
}
};
</script>

<style scoped>
label {
display: block;
margin-top: 10px;
}

.card-container.card {
max-width: 350px !important;
}

.card {
background-color: #f7f7f7;
margin: 0 auto 25px;
margin-top: 50px;
-moz-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
-webkit-box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3);
}

.profile-img-card {
width: 96px;
height: 96px;
margin: 0 auto 10px;
display: block;
}
</style>

``````

Profile Page

This page gets current User from Vuex Store and show information. If the User is not logged in, it directs to Login Page.

src/views/Profile.vue

``````<template>
<div class="container">
<h3>
</h3>
<p>
<strong>Token:</strong>
{{currentUser.accessToken.substring(0, 20)}} ... {{currentUser.accessToken.substr(currentUser.accessToken.length - 20)}}
</p>
<p>
<strong>Id:</strong>
{{currentUser.id}}
</p>
<p>
<strong>Email:</strong>
{{currentUser.email}}
</p>
<strong>Authorities:</strong>
<ul>
<li v-for="(role,index) in currentUser.roles" :key="index">{{role}}</li>
</ul>
</div>
</template>

<script>
export default {
name: 'profile',
computed: {
currentUser() {
return this.\$store.state.auth.user;
}
},
mounted() {
if (!this.currentUser) {
}
}
};
</script>

``````
Create Vue Components for accessing Resources

These components will use `UserService` to request data.

views

Home.vue

BoardModerator.vue

BoardUser.vue

This is a public page.

src/views/Home.vue

``````<template>
<div class="container">
<h3>{{content}}</h3>
</div>
</template>

<script>
import UserService from '../services/user.service';

export default {
name: 'home',
data() {
return {
content: ''
};
},
mounted() {
UserService.getPublicContent().then(
response => {
this.content = response.data;
},
error => {
this.content = error.response.data.message;
}
);
}
};
</script>

``````

Role-based Pages

We have 3 pages for accessing protected data:

• BoardUser page calls `UserService.getUserBoard()`
• BoardModerator page calls `UserService.getModeratorBoard()`
• BoardAdmin page calls `UserService.getAdminBoard()`

src/views/BoardUser.vue

``````<template>
<div class="container">
<h3>{{content}}</h3>
</div>
</template>

<script>
import UserService from '../services/user.service';

export default {
name: 'user',
data() {
return {
content: ''
};
},
mounted() {
UserService.getUserBoard().then(
response => {
this.content = response.data;
},
error => {
this.content = error.response.data.message;
}
);
}
};
</script>

``````
Define Routes for Vue Router

Now we define all routes for our Vue Application.

src/router.js

``````import Vue from 'vue';
import Router from 'vue-router';
import Home from './views/Home.vue';
import Register from './views/Register.vue';

Vue.use(Router);

export const router = new Router({
mode: 'history',
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/home',
component: Home
},
{
},
{
path: '/register',
component: Register
},
{
path: '/profile',
name: 'profile',
component: () => import('./views/Profile.vue')
},
{
},
{
path: '/mod',
name: 'moderator',
component: () => import('./views/BoardModerator.vue')
},
{
path: '/user',
name: 'user',
component: () => import('./views/BoardUser.vue')
}
]
});

``````

This is the root container for our application that contains navigation bar. We will add `router-view` here.

src/App.vue

``````<template>
<div id="app">
<nav class="navbar navbar-expand navbar-dark bg-dark">
<a href="#" class="navbar-brand">bezKoder</a>
<div class="navbar-nav mr-auto">
<li class="nav-item">
<font-awesome-icon icon="home" /> Home
</a>
</li>
</li>
<li class="nav-item" v-if="showModeratorBoard">
</li>
<li class="nav-item">
</li>
</div>

<div class="navbar-nav ml-auto" v-if="!currentUser">
<li class="nav-item">
</a>
</li>
<li class="nav-item">
</a>
</li>
</div>

<div class="navbar-nav ml-auto" v-if="currentUser">
<li class="nav-item">
<font-awesome-icon icon="user" />
</a>
</li>
<li class="nav-item">
<font-awesome-icon icon="sign-out-alt" /> LogOut
</a>
</li>
</div>
</nav>

<div class="container">
<router-view />
</div>
</div>
</template>

<script>
export default {
computed: {
currentUser() {
return this.\$store.state.auth.user;
},
if (this.currentUser) {
}

return false;
},
showModeratorBoard() {
if (this.currentUser) {
return this.currentUser.roles.includes('ROLE_MODERATOR');
}

return false;
}
},
methods: {
logOut() {
this.\$store.dispatch('auth/logout');
}
}
};
</script>

``````

Our navbar looks more professional when using `font-awesome-icon`.
We also make the navbar dynamically change by current User’s `roles` which are retrieved from Vuex Store `state`.

Handle Unauthorized Access

If you want to check Authorized status everytime a navigating action is trigger, just add `router.beforeEach()` at the end of src/router.js like this:

``````router.beforeEach((to, from, next) => {
const authRequired = !publicPages.includes(to.path);
const loggedIn = localStorage.getItem('user');

// try to access a restricted page + not logged in
if (authRequired && !loggedIn) {
}

next();
});

``````
Conclusion

Congratulation!

Today we’ve done so many interesting things. I hope you understand the overall layers of our Vue application, and apply it in your project at ease. Now you can build a front-end app that supports JWT Authentication with Vue.js, Vuex and Vue Router.

Happy learning, see you again!

Performance Boost Using Highcharts.js and Vue.js

How to Maintain Performance with Big Datasets Using Highcharts. js and Vue. Sometimes you just need to show big datasets in your project. However, the library that you've used so far, as soon as you start to add data, becomes clunky and slow.

Sometimes you just need to show big datasets in your project. However, the library that you’ve used so far, as soon as you start to add data, becomes clunky and slow. You start to optimize your code, make cuts, or simplifications in datasets… In this article I’m going to show you that it does not have to be that way

Used by “80% of the largest companies in the world”, Highcharts is a powerful tool that allows you to plot massive series of data in a dynamic manner. As it’s free for non-commercial use, you can easily check for yourself if it’s going to suit your tastes. This project will also use highcharts-vue, which is a wrapper for Highcharts.

Installation:

The tools that we are going to need for the job are:

• Highcharts
• Highcharts vue
• Axios

You can easily install them all at once using npm command:

``````npm i highcharts highcharts-vue axios -S

``````

Now that we have all the pieces, let’s add them in the main.js file:

``````import Highcharts from "highcharts";
import HighchartsVue from "highcharts-vue";
import boost from "highcharts/modules/boost";

Vue.use(HighchartsVue);
boost(Highcharts);

``````

You may be wondering, what this boost module is. I think that, to best explain it, the official documentation can be cited:

Boost is a stripped-down renderer-in-a-module for Highcharts and Highstock. It bypasses some of the standard Highcharts features (such as animation), and focuses on pushing as many points as possible as quickly as possible.

So, to sum it up, this module will make our charts run faster, but at the cost of some minor drawbacks. For example, you won’t be able to use dotted lines for your series. But, don’t you worry, the key parts are still fully functional.

Disclaimer: As the boost module is still in development, it can cause several bugs. For example, when using timestamps as x value, `boost.useGPUTranslations` will cause points to render in wrong places while zoomed, so you will need to do additional research, or just ask on the Highcharts forums.

Mocking the data:

As we need to have some data to show, and you probably don’t have any endpoints hanging around, we will need to generate some dummy data. We will need to create an object that has two (or more) attributes filled with chart data (for the sake of showing performance - about 100k points each, but you can totally try with 200-300k, or more). Highcharts allows us to add such as series in two ways:

• array of {x,y} objects
• array of values (where you specify the start of each series, as well as intervals)

This article covers how to make use of the first way, but you can always read the official Highcharts documentation to see other possibilities. To get the data, if you don’t want to generate it yourself, you can use my `test.json` (it’s in a public folder on the repo).

Let’s make use of it:

Now that we have some data to show, we can filtrate it. Even though this is a simplified version of the real application, we can create our architecture in a way that somewhat reflects the real case. Therefore, we can create 3 files:

• ChartFiltration.vue
• Chart.vue
• store.js

`ChartFiltration.vue` will be, a parent of a Chart component. Its job will be issuing fetches and to know when the data is ready. `Chart.vue` will simply be used to show the series that are being passed by props. All logic related to processing the chart data will be stored in a store module.

First App.vue

``````<template>
<div id="app">
<ChartFiltration />
</div>
</template>

<script>
import ChartFiltration from "./components/ChartFiltration";

export default {
components: { ChartFiltration }
};
</script>

``````

Nothing too fancy here, just some imports.

ChartFiltration.vue

``````<template>
<div v-if="series">
<Chart :series="series" />
</div>
<div v-else>
</div>
</template>

<script>
import { mapState } from "vuex";
import Chart from "./Chart";

export default {
name: "ChartFiltration",
components: { Chart },
mounted() {
this.\$store.dispatch("fetchData");
},
computed: mapState({
series: state => state.data
})
};
</script>

``````

As you can see, when the component is being mounted, the fetch in the store will be dispatched. The data will be mapped to a computed series. As I use conditional rendering, `Chart.vue` component will be rendered only when a series will have its length (because they will be returned as an array).

store.js

``````import Vue from "vue";
import Vuex from "vuex";
import axios from "axios";

Vue.use(Vuex);

const RESET_ERROR = null;
const generateSeries = data => {
return Object.keys(data).map(attribute => {
return {
type: "line",
boostThreshold: 1,
turboThreshold: 0,
animation: false,
name: attribute,
data: data[attribute],
marker: { enabled: true, radius: 3 },
states: { hover: { lineWidthPlus: 0 } }
};
});
};
export default new Vuex.Store({
state: {
data: null,
error: null
},
mutations: {
SET_DATA(state, data) {
state.data = generateSeries(data);
},
SET_ERROR(state, error) {
state.error = error;
}
},
actions: {
async fetchData({ commit }) {
commit("SET_ERROR", RESET_ERROR);

axios
.get("/test.json")
.then(res => {
commit("SET_DATA", res.data);
})
.catch(err => {
commit("SET_ERROR", err);
});
}
}
});

``````

In this article I simply want to show how to work with data in Highcharts. There is no need to use modules for the store, like we would in a real application and, therefore, this is why I will use a single store file. Let’s focus on `fetchData` action. I simulate the http call with axios. After the data has been “fetched”, we will commit the `SET_DATA` mutation. Highcharts has its specific way of building chart objects. Because there can’t be too much logic in mutations, we add an additional helper function to process our response properly.

``````const generateSeries = data => {
return Object.keys(data).map(attribute => {
return {
type: "line",
boostThreshold: 1,
turboThreshold: 0,
animation: false,
name: attribute,
data: data[attribute],
marker: { enabled: true, radius: 3 },
states: { hover: { lineWidthPlus: 0 } }
};
});
};

``````

The helper function simply iterates on object to get its attributes. After each iteration, we return the Highcharts series object, and this is what we will focus on:

• type: here you can specify a type of series
• boostThreshold: point threshold for when a series should enter boost mode. 1 means that we always want to use boost, 0 means never
• turboThreshold: for a bigger {x,y} series, it’s better to disable it (by setting 0) as it will not render. If the set threshold is passed, only one dimensional arrays of numbers, or two dimensional arrays with x and y values, are allowed
• animation: as animations slow down our chart, we don’t want them
• name: name of the series shown in the legend
• data: here, we need to assign our array of datapoints
• marker: size of the markers on the chart
• states: here, we will disable the line thickening on hover, as it will add lag for big datasets

What can we set additionally ?

• color: remember that, when using the boost module, you can only use simple colors (rgb/hex). You can also set them with css, but it’s trickier.
• Honestly, whatever you want, as this is a simple object that you will have access to by using this keyword in the chart object (for example, in the tooltip formatter). You can add units for series, or another type of name to show, but remember that you will need to handle logic for those by yourself.

Here is a list of attributes that you can officially assign for a series.

Now that we have our data processed, we can focus on showing it.

Chart.vue

``````<template>
<highcharts :options="chartOptions" />
</template>
<script>
export default {
name: "Chart",
props: {
series: { type: Array, required: true }
},
computed: {
chartOptions() {
return {
chart: {
type: "line",
height: "700px",
redraw: true,
animation: false,
zoomType: "xy",
panning: true,
panKey: "shift"
},
boost: { enabled: true },
tooltip: {
formatter() {
const time = new Date(this.x).toJSON();
const name = this.series.name;
return `<b>\${name}</b><br />
value: \${this.y} <br />
time: \${time}`;
}
},
series: this.series,
xAxis: {
type: "datetime"
}
};
}
}
};
</script>

``````

This components sole function is to create a chartOptions object that is passed to the highcharts-vue wrapper. We pass the series as props. On each change, a new chartOptions object will be computed and will force the whole component to rerender. Let’s look at the function that creates it:

``````chartOptions() {
return {
chart: {
type: "line",
height: "700px",
animation: false,
zoomType: "xy",
panning: true,
panKey: "shift"
},
boost: { enabled: true },
tooltip: {
formatter() {
const time = new Date(this.x).toJSON();
const name = this.series.name;
return `<b>\${name}</b><br />
value: \${this.y} <br />
time: \${time}`;
}
},
series: this.series,
xAxis: {
type: "datetime"
}
};
}

``````
• chart: has basic information about chart.
• type: specifies which type of chart we are going to show
• height: we can simply specify how much height in px this chart is going to have
• animation: disables all animations which may slow down the chart
• zoomType: specifies what type of zoom we can use. ‘xy’ means that we can zoom in both directions
• panning: true allows us to pan the chart after zooming
• panKey: specifies which key is used for panning
• boost: {enabled: true} : this is used to tell the chart to use the boost module
• tooltip: the tooltip is generated by default, but by using formatter(), we can specify exactly how it will look. Here, we have access (by this keyword) for each series attribute.
• series: this is where we put the processed array of highcharts objects
• xAxis: it’s used for informing chart, what is the type of series, specifying title, label format, and lots of other things.

The list of values that can be set for any of those attributes can be found here.

And, honestly, this is all. By moving processing logic to the store, we won’t cause any unnecessary computations inside of the component, which will improve speed immensely. In `ChartFiltrations.vue`, we can add some buttons to add additional filtrations to the chart. For example, we can add buttons to specify if we want to see only one type of attribute (remember that we need to still do the filtrations inside the store). Additionally, as in this example, we have both current and voltage. As you should know, they have different units, so to make our chart more lucid, we can use multiple y axises. It can be done simply by adding a yAxis object:

``````  yAxis: [
{
title: { text: 'Current [A]' },
gridLineWidth: 0.5,
showEmpty: false
},
{
title: { text: 'Voltage [V]' },
gridLineWidth: 0.5,
showEmpty: false
}
]

``````

to the chartOptions object, specifying to which y axis the dataset belongs while creating highcharts series objects:

``````const generateSeries = data => {
return Object.keys(data).map(attribute => {
return {
type: "line",
yAxis: attribute === "current" ? 0 : 1
};
});
};

``````

Let’s see how it looks in action:

As you can see, we had two series of 100k points, and they are working smoothly. In our project, sometimes we have 1 mln points to show at once, and performance is still superb. So, we can say with certainty that Highcharts fulfills its role, for sure.

In this article, I have hopefully shown you that lots of data does not come with a need to make performance cuts. This implementation is only one of numerous approaches to this particular topic. If you have any comments or questions, I will be happy to answer them through the comments.

You can find a working example here.