오픈 소스 모험: 에피소드 42: 러시아 인력 손실 예상
39354 단어 svelted3javascript
이것은 다른 종류와 다르게 작동할 것입니다. 현실적으로 인력이 "고갈"될 수 없기 때문에 수백만 명이 사망하더라도 더 많은 훈련을 할 수 있습니다.
App.svelte
두 개의 CSV에서 데이터를 로드하고 병합하도록 수정
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>
store.js
정규 군인인 KIA의 %("분리주의"민병대, PMC, 시리아인, Rosgvardia가 아님)와 KIA 대 WIA 비율(역사적으로 3배이지만 러시아인에게는 더 낮다고 믿을 만한 이유가 있음)을 나타내는 이 두 가지만 추가하면 됩니다. 여기):
export let kiaRegular = writable(80)
export let wiaToKia = writable(250)
SoldierLosses.svelte
많은 작업을 수행하지 않고 올바른 데이터를 조각내고 두 개의 하위 구성 요소를 포함합니다.
<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 />
SoldierForm.svelte
새로운 형식 기능이 있는 WIA 대 KIA 비율의 두 가지 추가 컨트롤만 있으므로
250
는 2.5x
와 같이 표시됩니다.<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>
SoldierLossesGraph.svelte
<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} />
이 구성 요소는 반복되는 계산을 많이 수행하므로 어떻게든 리팩터링해야 합니다.
SoldierGraph.svelte
그리고 우리가 가지고 있는 것을 표시하기 위한 마지막 새 구성 요소는 다음과 같습니다.
<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 Pagesyou can see it here에 배포했습니다.
다음에 온다
다음 몇 편의 에피소드에서는 전쟁을 잠시 쉬고 다른 기술을 살펴보겠습니다.
Reference
이 문제에 관하여(오픈 소스 모험: 에피소드 42: 러시아 인력 손실 예상), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/taw/open-source-adventures-episode-42-projecting-russian-personnel-losses-1j2b텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)