Adding gridlines

We're going to skip step 5 and use step 6 to get our feet wet with angular math. We'll draw angular grid lines for each month, circular grid lines for temperature, and label both axes.

Project Source Code

Get the project source code below, and follow along with the lesson material.

Download Project Source Code

To set up the project on your local machine, please follow the directions provided in the README.md file. If you run into any issues with running the project source code, then feel free to reach out to the author in the course's Discord channel.

This lesson preview is part of the Fullstack D3 Masterclass course and can be unlocked immediately with a single-time purchase. Already have access to this course? Log in here.

This video is available to students only
Unlock This Course

Get unlimited access to Fullstack D3 Masterclass with a single-time purchase.

Thumbnail for the \newline course Fullstack D3 Masterclass
  • [00:00 - 00:10] So at next we are going to actually draw our peripherals. And if we looked at our chart drawing checklist, we would see that the next step is usually to draw the data.

    [00:11 - 00:17] But we're going to move the six step before. And there's two reasons for this.

    [00:18 - 00:34] One is because we're going to kind of dive into Angular Math and during the grid lines it's kind of a good way to get our feet wet before we dive into drawing data. And the second reason is because we can see that our grid lines are underneath our data elements.

    [00:35 - 00:48] We can see this temperature line is obscuring some of the grid lines. And remember in SVG you can't use the index so the elements are layered based on when they're added to the DOM in that order.

    [00:49 - 00:58] So we can either draw them first or create a group, draw the data, and then add them to that group, which is still layered underneath the data. But let's just do them first.

    [00:59 - 01:17] It makes more sense in this situation. And if it makes you feel a little bit uncomfortable to move these chart steps around, just remember that chart drawing checklist is meant as kind of just a friendly guide if you want to move the steps around or even not do some of the steps.

    [01:18 - 01:26] It's still good. And just use it as a helpful guide and not something you have to follow verbat im.

    [01:27 - 01:41] Alright, so for drawing our peripherals we're going to start with these month spokes that go all the way around the circle. And we already know the first and last state in our data set.

    [01:42 - 01:50] We've used it for the domain of our angle scale. But we don't know how to get a list of every single month between that first and last state.

    [01:51 - 01:56] So I wanted to introduce something to you. D3 has these time intervals.

    [01:57 - 02:04] You can see them here. There's time day, time hour, time month, time week, time year.

    [02:05 - 02:16] And these are here to help you with this kind of thing. So if we wanted every single month in between these two dates we could use time month.range.

    [02:17 - 02:36] And I wanted to log out timemonth in general and you can click through and look at the source code and kind of look at the different methods that they've created for us to use within the D3 source. And we're going to use this dot range function.

    [02:37 - 02:51] And a lot of the other ones are really useful. For example, timemonth.floor will find the first date within the current month.

    [02:52 - 02:56] So that's December 1st. You could also do ceiling with the seals.

    [02:57 - 03:07] So that'll be the last day in this month. I guess it just pops over to the first date in the next month.

    [03:08 - 03:13] So that's January 1st next year. But what we're interested in is range.

    [03:14 - 03:35] So we want to grab every single month in between the first and the last date in our angle scale domain. And remember this is going to return an array.

    [03:36 - 03:49] So we're going to get an array of the first and the last date. And so range once two parameters at once the first date comma the next date and those are two separate parameters.

    [03:50 - 03:57] We're going to use this spread syntax to kind of spread them. So it's the first and second parameter instead of one parameter.

    [03:58 - 04:10] That's an array of two values. So if we do that, now we can see we have every single first day of a month within our date within our data set.

    [04:11 - 04:15] So this is a great start. Let's put this in a variable.

    [04:16 - 04:23] So let's call it months. And then yep.

    [04:24 - 04:26] And now we can use it. So now we want to draw one line for every month.

    [04:27 - 04:40] So let's actually just loop over these. So for every month, we want to draw one line.

    [04:41 - 04:47] So we need to convert the date to an angle. So we already have an angle scale converting a date to an angle.

    [04:48 - 05:02] So we can grab that and create the angle and just pass that month in there. So this should be a value from zero to two pi, which is going to be like six point three.

    [05:03 - 05:07] Let's just double check that. Okay, great.

    [05:08 - 05:24] And then what we want to do with this is append a new line. So let's just create a group here to contain all of our peripherals.

    [05:25 - 05:33] And then append actually we want this outside of our wrapper. So outside of our bounds.

    [05:34 - 05:41] So we're going to append it to our wrapper. And it's just a group element to keep these things organized.

    [05:42 - 05:58] And then here we just want peripherals append a new line element. Okay, great.

    [05:59 - 06:09] So we're not drawing anything. And what we need to do is figure out where this start and the end of each of these lines are given this angle.

    [06:10 - 06:30] So one thing that we can do here, generally we have our bounds shifted by our left and top margin, but we're kind of working in the round. So what might make more sense for this chart is if instead we started our bounds within in the center of the circle and we kind of go around the circle from there.

    [06:31 - 06:55] So we're not needing to shift anything, but and this will make more sense a little bit in the future. So instead of our bounds only shifting by our left and top margin, we're actually going to shift them also by the radius of our circle.

    [06:56 - 07:10] So we're just going to add dimensions that bounded radius. And we're going to add that to the left and add that to the top here.

    [07:11 - 07:27] So again, instead of the bounds looking like this, we're going to shift them and have them look a little bit more like this. So next we need to create a function that'll turn our angle into an x, y coordinate.

    [07:28 - 07:42] So let's create a function up here called get coordinates for angle. And it's going to take in an angle and also an offset.

    [07:43 - 08:04] So the offset is going to be how far away do you want this from the current position. So if our angle is zero degrees and our offset is one, we're going to be returning an x, y position of one zero because it's going to shift over a little bit.

    [08:05 - 08:21] So this will give us an x, y position of the end of our line. So in order to do this, we're going to have to go back to high school trigon ometry.

    [08:22 - 08:37] And we're going to use sine, cosine, and/or tangent. And just as a reminder, in order to get the end of the line, we can draw this triangle and we have the names of the sides of our triangle.

    [08:38 - 08:49] So this top one is the adjacent line. The y one is the opposite from this end of the triangle and the long line is the hypotenuse.

    [08:50 - 09:10] And this is always going to equal the radius of our circle. And basically what we need to do is we have theta, we have the angle, but we need to solve for the adjacent line, which is going to be our x coordinate and the length of our opposite line, which is going to be our y coordinate.

    [09:11 - 09:43] And if we remember, I have a monomic, which is socatoa, socatoa, or you could just look at this diagram, basically, if the one variable we know is the hypotenuse, which is going to be the radius of our circle. So in order to get the opposite, we can multiply the sine of our angle by the radius and we're going to get the length of the opposite side.

    [09:44 - 09:58] And that gives us the y position. And similarly, if we want the length of our adjacent line, which is going to be the x position, we can multiply cosine of our angle by the hypotenuse to get that adjacent length.

    [09:59 - 10:15] So let's take all of that math and put it into practice. So in order to get the x position, and this is just going to return an array, so x will come first, and x is going to be adjacent.

    [10:16 - 10:45] So what we need to do is grab the cosine of the angle and multiply it by our radius. So we're just going to multiply that by the offset because it's going to return .

    [10:46 - 11:09] Yep, so that'll just extend it out however many pixels that we need. So if we didn't multiply it by the offset, it would just return something that was one pixel away, assuming that our radius, or one radius away, actually.

    [11:10 - 11:22] And instead, our offset is in terms of the length of the radius. So this is if offset is one, it's going to be one radius away, so at the end of our circle.

    [11:23 - 11:35] And then we basically want to do the exact same thing for sine, which will give us the y position of our point. So here, let's just make sure this makes any sense at all.

    [11:36 - 11:59] So we're going to log out the coordinates for an angle, we're going to use our angle, and then let offset just be one. So for every month, this is returning an xy position, and we can see because the x goes to negative and the y also goes to negative, it's going all the way around our circle.

    [12:00 - 12:10] One thing we're going to want to change is by default, this starts at the top. So with zero radians, we're moving the dot up.

    [12:11 - 12:23] But what's going to make more sense for our chart is if it starts at the right. So let's go ahead and rotate this by a quarter turn.

    [12:24 - 12:40] So here, let's just subtract a quarter turn, so in radians, that's math pi divided by two. So math, math pi divided by two.

    [12:41 - 12:50] And let's do that for our y as well. Okay, great.

    [12:51 - 12:58] So how do we use this? So for drawing our lines, we're going to get the x and y position for the end of our line.

    [12:59 - 13:10] So and we can just do structure it right here. So we're not creating a variable and then grabbing the first and second value, we're just grabbing x and y directly.

    [13:11 - 13:24] And we're going to set the, because our line is going to start at zero zero, since they all start at the center. We only need to set the x two and y two values.

    [13:25 - 13:31] So here is y two, here's x two. And we're not seeing it still.

    [13:32 - 13:41] And that's because we need to change the styling. So let's go ahead and give it a class.

    [13:42 - 13:50] Name it grid line. And then in our CSS file, let's go ahead and find that.

    [13:51 - 14:02] Here we go. Let's add grid line and then set this stroke to this nice gray.

    [14:03 - 14:15] But go ahead and use any gray that you like, just something that's a little bit muted. So we're not detracting from the rest of the chart.

    [14:16 - 14:23] Okay, so we're seeing our spokes, but they're in the wrong place. Let's double check that we're doing the right thing.

    [14:24 - 14:32] Right. So what we want instead is for peripherals to sit within our bounds.

    [14:33 - 14:39] Yeah, let's go ahead and instead of appending them. So the refer, we're going to append them to our bounds.

    [14:40 - 14:43] And there we go. Now they're straight in the center of our chart.

    [14:44 - 14:54] And we have 12 spokes going out for each one of the months. So next we have our spokes, but we want to add a text label to each of these.

    [14:55 - 15:14] So let's go ahead and add text for each one of these. So underneath next after our lines, we want to add some text, but we don't want it to sit right on top of that end of our spokes.

    [15:15 - 15:28] Let's instead have it move a little bit farther away. In practice, I've found that it's about one and a third length of the radius away from the center of the chart.

    [15:29 - 15:35] So it's complaining because we're using the same variable name. So label X and label Y.

    [15:36 - 15:59] And we basically want to do the same thing as these lines. But instead append text and we're going to add the text, just so we can see it.

    [16:00 - 16:13] And we can use d3.time format and just use, I think it's B, we will see very soon. And then past the month, the JavaScript date time in.

    [16:14 - 16:20] So in order to see these, we're going to need to do something very similar that we did to our line with text. It's X and Y.

    [16:21 - 16:31] And we want to set them at label X and label Y. There we go.

    [16:32 - 16:50] And I think in our final, we're using this shortened names just to keep the text really concise. So one thing that you might notice here is our October label is sitting closer to the line than our April label.

    [16:51 - 17:03] And that's because all of our text by default is positioned by the left edge. So the points are always going to line up with the left edge of our text.

    [17:04 - 17:19] And we can see, especially with January and July, they're not sitting in the middle. So what we actually need to do is set the text anchor.

    [17:20 - 17:27] And it's not going to be the same for all of them. Having it positioned with the start makes sense for labels on the right.

    [17:28 - 17:51] But we want to use N for the labels on the left and the middle for the labels kind of closer to the middle. So we can, based on the X position over a label, let's just say if it's less than five, then we want it in the middle.

    [17:52 - 18:09] Otherwise if it's on the right side, we want it positioned with start. And otherwise we want to position it with the end.

    [18:10 - 18:22] And the other thing we do is make this an absolute value. So we're setting them in the middle no matter if they're on the right or the left side of the center, just if they're within five pixels.

    [18:23 - 18:35] So we can use math.abs, which we'll just use the absolute value. Let's just line these up so it's a little bit easier to read.

    [18:36 - 18:48] So here we can see October is just as far away as April and January and July are centered with the center of our chart. They're also a little bit vertically uncentered.

    [18:49 - 19:02] So if we give these class name, let's give them a name of a cryptic label. I think that's a great name.

    [19:03 - 19:20] And then if we go over to our CSS file, just to keep our styles in one place, let's first set the dominant baseline to middle. And this will scooch them down a little bit so they're vertically centered with our spokes.

    [19:21 - 19:28] And then let's style them a little bit differently. So let's fade them.

    [19:29 - 19:35] We have this hex value if you want to fall along. Otherwise just do your own thing.

    [19:36 - 19:50] One size, let's just bump the font down a little bit so they're not so large but still readable. They're looking a little bit a new mix.

    [19:51 - 20:06] So let's bump the weight up a little bit. And then scooch them a little bit further away.

    [20:07 - 20:15] You know, let's bump down the weight a little bit. This is a bit much, maybe 700.

    [20:16 - 20:21] 600? Yeah, I like that.

    [20:22 - 20:28] Okay, great. So now we have our spokes for every single month.

    [20:29 - 20:45] And next we want to add the rings radiating out from the center that show the temperature of our area right here for the minimum and maximum temperature. And in order to do that, we need a radius scale.

    [20:46 - 21:01] So going from the center all the way to the outside of this ring, we need this to go from our lowest temperature to our highest temperature. So this temperature area will have some place to sit.

    [21:02 - 21:12] So next after angle sail, we're going to make a radius scale. And then that's just going to be a linear scale.

    [21:13 - 21:27] We want to domain and arrange. And basically for the domain, we want the extent for both the temperature min and temperature max values.

    [21:28 - 21:49] So we can still use extent, but we're going to need an array of both those minimums and the maximum values just so we make sure we're handling all of those. So we can map over the data set and use our temperature min accessor.

    [21:50 - 22:00] So those will give us an array of all the minimum temperatures. And let's do the same thing for our maximum temperatures.

    [22:01 - 22:08] So let's actually log this out to make sure this is making any sense. Okay, great.

    [22:09 - 22:19] That makes more sense. So in New York City, over a year, the lowest temperature was like 3.6 and the highest was about 94.

    [22:20 - 22:28] And then for the range, we want this to go from the center of our chart all the way to the outside. So the center is going to be zero.

    [22:29 - 22:38] And we want it all the way out to the end. So let's use bounded radius.

    [22:39 - 22:44] Okay, great. So now we can use our radius scale.

    [22:45 - 22:59] We go all the way back down here. We're going to want to draw a ring for every tick within our radius scale.

    [23:00 - 23:11] All right, let's go ahead and do that. So let's get our ticks first to temperature ticks.

    [23:12 - 23:16] That word is starting to look really weird. Radius scale.

    [23:17 - 23:22] And then let's just let's grab some ticks. And it usually gives back around 10.

    [23:23 - 23:29] So let's specify four. Just we're not getting overwhelmed here.

    [23:30 - 23:38] So let's log that out. And this should be an array of about four temperatures.

    [23:39 - 23:49] That's great. And then what we need to do is we need to draw a ring for each of these.

    [23:50 - 23:58] Yeah, let's go ahead and try that. So let's just name them grid circles.

    [23:59 - 24:07] And then we're going to map over each one of these ticks. We could use a data bind here.

    [24:08 - 24:14] We're probably never going to update this. So I might just use a map just to keep these simple.

    [24:15 - 24:26] And then here for every tick, we're going to add a circle to our peripherals group. A pen circle.

    [24:27 - 24:34] The radius is going to be our radius scale for that temperature. So attribute radius.

    [24:35 - 24:41] And we're going to use our scale. We're going to use that temperature, which we have under D.

    [24:42 - 25:00] And then because by default, our elements are going to be filled with black, we 're going to go ahead and give it a class name so we can add some CSS styles. Gridline.

    [25:01 - 25:08] So over here, we already have a gridline CSS style. Let's just set the fill to none.

    [25:09 - 25:17] Okay, great. So now we're seeing all of these rings around here.

    [25:18 - 25:28] It looks like our final chart goes all the way to the outside. Let's see.

    [25:29 - 25:42] Maybe what we want to do is add nice to our scale, which will end it on a round er value so that our ticks will return that last value. Okay, great.

    [25:43 - 25:55] So now it's ending probably around 100. And we're getting a nice ring around the outside that kind of covers the end of those spokes.

    [25:56 - 26:03] So the next thing we want to do is we want to add labels. And this should be the last step for creating these gridlines.

    [26:04 - 26:28] I know this has been a bit more work than we've done with our peripherals in the past, but that's because it's a little bit more custom. All right, so after we draw these circles, let's kind of do the same thing, but they're going to be called grid labels.

    [26:29 - 26:45] And then in here, we're going to say we're going to add a text instead of a circle. So the labels depend text.

    [26:46 - 27:00] And how are we going to get the position of this? So for our text, let's return the radius scale for, right.

    [27:01 - 27:17] So what we're going to do for this chart is we're going to have them march all the way up this vertical spoke a little bit to the right. And so we're going to want the Y position to line up with that temperature.

    [27:18 - 27:29] So we're going to use radius scale for that temperature. And let's go ahead and add some text so we can see this.

    [27:30 - 27:42] What we're going to do is we're going to use HTML because we want to add that degree simple. So and first we want the temperature.

    [27:43 - 28:01] So here we can just do D for now and then degrees Fahrenheit. Sometimes depending on what the weather set is, you might need to format this number and there might be a decimal that goes on really long.

    [28:02 - 28:18] So we can use D for that to make sure that it doesn't have any decimals because those are just going to be distracting. Another thing I can do here is offset them a little bit horizontally.

    [28:19 - 28:35] So X let's just switch them over about four pixels and then for the radius. Let's maybe switch them down about two pixels.

    [28:36 - 28:40] And then we're really going to want some styles here. So let's give them a class.

    [28:41 - 28:47] Let's name it tick label temperature. There we go.

    [28:48 - 28:58] And then one other thing I wanted to do, you'll see in this finished one that there's no label for zero. It's just kind of cluttering it up.

    [28:59 - 29:13] So what we can do here is we can say if we don't even do D's less than one return and don't draw anything. So then we're not getting that zero label here.

    [29:14 - 29:19] All right. So what we can do is we can go over to our CSS file.

    [29:20 - 29:28] We're going to add and use CSS rule. And let's grab this same fill.

    [29:29 - 29:40] We also want them to be centered vertically with that spoke. Just scooch their opacity down a little bit.

    [29:41 - 29:57] And this is, I don't know, I just like that color and I don't want to go find it. And let's also make their font size match the labels around the outside.

    [29:58 - 30:13] All right. So one difference that we're going to see is that for these labels, it seems like that ring stops and then starts right after the label.

    [30:14 - 30:20] It's kind of a trick. We're using background rectangles to sit below the text but above those circles .

    [30:21 - 30:29] So you're not getting this collision with the text and the line. It makes these a little bit harder to read.

    [30:30 - 30:48] So what we can do is we can go back to our JavaScript code and we're going to, before we draw the labels, draw these rectangles. Maybe let's just copy and paste this real quick.

    [30:49 - 31:08] And we'll call them tick label backgrounds. And then close up that loop and we're going to append a rectangle instead of text.

    [31:09 - 31:14] We're going to want it to sit a little bit above the text. So maybe minus 10.

    [31:15 - 31:19] The X can probably be at zero. So we can just take this out because that's the default.

    [31:20 - 31:33] We're going to need to set the width and the height. So the width is, it's pretty hard to know how long a text string is with SVG elements or even HTML for that matter.

    [31:34 - 31:40] Let's just go with 40 and then it seems like these are all around the same width. So it should work.

    [31:41 - 31:46] And then let's give them a height, maybe around 20 pixels. That looks good.

    [31:47 - 31:55] It just covers this longest one up here. So let's also just give it a fill.

    [31:56 - 32:15] And I think the, I don't think the background is quite white, but instead it's this F8, F9, there we go. So now it kind of looks like our rings stop and start right after our text.

    [32:16 - 32:43] And it's just a really nice way to make those labels readable but not have them be too intrusive. One other thing I wanted to do before I moved on to things that might be a little bit more complicated is we can create these utility functions that get X or Y position from a data point.

    [32:44 - 32:53] Let's just throw them up here. So let's me get X from data point.

    [32:54 - 33:22] It's going to take a data point and also an offset. And basically that's going to use this get coordinates from angle function and return.

    [33:23 - 33:43] Okay, the first element. So for this one we're going to use the angle scale and pass it the date access or for this date.

    [33:44 - 33:54] And we also went up through the offset in here as well. Just make this a little bit easier to read.

    [33:55 - 34:02] So what we're doing here is we're taking one data point. We're turning it into a date.

    [34:03 - 34:07] And then we're turning that date into the angle. So now we know what angle around the circle we are.

    [34:08 - 34:22] And then we're going to grab the coordinates for that angle and return the first part of that coordinate which is going to be the X value. And we're also going to do that for the Y position.

    [34:23 - 34:45] There's going to be the first one here. And this is just setting us up to work a little bit more quickly when we do get to that data point and are either adding annotations or if we want to draw anything else on this chart.

    [34:46 - 34:53] All right, so up next, I know this was really long but up next we could say actually start drawing data elements which is really exciting.