首页 文章

使用Razor模型数据填充javascript图表

提问于
浏览
1

我有一个折线图http://www.chartjs.org/docs/#line-chart-introduction我想用MVC6 / Razor中的viewmodel填充数据

我的Viewmodels是

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; }
}

我的观点是我的视图中的脚本部分是:

@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>
}

所以我想用我的 HistoicPointsViewModel.YAxisDates 作为Y轴坐标然后我想为我的PlayerHistores中的每个玩家创建一个数据集,它从 PlayerHistoricViewModel.Points 获取数据作为绘制到图形中的数据

我的问题是使用Razor编写动态javascript,所以它看起来就像这个例子

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]
    }
]
};

3 回答

  • 1

    我认为最简单的方法是创建相应的 ChartModel ,它可以被序列化为您需要的确切JSON结构:

    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));
       }
    }
    

    然后在视图中你可以做类似的事情

    <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>
    

    对于序列化,我使用JSON.NET

  • 2

    首先,我建议不要混合使用javascript和razor,因为内联javascript很容易出现XSS .

    我会在一些你可以在剃刀中创建的不可见元素上使用数据属性,然后从javascript中读取这些数据属性 .

    所以只需创建具有数据属性的div(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
                    />
                }
    

    并在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);
    });
    

    这样你就可以从razor中分离出javascript了 .

  • 1

    你需要将模型列表编码为json,你可以使用razor的json helper来完成这个,试试这个:

    var datelist = @Html.Raw(Json.Encode(Model.HistoicPoints.YAxisDates.Select(v => v.ToString("MMMM")));
    

    ToString("MMMM") 将为您提供整个月份的名称 .

    同样对于历史悠久的球员来说

    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
    })));
    

    我已经使用 Color 类创建了颜色,如果你想使用它或只是将rgba设置为字符串 .

    基本上你在javascript代码中执行此操作 .

    var data = {
        labels: '@datelist',
        datasets: '@playerHistory'
    };
    

相关问题