오픈 소스 모험: 에피소드 31: D3 및 Svelte를 사용하여 러시아 탱크 손실 시각화

14829 단어 javascriptsvelted3
이전 두 에피소드에서 나는 툴링 없이 동일한 D3 앱을 만든 다음 Parcel을 사용했습니다. 다시 해봅시다. 하지만 Svelte를 사용하고 D3는 DOM 조작이 아닌 데이터 크런칭에만 사용합니다.

D3는 여전히 그래프에 축과 선을 그리는 것과 같은 인터페이스의 일부를 수행하지만 해당 데이터를 Svelte에 전달한 다음 DOM 변경을 수행합니다.

새 Svelte 앱 만들기



Svelte 및 D3로 앱을 시작하려면 다음을 수행할 수 있습니다.

$ npx degit sveltejs/template myapp
$ cd myapp
$ npm install d3


여기에는 그다지 신경쓰지 않는 몇 가지 추가 항목이 포함되어 있으므로 관련 없는 파일을 많이 삭제하고 불쾌한 세미콜론을 제거하여 남은 구문을 정리했습니다.

공개/index.html



이것은 약간의 정리와 함께 상용구에서 나온 것입니다. 가장 중요한 부분은 GitHub 페이지에서 작동하도록 절대 URL에서 상대 URL로 전환하는 것입니다.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <link rel="stylesheet" href="./build/bundle.css">
  <script defer src="./build/bundle.js"></script>
</head>
<body>
</body>
</html>


src/main.js



이것은 약간의 정리와 함께 상용구에서 나온 것입니다.

import App from "./App.svelte"

let app = new App({target: document.body})

export default app


src/App.svelte



이 구성 요소는 데이터를 로드한 다음 실제 그래프 그리기 코드를 호출하는 역할을 합니다.

또한 일부 전역 스타일링을 수행합니다. 이것은 틀림없이 별도의 정적 CSS 파일에 넣을 수 있습니다.

<script>
import * as d3 from "d3"
import Graph from "./Graph.svelte"

let parseRow = ({date,tank}) => ({date: new Date(date), tank: +tank})

let loadData = async () => {
    let url = "./russia_losses_equipment.csv"
    let data = await d3.csv(url, parseRow)
    data.unshift({date: new Date("2022-02-24"), tank: 0})
    return data
}

let dataPromise = loadData()
</script>

{#await dataPromise then data}
    <Graph {data} />
{/await}

<style>
:global(body) {
    margin: 0;
    min-height: 100vh;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
}
</style>


src/Graph.svelte



마지막으로 주요 구성 요소:

<script>
import * as d3 from "d3"

export let data

let xScale = d3.scaleTime()
    .domain(d3.extent(data, d => d.date))
    .range([0, 600])

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

let pathData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.tank))
  (data)

let xAxis, yAxis

$: {
  d3.select(xAxis).selectAll("*").remove()
  d3.select(xAxis).call(d3.axisBottom(xScale))
}
$: {
  d3.select(yAxis).selectAll("*").remove()
  d3.select(yAxis).call(d3.axisLeft(yScale))
}
</script>

<h1>Russian Tank Losses</h1>
<svg>
  <g class="graph">
    <path d={pathData}/>
  </g>
  <g class="x-axis" bind:this={xAxis}></g>
  <g class="y-axis" bind:this={yAxis}></g>
</svg>

<style>
svg {
  height: 600px;
  width: 800px;
}
.graph {
  transform: translate(100px, 100px);
}
path {
  fill: none;
  stroke: red;
  stroke-width: 1.5;
}
.x-axis {
  transform: translate(100px, 500px);
}
.y-axis {
  transform: translate(100px, 100px);
}
</style>


여기에는 많은 일이 있습니다.
  • async 항목을 처리할 필요가 없습니다. data가 이미 적절하게 준비되어 있고 표시하기만 하면 됩니다
  • .
  • 이전과 마찬가지로 스케일을 생성합니다. 여기서는 Svelte와 관련된 것이 없습니다
  • .
  • 선 그래프는 D3 부분을 Svelte 부분과 잘 구분합니다. 구문은 d3.line().x(d => xScale(d.date)).y(d => yScale(d.tank)) 로 함수를 구성한 다음 (data) 로 호출하기 때문에 매우 이례적입니다. 그런 다음 이 데이터를 <path d={pathData}/>에 전달합니다.
  • CSS를 사용하여 모든 정적 시각적 속성을 처리할 수 있습니다
  • .
  • 축이 어색합니다. 각 축은 SVG 요소가 많기 때문에 D3는 여기에서 약간의 DOM 액세스가 필요합니다. Svelte는 이것으로 상당히 유연하지만 이 난장판을 <Axis position="bottom" scale={xScale} x=100 y=500 />와 같은 별도의 구성 요소로 옮기는 것이 더 나을 수 있습니다.

  • 지금까지의 이야기



    All the code is on GitHub .

    저는 이것을 GitHub Pagesyou can see it here에 배포했습니다.

    다음에 온다



    다음 에피소드에서는 앱에 몇 가지 기능을 추가하겠습니다. 최종 목표는 러시아가 탱크가 바닥날 때까지 얼마나 걸릴지 알아내는 것이지만, 에피소드보다 오래 걸릴 수 있습니다.

    좋은 웹페이지 즐겨찾기