I am using Dotnet Highchart that is based on C# code that has output code javascript.
Dotnet HighChart
This is almost how my chart looks like:
I am using data from my database to give this chart data by using LINQ queries.
I have a column "Completed Date" in my entity and I need to make two textboxes with datepicker so user can choose Start and end dates of Completed Date.Then the user should be able to click on a submit button and then the chart should update and show the statistic between the two dates. I have the complete LINQ Query for this
This is the LINQ query that I am going to use:
public List<CoreValueAndAverageGrade> GetAverageGradeForAllCoreValues(DateTime startDate, DateTime endDate)
{
return db.CoreValue
.Where(coreValue => coreValue.CoreValueQuestion
.Any(coreValueQuestion => coreValueQuestion.SubjectType.Ignored_Statistic == false))
.Select(coreValue => new CoreValueAndAverageGrade
{
CoreValue = coreValue,
AverageGrade = coreValue.CoreValueQuestion
.Where(coreValueQuestion => coreValueQuestion.SubjectType.Ignored_Statistic == false)
.Average(coreValueQuestion => coreValueQuestion.SelectedQuestions
.Where(selectedQuestion => selectedQuestion.GoalCardQuestionAnswer != null
&& selectedQuestion.GoalCardQuestionAnswer.Grade.HasValue
&& selectedQuestion.GoalCard.Completed_Date >= startDate
&& selectedQuestion.GoalCard.Completed_Date <= endDate
)
.Average(selectedQuestion => selectedQuestion.GoalCardQuestionAnswer.Grade.Value))
})
.ToList();
}
This is my ViewModel
public class OfficeStatisticNKIViewModel
{
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
In my GET action method I have following code:
public ActionResult OfficeStatistic()
{
{
OfficeStatisticNKIViewModel model = new OfficeStatisticNKIViewModel();
model.EndDate = DateTime.Now;
model.StartDate = DateTime.Now;
var averageGrades = OfficeStatisticRepository.GetAverageGradeForAllCoreValues(model.StartDate, model.EndDate);
var dataItems = (averageGrades.Select(averageGrade => averageGrade.AverageGrade).ToArray());
Data data = new Data(
dataItems.Select(y => new Point {Color = GetBarColour(y), Y = y}).ToArray());
Highcharts chart1 = new Highcharts("Chart")
.SetXAxis(new XAxis { Categories = averageGrades.Select(averageGrade => averageGrade.CoreValue.Name).ToArray() })
.SetYAxis(new YAxis { Min = 0, Max = 10, TickInterval = 1, Title = new YAxisTitle { Text = "Betygskalan" } })
.SetSeries(new Series { Data = data, Name = "Snittbetyg" })
.SetLegend(new Legend { Enabled = false })
.SetTitle(new Title { Text = "Örebro Statistik", })
.InitChart(new Chart { DefaultSeriesType = ChartTypes.Column });
return View(new Container(new[] { chart1 }));
}
The problem is that I have no idea how to do the post action method, The chart needs to update with the new the statistic, do I need some kind of ajax or can I do this on the serverside?
Any kind of help or tips is very appreciated!
Thanks in advance!
http://dotnethighcharts.codeplex.com/discussions/350721/
Related
enter image description here
suppose A is my Table and inside this table i have one column like times
inside column name times i have n number of times
Example :-1st:-02:30
2nd:-03:25
3rd:-00:45
i want output like TotalTime=06:40
i got out put using jquery but i want how to do inside a controller using foreach loop please help me
my controller code:-
[HttpPost]
public ActionResult getTimeSheetByBasit(DateTime? CurrentDate, string ActivityTime)
//obj.UserDocumentList = ThidDb.UserDocument.Where(x => x.CreatedBy == UserId).ToList();
{
VM_TimeSheet ObjVM_TimeSheet = new VM_TimeSheet();
int LoggedUser = User.KEY();
string LoggedUserName = User.UserName();
string UserEmail = User.EmailID();
DateTime TimeIn, TimeOut;
string TimeInn, TimeOuut, TotalTime;
//code add here fot adding text box time with total houres enter by user select time Sheet
using (SecurenetDB SecurenetDB = new SecurenetDB())
{
ObjVM_TimeSheet.TimesheetList = SecurenetDB.AD_TimeSheet.Where(x => DbFunctions.TruncateTime(x.ActivityDate.Value) == DbFunctions.TruncateTime(CurrentDate) && x.UserKEY == LoggedUser).ToList();
TimeIn = SecurenetDB.AD_CardPunching.Where(x => DbFunctions.TruncateTime(x.EventDate) == DbFunctions.TruncateTime(CurrentDate) && x.UserName == LoggedUserName).Select(x => x.Time_In).FirstOrDefault();
TimeOut = SecurenetDB.AD_CardPunching.Where(x => DbFunctions.TruncateTime(x.EventDate) == DbFunctions.TruncateTime(CurrentDate) && x.UserName == LoggedUserName).Select(x => x.Time_Out).FirstOrDefault();
TimeInn = TimeIn.ToString("hh:mm tt");
TimeOuut = TimeOut.ToString("hh:mm tt");
TotalTime = SecurenetDB.AD_CardPunching.Where(x => DbFunctions.TruncateTime(x.EventDate) == DbFunctions.TruncateTime(CurrentDate) && x.UserName == LoggedUserName).Select(x => x.TotalHours).FirstOrDefault();
// ObjVM_TimeSheet.TimesheetList=SecurenetDB.AD_TimeSheet.Where(x=>x.Hours== TextTime && x.UserKEY == LoggedUser).ToList();
var sum = "00:00";
foreach(var iteam in ActivityTime)
{
sum = sum + iteam;
}
}
return Json(new
{
TimeSheetData = this.RenderPartialViewToString("TimeSheetData", ObjVM_TimeSheet.TimesheetList),
TimeIn = TimeInn,
TimeOut = TimeOuut,
TotalTime = TotalTime
}, JsonRequestBehavior.AllowGet);
}
enter image description here
Use TimeSpan
string[] times = new string[] {"02:30", "03:25", "00:45"};
TimeSpan totalTime = new TimeSpan(0);
foreach (string time in times)
{
TimeSpan ts = TimeSpan.Parse(time);
totalTime += ts;
}
Console.WriteLine(totalTime.ToString(#"hh\:mm"));
Output
06:40
I have a page that allows the user to select a start date. When they select that specific date I would like them to be able to navigate to a different page and then back to that page with the start date remaining the same. Does anyone know how to do this using a session variable in MVC4?
m.StartDate = DateTime.Today.AddDays(-1);
m.EndDate = DateTime.Today.AddDays(-1);
m.StartDate = new DateTime(2018, 10, 18);
m.EndDate = new DateTime(2018, 10, 18);
Session["StartDate"] = m.StartDate;
if(Session["StartDate"] !=null)
{
//show the date selected by the user
}
else {
m.StartDate = new DateTime(2018, 10, 18);
m.EndDate = new DateTime(2018, 10, 18);
}
parameters.StartDate = m.StartDate;
parameters.EndDate = m.EndDate;
View Model:
public List<rptStoreTransferLog> lstFilteredrptStoreTransferLog = new List<rptStoreTransferLog>();
public List<rptStoreTransferLog> rptStoreTransferLog = new List<rptStoreTransferLog>();
public List<StoreDefinition> lstStoreDefinition = new List<StoreDefinition>();
public SelectionFilter SelectionFilter;
public DateTime StartDate;
public DateTime EndDate;
public bool SingleDateSelect;
public string SearchText = "";
public string SearchPlaceholderText = "";
public string PreviousColumnSearch = "StoreName";
public string strSingleDateSelect = " Single Date Select";
public int PreviousSelectedDivisionID;
public int PreviousSelectedProfitCentreID;
public int PreviousSelectedJobID;
public int PreviousSelectedStatusID;
public SelectReportSelections SelectReportSelections = new SelectReportSelections();
View:
#helper GetSingleDateSelect()
{
if (Model.SingleDateSelect == true)
{
#Html.CheckBoxFor(m => m.SingleDateSelect, new { #checked = "checked" });
#Html.DisplayTextFor(m => m.strSingleDateSelect)
}
else
{
#Html.CheckBoxFor(m => m.SingleDateSelect);
#Html.DisplayTextFor(m => m.strSingleDateSelect)
}
}
You can only do this if they submit the value to your controller action.
It's unclear from your question exactly how you've wired it up, but you need the date to be an input for the model property, then you'd store that in the session if you wanted to. However normally you'd just send it back in the model for the second page, and keep it there as a hidden value. Then your app remains nice and stateless and you don't have to worry about session variables.
I have a C# list items as follows-
List<MyClass> All_Items = GetListItems();
GetListItems() returns the result as follows-
Category StartDate EndDate
AA 2008-05-1
AA 2012-02-1
BB 2009-09-1
BB 2010-08-1
CC 2009-10-1
Using LINQ on All_Items, I want to update EndDate column in a way that if
If the current Category's StartDate is less than the Start Date of next bigger date item within same Category then use one less day than that of bigger date.
If there is no bigger date remaining then update to 2099-12-31
Final result is as follows-
Category StartDate EndDate
AA 2008-05-1 2012-01-31
AA 2012-02-1 2099-12-31
BB 2009-09-1 2010-07-31
BB 2010-08-1 2099-12-31
CC 2009-10-1 2099-12-31
I can only think of getting it done using too many loops. What is the better option?
Try this code. It Loops over all items and selects the next bigger item.StartDate for the same category.
If such an item is not available it sets you default date.
I couldn't Test the code as I'm writing on my mobile, so any correction is welcome.
foreach(var item in All_Items)
{
var nextItem = (from i in All_Items
where i != null &&
i.Category == item.Category &&
i.StartDate > item.StartDate
orderby i.StartDate
select i).FirstOrDefault();
item.EndDate = nextItem != null ? nextItem.StartDate.AddDays(-1) : new DateTime(2099,12,31);
}
LINQ is not good for processing dependencies between elements of a sequence, and for sure is not intended for updating.
Here is the simple and efficient way to achieve the goal:
var groups = All_Items.OrderBy(item => item.StartDate).GroupBy(item => item.Category);
foreach (var group in groups)
{
MyClass last = null;
foreach (var item in group)
{
if (last != null) last.EndDate = item.StartDate.AddDays(-1);
last = item;
}
last.EndDate = new DateTime(2099, 12, 31);
}
So we use LINQ just to order the elements by StartDate and group the result by Category (which preserves the ordering inside each group). Then simply iterate the LINQ query result and update the EndDate accordingly.
You can select dates for each category and put it into dictionary to save time later.
Then you just go through all your items and check if the start date less than next in category or not, according to you requirements.
Here it is:
var categoryDictionary = All_Items
.GroupBy(i => i.Category)
.ToDictionary(
g => g.Key,
g => g.Select(i => i.StartDate));
var defaultDate = DateTime.Parse("2099-12-31");
foreach (var item in All_Items)
{
var nextDateInCategory = categoryDictionary[item.Category]
.Where(i => i > item.StartDate)
.OrderBy(i => i)
.FirstOrDefault();
item.EndDate =
nextDateInCategory != default(DateTime)
? nextDateInCategory.AddDays(-1)
: defaultDate;
}
Let's assume your MyClass looks something like this:
public class MyClass
{
public string Category { get; set; }
public DateTime StartDate { get; set; }
public DateTime EndDate { get; set; }
}
Here is how you can do it, see the comments in the code for an explanation.
IEnumerable<MyClass> All_Items = new List<MyClass>
{
new MyClass { Category = "AA", StartDate = new DateTime(2008, 5, 1) },
new MyClass { Category = "AA", StartDate = new DateTime(2012, 2, 1) },
new MyClass { Category = "BB", StartDate = new DateTime(2009, 9, 1) },
new MyClass { Category = "BB", StartDate = new DateTime(2010, 8, 1) },
new MyClass { Category = "CC", StartDate = new DateTime(2009, 10, 1) }
}
// Group by category
.GroupBy(c => c.Category)
// Colapse the groups into a single IEnumerable
.SelectMany(g =>
{
// Store the already used dates
List<DateTime> usedDates = new List<DateTime>();
// Get a new MyClass that has the EndDate set, from each MyClass in the category
return g.Select(c =>
{
// Get all biggerDates that were not used already
var biggerDates = g.Where(gc => gc.StartDate > c.StartDate && !usedDates.Any(ud => ud == gc.StartDate));
// Set the endDate to the default one
DateTime date = new DateTime(2099, 12, 31);
// If a bigger date was found, mark it as used and set the EndDate to it
if (biggerDates.Any()) {
date = biggerDates.Min(gc => gc.StartDate).AddDays(-1);
usedDates.Add(date);
}
return new MyClass
{
Category = c.Category,
StartDate = c.StartDate,
EndDate = date
};
});
});
In a single LINQ statement (maxEndDate is 2099-12-31):
All_Items.GroupBy(category => category.Category).Select(key =>
{
var maxCategoryStartDate = key.Max(value => value.StartDate);
return key.Select(v => {
if (DateTime.Equals(v.StartDate, maxCategoryStartDate))
{
v.EndDate = maxEndDate;
}
else
{
v.EndDate = maxCategoryStartDate - TimeSpan.FromDays(1);
}
return v;
});
}
).SelectMany(x => x);
I am trying to modify the default WebAPI controller in VS2013 to return data in a way that can be consumed by HighCharts (in this case a Javascript timestamp and a value), and I've gotten pretty close with this code:
// GET: api/Readings
public HttpResponseMessage GetReadings(DateTime? starttime = null, DateTime? endtime = null, string name = "", string deviceId = "", bool latest = false, bool highcharts = false)
{
if (starttime == null)
{
starttime = DateTime.UtcNow.AddHours(-1);
}
if (endtime == null)
{
endtime = DateTime.UtcNow;
}
var readings = from r in db.Readings
join d in db.Devices on r.DeviceID equals d.Id
where (r.Timestamp >= starttime && r.Timestamp <= endtime)
select r;
if (name != "")
{
readings = readings.Where(p => p.Name == name);
}
if (deviceId != "")
{
readings = readings.Where(p => p.DeviceID == deviceId);
}
if (latest)
{
readings = readings.OrderByDescending(r => r.Timestamp).Take(1);
}
else
{
readings = readings.OrderBy(r => r.Timestamp);
}
if (highcharts)
{
var values = new List<Tuple<long, double>> { };
var data = readings.ToArray();
foreach (var item in data)
{
values.Add(new Tuple<long, double>(item.Timestamp.ToJavascriptTimestamp(), item.Value) );
}
return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, values);
}
return ControllerContext.Request.CreateResponse(HttpStatusCode.OK, readings);
}
The challenge I am facing is that the output produced, which I want to look like this (sample from http://www.highcharts.com/studies/live-server-data.php, used in http://www.highcharts.com/studies/live-server.htm and from the tutorial http://www.highcharts.com/docs/working-with-data/live-data):
[1433364572000, 3]
Instead looks like this:
[{"m_Item1":1433364610337,"m_Item2":65.5}]
It appears that when the list of tuples gets serialized, it adds the generic m_Item1 and m_item2 keys.
I need to know what to do with my data in the if (highcharts) block to get it to output in the required highcharts friendly format.
I've got a collection of object which contains data as follows:
FromTime Duration
2010-12-28 24.0000
2010-12-29 24.0000
2010-12-30 24.0000
2010-12-31 22.0000
2011-01-02 1.9167
2011-01-03 24.0000
2011-01-04 24.0000
2011-01-05 24.0000
2011-01-06 24.0000
2011-01-07 22.0000
2011-01-09 1.9167
2011-01-10 24.0000
In the "FromTime" column, there are data "gaps" i.e. 2011-01-01 and 2011-01-08 are "missing". So what I'd like to do is to loop through a range of dates (in this instance 2010-12-28 to 2011-01-10) and "fill in" the "missing" data with a duration of 0.
As I've just started with LINQ, I feel that it should be "fairly" easy but I can't quite get it right. I'm reading the book "LINQ in Action" but feel that I'm still quite a way off before I can resolve this particular issue. So any help would be much appreciated.
David
I'll define class like bellow:
public class DurDate
{
public DateTime date = DateTime.ToDay;
public decimal dure = 0;
}
and will wrote function like bellow:
private IEnumerable<DurDate> GetAllDates(IEnumerable<DurDate> lstDur)
{
var min = lstDur.Min(x => x.date).Date;
var max = lstDur.Max(x => x.date).Date;
var nonexistenceDates = Enumerable.Range(0, (int) max.Subtract(min).TotalDays)
.Where(x =>!lstDur.Any(p => p.date.Date == min.Date.AddDays(x)))
.Select(p => new DurDate {date = min.Date.AddDays(p), dure = 0});
return lstDur.Concat(nonexistenceDates).OrderBy(x=>x.date);
}
Sample test case:
List<DurDate> lstDur = new List<DurDate> { new DurDate { date = DateTime.Today, dure = 10 }, new DurDate { date = DateTime.Today.AddDays(-5), dure = 12 } };
Edit: It works simply, first I'll going to find min and max range:
var min = lstDur.Min(x => x.date).Date;
var max = lstDur.Max(x => x.date).Date;
What are the days not in the given range:
Where(x =>!lstDur.Any(p => p.date.Date == min.Date.AddDays(x)))
After finding this days, I'll going to select them:
Select(p => new DurDate {date = min.Date.AddDays(p), dure = 0})
At last concatenate the initial values to this list (and sort them):
lstDur.Concat(nonexistenceDates).OrderBy(x=>x.date);
Something like that. I didn't tested it, but I believe, that you will got the idea:
var data = new[]
{
new { Date = DateTime.Now.AddDays(-5), Duration = 3.56 },
new { Date = DateTime.Now.AddDays(-3), Duration = 3.436 },
new { Date = DateTime.Now.AddDays(-1), Duration = 1.56 },
};
Func<DateTime, DateTime, IEnumerable<DateTime>> range = (DateTime from, DateTime to) =>
{
List<DateTime> dates = new List<DateTime>();
from = from.Date;
to = to.Date;
while (from <= to)
{
dates.Add(from);
from = from.AddDays(1);
}
return dates;
};
var result = range(data.Min(e => e.Date.Date), data.Max(e => e.Date.Date))
.Join(data, e => e.Date.Date, e => e.Date, (d, x) => new {
Date = d,
Duration = x == null
? 0.0
: x.Duration
});
Also it would be better to replace this range lambda with some static method.