오픈 소스 모험: 에피소드 51: 러시아 손실 앱 연마

29175 단어 javascriptsvelted3
주로 내 앱에 대한 몇 가지 피드백이 있습니다.
  • "Projection basis in days"의 의미가 명확하지 않아 "지난 N일에서 추정"으로 대체했습니다
  • .
  • 인원 손실 그래프가 무엇을 의미하는지 명확하지 않음, 설명이 없는 3가지 색상이 있음(KIA, WIA, 합계)

  • 나는 또한 더 많은 일을하고 싶습니다 :
  • 소스 정보가 있는 바닥글을 추가합니다
  • .
  • 연말 예상 인적 손실 요약 추가
  • 슬라이더가 갈 수 있는 최소/최대를 약간 조정(기본값은 동일하게 유지될 수 있음)

  • 그럼 시작하겠습니다!

    바닥글.svelte



    정적 HTML 일뿐입니다.

    <footer>
      Initial forces from <a href="https://www.iiss.org/publications/the-military-balance">IISS Military Balance 2022</a>.
      Daily losses from <a href="https://www.kaggle.com/datasets/piterfm/2022-ukraine-russian-war">Ukraine Armed Forces.</a>
      <a href="https://github.com/taw/open-source-adventures">Source code available on GitHub</a>.
    </footer>
    
    <style>
      footer {
        margin-top: 32px;
        color: #444;
      }
    </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 round100 = (x) => Math.round(x / 100) * 100
    
    let formatEoy = (x) => d3.format(".1f")(x / 1000.0) + "k"
    
    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")
    $: graphTime = lastDate - maxDate
    
    // How many KIA+WIA by lastDate
    $: unitsMax = Math.round(graphTime * futureTotalRate) + totalSoFar
    
    $: kiaSoFar = d3.max(adjustedData, d => d.kia)
    $: wiaSoFar = d3.max(adjustedData, d => d.wia)
    $: eoyKia = round100(graphTime * futureKiaRate + kiaSoFar)
    $: eoyWia = round100(graphTime * futureWiaRate + wiaSoFar)
    $: eoyTotal = eoyKia + eoyWia
    
    $: eoyIKia = round100(eoyKia / $kiaRegular * (100 - $kiaRegular))
    $: eoyIWia = round100(eoyWia / $kiaRegular * (100 - $kiaRegular))
    $: eoyITotal = eoyIKia + eoyIWia
    
    $: trendData = [
      adjustedData[0],
      at(adjustedData, -1),
      {
        date: lastDate,
        kia: Math.round(graphTime * futureKiaRate) + d3.max(adjustedData, d => d.kia),
        wia: Math.round(graphTime * futureWiaRate) + d3.max(adjustedData, d => d.wia),
        total: Math.round(graphTime * 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} />
    <div>
      <span class="box kia"></span> Killed
      <span class="box wia"></span> Wounded
      <span class="box total"></span> Total
    </div>
    <div>By end of the year, Russia will lose {formatEoy(eoyTotal)} ({formatEoy(eoyKia)} killed, {formatEoy(eoyWia)} wounded) regular soldiers.</div>
    <div>As well as {formatEoy(eoyITotal)} ({formatEoy(eoyIKia)} killed, {formatEoy(eoyIWia)} wounded) irregulars (separatists, PMCs etc.)</div>
    
    <style>
      .box {
        display: inline-block;
        height: 10px;
        width: 10px;
        border: 1px solid black;
      }
      .box.kia {
        background-color: red;
      }
      .box.wia {
        background-color: green;
      }
      .box.total {
        background-color: blue;
      }
    </style>
    


    이렇게 하면 다음과 같은 요약이 생성됩니다.

    By end of the year, Russia will lose 208.6k (59.6k killed, 149.0k wounded) regular soldiers.
    As well as 52.2k (14.9k killed, 37.3k wounded) irregulars (separatists, PMCs etc.)



    지금까지의 이야기



    All the code is on GitHub .

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

    좋은 웹페이지 즐겨찾기