Получить больше данных для линейного графика по вопросам 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...
}
}