代码之家  ›  专栏  ›  技术社区  ›  hitautodestruct

如何使用chartistjs在同一个图中相对拉伸两个索引数不同的序列?

  •  0
  • hitautodestruct  · 技术社区  · 6 年前

    序曲

    使用Chartist,我知道有一个选项可以在两个不同的数据集中“填充漏洞”,这两个数据集的项数不相等,如下例所示:

    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)。

    问题

    有没有办法让图表师把第二个数列和第一个数列相对,把第二个数列的线展开,使之与第一个数列相匹配,直到最长数列的最后一个值?

    1 回复  |  直到 6 年前
        1
  •  2
  •   user3297291    6 年前

    您可以编写一些帮助程序来修改数据数组:

    • 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>