Получить больше данных для линейного графика по вопросам Zoom/ OnPan

Я пытаюсь получить больше данных на мою линейную диаграмму chartjs (или использовать некоторые кэшированные резервные данные) onZoom/onPan, но у меня много проблем с этим.

Моя исходная база кода очень сложна, и я не могу полностью скопировать ее здесь, но я поделюсь тем, что уже пробовал.

1-е решение: Chartjs-plugin-zoom акции onZoom а также onPan обратные вызовы, как упомянуто здесь, но они не предоставляют никакого контекста (chart, x, y) с этими обратными вызовами, и вызывают при панорамировании / масштабировании, и это даже неправильно.

Этот PR решает несколько вопросов, но еще не объединен: Ссылка

2-е решение: я пытаюсь получить данные об изменениях в диаграмме JS в beforeUpdate обратный вызов, но это также вызывает много проблем для меня. По умолчанию я показываю около 1000 точек данных на графике, и поскольку мой график обновляется каждую секунду, я пытаюсь создать резервную копию данных, которые будут содержать переданные точки данных за пределами 1000 точек данных, поэтому, когда кто-то увеличивает, я проверяю координаты слева и справа, и если они изменяются (увеличение), я хочу увеличить данные в наборе данных в beforeUpdate Перезвони.

scales: {
    xAxes: [{
                    id: 'x-axis-0',
                    type: 'time',
                    beforeUpdate: function (chart) {
                        const scale = chart.chart.scales['x-axis-0']
                        if (scale.margins) {
                            const left = scale.getValueForPixel(scale.left)
                            const right = scale.getValueForPixel(scale.right)
                            const diffSec = (right - left) / 1000;
                            if (diffSec < 240) {
                                chart.chart.options.scales.xAxes[0].time.unit = 'second'
                            } else if (diffSec < 4*3600) {
                                chart.chart.options.scales.xAxes[0].time.unit = 'minute'
                            } else {
                                chart.chart.options.scales.xAxes[0].time.unit = 'minute'
                                chart.chart.options.scales.xAxes[0].time.stepSize = 10
                            }
                        }
// Ignore this if condition it is just for testing/debugging
                        if (chart.chart.data.labels.length > 1) {
                            // there are three line in graph
                            chart.chart.data.datasets[0].data = getMinArray(diffSec)
                            chart.chart.data.datasets[1].data = getAvgArray(diffSec)
                            chart.chart.data.datasets[2].data = getMaxArray(diffSec)
                            chart.chart.data.labels = getLabels(diffSec)
                            chart.update()
                          }
                    }
    }

Во втором методе я получаю больше ошибок, таких как:

Ошибка типа: невозможно прочитать свойство 'hidden' из неопределенного

У вас есть третье решение? пожалуйста, бросьте это ниже.

РЕДАКТИРОВАТЬ: я пробовал с разными версиями

"chart.js": "2.8.0",
"chartjs-plugin-zoom": "^0.7.0",

Кажется, что первое решение работает сейчас, но есть еще одна проблема:

  • onZoom вызывается при масштабировании, а не

    Function called once zooming is completed

    как упомянуто в Readme, так что это не поможет в извлечении данных из API.

2 ответа

Chartjs-plugin-zoom совместно использует обратные вызовы onZoom и onPan, как упомянуто здесь, но они не предоставляют никакого контекста (chart, x, y) с этими обратными вызовами

Там на самом деле контекст предоставляется. Он вызывается с объектом, содержащим диаграмму, так что вы можете сделать:

function callback(context) {
  console.log('Here is the chart: ' + context.chart);
}

Я нашел решение, и оно хорошо работает в beforeUpdate Перезвони.

У меня есть 1-3 набора данных в моих графиках, и решение работает для любого количества наборов данных, которые вы хотите поместить, но для временного ряда только с наличием allLabels а также allData использовать в графе.

У меня более сложный вариант использования, но я делюсь простейшим кодом для beforeUpdate а также filterData код:


function filterData(chartInstance, leftLegendTime) {

    let diff = chartInstance.data.labels[0].getTime() - leftLegendTime
    // Check min 10 sec difference between graph and zoomed out graph to get safe from over updates
    if (!chartInstance.data.labels || diff === 0 || diff <= 10000) return

    let allLabels = chartInstance.data.datasets[0].allLabels

    // Matching graph's left axis start...
    let leftIndex = allLabels.map(
        (elem) => parseInt(elem.getTime()/1000)
    ).indexOf(parseInt(leftLegendTime/1000))

    if (leftIndex === -1) return;

    chartInstance.data = {...chartInstance.data, labels: allLabels.slice(leftIndex)}

    for (let i = 0;i < chartInstance.data.datasets.length; i++) {
        chartInstance.data.datasets[i] = {
            ...chartInstance.data.datasets[i],
            data: chartInstance.data.datasets[i].allData.slice(leftIndex)
        }
    }

    chartInstance.update()
}


// ...in graphOptions:
scales: {
        xAxes: [{
        id: 'x-axis-0',
        type: 'time',
        beforeUpdate: function (chart) {
        const scale = chart.chart.scales['x-axis-0']
        if (scale.margins) {
            const left = scale.getValueForPixel(scale.left)
            filterData(chart.chart, left._d.getTime())
        }
     }
}],
zoom: {
    enabled: true,
    drag: false, // cannot have drag-to-zoom and pan at once
    mode: 'x',
    rangeMax: {
        x: new Date(Date.now() + 1000)
    },
    rangeMin: {
        x: new Date(Date.now() - 900 * 1000) // eg. to show max history...
    }
}
Другие вопросы по тегам