在ChartJS中使用spanGaps时获取空值的坐标?

问题描述 投票:0回答:1

我想知道 ChartJS 是否公开了一个插件 API,允许我们获取已被 ChartJS“跨越”的

null
点的坐标?

例如,如本问题所示 当将

null
设置为“true”时,ChartJS 可以通过
spanGaps
点实现平滑曲线。

所以我们可以有这样的数据点。

data: [7, null, 11, null,  5 , null,  8, null,   3, null,  7],

对应这些标签。

["Red", "Blue", "Yellow", "Green", "Purple", "Orange", "Blue", "Yellow", "Green", "Purple", "Green"],

有没有办法(也许通过插件API)来获取空值?

因此,对于图表 JS 绘制的给定二次曲线:

data: [7, null, 11, null,  5 , null,  8, null,   3, null,  7],

我们可以调用例如:

const arr = ChartJSPluginAPI.deriveNulls(data);

并得到类似的东西:

data: [7, 8, 11, 6,  5 , 6,  8, 4,   3, 5,  7],

想法?

javascript typescript canvas chart.js html5-canvas
1个回答
0
投票

找到由图表.js 计算的插值是 这并不简单,因为 Chart.js 以图形模式执行插值 只是,所以我们必须获得现有点的图形值 对于相关的数据集元, 执行插值,然后回到真实空间,使用 y 轴缩放。 然而,这比尝试在真实空间中以数学方式模拟插值更安全。

寻找中间值的第一件事是确定 Chart.js 使用函数对曲线的所有值进行插值; 共有三个功能:

_steppedInterpolation

阶梯式
折线图, _bezierInterpolation
 如果设置了 
tension
 选项,
默认线性插值为 
_pointInLine

const _bezierInterpolation = Chart.helpers._bezierInterpolation, _steppedInterpolation = Chart.helpers._steppedInterpolation, _pointInLine = Chart.helpers._pointInLine;
注意,如果使用模块,需要导入

helpers

模块
分别。

很重要的一点是在动画结束后进行计算 完成,因为例如贝塞尔系数(如果贝塞尔插值 被使用)在动画过程中不断重新计算,并且它们的最终 动画结束后才能获取值 最终确定。因此,我们在动画中实现计算

onComplete


处理者:

onComplete: function({chart}){ const datasetMetas = chart.getSortedVisibleDatasetMetas(); for(const datasetMeta of datasetMetas){ if(datasetMeta.type === 'line'){ const controller = datasetMeta.controller, spanGaps = controller.options.spanGaps, dataRaw = controller._data; if(spanGaps && dataRaw.includes(null)){ const gData = datasetMeta.data, yScale = datasetMeta.yScale, yValues = []; // the final result const tension = controller.options.tension || controller.options.elements.line.tension; interpolation = controller.options.stepped ? _steppedInterpolation : tension ? _bezierInterpolation : _pointInLine; for(let i = 0; i < gData.length; i++){ if(dataRaw[i] !== null){ yValues.push(dataRaw[i]); } else if(i === 0 || i ===gData.length-1){ yValues.push(null); // no interpolation for extreme points } else{ const pLeft = gData[i-1], pThis = gData[i], pRight = gData[i+1]; const xgLeft = pLeft.x, xg = pThis.x, xgRight = pRight.x, frac = (xg - xgLeft) / (xgRight - xgLeft); let {y: yg} = interpolation(pLeft, pRight, frac); yValues.push(yScale.getValueForPixel(yg)); } } console.log(`For dataset ${controller.index}:`, yValues); } } } }
此解决方案假设索引轴为 

x

,数值轴为 
y
;
无论
type
轴的
x
如何(
category
linear
time
等)。

这是将此解决方案应用于 OP 示例的完整片段。

const _bezierInterpolation = Chart.helpers._bezierInterpolation, _steppedInterpolation = Chart.helpers._steppedInterpolation, _pointInLine = Chart.helpers._pointInLine; // note: different access with modules const config = { type: 'line', data: { labels: ["Red", "Blue", "Yellow", "Green", "Purple", "Orange", "Blue", "Yellow", "Green", "Purple", "Green"], datasets: [{ label: '# of Votes', data: [7, null, 11, null, 5 , null, 8, null, 3, null, 7], spanGaps: true, fill: true, borderWidth: 1, pointHitRadius: 25, tension: 0.4 }] }, options: { animation:{ onComplete: function({chart}){ const datesetMetas = chart.getSortedVisibleDatasetMetas(); for(const datasetMeta of datesetMetas){ if(datasetMeta.type === 'line'){ const controller = datasetMeta.controller, spanGaps = controller.options.spanGaps, dataRaw = controller._data; if(spanGaps && dataRaw.includes(null)){ const gData = datasetMeta.data, yScale = datasetMeta.yScale, yValues = []; // the final result const tension = controller.options.tension || controller.options.elements.line.tension; interpolation = controller.options.stepped ? _steppedInterpolation : tension ? _bezierInterpolation : _pointInLine; for(let i = 0; i < gData.length; i++){ if(dataRaw[i] !== null){ yValues.push(dataRaw[i]); } else if(i === 0 || i ===gData.length-1){ yValues.push(null); // no interpolation for extreme points } else{ const pLeft = gData[i-1], pThis = gData[i], pRight = gData[i+1]; const xgLeft = pLeft.x, xg = pThis.x, xgRight = pRight.x, frac = (xg - xgLeft) / (xgRight - xgLeft); let {y: yg} = interpolation(pLeft, pRight, frac); yValues.push(yScale.getValueForPixel(yg)); } } console.log(`For dataset ${controller.index}:`, yValues); } } } } }, scales: { y: { min: 0, max: 20 } } } } const chart = new Chart('chartJSContainer', config);
<div style="min-height: 60vh">
    <canvas id="chartJSContainer" style="background-color: #eee;">
    </canvas>
</div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.1/chart.umd.js" integrity="sha512-ZwR1/gSZM3ai6vCdI+LVF1zSq/5HznD3ZSTk7kajkaj4D292NLuduDCO1c/NT8Id+jE58KYLKT7hXnbtryGmMg==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>

© www.soinside.com 2019 - 2024. All rights reserved.