using System; using System.Collections.Generic; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; namespace GanttChart { /// /// 甘特图控件 /// 该部分类处理甘特图逻辑 /// public partial class GanttChartView { /// /// 鼠标是否经过日分割线 /// /// /// private bool IsHoverDateSplitLine(Point e) { var t = (e.X + _HScrollBar.Value - RowHeaderWidth + this.DateWidth) % this.DateWidth; return e.X > this.RowHeaderWidth + 3 && e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && (this.DateWidth - 2 <= t || t <= 1); } /// /// 鼠标是否经过行标题 /// /// /// private bool IsHoverRowHeader(Point e) { return e.X <= this.RowHeaderWidth && e.Y > this.ColumnHeight; } /// /// 鼠标是否经过行 /// /// /// private bool IsHoverRow(Point e) { var y = e.Y + _VScrollBar.Value; return e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && e.Y > this.ColumnHeight && Rows != null ? Rows.Any(r=>r.Top <= y && r.Bottom >= y) : false; } /// /// 鼠标是否经过项 /// /// /// private bool IsHoverItem(Point e) { if(e.X > this.RowHeaderWidth && e.Y > this.ColumnHeight && Rows != null) { var row = GetRow(e); if (row != null && row.Items != null && row.Items.Any()) { var x = e.X + _HScrollBar.Value; var y = e.Y + _VScrollBar.Value; return row.Items.Any(r=>r.Left<=x && x <= r.Left + Math.Max(r.Width, r.TextWidth) && r.Top <= y && y <= r.Top + ItemHeight); } } return false; } /// /// 获取项 /// /// /// private GanttChartViewItem GetItem(Point e) { if (e.X > this.RowHeaderWidth && e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && e.Y > this.ColumnHeight && Rows != null) { var row = GetRow(e); if (row != null && row.Items != null && row.Items.Any()) { var x = e.X + _HScrollBar.Value; var y = e.Y + _VScrollBar.Value; return row.Items.OrderBy(r=>r.Left).LastOrDefault(r => r.Left <= x && x <= r.Left + Math.Max(r.Width, r.TextWidth) && r.Top <= y && y <= r.Top + ItemHeight); } } return null; } /// /// 获取行 /// /// /// private GanttChartViewRow GetRow(Point e) { if (e.X < ((EndDate.Date - StartDate.Date).TotalDays + 1) * DateWidth + RowHeaderWidth - _HScrollBar.Value && e.Y > this.ColumnHeight && e.Y + _VScrollBar.Value < (Rows == null || !Rows.Any() ? 0 : Rows.Max(r=>r.Bottom)) && Rows != null) { var y = e.Y + _VScrollBar.Value; return Rows.FirstOrDefault(r => r.Top <= y && r.Bottom >= y); } return null; } /// /// 计算所有行和项的大小 /// private void ComputeRowsAndItemsSize() { var minuteWidth = DateWidth / 24f / 60f; var currentRowY = ColumnHeight; foreach (var row in Rows) { row.Top = currentRowY; var currentItemY = currentRowY + RowSpacing; row.Bottom = currentRowY; if(row.Items != null) { var beforeTop = row.Top + RowSpacing; var beforeRight = 0; var items = row.Items.OrderBy(r => r.StartTime).ToList(); for ( int i = 0; i < items.Count; i++) { var item = items[i]; if (item.EndTime >= StartTime && item.StartTime <= EndTime && item.EndTime >= item.StartTime) { item.Left = (int)((item.StartTime - StartTime).TotalMinutes * minuteWidth) + RowHeaderWidth; item.Width = (int)((item.EndTime - item.StartTime).TotalMinutes * minuteWidth); item.TextWidth = TextRenderer.MeasureText(item.Title, ItemTextFont, System.Drawing.Size.Empty).Width; if (item.Left < beforeRight || BlockType == GanttChartViewItemBlockType.Block && i > 0) { var its = items.Take(i).GroupBy(r=>r.Top).Select(r=>r.OrderByDescending(p => p.Left + p.TextWidth).First()); if(BlockType == GanttChartViewItemBlockType.Return && its.Any(r=>r.Left + r.TextWidth < item.Left)) { var it = its.First(r => r.Left + r.TextWidth < item.Left); item.Top = it.Top; beforeTop = it.Top; } else { if(BlockType == GanttChartViewItemBlockType.Return && its.Any()) { beforeTop = its.Max(r => r.Top); } item.Top = beforeTop + ItemHeight + ItemSpacing; beforeTop += ItemHeight + ItemSpacing; } } else { if (i > 0) { if (BlockType == GanttChartViewItemBlockType.Return && beforeTop != row.Top + RowSpacing) { beforeTop = row.Top + RowSpacing; } } item.Top = beforeTop; } if (BlockType == GanttChartViewItemBlockType.Compact) { beforeRight = item.Left + item.Width; } else { beforeRight = item.Left + Math.Max(item.TextWidth, item.Width); } if (item.Ranges != null && item.Ranges.Any()) { var subs = item.Ranges.OrderBy(r => r.StartTime); foreach (var sub in subs) { sub.Left = item.Left + (int)((sub.StartTime - item.StartTime).TotalMinutes * minuteWidth); sub.Width = (int)((sub.EndTime - sub.StartTime).TotalMinutes * minuteWidth); } } } else { //row.Items.Remove(item); //i--; } } } if (row.Items == null || !row.Items.Any(r=>r.Left > 0)) { row.Bottom = row.Top + ItemHeight + RowSpacing * 2; } else { row.Bottom = Math.Max(row.Items.Max(r => r.Top), ColumnHeight + RowSpacing) + ItemHeight + RowSpacing; } currentRowY = row.Bottom; } } /// /// 计算提示框的位置 /// /// /// private Point ComputeTooltipLocation(Point e) { var size = TooltipOuterSize; var x = e.X; if (e.X + size.Width > _ContentControl.Width) { var t = e.X - size.Width; if (t < 0 && 0 - t < (e.X + size.Width) - _ContentControl.Width || t >= 0) { x = t; } } var y = _ShowTooltipItem.Top - _VScrollBar.Value + ItemHeight + ItemSpacing; if(y + size.Height > _ContentControl.Height) { var t = _ShowTooltipItem.Top - _VScrollBar.Value - ItemSpacing - size.Height; if (t < 0 && 0 - t < (y + size.Height) - _ContentControl.Height || t >= 0) { y = t; } } return new Point(x, y); } } }