未分類
ウォーターフォールチャートのデータフロー
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
このスクリプトは以下を行います:
- SQLiteからデータを読み込み
PLDetailedData形式に変換- 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"
/>
渡されるプロパティ:
| プロパティ | 型 | 説明 |
|---|---|---|
data | PLDetailedData | P/L詳細データ(必須) |
height | number | チャートの高さ (px) |
barWidth | number | バーの幅 (px) |
barGap | number | バー間の間隔 (px) |
fontSize | number | ラベルのフォントサイズ |
valueFontSize | number | 値のフォントサイズ |
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
}
}
まとめ
- SQLite →
generate-financial-data.mjs→ financial-data.ts - financial-data.ts →
getAllCompanies()→ proportional-animation.vue - selectedCompany →
useCompanyFinancialMetrics()→ getPlDetailedAtIndex() - PLDetailedData →
:dataprop → PLWaterfallChart.vue - calculateWaterfallPositions() → SVG描画