Storybook:更改控件的值不会重新呈现 Chart.js 画布
Posted
技术标签:
【中文标题】Storybook:更改控件的值不会重新呈现 Chart.js 画布【英文标题】:Storybook: Changing the value of the control doesnot rerender the Chart.js canvas 【发布时间】:2021-06-21 10:22:43 【问题描述】:我正在使用基于Storybook
的Angular
。我想做的就是根据 Storybook 控件中给出的值重新渲染图表。但是即使在更改控件的值之后,图表仍然保持不变。我尝试了很多解决方法,但仍然处于第一阶段。我想显示的图表是一个等值线。我使用Chartjs
和chartjs-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;
我的故事.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 已更改,因此我想相应地重新渲染地图。任何帮助将不胜感激。
【问题讨论】:
我没有编写故事书,但如果您要更改 @Input 的值,则需要在 ngOnChanges 上调用getGeoData()
。或者,我认为您获取新数据并更新它(chartjs.org/docs/latest/developers/api.html#updateconfig),而不是再次创建图表实例。无论哪种方式,您都需要在 ngOnChanges 中调用它们。
@GowthamRajJ 哦,是的! ngOnChanges
成功了!谢谢!
很高兴它有帮助:) 我已经添加了这个答案。
【参考方案1】:
设置图表的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;
【讨论】:
以上是关于Storybook:更改控件的值不会重新呈现 Chart.js 画布的主要内容,如果未能解决你的问题,请参考以下文章
React Context 和 Storybook:在组件故事中更改 React Context 的值
使用 ContextAPI 不会重新呈现其使用者,但会更改内容。为啥?