途中で飽きてしまって、エラーチェックも中途半端でコードも美しくなくて気に入らないけど、取りあえず公開します。
気が向いたらリファクタリングするけど、今のコードでも引ける。
Option Explicit
'カレンダー先頭
Public Const CalenderStartAddress As String = "F6"
'データ開始行
Public Const DataStartRow As Integer = 8
'マスタスケジュールワークシート
Public Const MasterSheetName As String = "マスタスケジュール"
'基点日アドレス
Public Const BaseDateAddress As String = "C3"
Public Enum eCol
Blank1 = 1
Taskstart
Taskend
Progress
Blank2
End Enum
Option Explicit
Private InazumaSheet As Worksheet 'ワークシートオブジェクト
Private baseDate As Date '基準日
Private axis() As Variant '描画する座標
Private rngCalender As Range 'カレンダー領域
Private rngTaskDate As Range 'タスク開始・終了日領域
Private nowXAxis As Single '現在位置のX軸
Private nowYAxis As Single '現在位置のY軸
'---------------------------------------------------------------------------------------------------
'【処 理 名】稲妻
'【処理概要】イナズマ線を引く
'【引 数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Public Sub 稲妻()
'初期化
Call init
'入力チェック
If Not check Then
GoTo LBL_TERM
End If
'カレンダー領域取得
Call getCalenderRange
'現在時点座標取得
Call getNowPoint(rngCalender)
'タスクの座標取得
Call getTaskInfo
'イナズマ線描画
Call drawInazumaLine
LBL_TERM:
'終期処理
Call term
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】初期処理
'【処理概要】初期処理
'【引 数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub init()
'ワークシートオブジェクト取得
Set InazumaSheet = ThisWorkbook.Worksheets(MasterSheetName)
'基準日取得
baseDate = InazumaSheet.Range(BaseDateAddress).Value
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】終期処理
'【処理概要】終期処理
'【引 数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub term()
Set InazumaSheet = Nothing
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】入力チェック
'【処理概要】入力チェックを実施する
'【引 数】なし
'【返 却 値】True エラーなし
' False エラーあり
'---------------------------------------------------------------------------------------------------
Private Function check() As Boolean
If InazumaSheet.Range(BaseDateAddress).Value = "" Then
MsgBox "基点日を入力してください。"
GoTo LBL_ERROR
End If
If Not IsDate(InazumaSheet.Range(BaseDateAddress).Value) Then
MsgBox "基点日に日付を入力してください。"
GoTo LBL_ERROR
End If
check = True
Exit Function
LBL_ERROR:
check = False
Exit Function
End Function
'---------------------------------------------------------------------------------------------------
'【処 理 名】カレンダー領域取得
'【処理概要】カレンダー領域を取得する
'【引 数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub getCalenderRange()
Dim rowIndex As Integer
Dim endCol As Integer
'行インデックス
rowIndex = InazumaSheet.Range(CalenderStartAddress).Row
'列インデックス
endCol = InazumaSheet.Cells(rowIndex, Columns.Count).End(xlToLeft).Column
'カレンダー領域取得
Set rngCalender = InazumaSheet.Range(CalenderStartAddress, _
InazumaSheet.Cells(rowIndex, endCol))
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】現在時点座標取得
'【処理概要】カレンダーの中から、現在時点を取得する
'【引 数】ByVal rngCalender As Range カレンダー領域
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub getNowPoint(ByVal rngCalender As Range)
Dim rng As Range '作業領域
Dim baseDateSerial As Variant '基準日
Dim baseDay As Integer '基準日の日付
Dim lastDay As Date
'基準日
baseDateSerial = DateSerial(Year(baseDate), Month(baseDate), 1)
'基準日の次の最終日
lastDay = DateSerial(Year(baseDate), Month(baseDate) + 1, 0)
'基準日の日付
baseDay = Day(baseDate)
'カレンダーから基準日の年月を探す
For Each rng In rngCalender
'マージされている先頭セル以外はスキップ
If rng.Address <> rng.MergeArea(1).Address Then GoTo LBL_NEXT
'基準日と同じ月の場合
If DateSerial(Year(rng.Value), Month(rng.Value), 1) = baseDateSerial Then
'基準日のX軸を取得
nowXAxis = rng.Left + ((rng.Width / Day(lastDay)) * baseDay)
'基準日のY軸を取得
nowYAxis = rng.Top
Exit For
End If
LBL_NEXT:
Next
'描画軸配列へ格納する
ReDim axis(1, 0)
axis(0, 0) = nowXAxis
axis(1, 0) = nowYAxis
Call setAxis(nowXAxis, nowYAxis + rng.Height)
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】タスク座標取得
'【処理概要】タスクの座標を取得する
'【引 数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub getTaskInfo()
Dim endRow As Long
Dim rowIndex As Long
endRow = InazumaSheet.Cells(Rows.Count, eCol.Taskstart).End(xlUp).Row
For rowIndex = DataStartRow To endRow
Call getTaskAxis(rowIndex)
Next
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】座標取得
'【処理概要】座標を取得する
'【引 数】ByVal rowIndex As Long
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub getTaskAxis(ByVal rowIndex As Long)
Dim startDate As Date
Dim endDate As Date
Dim rng As Range '作業領域
Dim startAxis As Single
Dim endAxis As Single
Dim progressAxis As Single
Dim yAxis As Single
Dim cellHeight As Single 'セル高さ
'開始日
startDate = InazumaSheet.Cells(rowIndex, eCol.Taskstart)
'終了日
endDate = InazumaSheet.Cells(rowIndex, eCol.Taskend)
'Y軸を取得
yAxis = InazumaSheet.Cells(rowIndex, eCol.Taskstart).Top
'セルの高さを取得
cellHeight = InazumaSheet.Cells(rowIndex, eCol.Taskstart).Height
For Each rng In rngCalender
'マージされている先頭セル以外はスキップ
If rng.Address <> rng.MergeArea(1).Address Then GoTo LBL_NEXT
'-------------------------------------------------------------------------------
' 開始日の座標を取得する
'-------------------------------------------------------------------------------
If isInTerm(rng, startDate) Then
startAxis = getAxis(startDate, rng)
End If
'-------------------------------------------------------------------------------
' 完了日の座標を取得する
'-------------------------------------------------------------------------------
If isInTerm(rng, endDate) Then
endAxis = getAxis(endDate, rng)
Exit For
End If
LBL_NEXT:
Next
'-------------------------------------------------------------------------------
' 進捗の座標を取得する
'-------------------------------------------------------------------------------
If InazumaSheet.Cells(rowIndex, eCol.Progress) = 1 Then
progressAxis = nowXAxis
Else
progressAxis = startAxis + ((endAxis - startAxis) * InazumaSheet.Cells(rowIndex, eCol.Progress))
End If
'開始点
Call setAxis(nowXAxis, yAxis)
'進捗点
Call setAxis(progressAxis, yAxis + (cellHeight / 2))
'終点
Call setAxis(nowXAxis, yAxis + cellHeight)
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】座標軸取得
'【処理概要】座標軸を取得する
'【引 数】ByVal targetDate As Date
' ByVal rng As Range
'【返 却 値】座標
'---------------------------------------------------------------------------------------------------
Function getAxis(ByVal targetDate As Date, ByVal rng As Range) As Single
Dim lastDay As Date '該当月の最終日
'対象年月日の月の最終日
lastDay = DateSerial(Year(targetDate), Month(targetDate) + 1, 0)
'X軸取得
getAxis = rng.Left + ((rng.Width / Day(lastDay)) * Day(targetDate))
End Function
'---------------------------------------------------------------------------------------------------
'【処 理 名】期間内比較
'【処理概要】同じ月であるか比較する
'【引 数】ByVal rng As Range
' ByVal targetDate As Date
'【返 却 値】True エラーなし
' False エラーあり
'---------------------------------------------------------------------------------------------------
Private Function isInTerm(ByVal rng As Range, ByVal targetDate As Date) As Boolean
Dim tergetSerialDate As Date
tergetSerialDate = DateSerial(Year(targetDate), Month(targetDate), 1)
isInTerm = False
If DateSerial(Year(rng.Value), Month(rng.Value), 1) = tergetSerialDate Then
isInTerm = True
End If
End Function
'---------------------------------------------------------------------------------------------------
'【処 理 名】座標配列へ格納
'【処理概要】座標配列に描画点の座標を格納する
'【引 数】ByVal xAxis As Single
' ByVal yAxis As Single
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub setAxis(ByVal xAxis As Single, ByVal yAxis As Single)
Dim elemIndex As Long '座標配列の要素数
elemIndex = UBound(axis, 2) + 1
ReDim Preserve axis(1, elemIndex)
axis(0, elemIndex) = xAxis
axis(1, elemIndex) = yAxis
End Sub
'---------------------------------------------------------------------------------------------------
'【処 理 名】イナズマ線描画
'【処理概要】イナズマ線を描画する
'【引 数】なし
'【返 却 値】なし
'---------------------------------------------------------------------------------------------------
Private Sub drawInazumaLine()
Dim index As Long
'描画
With InazumaSheet.Shapes.BuildFreeform(msoEditingCorner, axis(0, 0), axis(1, 0))
For index = 1 To UBound(axis, 2)
.AddNodes msoSegmentCurve, msoEditingCorner, axis(0, index), axis(1, index)
Next
With .ConvertToShape
.Line.Weight = 1.5
.Line.ForeColor.RGB = RGB(255, 0, 0)
End With
End With
End Sub

イナズマにかける熱量がすごいです\(^o^)/
ちなみに、ルーク篁さんは聖飢魔Ⅱの青い稲妻です。
これを実行したら、こうなる。という図がみたい。
だよね。
つい面倒でさあ(笑)
コードをきれいに書き直したら、もっと丁寧に書き直そうと思う。