绘制图表.js包含 ajax 数据和响应式.一些问题和疑问

Draw a Chart.js with ajax data and responsive. A few problems and questions

本文关键字:问题 响应 绘制 js 包含 ajax 数据      更新时间:2023-09-26

我正在使用图表.js(http://www.chartjs.org/docs/)进行图表绘制。

我需要从 Ajax 请求和图表中获取数据才能做出响应。

在我的HTML代码中,我添加了一个画布,如下所示:

<div>
  <canvas id="userscreated" class="plot" data-url="/stats/userscreated"></canvas>
</div>

在我的javascript(JQuery)代码中,我有:

var data2;
$.ajax({
  url: $('#userscreated').data('url'),
  async: true,
  dataType: 'json',
  type: "get",
}).done(function (data) {
    data2 = data;
    // Draw chart
    var context = $('#userscreated').get(0).getContext("2d");
    var wrapper = $('#userscreated').parent();
    var width = $('#userscreated').attr('width', $(wrapper).width());
    new Chart(context).Line(
    {
      labels: data.Dates,
      datasets: [
        { fillColor: #404040, data: data.Users }
      ]
    },
    { animation: false }
  );
});
// Redraw the chart with the same data
$(window).resize(function () {
  var context = $('#userscreated').get(0).getContext("2d");
  var wrapper = $('#userscreated').parent();
  var width = $('#userscreated').attr('width', $(wrapper).width());
  new Chart(context).Line(
    {
      labels: data2.Dates,
      datasets: [
        { fillColor: #404040, data: data2.Users }
      ]
    },
    { animation: false }
  );
});

问题

  1. 调整窗口大小时不会调整图表的大小。
  2. 有没有更好的代码来做到这一点?我想我正在重复很多代码。
  3. 在谷歌中,绘图速度很快。在火狐中,有时它会挂起一段时间。我的代码有什么问题吗?
  4. 请求是否应该是异步的?

你可以使异步 AJAX 调用没有问题。重要的是,仅在成功回调触发后设置图表。否则,会遇到画布上下文未定义的问题。对 respondCanvas 的第一次调用执行初始设置,而后续调用执行大小调整。

这是对我有用的:

var max = 0;
var steps = 10;
var chartData = {};
function respondCanvas() {
    var c = $('#summary');
    var ctx = c.get(0).getContext("2d");
    var container = c.parent();
    var $container = $(container);
    c.attr('width', $container.width()); //max width
    c.attr('height', $container.height()); //max height                   
    //Call a function to redraw other content (texts, images etc)
    var chart = new Chart(ctx).Line(chartData, {
        scaleOverride: true,
        scaleSteps: steps,
        scaleStepWidth: Math.ceil(max / steps),
        scaleStartValue: 0
    });
}
var GetChartData = function () {
    $.ajax({
        url: serviceUri,
        method: 'GET',
        dataType: 'json',
        success: function (d) {
           chartData = {
                labels: d.AxisLabels,
                datasets: [
                    {
                        fillColor: "rgba(220,220,220,0.5)",
                        strokeColor: "rgba(220,220,220,1)",
                        pointColor: "rgba(220,220,220,1)",
                        pointStrokeColor: "#fff",
                        data: d.DataSets[0]
                    }
                ]
            };
            max = Math.max.apply(Math, d.DataSets[0]);
            steps = 10;
            respondCanvas();
        }
    });
};
$(document).ready(function() {
    $(window).resize(respondCanvas);
    GetChartData();
});

如果要在呼叫之间插入一个小延迟,可以使用超时:

$(document).ready(function() {
    $(window).resize(setTimeout(respondCanvas, 500));
    GetChartData();
});

延迟将使调整大小更具响应性,以防图形上有大型数据集。

你可以在图表中设置它.js

new Chart(context, {
  type:"line",
  labels: data.Dates,
  datasets: [
    { fillColor: #404040, data: data.Users }
  ]
  options: { responsive: false }
});

对于那些在 2021 年阅读本文的人:

图表更新.js v3.x.x

以下更新的答案 v3.x.x(不向后兼容 v2.x.x

首先,回答 4 个初始问题

  1. 调整窗口大小时不会调整图表的大小。
  2. 有没有更好的代码来做到这一点?我想我正在重复很多代码。
  3. 在谷歌中,绘图速度很快。在火狐中,有时它会挂起一段时间。我的代码有什么问题吗?
  4. 请求是否应该是异步的?
  1. 使用当前版本,它应该会自动调整大小,自己尝试运行下面的代码片段并调整浏览器窗口的大小。

  2. 诀窍是将图表分配给变量const myLineChart = 然后在需要时简单地调用myLineChart.update()。请注意,在调用 myLineChart.update() 之前,请以编程方式再次分配标签和数据集,否则数据更改将不会反映在图表中。

  3. 根据我的测试,现在在火狐中应该没问题。

  4. 哦,是的,绝对异步(带有回调或承诺的 ajax 或 http-request )。

// once the success function of your $.ajax request fires,
// put following code within your success-function
// for now, let's assume sample data
let data2 = {
  "Dates" : [
    "2021-08-02",
    "2021-08-03",
    "2021-08-04",
    "2021-08-05",
    "2021-08-06"
  ],
  "Users": [
    6,
    4,
    3,
    8,
    2
  ]
};
// Draw chart
const ctx = document.querySelector('canvas').getContext('2d');
const myLineChart = new Chart(ctx, {
  type: 'line',
  data: {
    labels: data2.Dates,
    datasets: [{
      label: 'Users created',
      data: data2.Users,
      borderColor: 'green',
      backgroundColor: '#404040',
      fill: true,
      animations: false // <-- now plural, instead of "animation" before
    }]
  }
});
// Redraw the chart with an added record
function updateData(event) {
  event.target.disabled = true;
  data2 = {
    "Dates" : [
      "2021-08-02",
      "2021-08-03",
      "2021-08-04",
      "2021-08-05",
      "2021-08-06",
      "2021-08-07"
    ],
    "Users": [
      6,
      4,
      3,
      8,
      2,
      12
    ]
  };
  // assign programmatically the datasets again, otherwise data changes won't show
  myLineChart.data.labels = data2.Dates;
  myLineChart.data.datasets[0].data = data2.Users;
  myLineChart.update();
};
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<!-- gets you the latest version of Chart.js, now at v3.5.0 -->
<button onclick="updateData(event)">add Data</button>
<canvas width="320" height="240"></canvas>

  1. 事实上
  2. 是的,我给你举个例子。
  3. 我没有看到任何可能导致问题的东西。除了 window.resize 可能会比您想要的更频繁地触发渲染新图表。
  4. 不。(我真的不知道为什么,这更多的是巧合。

代码:

window.getVisitCounts = ($canvas) ->
    url = Routes.visits_between_project_path($canvas.data('project-id'), {
        format: "json",
        start: $canvas.data('start'),
        end: $canvas.data('end')
    })

visits = []
days = []
 $.ajax
 url: url,
 async: false,
 dataType: "json",
 type: "GET",
 success: (data) - >
 for point in data.chart.data
 visits.push(point.visits)
 days.push(point.date)
 {
     days: days,
     visits: visits
 }
 window.createChartData = (raw) - > {
     labels: raw.days,
     datasets: [{
         fillColor: "rgba(151,187,205,0.5)",
         strokeColor: "rgba(151,187,205,1)",
         pointColor: "rgba(151,187,205,1)",
         pointStrokeColor: "#fff",
         data: raw.visits,
     }]
 }
 window.setupCanvas = ($canvas, data) - >
     newWidth = $canvas.parent().width()
 $canvas.prop
 width: newWidth
 height: 400
 options = {
     scaleOverride: true,
     scaleSteps: 10,
     scaleStepWidth: Math.ceil(Math.max.apply(Math, data.datasets[0].data) / 10),
     scaleStartValue: 0
 }
 ctx = $canvas.get(0).getContext("2d")
 new Chart(ctx).Line(data, options)
 $ - > @canvas = $("#analytics-canvas")
 if@ canvas.length != 0@ visits = window.createChartData(window.getVisitCounts(@canvas))
 window.setupCanvas(@canvas, @visits)
 $(window).on('resizeEnd', - >
     setupCanvas(document.canvas, document.visits)
 )
 $(window).resize - >
 if (@resizeTO)
     clearTimeout(@resizeTO)
 @resizeTO = setTimeout(- >
     $(this).trigger "resizeEnd"
     500
 )