• #refactoring
  • #debugging
  • #lessons-learned
  • #chart
  • #financial-quiz
未分類

チャートX軸整列の学び

問題

右カラムの4つのチャート(利益率、EPS、SG&A比率、キャッシュフロー)で、X軸の年(2016〜LTM)が縦に揃っていなかった。

私(Claude)のアプローチ(失敗)

やったこと

  1. 各チャートファイルでpaddingを手動で統一しようとした
    // ProfitMarginChart.vue
    const padding = { top: 30, right: 20, bottom: 40, left: 90 }
    
    // EPSChart.vue
    const padding = { top: 30, right: 20, bottom: 40, left: 90 }
    
    // ExpenseRatioChart.vue
    const padding = { top: 30, right: 20, bottom: 40, left: 90 }
    
    // FCFChart.vue
    const padding = { top: 30, right: 20, bottom: 40, left: 90 }
    
  2. chartWidthchartHeightを手動で統一
  3. FCFChartのbarMarginを削除

問題点

  • 4ファイルを個別に編集 → 漏れや不整合が発生しやすい
  • コピペ作業 → 将来の変更時に全ファイル修正が必要
  • 根本原因を見落とし → なぜ揃わないのか構造的に理解していなかった
  • 何度も微調整 → left: 50 → 70 → 90 と試行錯誤

ユーザーのアプローチ(成功)

共通定数ファイルの作成

// chartLayout.ts
export const CHART_WIDTH = 600
export const CHART_PADDING_X = { left: 90, right: 20 }
export const CHART_EDGE_INSET = 10  // X軸の左右余白

共通composableの作成

// composables/useChartDimensions.ts
export function useChartDimensions(baseWidth: number, baseHeight: number) {
  const containerRef = ref<HTMLElement | null>(null)
  const width = ref(baseWidth)
  const height = ref(baseHeight)

  // コンテナサイズに応じてレスポンシブに調整
  // ...

  return { containerRef, width, height }
}

各チャートでimportして使用

// ProfitMarginChart.vue
import { CHART_EDGE_INSET, CHART_PADDING_X, CHART_WIDTH } from './chartLayout'
import { useChartDimensions } from './composables/useChartDimensions'

const { containerRef, width: chartWidth, height: chartHeight } = useChartDimensions(CHART_WIDTH, 200)
const padding = { top: 30, right: CHART_PADDING_X.right, bottom: 40, left: CHART_PADDING_X.left }

const getX = (index: number): number => {
  const count = props.marginData.length
  const innerWidth = Math.max(0, plotWidth.value - CHART_EDGE_INSET * 2)
  if (count <= 1) return padding.left + CHART_EDGE_INSET + innerWidth / 2
  return padding.left + CHART_EDGE_INSET + (index / (count - 1)) * innerWidth
}

比較

観点私のアプローチユーザーのアプローチ
変更箇所4ファイル × 複数行1共通ファイル + 各ファイルのimport
将来の変更4ファイル全て修正共通ファイル1箇所のみ
整合性保証手動確認が必要コードで保証
getX関数各ファイルで別実装共通ロジック(CHART_EDGE_INSETで統一)
レスポンシブ対応固定値のみcomposableで動的対応可能

教訓

1. 「同じ値を複数箇所に書く」は設計の失敗

同じ定数(padding、width等)を複数ファイルで使う場合は、共通ファイルにまとめるべき。

2. 試行錯誤の前に構造を理解する

「left: 50で揃わない → 70に → まだ揃わない → 90に」という試行錯誤は、根本原因(FCFChartのbarMargin等)を見落としている証拠。

3. composableパターンの活用

Vue 3のcomposableは、チャートのサイズ計算などの共通ロジックをカプセル化するのに最適。

4. 定数の命名で意図を明確に

  • CHART_PADDING_X → X方向のパディング
  • CHART_EDGE_INSET → データポイントの左右余白

命名で意図が明確になり、誤用を防げる。


適用後の結果

// 全チャートで"2016"のx座標が一致
[
  {"chart":0,"year2016_x":"814.09"},
  {"chart":1,"year2016_x":"814.09"},
  {"chart":2,"year2016_x":"814.09"},
  {"chart":3,"year2016_x":"814.09"}
]

次回への適用

チャートやUIコンポーネントで「複数ファイルで同じ値を使う」場面では:

  1. まず共通定数ファイルを作るchartLayout.ts等)
  2. ロジックが共通なら composable化useChartDimensions等)
  3. 各コンポーネントはimportして使う
  4. 手動での値コピペは避ける