如何使用 chartist js 在同一图表中相对拉伸两个具有不同数量索引的系列?
How do I relatively stretch two series with a different number of indexes in the same graph using chartist js?
序曲
使用 Chartist 我知道在两个不同的数据集中有一个 "fill holes" 的选项,它们没有相同数量的项目,如下例所示:
var chart = new Chartist.Line('.ct-chart', {
labels: [1, 2, 3, 4, 5, 6, 7],
series: [
[5, 5, 10, 8, 7, 5, 4],
[10, 15, null, 12, null, null, null]
]
}, {
lineSmooth: Chartist.Interpolation.cardinal({
fillHoles: true,
})
});
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet"/>
<div class="ct-chart"></div>
注意示例中的第二个系列将只显示一行到最后一个不是 null
的值(在索引 4 处)。
问题
有没有办法让图表师使第二个系列相对于第一个系列,展开第二个系列线以匹配第一个系列,直到最长系列的最后一个值?
您可以编写一些帮助程序来修改您的数据数组:
trimNulls
从数组的开头和结尾删除任何 null
值:
[10, 15, null, 12, null, null, null] -> [10, 15, null, 12]
stretch
获取一个数组和所需的长度并将原始值分配给新索引:
[10, 15, null, 12] -> 7 -> [10, null, 15, null, null, null, 12]
alignSeries
获取一系列数据系列并将它们中的每一个与最宽的一个对齐。
[ [ 1, 2, 3, 4], [1, 4], [null, 1, 4] ] ->
[ [ 1, 2, 3, 4], [1, null, null, 4], [1, null, null, 4] ]
在 运行 示例中,包含旧行以供参考:
const trimNulls = (data) => {
// Find the first non-null value
const start = data.findIndex(y => y !== null);
// Find the last non-null value
const end = data.length - Array.from(data).reverse()
.findIndex(y => y !== null);
// Return the elements between those boundaries
return data.slice(start, end);
}
const stretch = (data, newLength) => {
// Create array of required number of nulls
const stretched = Array(newLength).fill(null);
// Determine the stretch factor
const s = newLength / data.length;
// For every value we want to keep, place it
// at its new, stretched index
data.forEach((y, x) => {
stretched[Math.ceil(x * s)] = y;
});
// Return the newly created array
return stretched;
}
// Takes a list of series and aligns their starts and ends, stretching
// in between
const alignSeries = series => {
// Trim each series
const trimmed = series.map(trimNulls);
// Find the longest one
const maxLength = Math.max(...trimmed.map(t => t.length));
// Stretch all series to the longest length and return
return trimmed.map(t => stretch(t, maxLength));
};
var chart = new Chartist.Line('.ct-chart', {
labels: [1, 2, 3, 4, 5, 6, 7],
series: [
...alignSeries([
[5, 5, 10, 8, 7, 5, 4],
[10, 15, null, 12, null, null, null]
]),
// For reference
[10, 15, null, 12, null, null, null]
]
}, {
lineSmooth: Chartist.Interpolation.cardinal({
fillHoles: true,
})
});
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet"/>
<div class="ct-chart"></div>
序曲
使用 Chartist 我知道在两个不同的数据集中有一个 "fill holes" 的选项,它们没有相同数量的项目,如下例所示:
var chart = new Chartist.Line('.ct-chart', {
labels: [1, 2, 3, 4, 5, 6, 7],
series: [
[5, 5, 10, 8, 7, 5, 4],
[10, 15, null, 12, null, null, null]
]
}, {
lineSmooth: Chartist.Interpolation.cardinal({
fillHoles: true,
})
});
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet"/>
<div class="ct-chart"></div>
注意示例中的第二个系列将只显示一行到最后一个不是 null
的值(在索引 4 处)。
问题
有没有办法让图表师使第二个系列相对于第一个系列,展开第二个系列线以匹配第一个系列,直到最长系列的最后一个值?
您可以编写一些帮助程序来修改您的数据数组:
trimNulls
从数组的开头和结尾删除任何null
值:[10, 15, null, 12, null, null, null] -> [10, 15, null, 12]
stretch
获取一个数组和所需的长度并将原始值分配给新索引:[10, 15, null, 12] -> 7 -> [10, null, 15, null, null, null, 12]
alignSeries
获取一系列数据系列并将它们中的每一个与最宽的一个对齐。[ [ 1, 2, 3, 4], [1, 4], [null, 1, 4] ] -> [ [ 1, 2, 3, 4], [1, null, null, 4], [1, null, null, 4] ]
在 运行 示例中,包含旧行以供参考:
const trimNulls = (data) => {
// Find the first non-null value
const start = data.findIndex(y => y !== null);
// Find the last non-null value
const end = data.length - Array.from(data).reverse()
.findIndex(y => y !== null);
// Return the elements between those boundaries
return data.slice(start, end);
}
const stretch = (data, newLength) => {
// Create array of required number of nulls
const stretched = Array(newLength).fill(null);
// Determine the stretch factor
const s = newLength / data.length;
// For every value we want to keep, place it
// at its new, stretched index
data.forEach((y, x) => {
stretched[Math.ceil(x * s)] = y;
});
// Return the newly created array
return stretched;
}
// Takes a list of series and aligns their starts and ends, stretching
// in between
const alignSeries = series => {
// Trim each series
const trimmed = series.map(trimNulls);
// Find the longest one
const maxLength = Math.max(...trimmed.map(t => t.length));
// Stretch all series to the longest length and return
return trimmed.map(t => stretch(t, maxLength));
};
var chart = new Chartist.Line('.ct-chart', {
labels: [1, 2, 3, 4, 5, 6, 7],
series: [
...alignSeries([
[5, 5, 10, 8, 7, 5, 4],
[10, 15, null, 12, null, null, null]
]),
// For reference
[10, 15, null, 12, null, null, null]
]
}, {
lineSmooth: Chartist.Interpolation.cardinal({
fillHoles: true,
})
});
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet"/>
<div class="ct-chart"></div>