オープンソースの冒険:エピソード42


ロシアの損失アプリは、もう一つのものを必要とします.
これは他の種類とは違って働きます.彼らは現実に「人員を使い果たす」ことができないので、何百万人もの死者がいてももっと訓練することができます.

アプリ。スベルト


我々は2つのCVSからデータをロードして、それらをマージするためにApp.svelteを修正する必要があります.JavaScriptはまだArray.prototype.zipを持っていないので、古いスタイルのループを行います.
<script>
import * as d3 from "d3"
import TankLosses from "./TankLosses.svelte"
import ArmoredLosses from "./ArmoredLosses.svelte"
import ArtilleryLosses from "./ArtilleryLosses.svelte"
import SoldierLosses from "./SoldierLosses.svelte"
import { dataDays } from "./stores"

let parseRow = (row1, row2) => ({
  date: new Date(row1.date),
  tank: +row1.tank,
  apc: +row1.APC,
  art: +row1["field artillery"] + +row1["MRL"],
  kia: +row2.personnel,
})

let loadData = async () => {
  let data1 = await d3.csv("./russia_losses_equipment.csv")
  let data2 = await d3.csv("./russia_losses_personnel.csv")
  let data = [{date: new Date("2022-02-24"), tank: 0, apc: 0, art: 0, kia: 0}]
  for(let i = 0; i < data1.length; i++) {
    data.push(parseRow(data1[i], data2[i]))
  }
  $dataDays = data.length - 1
  return data
}

let dataPromise = loadData()
</script>

{#await dataPromise then data}
  <TankLosses {data} />
  <ArmoredLosses {data} />
  <ArtilleryLosses {data} />
  <SoldierLosses {data} />
{/await}

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

店。js


我々は、これらの2つを追加する必要があります、唯一の正規の兵士であるKiaの%を表す必要があります(それは「分離主義者」民兵、PMCS、シリア人、ロスヴァルジアではなく)、そしてKIAにWIA比(3倍歴史的に、しかし、ここではロシア人にとってより低いと思われる理由があります).
export let kiaRegular = writable(80)
export let wiaToKia = writable(250)

兵士損失。スベルト


これは、ちょうど右のデータをスライスし、2つの子コンポーネントが含まれていません.
<script>
import SoldierForm from "./SoldierForm.svelte"
import SoldierLossesGraph from "./SoldierLossesGraph.svelte"

export let data

let lossData = data.map(({date, kia}) => ({date, unit: kia}))
</script>

<h1>Russian Soldiers Losses</h1>
<SoldierLossesGraph {lossData} />
<SoldierForm />

兵士。スベルト


2つの追加のコントロールがあり、WIAに新しいフォーマット関数を使用しています.
<script>
import Slider from "./Slider.svelte"
import CommonSliders from "./CommonSliders.svelte"
import { kiaRegular, wiaToKia } from "./stores"
</script>

<form>
  <CommonSliders />
  <Slider label="Percentage of KIA that are regular troops" min={50} max={100} value={$kiaRegular} format={(v) => `${v}%`} />
  <Slider label="Wounded to Killed Ratio" min={100} max={1000} value={$wiaToKia} format={(v) => `${v/100.0}x`} />
</form>

<style>
form {
  display: grid;
  grid-template-columns: auto auto auto;
}
</style>

250


<script>
import * as d3 from "d3"
import SoldierGraph from "./SoldierGraph.svelte"
import { lossAdjustment, projectionBasis, wiaToKia, kiaRegular, futureIntensity } from "./stores"

export let lossData

let adjustRow = ({date, unit}, totalLossAdjustment, wiaToKia) => {
  let kia = Math.round(unit * totalLossAdjustment)
  let wia = Math.round(kia * wiaToKia / 100)
  let total = kia + wia
  return {date, kia, wia, total}
}
let adjust = (data, totalLossAdjustment, wiaToKia) => data.map(row => adjustRow(row, totalLossAdjustment, wiaToKia))

let at = (array, idx) => ((idx < 0) ? array[array.length + idx] : array[idx])

let [minDate, maxDate] = d3.extent(lossData, d => d.date)

$: adjustedData = adjust(lossData, ($kiaRegular/100) * (1 + $lossAdjustment / 100.0), $wiaToKia)
$: totalSoFar = d3.max(adjustedData, d => d.total)

$: timeInProjection = at(adjustedData, -$projectionBasis-1).date - at(adjustedData, -1).date
$: kiaInProjection = at(adjustedData, -$projectionBasis-1).kia - at(adjustedData, -1).kia
$: wiaInProjection = at(adjustedData, -$projectionBasis-1).wia - at(adjustedData, -1).wia
$: currentKiaRate = kiaInProjection / timeInProjection
$: currentWiaRate = wiaInProjection / timeInProjection

$: futureKiaRate = (currentKiaRate * $futureIntensity / 100.0)
$: futureWiaRate = (currentWiaRate * $futureIntensity / 100.0)
$: futureTotalRate = futureKiaRate + futureWiaRate

// Just hardcode as there's no obvious "finish date"
$: lastDate = new Date("2023-01-01")

// How many KIA+WIA by lastDate
$: unitsMax = Math.round((lastDate - maxDate) * futureTotalRate) + totalSoFar

$: trendData = [
  adjustedData[0],
  at(adjustedData, -1),
  {
    date: lastDate,
    kia: Math.round((lastDate - maxDate) * futureKiaRate) + d3.max(adjustedData, d => d.kia),
    wia: Math.round((lastDate - maxDate) * futureWiaRate) + d3.max(adjustedData, d => d.wia),
    total: Math.round((lastDate - maxDate) * futureTotalRate) + d3.max(adjustedData, d => d.total),
  },
]

$: xScale = d3.scaleTime()
  .domain([minDate, lastDate])
  .range([0, 700])

$: yScale = d3.scaleLinear()
  .domain([0, unitsMax])
  .nice()
  .range([500, 0])

$: yAxis = d3
  .axisLeft()
  .scale(yScale)

$: xAxis = d3.axisBottom()
  .scale(xScale)
  .tickFormat(d3.timeFormat("%e %b %Y"))

$: kiaData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.kia))
  (adjustedData)

$: wiaData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.wia))
  (adjustedData)

$: totalData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.total))
  (adjustedData)

$: kiaTrendData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.kia))
  (trendData)

$: wiaTrendData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.wia))
  (trendData)

$: totalTrendData = d3.line()
  .x(d => xScale(d.date))
  .y(d => yScale(d.total))
  (trendData)
</script>

<SoldierGraph {xAxis} {yAxis} {kiaData} {wiaData} {totalData} {kiaTrendData} {wiaTrendData} {totalTrendData} />
このコンポーネントは多くの繰り返し計算を行います、そして、多分、私はどうにか、彼らをrefactorしなければなりません.

2.5 x


最後に新しいコンポーネントを表示します.
<script>
import Axis from "./Axis.svelte"
export let xAxis, yAxis, kiaData, wiaData, totalData, kiaTrendData, wiaTrendData, totalTrendData
</script>

<svg viewBox="0 0 800 600">
  <g class="graph">
    <path class="kia" d={kiaData} />
    <path class="wia" d={wiaData} />
    <path class="total" d={totalData} />
    <path class="kia trendline" d={kiaTrendData} />
    <path class="wia trendline" d={wiaTrendData} />
    <path class="total trendline" d={totalTrendData} />
  </g>
  <g class="x-axis"><Axis axis={xAxis}/></g>
  <g class="y-axis"><Axis axis={yAxis}/></g>
</svg>

<style>
svg {
  width: 800px;
  max-width: 100vw;
  display: block;
}
.graph {
  transform: translate(50px, 20px);
}
path {
  fill: none;
  stroke-width: 1.5;
}
path.kia {
  stroke: red;
}
path.wia {
  stroke: green;
}
path.total {
  stroke: blue;
}
path.trendline {
  stroke-dasharray: 3px;
}
.x-axis {
  transform: translate(50px, 520px);
}
.y-axis {
  transform: translate(50px, 20px);
}
</style>

今までの話


All the code is on GitHub .
私は、githubページ(you can see it here)でこれを配備しました.

今度来る


次のいくつかのエピソードでは、戦争からの休憩を取るし、いくつかの他の技術をチェックアウトします.