• #Vue
  • #財務
  • #コンポーネント
  • #データフロー
未分類

ウォーターフォールチャートのデータフロー

proportional-animation.vue ページで使用されている PLWaterfallChart コンポーネントへのデータの流れを以下に解説します。

全体アーキテクチャ

┌──────────────────────────────────────────────────────────────────────┐
│  data/koyfin.db (SQLite)                                             │
│  ├─ Balance Sheet テーブル                                           │
│  ├─ Income Statement テーブル                                        │
│  └─ Cash Flow テーブル                                               │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ node scripts/generate-financial-data.mjs
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│  app/composables/financial-data.ts (~3.4MB)                          │
│  ├─ financialData: FinancialDataStore                                │
│  └─ getAllCompanies(): CompanyData[]                                 │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ import { getAllCompanies }
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│  proportional-animation.vue                                          │
│  ├─ companiesArray = getAllCompanies()                               │
│  ├─ selectedCompany = companiesArray[selectedCompanyIndex]           │
│  └─ useCompanyFinancialMetrics(selectedCompany, periodIndex)         │
└──────────────────────────────────────────────────────────────────────┘
                                    │
                                    │ getPlDetailedAtIndex(periodIndex)
                                    ▼
┌──────────────────────────────────────────────────────────────────────┐
│  PLWaterfallChart.vue                                                │
│  └─ props.data: PLDetailedData                                       │
└──────────────────────────────────────────────────────────────────────┘

1. データソース: SQLite

財務データは data/koyfin.db に格納されています。

  • Income Statement テーブル: 損益計算書データ
  • Balance Sheet テーブル: 貸借対照表データ
  • Cash Flow テーブル: キャッシュフロー計算書データ

2. データ生成スクリプト

scripts/generate-financial-data.mjs がSQLiteから TypeScript ファイルを自動生成します。

cd apps/web
node scripts/generate-financial-data.mjs

出力先: app/composables/financial-data.ts

このスクリプトは以下を行います:

  1. SQLiteからデータを読み込み
  2. PLDetailedData 形式に変換
  3. TypeScript コードとして出力

3. 型定義: PLDetailedData

app/types/financial.ts で定義されています。

export interface PLDetailedData {
  revenue: number           // 売上高
  costOfRevenue: number     // 売上原価
  grossProfit: number       // 売上総利益
  sgaExpenses: number       // 販売費及び一般管理費
  rdExpenses: number        // 研究開発費
  daExpenses: number        // 減価償却費
  otherOperatingExpenses: number  // その他営業費用
  operatingIncome: number   // 営業利益
  nonOperatingIncome: number     // 営業外収益
  nonOperatingExpenses: number   // 営業外費用
  preTaxIncome: number      // 税引前利益
  taxes: number             // 法人税等
  netIncome: number         // 純利益
}

4. ページでのデータ取得

proportional-animation.vue では、以下のようにデータを取得しています。

4.1 企業データの取得

import { getAllCompanies } from '~/composables/financial-data'

const companiesArray = computed(() => {
  const allCompanies = getAllCompanies()
  // セクター別・時価総額順でソート
  return allCompanies.sort((a, b) => { /* ... */ })
})

4.2 選択中の企業

const selectedCompanyIndex = ref(0)

const selectedCompany = computed(() => {
  return companiesArray.value[selectedCompanyIndex.value]
})

4.3 Composableでデータ加工

import { useCompanyFinancialMetrics } from '~/components/financial-quiz/proportional-animation'

const {
  periodLabels,
  getPlDetailedAtIndex
} = useCompanyFinancialMetrics(selectedCompany, periodIndex)

4.4 ウォーターフォール用データ

const currentPlDetailed = computed(() =>
  getPlDetailedAtIndex(periodIndex.value)
)

5. コンポーネントへのデータ渡し

<PLWaterfallChart
  v-if="currentPlDetailed"
  :data="currentPlDetailed"
  :height="180"
  :bar-width="20"
  :bar-gap="38"
  :font-size="9"
  :value-font-size="10"
/>

渡されるプロパティ:

プロパティ説明
dataPLDetailedDataP/L詳細データ(必須)
heightnumberチャートの高さ (px)
barWidthnumberバーの幅 (px)
barGapnumberバー間の間隔 (px)
fontSizenumberラベルのフォントサイズ
valueFontSizenumber値のフォントサイズ

6. PLWaterfallChart の内部処理

コンポーネント内部では、calculateWaterfallPositions() 関数でデータを変換しています。

ウォーターフォールの流れ

Revenue
  │ - Cost of Revenue
  ▼
Gross Profit
  │ - SG&A
  │ - R&D
  │ - D&A
  │ - Other Operating
  ▼
Operating Income
  │ ± Non-operating
  ▼
Pre-Tax Income
  │ - Taxes
  ▼
Net Income

バーの種類

type説明
income収益(上向き)赤系
expense費用(下向き)青系
profit利益(中間結果)緑系
loss損失(マイナス利益)緑系(ラベル赤)

7. Composable の役割

useCompanyFinancialMetrics は企業データから各種指標を算出するcomposableです。

位置: app/components/financial-quiz/proportional-animation/composables/useCompanyFinancialMetrics.ts

export function useCompanyFinancialMetrics(
  company: Ref<CompanyData | null | undefined>,
  periodIndex?: Ref<number>
) {
  // getPlDetailedAtIndex: 指定期間のP/L詳細を取得
  const getPlDetailedAtIndex = (index: number): PLDetailedData | null => {
    if (!company.value || index >= company.value.periods.length) return null
    return company.value.periods[index].data.plDetailed ?? null
  }

  return {
    periodLabels,
    marginData,
    epsData,
    // ...他の指標
    getPlDetailedAtIndex
  }
}

まとめ

  1. SQLitegenerate-financial-data.mjsfinancial-data.ts
  2. financial-data.tsgetAllCompanies()proportional-animation.vue
  3. selectedCompanyuseCompanyFinancialMetrics()getPlDetailedAtIndex()
  4. PLDetailedData:data prop → PLWaterfallChart.vue
  5. calculateWaterfallPositions() → SVG描画