イナズマ線の描画

WBSガントチャートはもっぱらExcelで作る。そのガントチャート上にタスクの進捗状況を表す、いわゆる「イナズマ線」を描くのは面倒。特に、Excle2007からは線(Shape)の仕様が変わったせいか、進捗の遅れ/前倒しを表す頂点の追加が思い通りに出来ない。ただExcel2003で描画したイナズマ線はExcle2007でも2003と同じように編集できるので、2003のWBSをコピーして使っている。それもなんだかね...。それに輪をかけて面倒にしているのが、

これまでの経過がわかるよう、過去のイナズマ線も残しておくこと

というご指導。はぁ。最新だけじゃだめなんですか...。WBSの途中にタスク(=行)を挿入すると頂点が、すでに描かれているイナズマ線の頂点がずれるから、その修正にエライ時間がかかるのよ。特にタスク数が多い場合は。WBSは生き物で、日々刻々と変化しているのをエロイ人はしらないんだろうね。まぁ我が社の場合、そこまで真面目にWBSを作って管理する人は少ないから仕方ないけどね(爆。

そんなわけで、イナズマ線描画機能付きガントチャート探してみるとあるのはある。しかし、

  • 現時点のイナズマ線しか描画出来ない
  • タスク追加に対応していない

ものしか見つからない。探し方が悪いせいかもしれないけど、それなら作るしかないな。ということでちょっとやってみる。

まずは基準となるイナズマ線を描画する。前提として1列=1日のように「列」進捗管理する最小単位とする。たとえばセルE1~E10の左端に線を引くのはこんな感じ。

	Dim progress As Shape		' イナズマ線
	Dim sx As Single, sy As Single	' 開始座標
	Dim ex As Single, ey As Single	' 終了座標
	Dim ffb As FreeformBuilder

	' セルE1~E10の左端に線を描画(col=5は列E)
	sx = Worksheets.Cells(1, 5).Left
	sy = Worksheets.Cells(1, 5).Top
	ex = sx
	ey = Worksheets.Cells(10, 5).Top

	Set ffb = Worksheets.Shapes.BuildFreeform(msoEditingCorner, sx, sy)
	ffb.AddNodes msoSegmentLine, msoEditingCorner, ex, ey
	Set progress = ffb.ConvertToShape

	With progress.Line
		.DashStyle = msoLineSolid	' スタイル
		.Weight = 2 			' 太さ
		.ForeColor.RGB = RGB(255, 0, 0)	' 最新は赤
	End With

これで真っ直ぐなイナズマ線が描けたので、これに進捗を頂点として追加していく。たとえば3行目のタスクを2日遅れとするならこんな感じ。

	Dim tx As Single, ty As Single	'// 頂点座標

	' 曲げ始め座標
	' sx = 基準線のまま
	sy = Worksheets.Cells(3, 5).Top

	' 曲げ終わり座標
	' ex = 基準線のまま
	ey = Worksheets.Cells(3 + 1, 5).Top

	'	頂点座標(-2は2日遅れの意)
	tx = Worksheets.Cells(3, (5-2)).Left
	'	行の中央に頂点が来るようにする
	ty = (ey - sy) / 2 + sy

	' 頂点を描画
	With progress
		.Nodes.Insert .Nodes.Count - 1, msoSegmentLine, msoEditingAuto, sx, sy
		.Nodes.Insert .Nodes.Count - 1, msoSegmentLine, msoEditingAuto, tx, ty
		.Nodes.Insert .Nodes.Count - 1, msoSegmentLine, msoEditingAuto, ex, ey
	End With

もし2日進んでいるなら次のようにする。

tx = Worksheets.Cells(3, (5+2)).Left

イナズマ線描画の基本はこれだけ。あとはリテラルをパラーメタ化して、過去分も含めて描画できるようにすればOK。

で、その過去分はどうやって描画するか?単純な話、

イナズマ線を描画するタイミングで各タスクの基準線に対する偏差(上記の例で言えば、-2とか+2)を記録しておく

でいいのでは?この方法でイナズマ線を描画するなら、タスク毎の偏差を記入する列が必要になる。そこでその内容(偏差)をあるタイミング(たとえば[確定]ボタンが押された時、とか)で、シート右側の非表示列にコピーして保存してする。途中にタスクを追加したた(=行が追加された)場合は、一旦イナズマ線をすべて削除後、この保存してある偏差を使って再描画する。そのときコピー列の当該行は未入力なので、これを0(予定通り)扱いにすれば、そのタスクの(過去分の)イナズマ線はまっすぐとなる。OK?*1

じゃ過去分はどうやって消すか?上のコードだとイナズマ線は「フリーフォームxxx」という名前になっているので、それを手がかりに消してしまうのが簡単。

	' イナズマ線を削除
	For Each s In Worksheets(1).Shapes
		If InStr(s.name, "フリーフォーム") > 0 Then
			s.Delete
		End If
	Next

もしそのworksheetに「フリーフォームxxx」と名付けられた別なShapeがあったら?イナズマ線を引く時、明示的な名前を付けて、それをキーに消すしかないような気がする*2

多分これでやりたいことはできるようになるけど、WBSガントチャートは単なる道具(ツール)。それを活かすも殺すも

進捗を客観的な根拠に基づいてとらえているか?

次第だと思う。たとえば今、10人日かかるタスクに取り掛かっているとして、今日時点の進捗(「予定通り」「○日進んでいる」「△日遅れている」、など)を客観的に表せるか?極論すれば「進捗が数式(数字)で表せるか?」ということ。評価基準はいろいろあると思うけど、数字で表せなければ進捗管理しているとはいえない。例外をスローしなきゃいけないのが、

  • 数値的な根拠もなく、感覚的に「予定通り」としている場合
  • 遅れているけど「予定通り」で押し通そうとしている場合

特に後者は破滅的な結果をもたらしかねない。客観的根拠に基づかない進捗は、怪しいと思っても担当者の「大丈夫論」を覆せず押し切られてしまう恐れ・大。もう一歩踏み込んで数字で説明できるように指導すべきだけど「振り逃げ」が社風なのでそこまでやる人は稀。さらにもう一歩踏み込むなら、

なぜ(進捗が遅れている、かつ回復も絶望的だと認識している)担当が「大丈夫です」で押し通そうとするか?

へメスを入れるべきなんだけど、そこはみんな「パンドラの箱」だと知っているので、触れようとはしない┐(´д`)┌ヤレヤレ

*1:「その時点では、そのタスクは存在しなかったのだからイナズマ線がまっすぐ引かれるのはおかしい」という厳格な方は、もうちょっとロジックが必要だけど、この考えでいけるはず

*2:試してないけど