Write JavaScript like a pro. Javascript Icon

Follow the ultimate JavaScript roadmap.

Create your first data visualization chart in VueJS with D3!

What is data visualization? In a nutshell, it’s just a presentation of data in a graphical format. Using charts or graphs to visualize large amounts of complex data is easier for a human brain to understand. It helps us to see exactly what we need from our dataset and quickly process the required information.

One of the most popular libraries for data visualizations in JavaScript is D3.js. As stated in the D3 overview, it’s combining powerful visualization components and a data-driven approach to DOM manipulation. In other words, it’s similar to how jQuery works with the DOM. But what if we want to use a JS framework like Vue.js to build a data visualization? Vue has its own approach to DOM manipulation, would it collide with D3 way of doing things?

Let’s try to build a simple visualization to see how these tools work together.

What are we going to build?

In the first part, we will build a simple application to generate a star-shaped graph and change it dynamically using Vue.js framework.

Green star changing

If you want just to check the source code, it’s here.

Scaffolding the project

We’re going to use the Vue CLI to scaffold our project. You will need Vue CLI installed, if you don’t have it, please run:

npm install -g @vue/cli
# OR
yarn global add @vue/cli

Now we’re ready to create a new Vue application. We can do it by running the following command in the terminal:

vue create my-d3-app

You will be prompted with the list of options. For now, we can go with the Default setup.

Now you can open your application in the code editor and run serve command in the root of the project to see your it in the browser.

Vue CLI default view

Let’s delete all the content from components/HelloWorld.vue and rename it into Chart.vue - we’re going to place our chart here.

We need also to edit our App.vue file to include our chart there: remove the logo and rename an imported component into Chart as well:

<!-- App.vue -->

<template>
  <main>
    <Chart />
  </main>
</template>

<script>
  import Chart from './components/Chart.vue';
  export default {
    name: 'app',
    components: {
      Chart,
    },
  };
</script>

The only thing left is to install D3.js as a dependency via npm:

npm install d3
# OR
yarn add d3

Now we’re ready to work on our chart!

Starting with SVG

To draw our star, we will use an SVG. So the first thing to add to our Chart component template is actually a <svg> tag with a width and height of 500px:

<!-- Chart.vue -->

<template>
  <section>
    <svg width="500" height="500"></svg>
  </section>
</template>
Angular Directives In-Depth eBook Cover

Free eBook

Directives, simple right? Wrong! On the outside they look simple, but even skilled Angular devs haven’t grasped every concept in this eBook.

  • Green Tick Icon Observables and Async Pipe
  • Green Tick Icon Identity Checking and Performance
  • Green Tick Icon Web Components <ng-template> syntax
  • Green Tick Icon <ng-container> and Observable Composition
  • Green Tick Icon Advanced Rendering Patterns
  • Green Tick Icon Setters and Getters for Styles and Class Bindings

To test our SVG, let’s draw a simple circle there. We can do it with the circle tag with four attributes:

<svg width="500" height="500">
  <circle cx="60" cy="60" r="50" fill="red" />
</svg>

Currently, our SVG looks like this:

Red circle

But it’s still the pure SVG without any kind of D3 magic. Let’s fix this with transforming our circle into a star-shaped figure!

Some math behind the star

So, what do we need to draw a star in terms of geometry? First of all, a star is a radial shape. It means that star is based on a circle and can be created with only two attributes: an angle and a radius. As for radius, it’s easy to see that we will need two radiuses here: for outer and inner circles.

Star with inner and outer radius

What about angles? Let’s connect the circle center with star rays edges and take a look.

Star with outer radiuses

So, if the star has n rays (in our case n = 5), what should be an angle between these rays? As you can see, we’re dividing the circle into 5 equal parts like we would cut a pie on five equal pieces. The circle length is ; so the angle is 2π / n (or, in our case 2π / 5)

Angle between rays

What about points on the inner circle? We need them as well to draw the star correctly. Every point on the inner circle is placed right in the middle between two points on the outer circle. So, the angle between inner and outer points is 2π / 2n (or in our case 2π / 10)

Star with inner points angle

So what is the path for drawing a star? First, we draw the point on an outer circle; then we move for 2π / 10 and draw a point on the inner circle; one more 2π / 10 step and a point on the outer circle, etc.

Let’s try to implement this with D3!

Using D3 lineRadial method to generate the SVG path

First, let’s define our outer radius and a number of rays and place them in Vue component data:

<!-- Chart.vue -->

<template>
  ...
</template>

<script>
  export default {
    data() {
      return {
        outerRadius: 200,
        rays: 5,
      };
    },
  };
</script>

We’re going to set an inner radius to equal 50% of the outer one:

<script>
  export default {
    data() {
      ...
    },
    computed: {
      innerRadius() {
        return this.outerRadius * 0.5
      }
    }
  }
</script>

Now let’s create an array of points to draw the star. We’re going to use the algorithm described in the previous section. First, let’s specify the angle step between two neighbor points:

computed: {
  innerRadius() {
    return this.outerRadius * 0.5
  },
  radialPoints() {
    const step = 2 * Math.PI / (this.rays * 2)
  }
}

Then, we need to create an empty array for points and a for loop to fill it:

radialPoints() {
  const step = 2 * Math.PI / (this.rays * 2)
  const points = [];
  for (let i = 0; i <= this.rays * 2; i++) {
  }
}

As you can see, we will generate a new element of points array for every point on the inner and outer circles, and we have rays * 2 points. For every point, we also need a radius to define if the point lies on the inner circle or the outer one. It’s easy: let’s have every even point on the inner circle and every odd one on the outer circle:

radialPoints() {
  const step = 2 * Math.PI / (this.rays * 2)
  const points = [];
  for (let i = 0; i <= this.rays * 2; i++) {
    const currentRadius = i % 2 ? this.innerRadius : this.outerRadius;
  }
}

Then, we can push a new point to points array and return this array from the computed property:

radialPoints() {
  const step = 2 * Math.PI / (this.rays * 2)
  const points = [];
  for (let i = 0; i <= this.rays * 2; i++) {
    const currentRadius = i % 2 ? this.innerRadius : this.outerRadius;
    points.push([i * step, currentRadius])
  }
  return points;
}

As a result, we will have this array:

[
  [0,300],
  [0.6283185307179586,150],
  [1.2566370614359172,300],
  [1.8849555921538759,150],
  [2.5132741228718345,300],
  [3.141592653589793,150],
  [3.7699111843077517,300],
  [4.39822971502571,150],
  [5.026548245743669,300],
  [5.654866776461628,150],
  [6.283185307179586,300]
]

where first value is an angle from zero-point and second value is a radius.

Now we need somehow to draw this array on our SVG. For this, we need to generate an SVG path and that’s why we need D3 library. It has plenty of magic methods to ‘translate’ different kinds of math calculations to the actual SVG properties.

Right now we need a lineRadial method that takes an array of radial points and produces the SVG path to draw. But first we need to import this method to our Vue component:

<script>
  import { lineRadial } from 'd3-shape';

  export default {
    data() {
      ...
    },
    computed: {
      ...
    }
  }
</script>

And now we can create a computed property to calculate the radial data for SVG path:

radialData() {
  const radialLineGenerator = lineRadial();
  return radialLineGenerator(this.radialPoints);
}

Hooray! The only thing left is to draw this data using the SVG path component. Let’s replace our circle with it:

<template>
  <svg width="500" height="500">
    <path
      class="radial"
      :d="radialData"
      transform="translate(250, 250)"
      fill="green"
    ></path>
  </svg>
</template>

We used transform here to move the center of the star to the 250, 250 coordinate so it’s centered on our SVG background. And now we have a green star!

SVG star

Customizing star rays amount with Vue

What if we want to change the number of rays? Usually, D3.js manipulates DOM in jQuery-way: you would need to select an SVG and to change it’s path element with new data. But with Vue framework, we don’t need this! We can simply change our data properties and Vue will care about re-render process automatically.

Let’s try to change rays property:

data() {
  return {
    outerRadius: 200,
    rays: 8
  }
},

…and you can see the star changed immediately!

8-rays star

Can we make this process more interactive? Why not! Let’s add a range input to our Vue component right below the </svg> closing tag:

<section>
  <svg width="500" height="500">
    ...
  </svg>
  
    Rays
    
  
</section>

We want to limit our star to have 4 rays at minimum and 60 at maximum. Now we can bind this input to Vue rays property with v-model directive:

<input name="rays" type="range" min="4" max="60" v-model="rays" />

That’s it! Now when we change rays amount via input, Vue will re-render the star:

Green star changing

What’s next?

In the next article, we’re going to learn how to scale our data with D3 and how to create our own scales. We will add more properties to our star to look like this:

Star generator

Learn JavaScript the right way.

The most complete guide to learning JavaScript ever built.
Trusted by 82,951 students.

Todd Motto

with Todd Motto

Google Developer Expert icon Google Developer Expert

Related blogs 🚀

Free eBooks:

Angular Directives In-Depth eBook Cover

JavaScript Array Methods eBook Cover

NestJS Build a RESTful CRUD API eBook Cover