Maps with D3 and Svelte
Tags: svelte, javascript
Published: 2021-11-15 07:30:35

> This blog is fourth 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 in the series is a simple map of the world. In this chart Curran actually uses a Topojson file, then converts it into Geojson and then plots it. I am not planning to do that as it seems complicated and also for some reason the [topojson](https://github.com/topojson/topojson) library does not play nice with Node on my computer and I was too lazy to actually debug it 😬. So instead I are going to use a simple geojson I found on [D3 Graph Gallery](https://www.d3-graph-gallery.com/graph/backgroundmap_basic.html).

I am going to start from a fresh Svelte project instead of carrying on from the last. To do and install [d3](https://d3js.org/) along with its:
```bash
npx degit sveltejs/template world-map
cd word-map
npm install
npm install d3
```
And to run the app itself:
```bash
npm run dev
```

Let clean everthing in the App.svelte. The dataset for the map is available [here](https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson). Let's use the [d3 json](https://github.com/d3/d3-fetch/blob/v3.0.1/README.md#json) method to load in the data and use it.
```js
import { json } from  "d3";

let  dataset  =  [];
json("https://raw.githubusercontent.com/holtzy/D3-graph-gallery/master/DATA/world.geojson"
).then((data)  => {
	dataset  =  data.features;
});
```
I am only using the features array in the geojson and this contains everything we need to draw the map. Let's start by making an SVG in the markup and adding a width and height property to it.
```html
<script>
	const  width  =  1200,
	height  =  600;
</script>
<main>
	<svg  {width}  {height}>
	</svg>
</main>
```

If you `console.log` the dataset at this point (and well go deeper and deeper into the json tree) you'll notice that the geojson contains the boundary information using a construct called `geometry`. The only problem with this is that, this construct is not a svg path and is instead of course a co-ordinate you can plot. To solve this problem D3 provides a powerful geographic path generator, [d3.geoPath](https://github.com/d3/d3-geo#geoPath) which can take in a given GeoJSON feature or geometry to generate an SVG path. 

D3 also provides a lot of geographical projections as well to transform how the map looks like. I am going to split out this logic to drawing the paths themeselves into a different component called `Marks`. So let import the new component into `App.svelte` like so:
```js
import Marks from "./Marks.svelte"
```
And pass the dataset to the component like so:
```html
<Marks  {dataset} />
```
Now of course this component does not exist, so lets go about making it real. We'll also import the projections and path generator,
```html
<script>
	import { geoPath, geoNaturalEarth1 } from  "d3";
	export let  dataset  =  [];
	const  projection  =  geoNaturalEarth1();
	const  path  =  geoPath(projection);
</script>
```
Afterwards its really easy. We just need to iterate over the dataset and pass the data to the `path` function:
```html
{#each  dataset  as data}
	<path  d={path(data)} />
{/each}
```
And now we have it, a perfectly horrible world map,
![World map basic](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mi826iwp5rt0v75zkc31.png)
I actually kind of like the stark, edgy nature of the map. I was going to style this, but this is actually rather nice.

So of course the next part will be dedicated to showing off a cool svelte feature I just found. Let first remove all the `fill` colour from the map and add a `stroke`.
```css
<style>
	path {
		fill: none;
		stroke:darkgreen;
	}
</style>
```
![Simple styled world map](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/twelxc4qd1j83obllota.png)
 

Svelte has great support for styling. One thing I like in particular are the [transition directives](https://svelte.dev/tutorial/transition). These are tools for using motion more effectively and gracefully in your app and generally making it look smoother.
Lets import the draw function from `svelte/transitons` and add it to the `path` tag.
```html
<script>
	import { draw } from  "svelte/transition";
</script>
```

```html
<path  transition:draw={{ duration: 5000, delay: 0 }}  d={path(data)} />
```

![Map draw gif ](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/z74vkgtgrjllioun844n.gif)


These transition directives actually pack in a lot of flexibility. We can pass in custom easing function to control the speed of the transition and we can even pass in custom CSS and JS to control the transtitions.
```js
import { quadInOut } from  "svelte/easing";
```
```html
<path
	transition:draw={{ duration: 5000, delay: 0, easing: quadInOut }}
	d={path(data)}
/>
```
![Image description](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fi3oskspth8ittcaixmn.gif)

Personally I think that's just awesome 🚀. Here's the final code.
{% gist https://gist.github.com/AnupJoseph/b4fc9a3eacc006ea5e5e20bb8f2c56d4 %}

Well that's it for today. Hope you have a nice day!