오픈 소스 모험: 에피소드 39: 러시아 손실 앱의 손실 비율 축
18842 단어 d3sveltejavascript
이것은 때때로 사용되는 시각적 디자인 패턴입니다. 두 개의 Y축이 있습니다. 왼쪽의 Y축은 손실의 절대값이고 오른쪽의 Y축은 손실률입니다.
약간의 주의가 필요합니다. 예를 들어 총 장갑 차량 수가 20093인 경우 다음 라운드 수(22000)로 반올림해야 하므로 왼쪽 축은 0에서 20093으로 이동합니다. 그러나 오른쪽 축은 0%에서 100%로 이동해야 합니다. , 여기서 100%는 22000이 아니라 20093과 일치합니다!
우리가 원하는 것은 다음과 같습니다.
[영상]
Graph.svelte
그래프 구성 요소는 전달한 내용만 표시합니다. 우리는
yAxisL
와 yAxisR
를 전달하고 구성 요소는 그것에 대해 많이 생각하지 않고 적절한 위치에 표시합니다.<script>
import Axis from "./Axis.svelte"
export let pathData, trendPathData, totalPathData, xAxis, yAxisL, yAxisR
</script>
<svg viewBox="0 0 800 600">
<g class="graph">
<path class="data" d={pathData}/>
<path class="trendline" d={trendPathData}/>
<path class="total" d={totalPathData}/>
</g>
<g class="x-axis"><Axis axis={xAxis}/></g>
<g class="y-axis-left"><Axis axis={yAxisL}/></g>
<g class="y-axis-right"><Axis axis={yAxisR}/></g>
</svg>
<style>
svg {
width: 800px;
max-width: 100vw;
display: block;
}
.graph {
transform: translate(50px, 20px);
}
path {
fill: none;
}
path.data {
stroke: red;
stroke-width: 1.5;
}
path.trendline {
stroke: red;
stroke-width: 1.5;
stroke-dasharray: 3px;
}
path.total {
stroke: blue;
stroke-width: 1.5;
}
.x-axis {
transform: translate(50px, 520px);
}
.y-axis-left {
transform: translate(50px, 20px);
}
.y-axis-right {
transform: translate(750px, 20px);
}
</style>
LossesGraph.svelte
모든 논리는
LossesGraph
구성 요소에 있습니다.<script>
import * as d3 from "d3"
import Graph from "./Graph.svelte"
export let lossData, total, adjustmentLoss, futureIntensity, label
let adjust = (data, adjustmentLoss) => data.map(({date, unit}) => ({date, unit: Math.round(unit * (1 + adjustmentLoss/100))}))
let [minDate, maxDate] = d3.extent(lossData, d => d.date)
$: adjustedData = adjust(lossData, adjustmentLoss)
$: alreadyDestroyed = d3.max(adjustedData, d => d.unit)
$: unitsMax = Math.max(alreadyDestroyed, total)
$: currentDestroyRate = alreadyDestroyed / (maxDate - minDate)
$: futureDestroyRate = (currentDestroyRate * futureIntensity / 100.0)
$: unitsTodo = total - alreadyDestroyed
$: lastDestroyedDate = new Date(+maxDate + (unitsTodo / futureDestroyRate))
$: xScale = d3.scaleTime()
.domain([minDate, lastDestroyedDate])
.range([0, 700])
$: yScale = d3.scaleLinear()
.domain([0, unitsMax])
.nice()
.range([500, 0])
$: pathData = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.unit))
(adjustedData)
$: trendPathData = d3.line()
.x(d => xScale(d.date))
.y(d => yScale(d.unit))
([adjustedData[0], adjustedData[adjustedData.length - 1], {unit: total, date: lastDestroyedDate}])
$: totalPathData = d3.line()
.x(xScale)
.y(yScale(unitsMax))
([minDate, lastDestroyedDate])
$: xAxis = d3.axisBottom()
.scale(xScale)
.tickFormat(d3.timeFormat("%e %b %Y"))
$: yAxisL = d3
.axisLeft()
.scale(yScale)
$: yScaleR = d3.scaleLinear()
.domain([0, 100])
.range([
yScale(0),
yScale(unitsMax)
])
$: yAxisR = d3
.axisRight()
.scale(yScaleR)
.tickFormat(n => `${n}%`)
</script>
<Graph {pathData} {trendPathData} {totalPathData} {xAxis} {yAxisL} {yAxisR} />
<div>Russia will lose its last {label} on {d3.timeFormat("%e %b %Y")(lastDestroyedDate)}</div>
가장 중요한 부분은
yScaleR
정의, 특히 pre-nice-ified range
로 정의되는 yScale
입니다. 따라서 0%
는 yScale(0)
와 정렬되어야 하지만 100%
는 yScale(unitsMax)
와 정렬되어야 합니다(이 예에서는 yScale(20093)
).yScale(22000)
는 특별한 작업을 수행하지 않는 모든 틱에 yAxisR
를 추가하는 것 외에는 일반적인 백분율 척도입니다.지금까지의 이야기
All the code is on GitHub .
저는 이것을 GitHub Pagesyou can see it here에 배포했습니다.
다음에 온다
다음 몇 편의 에피소드에서는 Russian Losses 앱에 추가하고 싶은 기능이 몇 가지 더 있습니다.
Reference
이 문제에 관하여(오픈 소스 모험: 에피소드 39: 러시아 손실 앱의 손실 비율 축), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/taw/open-source-adventures-episode-39-loss-percentage-axis-for-russian-losses-app-3m02텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)