Categories
Vue and D3

Adding Graphics to a Vue App with D3 — Selections and Scales

Spread the love

D3 lets us add graphics to a front-end web app easily.

Vue is a popular front end web framework.

They work great together. In this article, we’ll look at how to add graphics to a Vue app with D3.

Find Elements in Selections

We can find elements in selections.

For example, we can write:

<template>
  <div id="app">
    <div>
      <b>apple</b>
      <b>orange</b>
      <b>grape</b>
    </div>
  </div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      let selection = d3.selectAll("b").filter(":nth-child(odd)").nodes();
      selection.forEach((e) => {
        console.log(e.textContent);
      });
    });
  },
};
</script>

to get all the b elements and filter them to get all the even index ones.

Then we call forEach to get their text content.

We can call the filter with the d3.matcher method.

For instance, we can write:

<template>
  <div id="app">
    <div></div>
    <div>
      <h5>This is text1</h5>
      <h5>This is text2</h5>
      <h5>This is text3</h5>
      <h5>This is text4</h5>
    </div>
  </div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      const heading = d3.selectAll("h5");
      const matcher = heading.filter(d3.matcher("h5")).node();
      const filter = heading.filter(d3.matcher("h5")).node();
      console.log(matcher);
      console.log(filter);
    });
  },
};
</script>

to get the h5 elements with the matcher method to get the h5 element.

We can call d3.creator to create an element.

For instance, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      const selection = d3.select("body");
      selection.append(d3.creator("div"));
      const div = document.querySelector("div");
      div.innerText = "hello world.";
    });
  },
};
</script>

The d3.creator method creates a div.

Then we get the div with querySelector and set the innerText property to add text content to it.

Paths API

We can add a shape with the paths API.

For example, we can write:

<template>
  <div id="app">
    <svg width="600" height="100">
      <path transform="translate(20, 0)" />
    </svg>
  </div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      const data = [
        [0, 12],
        [50, 20],
        [100, 30],
        [200, 40],
        [300, 90],
      ];
      const lineGenerator = d3.line();
      const pathString = lineGenerator(data);
      d3.select("path").attr("d", pathString);
    });
  },
};
</script>

<style>
path {
  fill: green;
  stroke: #aaa;
}
</style>

We create the svg element.

Then we create the line with the d3.line method.

And then we pass in the data into the returned lineGenerator function.

Then we pass in the returned pathString into the attr method so set the SVG’s path.

Scales API

We can use the scales API to transform data in various ways.

For example, we can write:

<template>
  <div id="app"></div>
</template>
<script>
import * as d3 from "d3";
import Vue from "vue";

export default {
  name: "App",
  mounted() {
    Vue.nextTick(() => {
      const data = [100, 220, 330, 350, 400, 250];
      const width = 500,
        barHeight = 20,
        margin = 1;

      const scale = d3
        .scaleLinear()
        .domain([d3.min(data), d3.max(data)])
        .range([100, 400]);

     const svg = d3
        .select("body")
        .append("svg")
        .attr("width", width)
        .attr("height", barHeight * data.length);

     const g = svg
        .selectAll("g")
        .data(data)
        .enter()
        .append("g")
        .attr("transform", function (d, i) {
          return `translate(0, ${i * barHeight})`;
        });

      g.append("rect")
        .attr("width", function (d) {
          return scale(d);
        })
        .attr("height", barHeight - margin);

      g.append("text")
        .attr("x", function (d) {
          return scale(d);
        })
        .attr("y", barHeight / 2)
        .attr("dy", ".35em")
        .text(function (d) {
          return d;
        });
    });
  },
};
</script>

We have the data to display as bars.

And we have the width for the chart’s width.

barHeight has the bars’ height.

We create the scale object to scale the bars with:

const scale = d3
  .scaleLinear()
  .domain([d3.min(data), d3.max(data)])
  .range([100, 400]);

The scaleLinear method creates a continuous linear scale where we can map input data to the specified output range.

Then we add the SVG for the chart to the body with:

const svg = d3
  .select("body")
  .append("svg")
  .attr("width", width)
  .attr("height", barHeight * data.length);

Next, we add the bar group by writing:

const g = svg
  .selectAll("g")
  .data(data)
  .enter()
  .append("g")
  .attr("transform", function(d, i) {
    return `translate(0, ${i * barHeight})`;
  });

Then we set the widths of the bars by writing:

g.append("rect")
  .attr("width", function(d) {
    return scale(d);
  })
  .attr("height", barHeight - margin);

Then we set the bars to the length given by the data by writing:

g.append("text")
  .attr("x", function(d) {
    return scale(d);
  })
  .attr("y", barHeight / 2)
  .attr("dy", ".35em")
  .text(function(d) {
    return d;
  });

Conclusion

We can select items and create scales with D3.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *