Storybook:更改控件的值不会重新呈现 Chart.js canvas

Storybook: Changing the value of the control doesnot rerender the Chart.js canvas

我正在使用基于 AngularStorybook。我只想根据 Storybook 控件中给定的值重新呈现图表。但即使在更改控件的值后,图表仍保持静态。我尝试了很多解决方法,但仍然处于第一位。我要显示的图表是等值线图。我使用 Chartjschartjs-chart-geo 库来显示图表。

我在 Storybook 中的组件:

import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core';
import * as Chart from 'chart.js';
import * as ChartGeo from 'chartjs-chart-geo';
import { HttpClient } from '@angular/common/http';
@Component({
    selector: 'storybook-choropleth',
    template: `<div>
    <canvas id="mapCanvas"></canvas>
  </div>
  `,
    styleUrls: ['./choropleth.css'],
})
export default class ChoroplethComponent implements OnInit {
    @Input()
    url = 'https://unpkg.com/world-atlas/countries-50m.json';
    /**
     * Type of projecttion
     */
    // @Input()
    chartProjection: 'azimuthalEqualArea' | 'azimuthalEquidistant' | 'gnomonic' | 'orthographic' | 'stereographic'
        | 'equalEarth' | 'albers' | 'albersUsa' | 'conicConformal' | 'conicEqualArea' | 'conicEquidistant' | 'equirectangular' | 'mercator'
        | 'transverseMercator' | 'naturalEarth1' = 'mercator';
    chart: any;
    geoData: any;
    countries: any;
    constructor(
        private http: HttpClient
    ) {
    }
    ngOnInit() {
        this.getGeoData();
    }
    getGeoData() {
        this.http.get(this.url).subscribe((data) => {
            this.countries = ChartGeo.topojson.feature(data, data['objects']['countries']).features;
            let t = <HTMLCanvasElement>document.getElementById('mapCanvas');
            if (this.chart !== undefined) {
                this.chart.destroy();
            }
            // exclude antartica
            this.countries.splice(239, 1);
            console.log(this.countries);
            let dts = {
                labels: this.countries.map((d) => d.properties.name),
                datasets: [{
                    label: 'Countries',
                    data: this.countries.map((d) => ({ feature: d, value: Math.random() })),
                }]
            };
            console.log(this.countries);
            let configOptions = {
                maintainAspectRatio: true,
                responsive: true,
                showOutline: false,
                showGraticule: false,
                scale: {
                    projection: this.chartProjection
                } as any,
                geo: {
                    colorScale: {
                        display: true,
                        interpolate: 'blues',
                        missing: 'white',
                        legend: {
                            display: 'true',
                            position: 'bottom-right'
                        }
                    }
                }
            };
            
            this.chart = new Chart(t.getContext('2d'),
                {
                    type: 'choropleth',
                    data: dts,
                    options: configOptions
                }
            );
        });
    }
    getDts() {
        this.getGeoData();
        let dts = {
            labels: this.geoData.map((i) => i.properties.name),
            datasets: [
                {
                    outline: this.geoData,
                    data: this.geoData.map((i) => ({
                        feature: i,
                        value: i.properties.confirmed
                    }))
                }
            ]
        };
        return dts;
    }
    getConfigOptions() {
        let configOptions = {
            maintainAspectRatio: true,
            responsive: true,
            showOutline: false,
            showGraticule: false,
            scale: {
                projection: 'mercator'
            } as any,
            geo: {
                colorScale: {
                    display: true,
                    interpolate: 'reds',
                    missing: 'white',
                    legend: {
                        display: 'true',
                        position: 'bottom-right'
                    }
                }
            }
        };
        return configOptions;
    }
}

我的story.ts:

import { Story, Meta, moduleMetadata } from '@storybook/angular';
import Choropleth from './choropleth.component';
import { HttpClientModule } from '@angular/common/http';
import { withKnobs } from '@storybook/addon-knobs';
import { NO_ERRORS_SCHEMA } from '@angular/core';
export default {
    title: 'Choropleth',
    component: Choropleth,
    decorators: [
        withKnobs,
        moduleMetadata({
            //:point_down: Imports both components to allow component composition with storybook
            imports: [HttpClientModule],
            schemas: [NO_ERRORS_SCHEMA],
        })
    ],
    argTypes: {
        backgroundColor: { control: 'color' }
    },
} as Meta;
const Template: Story<Choropleth> = (args: Choropleth) => ({
    component: Choropleth,
    props: args
});
export const Primary = Template.bind({});
Primary.args = {
    url: 'https://unpkg.com/world-atlas/countries-50m.json'
};

在此,我想保持 URL 动态。由于 URL 在故事书的控件中发生了变化,我想相应地重新渲染地图。任何帮助将不胜感激。

设置图表的getGeoData方法只在组件初始化时调用,当@Input值改变时它不会运行。对于这些场景 Angular 提供了 ngOnChanges 生命周期钩子。这就是我们需要告诉 Angular 当 @Input 值发生变化时需要做什么的地方。

ngOnChanges(changes: SimpleChanges) {
  for (const propName in changes) {
    switch(propName) {
      case 'url':
      // action that needs to happen when url changes
      break;
      case 'chartProjection':
      // action that needs to happen when chartProjection changes
      break;
    }
  }
}