/// <summary> /// Gets a configured factory that creates the data required for the chart. /// </summary> /// <param name="summary">The summary.</param> /// <returns></returns> /// <exception cref="NotImplementedException"></exception> private ChartJsTimeSeriesDataFactory <ChartJsTimeSeriesDataPoint> GetChartJsFactory(List <SummaryInfo> summary, TimePeriod timePeriod) { var dateRange = timePeriod.GetDateRange(); ChartJsTimeSeriesTimeScaleSpecifier chartTimeScale = timePeriod.TimeUnit == TimePeriodUnitSpecifier.Year ? ChartJsTimeSeriesTimeScaleSpecifier.Month : ChartJsTimeSeriesTimeScaleSpecifier.Day; var factory = new ChartJsTimeSeriesDataFactory <ChartJsTimeSeriesDataPoint>(); factory.TimeScale = chartTimeScale; factory.StartDateTime = dateRange.Start; factory.EndDateTime = dateRange.End; factory.ChartStyle = ChartJsTimeSeriesChartStyleSpecifier.Line; factory.ChartColors = new List <string> { "#2ECC71", "#3498DB" }; var viewsSummary = summary.Where(m => m.DatasetName == VIEWS_DATASET_NAME); var completionSummary = summary.Where(m => m.DatasetName == COMPLETIONS_DATASET_NAME); var viewedDataset = new ChartJsTimeSeriesDataset(); viewedDataset.Name = VIEWS_DATASET_NAME; viewedDataset.DataPoints = viewsSummary .Select(m => new ChartJsTimeSeriesDataPoint { DateTime = m.InterationDateTime, Value = m.value }) .Cast <IChartJsTimeSeriesDataPoint>() .ToList(); var completionDataset = new ChartJsTimeSeriesDataset(); completionDataset.Name = COMPLETIONS_DATASET_NAME; completionDataset.DataPoints = completionSummary .Select(m => new ChartJsTimeSeriesDataPoint { DateTime = m.InterationDateTime, Value = m.value }) .Cast <IChartJsTimeSeriesDataPoint>() .ToList(); factory.Datasets.Add(completionDataset); factory.Datasets.Add(viewedDataset); return(factory); }
/// <summary> /// Convert a collection of time series datasets to category-value datasets, where the categories represent discrete periods in the specified time scale. /// </summary> /// <remarks> /// Quantizing the data points in this way will substantially improve the performance of Chart.js for large data sets. /// </remarks> private List <ChartJsCategoryValuesDataset> GetCategoryDatasets(ChartJsTimeSeriesTimeScaleSpecifier timeScale) { var quantizedDatasets = new List <ChartJsCategoryValuesDataset>(); foreach (var dataset in this.Datasets) { var datapoints = dataset.DataPoints; var datasetQuantized = new ChartJsCategoryValuesDataset(); datasetQuantized.Name = dataset.Name; datasetQuantized.BorderColor = dataset.BorderColor; datasetQuantized.FillColor = dataset.FillColor; if (timeScale == ChartJsTimeSeriesTimeScaleSpecifier.Day) { var quantizedDataPoints = datapoints .GroupBy(x => new { Day = x.DateTime }) .Select(x => new ChartJsCategoryValuesDataPoint { Category = x.Key.Day.ToString(DateFormatStringDayMonthYear), Value = x.Sum(y => y.Value), SortKey = x.Key.Day.ToString("yyyyMMdd"), }) .OrderBy(x => x.SortKey) .ToList(); datasetQuantized.DataPoints = quantizedDataPoints.Cast <IChartJsCategoryValuesDataPoint>().ToList(); } else if (timeScale == ChartJsTimeSeriesTimeScaleSpecifier.Month) { var quantizedDataPoints = datapoints .GroupBy(x => new { Month = new DateTime(x.DateTime.Year, x.DateTime.Month, 1) }) .Select(x => new ChartJsCategoryValuesDataPoint { Category = x.Key.Month.ToString(DateFormatStringMonthYear), Value = x.Sum(y => y.Value), SortKey = x.Key.Month.ToString("yyyyMM"), }) .OrderBy(x => x.SortKey) .ToList(); datasetQuantized.DataPoints = quantizedDataPoints.Cast <IChartJsCategoryValuesDataPoint>().ToList(); } else if (timeScale == ChartJsTimeSeriesTimeScaleSpecifier.Year) { var quantizedDataPoints = datapoints .GroupBy(x => new { Year = new DateTime(x.DateTime.Year, 1, 1) }) .Select(x => new ChartJsCategoryValuesDataPoint { Category = x.Key.Year.ToString("yyyy"), Value = x.Sum(y => y.Value), SortKey = x.Key.Year.ToString("yyyy"), }) .OrderBy(x => x.SortKey) .ToList(); datasetQuantized.DataPoints = quantizedDataPoints.Cast <IChartJsCategoryValuesDataPoint>().ToList(); } else { throw new NotImplementedException("Timescale is not implemented"); } quantizedDatasets.Add(datasetQuantized); } return(quantizedDatasets); }
/// <summary> /// Get a set of X-axis categories defined by the selected timescale and time period. /// </summary> /// <param name="timeScale">The time scale.</param> /// <returns></returns> /// <exception cref="System.NotImplementedException">Timescale is not implemented</exception> private List <ChartJsCategoryValuesDataPoint> GetTimescaleCategories(ChartJsTimeSeriesTimeScaleSpecifier timeScale) { // Determine the date range. var allDataPoints = this.Datasets.SelectMany(x => x.DataPoints); if (!allDataPoints.Any()) { return(new List <ChartJsCategoryValuesDataPoint>()); } var startDate = this.StartDateTime ?? allDataPoints.Min(x => x.DateTime); var endDate = this.EndDateTime ?? allDataPoints.Max(x => x.DateTime); var thisDate = startDate; var categoryDataPoints = new List <ChartJsCategoryValuesDataPoint>(); if (timeScale == ChartJsTimeSeriesTimeScaleSpecifier.Day) { // To test for the last date of the reporting period, get the next day. var lastDateNextDay = endDate.AddDays(1); while (thisDate < lastDateNextDay) { var categoryDataPoint = new ChartJsCategoryValuesDataPoint() { Category = thisDate.ToString(DateFormatStringDayMonthYear), SortKey = thisDate.ToString("yyyyMMdd") }; categoryDataPoints.Add(categoryDataPoint); thisDate = thisDate.AddDays(1); } } else if (timeScale == ChartJsTimeSeriesTimeScaleSpecifier.Month) { // To test for the last date of the reporting period, get the first day of the following month. var lastDateNextDay = new DateTime(endDate.Year, endDate.Month, 1).AddMonths(1); while (thisDate < lastDateNextDay) { var categoryDataPoint = new ChartJsCategoryValuesDataPoint() { Category = thisDate.ToString(DateFormatStringMonthYear), SortKey = thisDate.ToString("yyyyMM") }; categoryDataPoints.Add(categoryDataPoint); thisDate = thisDate.AddMonths(1); } } else if (timeScale == ChartJsTimeSeriesTimeScaleSpecifier.Year) { // To test for the last date of the reporting period, get the first day of the following year. var lastDateNextDay = new DateTime(endDate.Year, 1, 1).AddYears(1); while (thisDate < lastDateNextDay) { var categoryDataPoint = new ChartJsCategoryValuesDataPoint() { Category = thisDate.ToString("yyyy"), SortKey = thisDate.ToString("yyyy") }; categoryDataPoints.Add(categoryDataPoint); thisDate = thisDate.AddYears(1); } } else { throw new NotImplementedException("Timescale is not implemented"); } return(categoryDataPoints); }