Creating data visualizations in modern web apps often requires both flexibility and reactivity. Vue.js, a progressive JavaScript framework, is excellent for managing reactive UIs, while D3.js is one of the most powerful libraries for data-driven document manipulation and visualization.
In this guide, we’ll explore how to combine Vue and D3 to build dynamic, interactive charts.
Enjoy!
🤔 Why using D3 for Vue?
Vue handles the DOM reactively using a component-based structure, which is great for app state management. D3, on the other hand, directly manipulates the DOM to render SVG elements based on data. While that might seem like a conflict, with proper structure, they can complement each other well:
- Vue manages application state and layout.
- D3 handles drawing and updating the visualization.
Check examples of data visualization with D3.
🟢 Building a basic chart component
Let's create a simple bar chart component.
1.Create a new file BarChart.vue
:
<template>
<svg ref="svg"></svg>
</template>
<script setup>
import { onMounted, ref, watch } from 'vue'
import * as d3 from 'd3'
const props = defineProps({
data: {
type: Array,
required: true
},
width: {
type: Number,
default: 400
},
height: {
type: Number,
default: 200
}
})
const svg = ref(null)
const drawChart = () => {
const svgEl = d3.select(svg.value)
svgEl.selectAll('*').remove() // Clear previous renders
svgEl.attr('width', props.width).attr('height', props.height)
const x = d3
.scaleBand()
.domain(props.data.map((d, i) => i))
.range([0, props.width])
.padding(0.1)
const y = d3
.scaleLinear()
.domain([0, d3.max(props.data)])
.nice()
.range([props.height, 0])
svgEl
.selectAll('rect')
.data(props.data)
.join('rect')
.attr('x', (_, i) => x(i))
.attr('y', d => y(d))
.attr('width', x.bandwidth())
.attr('height', d => props.height - y(d))
.attr('fill', 'steelblue')
}
onMounted(drawChart)
watch(() => props.data, drawChart)
</script>
Let's stop for a second here to explain each part of the drawChart
method:
const drawChart = () => {
const svgEl = d3.select(svg.value)
svgEl.selectAll('*').remove() // Clear previous renders
-
d3.select(svg.value)
: Selects the actual<svg>
element from the DOM. -
selectAll('*').remove()
: Clears any previously drawn chart elements to avoid overlap when re-rendering.
svgEl.attr('width', props.width).attr('height', props.height)
- Sets the SVG canvas dimensions.
const x = d3
.scaleBand()
.domain(props.data.map((d, i) => i))
.range([0, props.width])
.padding(0.1)
-
d3.scaleBand()
: Creates a scale for discrete bands (bars). -
domain
: Maps indices of data to bands. -
range
: Spans the scale from 0 to the total width. -
padding(0.1)
: Adds spacing between bars.
const y = d3
.scaleLinear()
.domain([0, d3.max(props.data)])
.nice()
.range([props.height, 0])
-
d3.scaleLinear()
: Linear scale for bar heights. -
domain
: Goes from 0 to the max value in the data. -
nice()
: Rounds the domain to nice round numbers. -
range
: From SVG height (bottom) to 0 (top) because SVG Y-coordinates increase downward.
svgEl
.selectAll('rect')
.data(props.data)
.join('rect')
.attr('x', (_, i) => x(i))
.attr('y', d => y(d))
.attr('width', x.bandwidth())
.attr('height', d => props.height - y(d))
.attr('fill', 'steelblue')
-
.selectAll('rect')
: Prepares to bind data to<rect>
elements (bars). -
.data(props.data)
: Binds the array of values. -
.join('rect')
: Efficiently adds/removes<rect>
elements as needed. -
.attr('x', ...)
: Sets the x-position for each bar. -
.attr('y', ...)
: Sets the y-position (top) of each bar. -
.attr('width', ...)
: Sets bar width based on the scale’s bandwidth. -
.attr('height', ...)
: Calculates bar height from value. -
.attr('fill', ...)
: Sets bar color.
2.Use the BarChart component in your main app file:
<template>
<div>
<BarChart :data="chartData" />
</div>
</template>
<script setup>
import { ref } from 'vue'
import BarChart from './components/BarChart.vue'
const chartData = ref([10, 15, 20, 25, 30])
</script>
The chart should look more or less like this:
To scale up your Vue and D3 app, make sure to utilize following approaches:
- Encapsulate D3 logic in composables if complexity grows.
- Use transitions from D3 for smooth updates.
- Consider watching window size to make charts responsive.
- For advanced use cases, look into D3 modules like
d3-axis
,d3-shape
, andd3-brush
.
📖 Learn more
If you would like to learn more about Vue, Nuxt, JavaScript or other useful technologies, checkout VueSchool by clicking this link or by clicking the image below:
It covers most important concepts while building modern Vue or Nuxt applications that can help you in your daily work or side projects 😉
✅ Summary
By combining Vue’s reactive data handling with D3’s powerful visualization tools, you can build highly interactive, performant data visualizations. This approach is perfect for dashboards, real-time analytics, and more.
Take care and see you next time!
And happy coding as always 🖥️
Top comments (0)