• #vue
  • #financial
  • #implementation
  • #unit-switching
開発misc-dev完了

財務諸表の単位自動切り替え機能(B/M)実装記録

概要

比例縮尺財務諸表(proportional-animation-qqq.vue)において、企業の規模に応じて表示単位を自動的に切り替える機能を実装した。

  • 大企業: Billion($B)表示
  • 小規模企業: Million($M)表示

実装箇所

1. FCFChart.vue(キャッシュフローチャート)

ファイル: apps/web/app/components/financial-quiz/FCFChart.vue

実装内容

// 単位を自動決定(最大値が10B未満ならミリオン表示)
const unitInfo = computed(() => {
  if (props.cashFlowData.length === 0) return { divisor: 1000, suffix: 'B', step: 20 }

  const allValues = props.cashFlowData.flatMap(d => [
    Math.abs(d.operatingCF),
    Math.abs(d.capex),
    Math.abs(d.fcf)
  ])
  const maxValue = Math.max(...allValues)

  // 10,000M (10B) 未満ならミリオン表示
  if (maxValue < 10000) {
    // 1,000M 未満なら100刻み、それ以上なら500刻み
    const step = maxValue < 1000 ? 100 : maxValue < 5000 ? 500 : 1000
    return { divisor: 1, suffix: 'M', step }
  }

  // 10B以上ならビリオン表示
  return { divisor: 1000, suffix: 'B', step: 20 }
})

判定ロジック

最大値単位Y軸刻み
< 1,000MM100
1,000M - 5,000MM500
5,000M - 10,000MM1000
>= 10,000M (10B)B20

使用箇所

  • Y軸ラベル: ${{ tick }}{{ unitInfo.suffix }}
  • データポイント座標計算: d.operatingCF / divisor
  • 値フォーマット: formatValue() 関数

2. proportional-animation-qqq.vue(ページ)

ファイル: apps/web/app/pages/financial-quiz/proportional-animation-qqq.vue

実装内容

// 単位(総資産10B以上ならB、それ以外はM)
const unitSuffix = computed(() => {
  if (!selectedCompany.value) return 'M'
  const currentPeriod = selectedCompany.value.periods[periodIndex.value]
  if (!currentPeriod) return 'M'

  const bs = currentPeriod.data.bs
  const totalAssets =
    bs.currentAssets.reduce((sum, item) => sum + item.value, 0) +
    bs.fixedAssets.reduce((sum, item) => sum + item.value, 0)

  // 10,000M = 10B を閾値とする
  return totalAssets >= 10000 ? 'B' : 'M'
})

判定基準

  • 総資産(Total Assets) を基準に判定
  • 閾値: 10,000M(= 10B)
  • 総資産 = 流動資産 + 固定資産

表示箇所

メイン表示:

<div class="sector-row">
  <p class="sector-label">{{ selectedCompany.sector }} / {{ selectedCompany.industry }}</p>
  <span class="unit-label">(単位: ${{ unitSuffix }})</span>
</div>

エクスポートコンテナ(動画ダウンロード用):

<div class="sector-row">
  <p class="export-sector">{{ selectedCompany.sector }} / {{ selectedCompany.industry }}</p>
  <span class="unit-label">(単位: ${{ unitSuffix }})</span>
</div>

3. ProportionalFinancialStatementsAnimated.vue(参考)

ファイル: apps/web/app/components/financial-quiz/ProportionalFinancialStatementsAnimated.vue

このコンポーネント内でも単位計算のロジックが存在する(getUnitSuffix 関数など)。 ページ側の unitSuffix はこれと同じロジックを使用している。


CSS

/* メイン表示用 */
.sector-row {
  display: flex;
  justify-content: center;
  align-items: center;
  gap: 1rem;
  margin-top: 0.25rem;
}

.unit-label {
  font-size: 0.75rem;
  color: #666;
  font-weight: normal;
}

/* エクスポート用(大きいサイズ) */
.export-header .sector-row {
  margin-top: 8px;
}

.export-header .unit-label {
  font-size: 16px;
}

閾値の根拠

  • 10B(100億ドル) を閾値に設定
  • QQQ構成銘柄の多くは大企業(10B以上)
  • 小規模企業(TTD、LULU、MNST等)は10B未満

具体例

企業総資産表示単位
GOOGL536BB
META304BB
TTD5.9BM
LULU7.5BM
MNST9.6BM

今後の改善案

  1. FCFChartとページの閾値統一: 現在は別々に判定しているが、共通の定数として管理すべき
  2. 他のチャートへの適用: ProfitMarginChart、EPSChart、ExpenseRatioChartは現状%表示なので影響なし
  3. CompanyHeader共通化: company-header-component-plan.md 参照