I have a line chart I want to populate with data from a viewmodel in MVC6/Razor
My Viewmodels are
public class LeaderboardViewModel
{
public List<LeaderboardViewEntry> LeaderboardViewEntries { get; set; }
public HistoicPointsViewModel HistoicPoints { get; set; }
}
public class HistoicPointsViewModel
{
public HistoicPointsViewModel()
{
PlayerHistores = new List<PlayerHistoricViewModel>();
}
public DateTime[] YAxisDates { get; set; }
public List<PlayerHistoricViewModel> PlayerHistores { get; set; }
}
public class PlayerHistoricViewModel
{
public PlayerHistoricViewModel()
{
Points = new List<int?>();
}
public string PlayerName { get; set; }
public List<int?> Points { get; set; }
}
And my view is script section in my View is:
@model Foosball9001.ViewModels.Leaderboards.LeaderboardViewModel
<canvas id="myChart" width="800" height="400"></canvas>
@section Scripts{
<script type="text/javascript">
var data = {
labels: @Model.HistoicPoints.YAxisDates,
datasets: [
{
@foreach (PlayerHistoricViewModel x in Model.HistoicPoints.PlayerHistores)
{
{
label: x.PlayerName,
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: x.Points
}
}
}
]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myNewChart = new Chart(ctx).Line(data);
</script>
}
So I want to use my HistoicPointsViewModel.YAxisDates
as the Y axis coordinates and then I want to create a dataset for each player in my PlayerHistores where it takes the data from PlayerHistoricViewModel.Points
as the data to plot into the graph
My problem is writing the dynamic javascript using Razor so it looks like the example
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: "My Second dataset",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
I have a line chart http://www.chartjs/docs/#line-chart-introduction I want to populate with data from a viewmodel in MVC6/Razor
My Viewmodels are
public class LeaderboardViewModel
{
public List<LeaderboardViewEntry> LeaderboardViewEntries { get; set; }
public HistoicPointsViewModel HistoicPoints { get; set; }
}
public class HistoicPointsViewModel
{
public HistoicPointsViewModel()
{
PlayerHistores = new List<PlayerHistoricViewModel>();
}
public DateTime[] YAxisDates { get; set; }
public List<PlayerHistoricViewModel> PlayerHistores { get; set; }
}
public class PlayerHistoricViewModel
{
public PlayerHistoricViewModel()
{
Points = new List<int?>();
}
public string PlayerName { get; set; }
public List<int?> Points { get; set; }
}
And my view is script section in my View is:
@model Foosball9001.ViewModels.Leaderboards.LeaderboardViewModel
<canvas id="myChart" width="800" height="400"></canvas>
@section Scripts{
<script type="text/javascript">
var data = {
labels: @Model.HistoicPoints.YAxisDates,
datasets: [
{
@foreach (PlayerHistoricViewModel x in Model.HistoicPoints.PlayerHistores)
{
{
label: x.PlayerName,
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: x.Points
}
}
}
]
};
var ctx = document.getElementById("myChart").getContext("2d");
var myNewChart = new Chart(ctx).Line(data);
</script>
}
So I want to use my HistoicPointsViewModel.YAxisDates
as the Y axis coordinates and then I want to create a dataset for each player in my PlayerHistores where it takes the data from PlayerHistoricViewModel.Points
as the data to plot into the graph
My problem is writing the dynamic javascript using Razor so it looks like the example
var data = {
labels: ["January", "February", "March", "April", "May", "June", "July"],
datasets: [
{
label: "My First dataset",
fillColor: "rgba(220,220,220,0.2)",
strokeColor: "rgba(220,220,220,1)",
pointColor: "rgba(220,220,220,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(220,220,220,1)",
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: "My Second dataset",
fillColor: "rgba(151,187,205,0.2)",
strokeColor: "rgba(151,187,205,1)",
pointColor: "rgba(151,187,205,1)",
pointStrokeColor: "#fff",
pointHighlightFill: "#fff",
pointHighlightStroke: "rgba(151,187,205,1)",
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
Share
Improve this question
edited Sep 13, 2018 at 11:53
Svenmarim
3,7356 gold badges26 silver badges58 bronze badges
asked Dec 17, 2015 at 19:57
Mech0zMech0z
3,6476 gold badges51 silver badges87 bronze badges
2
- 1 If this is asp MVC 6, why do you have an asp MVC 4 tag? By the way, what's the model in your view? – ataravati Commented Dec 17, 2015 at 20:21
- @ataravati Sorry cleaned it up, added the Viewmodel to the view and added the viewmodel to the classes – Mech0z Commented Dec 17, 2015 at 20:43
3 Answers
Reset to default 4I think the easiest way would be to create corresponding ChartModel
that could be serialized to the exact JSON structure that you need:
public class DtatsetModel
{
public string label {get;set;}
public const string fillColor = "rgba(220,220,220,0.2)";
public const string strokeColor = "rgba(220,220,220,1)";
public const string pointColor = "rgba(220,220,220,1)";
public const string pointStrokeColor = "#fff";
public const string pointHighlightFill = "#fff";
public const string pointHighlightStroke = "rgba(151,187,205,1)";
public List<string> data {get;set;}
public DtatsetModel(PlayerHistoricViewModel x)
{
this.label = x.PlayerName;
this.data = x.Points.Where(p=>p.HasValue).Select(p=>p.ToString());
}
}
public class ChartModel
{
public List<string> labels {get;set;}
public List<DtatsetModel> datasets {get;set;}
public ChartModel(HistoicPointsViewModel x)
{
this.labels = x.Select(d=>d.ToString("MMMM"));
this.datasets = x.PlayerHistores.Select(h=>new DtatsetModel(h));
}
}
then in the view you can do something like
<script type="text/javascript">
var data = @Html.Raw(JsonConvert.SerializeObject(new ChartModel(Model.HistoicPoints)))
var ctx = document.getElementById("myChart").getContext("2d");
var myNewChart = new Chart(ctx).Line(data);
</script>
For serialization I used JSON.NET
First of all I would propose not mixing javascript and razor since inline javascript is prone for XSS.
I would make use of data attributes on some invisible elements that you can create in razor and then read those data attributes from javascript.
So just create divs with data attributes (data attributes description)
@foreach (PlayerHistoricViewModel x in Model.HistoicPoints.PlayerHistores)
{
<div
class="players"
data-label= "x.PlayerName",
data-fillColor= "rgba(220,220,220,0.2)",
data-strokeColor= "rgba(220,220,220,1)",
data-pointColor= "rgba(220,220,220,1)",
data-pointStrokeColor= "#fff",
data-pointHighlightFill= "#fff",
data-pointHighlightStroke= "rgba(220,220,220,1)",
data-points= "x.Points"//this will maybe need some work to make json array
/>
}
And in javascript:
var datasets = [];
$("div.players").each(function(){
var testdata = {
label = $(this).data('label');
fillColor = $(this).data('label');
...
points = $(this).data('points');
//if datapoints will be json array then it will be automatically parsed as such
}
datasets.push(testdata);
});
This way you have decoupled javascript from razor.
you need to encode the model list to a json you can do this using the json helper from razor, try this:
var datelist = @Html.Raw(Json.Encode(Model.HistoicPoints.YAxisDates.Select(v => v.ToString("MMMM")));
ToString("MMMM")
will give you the entire month name.
the same for the player historic
var playerHistory = @Html.Raw(Json.Encode(Model.HistoicPoints.PlayerHistores.Select(v => new
{
label = v.PlayerName,
fillColor = String.Format("rgba({0},{1},{2},{3})", Color.Blue.R, Color.AliceBlue.G, Color.AliceBlue.B, Color.AliceBlue.A),
strokeColor = String.Format("rgba({0},{1},{2},{3})", Color.Blue.R, Color.AliceBlue.G, Color.AliceBlue.B, Color.AliceBlue.A),
pointColor = String.Format("rgba({0},{1},{2},{3})", Color.Blue.R, Color.AliceBlue.G, Color.AliceBlue.B, Color.AliceBlue.A),
pointStrokeColor = "#fff",
pointHighlightFill = "#fff",
pointHighlightStroke = "rgba(220,220,220,1)",
data = v.Points
})));
I've created the colors using the Color
class if you want to use it or just set the rgba as a string.
and basically you do this in the javascript code.
var data = {
labels: '@datelist',
datasets: '@playerHistory'
};