Whilst you could say that it's possible to draw a zigzag using multiple
rect elements at different positions and rotations, it is certainly an infeasible and inefficient exercise. This is where the SVG
Let's get access to the D3.js library so that we can begin. In this case, we'll be including the library using the HTML
Up until this section, we've been making use of several basic shapes as they are defined in the W3C specification. These include the
ellipse1. In this section, however, we'll look at how we can create custom and complex shape using the SVG
Let's use the creation of a zigzag as an example. Whilst you could say that it's possible to draw a zigzag using multiple
rect elements at different positions and rotations (in the same way that you could draw any image with an unbounded number of
rect elements behaving as pixels), it is certainly an infeasible and inefficient exercise.
This is where the SVG
path element comes in. A path describes an outline of some shape that can be filled and/or stroked. Alternatively, a path could be left without a fill or stroke, so that it can be used to position text or define an animation path.
Paths are drawn as if a pen has been placed on paper at a current point, whereby following instructions move that pen in either lines or curves.
<svg> <path d="M20,60L60,20L100,60L140,20L180,60L220,20" stroke="black" fill="none"></path> </svg>
We can see the output of the above SVG markup is a zigzag pattern. This shape has been specified using the
d (data) property. In this case, we've used a series of moveto (
M) and lineto (
L) commands to construct our shape using coordinates.
We can see that the
fill property has been explicitly set to
"none". Otherwise, the default behaviour would be to fill the shape.
As we can see, this is not the desired output for our zigzag shape.
Let's see how we can create the same complex shape using D3.js.
A Container for the Output
This is where you will see the output of the code cells that follow it, provided they are referencing the corresponding
Creating an Empty SVG
We'll create a new detached
<svg> element and use the returned selection throughout the rest of this section.
const svg = d3.create("svg");
Creating a Complex Shape with Paths
To create the same zigzag as above we need to complete three steps.
- Populate a data structure with our coordinates.
- Construct a line generator with
- Generate a line by passing our populated data structure to the line generator.
Let's get started.
Populating a 2D Array
We'll use a simple 2D array for our data structure, passing in the coordinates that specify our zigzag shape. We'll store this in the
var data = [ [20, 60], [60, 20], [100, 60], [140, 20], [180, 60], [220, 20] ];
Constructing the Line Generator
Next, we'll need to construct our line generator using
d3.line(). We'll store this in the
var lineFun = d3.line();
Generate the Path
Then we'll generate the zigzag line by passing our path data into our line generator, i.e.
lineFun(data). This will be used to set the
d (or data) property of our
To create a
<path> element with D3.js we can invoke the
d3.append(name) function on our
svg selection and pass in the name of the element. We'll also specify the
var line = svg.append("path") .attr("d", lineFun(data)) .attr("stroke", "black") .attr("fill", "none");
Appending to the Container
Finally, let's append everything to our container.
d3 .select("#container") .append(() => svg.node());
We can see the output by checking on our container with the corresponding id, which in this case is where
If we inspect the HTML, we will see the
<path> elements have been added to the
<div> where the
id=container. We can also see that the
d attribute contains the path data that specifies our zigzag. We also have the
stroke set to black, and the
fill set to
<div id="container"> <svg> <path d="M20,60L60,20L100,60L140,20L180,60L220,20" stroke="black" fill="none"></path> </svg> </div>