/// <summary> /// Determin coloring of GantItem, based on dates and override when needed. /// </summary> /// <param name="item">The GantItem to check.</param> private void DeterminGantItemColor(GantItem item, int itemIndex) { // Items with invalid Date(s), need to be re-colored if (item.HasInvalidDates) { if (string.IsNullOrEmpty(item.Color)) { item.Color = NO_VALID_DATE_COLOR; } item.Description = item.Description; } else if (!item.HasValidStartDate) { if (string.IsNullOrEmpty(item.Color)) { item.Color = NO_VALID_START_DATE_COLOR; } item.Description = item.Description; } else if (!item.HasValidEndDate) { if (string.IsNullOrEmpty(item.Color)) { item.Color = NO_VALID_END_DATE_COLOR; } item.Description = item.Description; } // If dynamic coloring is requested, overwrite inline values else if (useDynamicColors) { if (string.IsNullOrEmpty(item.Color)) { int colorIndex = itemIndex % dynamicColorList.Length; item.Color = dynamicColorList[colorIndex]; } } // All items need a color, determine default color else if (string.IsNullOrEmpty(item.Color)) { // If a static color is set for chart, use that color if (!string.IsNullOrEmpty(this.staticColor)) { item.Color = this.staticColor; } // Else, use a default color else { item.Color = STATIC_BASE_COLOR; } } }
protected override void Render(HtmlTextWriter writer) { Page.ClientScript.RegisterStartupScript(typeof(Page), "GantManager", "var GantManager = {};", true); string myGant = "GantManager['" + this.ClientID + "'] = new Array();"; Page.ClientScript.RegisterStartupScript(typeof(Page), "Gant" + this.ClientID, myGant, true); // Get count of Gant Items. int itemCount = this.gantItems.Count; // If there are no gant items, just render empty control. if (itemCount == 0) { Label noItems = new Label(); noItems.CssClass = "GantChartNoItems"; noItems.Text = "No Items"; base.RenderBeginTag(writer); noItems.RenderControl(writer); base.RenderEndTag(writer); } else { // Keep track of items with no start or end dates // (i.e., DateTime.Min && DateTime.Min Dates) List <GantItem> gantItemsNoStart = new List <GantItem>(); List <GantItem> gantItemsNoEnd = new List <GantItem>(); // Index of visible items, not all items in chart will be visible // so no need to offset valid items which are next to invalid items int visibleGantIndex = 0; for (int i = 0; i < itemCount; i++) { GantItem item = this.gantItems[i]; item.ShowDescription = showGantItemDescriptions; // Set opacities item.RemainingOpacity = remainingItemOpacity; item.CompletedOpacity = completedItemOpacity; // Set mouse events, if not defined in individual items if (!string.IsNullOrEmpty(this.onItemMouseClick) && string.IsNullOrEmpty(item.OnMouseClick)) { item.OnMouseClick = this.onItemMouseClick; } if (!string.IsNullOrEmpty(this.onItemMouseOver) && string.IsNullOrEmpty(item.OnMouseOver)) { item.OnMouseOver = this.onItemMouseOver; } if (!string.IsNullOrEmpty(this.onItemMouseOut) && string.IsNullOrEmpty(item.OnMouseOut)) { item.OnMouseOut = this.onItemMouseOut; } // DETERMINE GLOBAL DATES // Determine earliest start date if (item.HasValidStartDate && (startDate == DateTime.MinValue || item.StartDate < startDate)) { startDate = new DateTime(item.StartDate.Ticks); } else { if (item.HasValidEndDate && startDate > item.EndDate) { startDate = new DateTime(item.EndDate.Ticks); } gantItemsNoStart.Add(item); } // Determine latest end date if (item.HasValidEndDate && (endDate == DateTime.MaxValue || item.EndDate > endDate)) { endDate = new DateTime(item.EndDate.Ticks); } else { if (item.HasValidStartDate && endDate < item.StartDate) { endDate = new DateTime(item.StartDate.Ticks); } gantItemsNoEnd.Add(item); } // Determine if item will be visible, i.e. it has valid end or start date (or both) if (!item.HasInvalidDates) { // Distance from the top of container is determine by factor of ITEM_TOP_OFFSET item.Top = (visibleGantIndex * ITEM_TOP_OFFSET) + 25; // Determine coloring of item DeterminGantItemColor(item, i); visibleGantIndex++; } } // Determin "real" start and end dates // i.e. Min and Max dates should not be valid if (startDate == DateTime.MinValue) { // If both dates are invalid // span is the beginng of this to begining of next year if (endDate == DateTime.MaxValue) { DateTime today = DateTime.Today; DateTime firstDayOfYear = new DateTime(today.Year, 1, 1); DateTime firstDayOfNextYear = new DateTime(today.Year + 1, 1, 1); startDate = firstDayOfYear; endDate = firstDayOfNextYear; } // Otherwirse, start date is a year before the end date else { startDate = new DateTime(endDate.Year - 1, 1, 1); } } else if (endDate == DateTime.MaxValue) { // Start date is valid at this point endDate = new DateTime(startDate.Year, 1, 1); } /// NORMALIZE START AND END DATE // Start and Ends always occur on 1st of month int startMonth = startDate.Month; int startYear = startDate.Year; if (startMonth == 1) { startMonth = 12; startYear = startYear - 1; } // Each marker should represent a differnt date/day, so the range of the chart // should cover at least the count of markers int currentChartDaySpan = (int)(endDate - startDate).TotalDays; if (currentChartDaySpan < markerCount) { long neededChartDaySpan = (new TimeSpan(markerCount, 0, 0, 0, 0) - (endDate - startDate)).Ticks; long daysBefore = neededChartDaySpan / (long)2.0; long daysAfter = neededChartDaySpan / (long)2.0; // Subtract and Add days to current start and end dates startDate = startDate.Subtract(new TimeSpan(daysBefore)); endDate = endDate.Add(new TimeSpan(daysAfter)); } else { long ticksPerMarker = (endDate - startDate).Ticks / (long)markerCount; startDate = startDate.Subtract(new TimeSpan(ticksPerMarker)); endDate = endDate.Add(new TimeSpan(ticksPerMarker)); } // A double representing the ticks from the start to the end of chart double chartDateSpan = (double)(endDate - startDate).Ticks; double increment = chartDateSpan / (double)markerCount; // Loop tghrough all items and deteremine widths based on // date range in chart for (int i = 0; i < itemCount; i++) { GantItem item = this.gantItems[i] as GantItem; // Only concernced with calculations with items that have valid dates if (item.HasValidStartDate || item.HasValidEndDate) { if (item.HasValidDates) { double itemDateSpan = (double)(item.EndDate - item.StartDate).Ticks; double itemDateFromStart = (double)(item.StartDate - startDate).Ticks; int itemDateSpanPercentage = (int)(itemDateSpan / chartDateSpan * 100.0); int itemDateSpanFromStart = (int)(itemDateFromStart / chartDateSpan * 100.0); // Items with valid dates need at least 1% width to be represented item.Style["width"] = Math.Max(1, itemDateSpanPercentage) + "%"; item.Left = itemDateSpanFromStart; } // Invalid items do not need widths set explicitly, will be handled by control else { if (item.HasValidStartDate) { double itemDateFromStart = (double)(item.StartDate - startDate).Ticks; int itemDateFromStartPercentage = (int)(itemDateFromStart / chartDateSpan * 100.0); item.Left = itemDateFromStartPercentage; } else if (item.HasValidEndDate) { double itemDateFromEnd = (double)(endDate - item.EndDate).Ticks; int itemDateFromEndPercentage = 100 - (int)(itemDateFromEnd / chartDateSpan * 100.0); item.Left = itemDateFromEndPercentage; } } } } // RENDERING // Content which is not part of GantChart (i.e., legend, headers, etc...) // should be rendered/writen directly to the output // instead of being Controls in the GantChart Control collection base.RenderBeginTag(writer); base.RenderContents(writer); // Render Title RenderGantTitle(writer); // Render Header RenderGantHeader(increment, writer); // Render Chart Background (w/ lines) RenderGantBackground(writer); // Render Legend RenderGantLegend(writer); base.RenderEndTag(writer); } }