Chart.js: 如何在工具提示中分组标签?

huangapple go评论121阅读模式
英文:

Chart.js: how do I group labels in toolips?

问题

我正在从ng2-nvd3(基于D3)迁移项目到ng2-charts(基于Chart.js),因为ng2-nvd3不再维护。

我的应用程序有一个血压图表,显示收缩压和舒张压。在ng2-nvd3中,这两个值在工具提示中组合在一起。此外,渲染的日期之间有更多的间距。以下是它的外观截图。

Chart.js: 如何在工具提示中分组标签?

这是将数据映射到UI可理解的代码:

// 获取最近30天的血压读数
this.bloodPressureService.last30Days().subscribe((bpReadings: any) => {
    bpReadings = bpReadings.body;
    this.bpReadings = bpReadings;
    // https://stackoverflow.com/a/34694155/65681
    this.bpOptions = { ...D3ChartService.getChartConfig() };
    if (bpReadings.readings.length) {
        this.bpOptions.title.text = bpReadings.period;
        this.bpOptions.chart.yAxis.axisLabel = '血压';
        let systolics, diastolics, upperValues, lowerValues;
        systolics = [];
        diastolics = [];
        upperValues = [];
        lowerValues = [];
        bpReadings.readings.forEach(item => {
            systolics.push({
                x: new Date(item.timestamp),
                y: item.systolic
            });
            diastolics.push({
                x: new Date(item.timestamp),
                y: item.diastolic
            });
            upperValues.push(item.systolic);
            lowerValues.push(item diastolic);
        });
        this.bpData = [
            {
                values: systolics,
                key: '收缩压',
                color: '#673ab7'
            },
            {
                values: diastolics,
                key: '舒张压',
                color: '#03a9f4'
            }
        ];
        // 设置y轴范围,比最大和最小值大10
        this.bpOptions.chart.yDomain = [Math.min.apply(Math, lowerValues) - 10, Math.max.apply(Math, upperValues) + 10];
    } else {
        this.bpReadings.readings = [];
    }
});

D3ChartService 定义如下:

declare const d3, nv: any;

/**
 * ChartService 用于定义D3的图表配置
 */
export class D3ChartService {

    static getChartConfig() {
        const today = new Date();
        const priorDate = new Date().setDate(today.getDate() - 30);
        return {
            chart: {
                type: 'lineChart',
                height: 200,
                margin: {
                    top: 20,
                    right: 20,
                    bottom: 40,
                    left: 55
                },
                x(d) {
                    return d.x;
                },
                y(d) {
                    return d.y;
                },
                useInteractiveGuideline: true,
                dispatch: {},
                xAxis: {
                    axisLabel: '日期',
                    showMaxMin: false,
                    tickFormat(d) {
                        return d3.time.format('%b %d')(new Date(d));
                    }
                },
                xDomain: [priorDate, today],
                yAxis: {
                    axisLabel: '',
                    axisLabelDistance: 30
                },
                transitionDuration: 250
            },
            title: {
                enable: true
            }
        };
    }
}

它在HTML模板中渲染如下:

<nvd3 [options]="bpOptions" [data]="bpData" class="with-3d-shadow with-transitions"></nvd3>

在使用ng2-charts时,工具提示仅在我悬停在图表上的数据点上时显示。

Chart.js: 如何在工具提示中分组标签?

是否可能使用Chart.js/ng2-charts将数据分组在工具提示中,以便显示特定日期的两个条目?

这是用于映射数据的代码:

// 获取最近30天的血压读数
this.bloodPressureService.last30Days().subscribe((bpReadings: any) => {
  bpReadings = bpReadings.body;
  this.bpReadings = bpReadings;

  if (bpReadings.readings.length) {
    this.bpOptions = {
      plugins: {
        legend: { display: true },
        title: {
          display: true,
          text: bpReadings.period,
        },
      },
      scales: {
        y: {
          beginAtZero: false,
        },
        x: {
          beginAtZero: false,
        },
      },
    };
    const labels: any = [];
    const systolics: any = [];
    const diastolics: any = [];
    const upperValues: any = [];
    const lowerValues: any = [];
    bpReadings.readings.forEach((item: IBloodPressure) => {
      const timestamp = dayjs(item.timestamp).format('MMM DD');
      labels.push(timestamp);
      systolics.push({
        x: timestamp,
        y: item.systolic,
      });
      diastolics.push({
        x: timestamp,
        y: item.diastolic,
      });
      upperValues.push(item.systolic);
      lowerValues.push(item.diastolic);
    });
    const datasets = [
      {
        data: systolics,
        label: '收缩压',
      },
      {
        data: diastolics,
        label: '舒张压',
      },
    ];
    this.bpData = {
      labels,
      datasets,
    };
    // 设置y轴范围,比最大和最小值大10
    this.bpOptions.scales = {
      y: {
        max: Math.max(...upperValues) + 10,
        min: Math.min(...lowerValues) - 10,
      },
    };
  } else {
    this.bpReadings.readings = [];
  }
});

它在HTML模板中渲染如下:

<canvas
  baseChart
  *ngIf="bpReadings?.readings && bpReadings?.readings?.length"
  height="125"
  [type]="'line'"
  [data]="bpData"
  [options]="bpOptions"
>
</canvas>

我还想知道如何稍微填充日期,以便图表有一些填充,数据点不会在X轴的两端。我尝试了以下内容,它似乎给我正确的日期。但是,添加后线条不会渲染。

this.bpOptions.scales = {
 

<details>
<summary>英文:</summary>

I&#39;m migrating a project from [ng2-nvd3](https://github.com/krispo/ng2-nvd3) (based on D3) to [ng2-charts](http://valor-software.github.io/ng2-charts/) (based on Chart.js) because ng2-nvd3 is no longer maintained. 

My app has a blood pressure chart that shows both systolic and diastolic entries. With ng2-nvd3, both values are grouped together in the tooltip. Also, the dates rendered have a bit more spacing in them. Here&#39;s a screenshot of what it looks like.

[![ng2-nvd3 graph][1]][1]

Here&#39;s the code to map the data to something the UI can understand:

```typescript
// Get blood pressure readings for the last 30 days
this.bloodPressureService.last30Days().subscribe((bpReadings: any) =&gt; {
    bpReadings = bpReadings.body;
    this.bpReadings = bpReadings;
    // https://stackoverflow.com/a/34694155/65681
    this.bpOptions = { ...D3ChartService.getChartConfig() };
    if (bpReadings.readings.length) {
        this.bpOptions.title.text = bpReadings.period;
        this.bpOptions.chart.yAxis.axisLabel = &#39;Blood Pressure&#39;;
        let systolics, diastolics, upperValues, lowerValues;
        systolics = [];
        diastolics = [];
        upperValues = [];
        lowerValues = [];
        bpReadings.readings.forEach(item =&gt; {
            systolics.push({
                x: new Date(item.timestamp),
                y: item.systolic
            });
            diastolics.push({
                x: new Date(item.timestamp),
                y: item.diastolic
            });
            upperValues.push(item.systolic);
            lowerValues.push(item.diastolic);
        });
        this.bpData = [
            {
                values: systolics,
                key: &#39;Systolic&#39;,
                color: &#39;#673ab7&#39;
            },
            {
                values: diastolics,
                key: &#39;Diastolic&#39;,
                color: &#39;#03a9f4&#39;
            }
        ];
        // set y scale to be 10 more than max and min
        this.bpOptions.chart.yDomain = [Math.min.apply(Math, lowerValues) - 10, Math.max.apply(Math, upperValues) + 10];
    } else {
        this.bpReadings.readings = [];
    }
});

The D3ChartService is defined as follows:

declare const d3, nv: any;

/**
 * ChartService to define the chart config for D3
 */
export class D3ChartService {

    static getChartConfig() {
        const today = new Date();
        const priorDate = new Date().setDate(today.getDate() - 30);
        return {
            chart: {
                type: &#39;lineChart&#39;,
                height: 200,
                margin: {
                    top: 20,
                    right: 20,
                    bottom: 40,
                    left: 55
                },
                x(d) {
                    return d.x;
                },
                y(d) {
                    return d.y;
                },
                useInteractiveGuideline: true,
                dispatch: {},
                xAxis: {
                    axisLabel: &#39;Dates&#39;,
                    showMaxMin: false,
                    tickFormat(d) {
                        return d3.time.format(&#39;%b %d&#39;)(new Date(d));
                    }
                },
                xDomain: [priorDate, today],
                yAxis: {
                    axisLabel: &#39;&#39;,
                    axisLabelDistance: 30
                },
                transitionDuration: 250
            },
            title: {
                enable: true
            }
        };
    }
}

It's rendered in the HTML template with:

&lt;nvd3 [options]=&quot;bpOptions&quot; [data]=&quot;bpData&quot; class=&quot;with-3d-shadow with-transitions&quot;&gt;&lt;/nvd3&gt;

With ng2-charts, the tooltip only shows when I hover over the data points on the graph.

Chart.js: 如何在工具提示中分组标签?

Is it possible to group the data in a tooltip with Chart.js/ng2-charts so it shows both entries for a particular day?

Here's the code used to map the data:

// Get blood pressure readings for the last 30 days
this.bloodPressureService.last30Days().subscribe((bpReadings: any) =&gt; {
  bpReadings = bpReadings.body;
  this.bpReadings = bpReadings;

  if (bpReadings.readings.length) {
    this.bpOptions = {
      plugins: {
        legend: { display: true },
        title: {
          display: true,
          text: bpReadings.period,
        },
      },
      scales: {
        y: {
          beginAtZero: false,
        },
        x: {
          beginAtZero: false,
        },
      },
    };
    // this.bpOptions.chart.yAxis.axisLabel = &#39;Blood Pressure&#39;;
    const labels: any = [];
    const systolics: any = [];
    const diastolics: any = [];
    const upperValues: any = [];
    const lowerValues: any = [];
    bpReadings.readings.forEach((item: IBloodPressure) =&gt; {
      const timestamp = dayjs(item.timestamp).format(&#39;MMM DD&#39;);
      labels.push(timestamp);
      systolics.push({
        x: timestamp,
        y: item.systolic,
      });
      diastolics.push({
        x: timestamp,
        y: item.diastolic,
      });
      upperValues.push(item.systolic);
      lowerValues.push(item.diastolic);
    });
    const datasets = [
      {
        data: systolics,
        label: &#39;Systolic&#39;,
      },
      {
        data: diastolics,
        label: &#39;Diastolic&#39;,
      },
    ];
    this.bpData = {
      labels,
      datasets,
    };
    // set y scale to be 10 more than max and min
    this.bpOptions.scales = {
      y: {
        max: Math.max(...upperValues) + 10,
        min: Math.min(...lowerValues) - 10,
      },
    };
  } else {
    this.bpReadings.readings = [];
  }
});

It's rendered by the HTML template with:

&lt;canvas
  baseChart
  *ngIf=&quot;bpReadings?.readings &amp;&amp; bpReadings?.readings?.length&quot;
  height=&quot;125&quot;
  [type]=&quot;&#39;line&#39;&quot;
  [data]=&quot;bpData&quot;
  [options]=&quot;bpOptions&quot;
&gt;
&lt;/canvas&gt;

I'm also curious to know how to pad the dates a bit, so the chart has some padding and the data points aren't at the very ends of the X axis.

I tried the following, which does seem to give me the correct dates. However, the lines don't render after I add it.

this.bpOptions.scales = {
  y: { ... },
  x: {
    min: dayjs(labels[0]).subtract(1, &#39;day&#39;).format(&#39;MMM DD&#39;),
    max: dayjs(labels[labels.length - 1]).add(1, &#39;day&#39;).format(&#39;MMM DD&#39;),
  }
};

答案1

得分: 1

尝试添加到图表 bpOptions

interaction: {
mode: &#39;index&#39;,
intersect: false, // 如果为 true,则仅在鼠标位置与图表上的项目相交时才应用交互模式。
},

文档中有更多关于交互的信息 interaction modes

英文:

Try add to chart bpOptions

interaction: {
mode: &#39;index&#39;,
intersect: false, // if true, the interaction mode only applies when the mouse position intersects an item on the chart.
},

more interactions in docs interaction modes

huangapple
  • 本文由 发表于 2023年2月24日 07:48:19
  • 转载请务必保留本文链接:https://go.coder-hub.com/75551414.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定