Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
April 7, 2022 12:30 am GMT

Open Source Adventures: Episode 32: Better Russian Tank Losses Graphs with D3 and Svelte

Before we answer the question when Russian will run out of tanks, let's refactor and improve our code a bit.

We want to achieve the following:

  • put awkward axis code in separate component
  • extend tank axis slightly so it ends up on a round number
  • change ticks on date axis, so they start on Feb 24
  • add trend line for overall data
  • reduce dead space around the graph

src/Axis.svelte

This component doesn't do any logic, it just bridges D3 DOM manipulation with Svelte, so we have less awkward code in the main component:

<script>import * as d3 from "d3"export let axislet axisNode$: {  d3.select(axisNode).selectAll("*").remove()  d3.select(axisNode).call(axis)}</script><g bind:this={axisNode}></g>

Rounded numbers on Y scale

We don't need any special code for this, as D3 already comes with a convenient .nice() function that pads domain on both sides to nearest round number. As 0 is already as round as it gets, it will only pad a bit on the top, in this case to 700:

let yScale = d3.scaleLinear()  .domain(d3.extent(data, d => d.tank))  .nice()  .range([500, 0])

Date formatting on X scale

This is a bit more complicated. The scale is fine, and we do not want to pad it with extra days. It should start Feb 24, and end at the last day we have data for.

We can solve that by manually telling D3 where to place ticks (with .ticks(d3.timeThursday) - as Feb 24 is Thursday), and then how to format them (with .tickFormat(d3.timeFormat("%d %b")))

This isn't perfect, as today doesn't have its own tick, but it will do for now.

let xAxis = d3.axisBottom()  .scale(xScale)  .ticks(d3.timeThursday)  .tickFormat(d3.timeFormat("%b %d"))

Trend line

Nothing fancy here, just connect first and last datapoint with dashed line.

let trendPathData = d3.line()  .x(d => xScale(d.date))  .y(d => yScale(d.tank))  ([data[0], data.at(-1)])

src/Graph.svelte

And here's the complete src/Graph.svelte. All other files are unchanged from previous episode:

<script>import * as d3 from "d3"import Axis from "./Axis.svelte"export let datalet xScale = d3.scaleTime()  .domain(d3.extent(data, d => d.date))  .range([0, 700])let yScale = d3.scaleLinear()  .domain(d3.extent(data, d => d.tank))  .nice()  .range([500, 0])let pathData = d3.line()  .x(d => xScale(d.date))  .y(d => yScale(d.tank))  (data)let trendPathData = d3.line()  .x(d => xScale(d.date))  .y(d => yScale(d.tank))  ([data[0], data.at(-1)])let xAxis = d3.axisBottom()  .scale(xScale)  .ticks(d3.timeThursday)  .tickFormat(d3.timeFormat("%b %d"))let yAxis = d3  .axisLeft()  .scale(yScale)</script><h1>Russian Tank Losses</h1><svg>  <g class="graph"><path d={pathData}/></g>  <g class="trendline"><path d={trendPathData}/></g>  <g class="x-axis"><Axis axis={xAxis}/></g>  <g class="y-axis"><Axis axis={yAxis}/></g></svg><style>svg {  height: 600px;  width: 800px;}.graph {  transform: translate(50px, 20px);}.graph path {  fill: none;  stroke: red;  stroke-width: 1.5;}.trendline {  transform: translate(50px, 20px);}.trendline path {  fill: none;  stroke: red;  stroke-width: 1.5;  stroke-dasharray: 3px;}.x-axis {  transform: translate(50px, 520px);}.y-axis {  transform: translate(50px, 20px);}</style>

Story so far

All the code is on GitHub.

I deployed this on GitHub Pages, you can see it here.

Coming next

In the next episode, we'll add some functionality to the app. The end goal is to try to figure out how long until Russia runs out of tanks, but that might take longer than an episode.


Original Link: https://dev.to/taw/open-source-adventures-episode-32-better-russian-tank-losses-graphs-with-d3-and-svelte-mci

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To