Line Chart with Svelte and D3
Tags: svelte, javascript
Published: 2021-10-20 04:44:09

> This blog is second in a series of (unofficial) course notes for the Data Visualization with React and D3 series by Curran Kelleher. Read the introductory blog post [here](https://dev.to/learners/series-intro-data-visualization-with-svelte-and-d3-4c07).

The next chart type in the course is a line-chart based on San Francisco temperature data, available [here](https://gist.githubusercontent.com/curran/60b40877ef898f19aeb8/raw/9476be5bd15fb15a6d5c733dd79788fb679c9be9/week_temperature_sf.csv). We will use the [scatter plot](https://dev.to/anupjoseph/make-a-scatter-plot-with-svelte-and-d3-56md) code from the last chart [here](https://gist.github.com/AnupJoseph/27a5f91d4a1ae6fae0b51cbe4394debd). Some interesting things about the dataset , its temporal in nature so the chart type must be able to show that change properly.

The `row` function in the last post is note very useful here.  Lets convert the `temperature` column in to numbers. Also one of the columns is a timestamp so let's use the JS `Date` constructor to handle that.
```js
const  row  =  function  (data)  {
	data.temperature  =  +data.temperature;
	data.timestamp  =  new  Date(data.timestamp);
	return data;
};

onMount(async  ()  => {
	dataset  =  await  csv(
"https://gist.githubusercontent.com/curran/60b40877ef898f19aeb8/raw/9476be5bd15fb15a6d5c733dd79788fb679c9be9/week_temperature_sf.csv",
	row).then((data)  => {
		return  data;
	});
});
```

I want to plot temperature on the Y-axis and timestamp on X-axis.Since X-axis is a timestamp we are going to use `scaleTime` from D3. I am going to modify the scales accordingly
```js
$: xScale  =  scaleTime()
	.domain(extent(dataset, (d)  =>  d.timestamp))
	.range([0, innerWidth]);

$: yScale  =  scaleLinear()
	.domain(extent(dataset, (d)  =>  d.temperature))
	.range([innerHeight, 0]);
```
Let's just pass the temperature and timestamp points to these scales in the scatter plot logic we had before. The `Axis` doesn't need to be changed. Let's change the `circle` logic as follows:
```html
<circle
	cx={xScale(data.timestamp)}
	cy={yScale(data.temperature)}
	r="5"
	style="fill:firebrick"
/>
```
![Scatter plot of the timestamps](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qnnwadeu79yhvtahopul.png)
 
Now we just need to connect these points. And it just so happens that D3 has a function to do exactly that. The `line` function in D3 gives a path provided a set of points. We can also specify the `curveNatural` to the line function.
```js
$: line_gen  =  line()
	.curve(curveNatural)
	.x((d)  =>  xScale(d.timestamp))
	.y((d)  =>  yScale(d.temperature))(dataset);
```
Let's add this line as a path element to the svg `<g>` element. And style it as well so that it shows up as a line and not a closed path.
```html
<path  d={line_gen} />
<style>
	path {
		fill: transparent;
		stroke: rgb(18, 153, 90);
	}
</style>
```
![Line chart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1n3h9dqay0hzq4oz81ju.png)
Yeah, I am not a fan of those red dots either. The line probably needs to be a bit thicker as well. Similarly we need to change the format of the ticks in the bottom axis. There are a few other stylistic changes as well and I am going to do them in a single sweep. This is the final chart produced:
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/u0cnb9t9s8bhcpntvuc7.png)

And here's the code for the same:

{% gist https://gist.github.com/AnupJoseph/cf95b2e316352b0542d15860343a802b %}
 
If you want a simple line chart or use a line chart as base for something else, then this is what you probably want. I actually want to go a bit deeper and achieve a sort of hand drawing like effect.

The property we need is `stroke-dasharray` and `stroke-dashoffset`. Think of it like so, instead of drawing a continous path, we are drawing a dashed path. However the dashes themselves are pretty big, as big as the path required for this data or more infact. Okay, rather than reading through that terrible explanation you can read through [Cassie Evans](https://www.cassie.codes/) fantasic, interactive explanation [here](https://www.cassie.codes/posts/creating-my-logo-animation/).

I am setting the `stroke-dasharray` to a nice large number.`stroke-dashoffset` is set to 0.
```css
path {
	fill: transparent;
	stroke: rgb(18, 153, 90);
	stroke-width: 2.5;
	stroke-linejoin: round;
	stroke-dasharray: 4400;
	stroke-dashoffset: 0;
}
```
Visually there's absolutely no difference. However the underlying changes allow us to create the animation. Let's do just that:
```css
path {

	fill: transparent;
	stroke: rgb(18, 153, 90);
	stroke-width: 2.5;
	stroke-linejoin: round;
	stroke-dasharray: 4400;
	stroke-dashoffset: 0;
	animation: draw 8.5s  ease;

}
@keyframes  draw {
	from {
		stroke-dashoffset: 4400;
	}
	to {
		stroke-dashoffset: 0;
	}
}
```
Initially the `stroke-dashoffset` is set at 4400. Hence the dash is outside the SVG  as each dash is of 4400 as well. As the transition continues the dash slowly becomes visible in the SVG viewBox.
![Line Chart](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2wett8krjfsttselkwtx.gif)
 
Now I actually wanted ever so slightly more than this. I wanted to have the circles we had earlier to appear on the path as the line moves ahead. I was unable to recreate the effect perfectly, but the effect is still pleasing so here goes. I am using the `fly` transition from Svelte. Let's modify `circle` accordingly.
```html
<circle
	cx={xScale(data.timestamp)}
	cy={yScale(data.temperature)}
	r="3"
	in:fly={{ duration: 5000, delay: i  *  15 }}
/>
```
And this is the chart produced by adding that code

![Line chart with circles appearing GIF](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xx6uzzsecit1wyofizeq.gif)
 
Beautiful!! I really like the teasing effect of the dots, appearing seeming at once all together yet seperate.

Here's the final code for the chart - 
{% gist https://gist.github.com/AnupJoseph/c01fc809beadf44eec8f01b2e79dc9c3 %}

That's all for today! Have a nice day!