Очертить ось X диаграммы

Я хочу использовать диаграмму диаграммы для визуализации моих точек данных. Chartjs, кажется, оживляет график по умолчанию, но он не оживляет значения по оси x. Ось x перемещается только по отдельным шагам.

Есть ли способ включить анимацию на оси?

Спасибо!

Ответ 1

Насколько мне известно, ChartJS не поддерживает х-осевую анимацию из коробки. Так что вам придется взломать его. Существует несколько способов сделать это, но, похоже, работают следующие методы.

Если вы хотите оживить данные на оси X

Когда диаграмма обновляется, выполняются следующие шаги: 1) Очерки рисуются, а затем 2) вызывается функция draw() для рисования данных. Существуют разные функции draw() для разных типов диаграмм, а функция для линейных диаграмм - Chart.controllers.line.prototype.draw. Функции draw() принимают один аргумент, который я назову animationFraction, который указывает, насколько полная анимация является дробной. Например, если анимация завершена на 5%, animationFraction будет 0.05, и если анимация будет заполнена на 100% (т.е. Если диаграмма находится в ее окончательной форме), animationFraction=1. Функция draw() вызывается на каждом этапе анимации для обновления отображения данных.

Один взломать анимацию оси x, а затем - обезвредить функцию линейной диаграммы draw() для перевода холста в горизонтальном измерении на каждом шаге рисования:

var hShift = (1-animationFraction)*ctx.canvas.width;

hShift - это горизонтальный сдвиг в пикселях диаграммы. Как определено выше, данные будут отсчитываться справа; если вы хотите, чтобы он подместился слева, вы можете сделать вышеуказанный отрицательный. Затем вы сохраняете состояние контекста canvas, трансформируете холст с помощью hShift, рисуете данные диаграммы и затем восстанавливаете холст в исходное состояние, чтобы на следующем кадре анимации оси были нарисованы в правильном месте:

ctx.save();
ctx.setTransform(1, 0, 0, 1, hShift, 0);
ctx.oldDraw.call(this, animationFraction);
ctx.restore();

В приведенном выше выражении this относится к объекту диаграммы, а oldDraw относится к исходной графической диаграмме, которая была сохранена ранее:

var oldDraw = Chart.controllers.line.prototype.draw;

Вы можете дополнительно настроить новую функцию draw() для чтения новых параметров анимации, которые позволяют вам настроить анимацию оси x и оси y:

var oldDraw = Chart.controllers.line.prototype.draw;
Chart.controllers.line.prototype.draw = function(animationFraction) {
    var animationConfig = this.chart.options.animation;
    if (animationConfig.xAxis === true) {
        var ctx = this.chart.chart.ctx;
        var hShift = (1-animationFraction)*ctx.canvas.width;
        ctx.save();
        ctx.setTransform(1, 0, 0, 1, hShift,0);
        if (animationConfig.yAxis === true) {
            oldDraw.call(this, animationFraction);
        } else {
            oldDraw.call(this, 1);
        }
        ctx.restore();
    } else if (animationConfig.yAxis === true) {
        oldDraw.call(this, animationFraction);
    } else {
        oldDraw.call(this, 1);
    }
}

Затем вы можете создать линейную диаграмму с обеими анимированными осями:

var lineChart = new Chart(ctx, {
    type: 'line',
    data: data,
    options: { 
        animation: { 
            duration: 5000,
            xAxis: true,
            yAxis: true,
        }
    }
});

См. https://jsfiddle.net/16L8sk2p/ для демонстрации.

Если вы хотите оживить пределы X-Axis

Если вы хотите анимировать границы оси x - т.е. переместите данные, отметки оси и метки меток, тогда вы можете использовать следующую стратегию. Это немного причудливо, поэтому может потребоваться некоторое усилие, чтобы выработать изломы для любого прецедента, но я считаю, что он должен работать в целом. Во-первых, вам нужно будет преобразовать линейный график в график разброса. Линейные диаграммы имеют категориальные x-оси, которые перемещаются по шагам, поэтому вы не можете установить границы оси между тиками, что вам нужно сделать, чтобы получить анимацию. Таким образом, вам нужно будет использовать график разброса строк, так как диаграммы рассеяния могут иметь произвольные пределы оси. Вы можете сделать это путем нумерации каждой точки данных и присвоения этого числа значению x для этой точки данных. Например, чтобы создать случайный набор данных, вы можете сделать:

var DATA_POINT_NUM = 58;
var data = {
    labels: [],
    datasets: [
        {
            data: [],
        },
    ]
}
for (var i=0; i<DATA_POINT_NUM; i++) {
    data.datasets[0].data.push({    x: i,
                                    y: Math.random()*10
                                });
    data.labels.push(String.fromCharCode(65+i));
}

Затем вам нужно будет написать функцию для преобразования между назначенными значениями x ваших точек данных и метками точек данных (т.е. категориями, которые будут отображаться на диаграммах по оси x):

function getXAxisLabel(value) {
    try {
        var xMin = lineChart.options.scales.xAxes[0].ticks.min;
    } catch(e) {
        var xMin = undefined;
    }
    if (xMin === value) {
        return '';
    } else {
        return data.labels[value];
    }
}

где lineChart - наш объект Chart, который будет определен ниже. Обратите внимание, что ChartJS рисует диаграмму несколько иначе, если есть метка по минимальному значению по оси x, поэтому вам нужно будет написать эту функцию, чтобы вернуть пустую строку, если value == - минимальное значение оси x. Затем вы можете определить объект Chart:

var lineChart = new Chart(ctx, {
    type: 'line',
    data: data,
    options: { 
        animation: false,
        scales: {
            xAxes: [{
                type: 'linear',
                position: 'bottom',
                ticks: {
                    min: 0,
                    max: 10,
                    callback: getXAxisLabel, // function(value) { return data.labels[value]; },
                    autoSkip: false,
                    maxRotation: 0,

                },
            }]
        }
    }
});

ticks.callback установлен на нашу функцию getXAxisLabel выше. Когда ChartJS рисует ось x, он передает значения x точек данных в функцию обратного вызова, а затем использует полученную строку как значение по оси x. Таким образом, мы можем нарисовать диаграмму рассеяния, такую ​​как линейная диаграмма. Я также установил autoSkip=false и maxRotation=0, чтобы удостовериться, что метки осей будут рисоваться согласованным образом.

Затем вы можете анимировать диаграмму, отрегулировав значения оси x ticks.min и ticks.max и вызывая метод диаграммы .update(). Чтобы проиллюстрировать это, приведенный ниже код просматривает вдоль оси х диаграммы, отображая по десять точек данных за раз.

var xMin = 0;                   // Starting minimum value for the x-axis
var xLength = 10;               // Length of the x-axis
var animationDuration = 5000;   // Duration of animation in ms

// Calculate animation properties
var framesPerSec = 100;
var frameTime = 1000/framesPerSec;
var xStep = (DATA_POINT_NUM-xMin+xLength)/(animationDuration/1000*framesPerSec);

function nextFrame() {
    var xMax = xMin+xLength;
    if (xMax < DATA_POINT_NUM-1) {

        if (xMax+xStep > DATA_POINT_NUM-1) {
            xMax = DATA_POINT_NUM-1;
            xMin = xMax-xLength;
        }
        lineChart.options.scales.xAxes[0].ticks.min = xMin;
        lineChart.options.scales.xAxes[0].ticks.max = xMax;
        lineChart.update();
        setTimeout(nextFrame, frameTime);
        xMin += 0.1;
    }
}

nextFrame();

Объединяя все это: https://jsfiddle.net/qLhojncy/

Ответ 2

Я не эксперт в javascript, но я нашел пример для Chartjs, который при добавлении новой точки данных обновляет ось x через анимацию, как кажется, может быть, это поможет вам: пример.

Пример источника: sitepoint.com