我已经在Angular 4应用程序中实现了HighChart。我的Highchart似乎两次加载了同一系列。我用@Input((设置RESSTESTESTESTRESULTS声明来调用的方法称为addseries。我可以看到突发点在那里撞到两次,并两次调用添加程序。我不确定如何防止两次被称为。如果我将添加程序移至ngoninit,那么它不会在加载图表并在页面的刷新上获得值,我可以看到值通过的值。这次它正确显示了一个系列。如果初始化是正确的位置,那么更改检测或从检索数据中滞后存在一些问题。有人可以告诉我我要去哪里出错
import { Component, OnInit, Input,ViewChild } from '@angular/core';
import { StressTestAnalysis } from '../../../../api/dtos';
import { ReactiveComponent } from '@wtw/toolkit/src/utils/base.component';
import { SplineChartComponent } from '../../../../shared/Highcharts/spline/spline-chart.component';
export interface ChartSeries {
data: number[][];
name: string;
color: string;
}
@Component({
selector: 'app-stress-test-analysis',
templateUrl: './stress-test-analysis.component.html'
})
export class StressTestAnalysisComponent extends ReactiveComponent implements OnInit {
isExpanded = false;
showTable = true;
private results: Array<StressTestAnalysis> = [];
@ViewChild(SplineChartComponent) public stressSplineChart: SplineChartComponent;
//@Input() results: Array<StressTestAnalysis> = [];
@Input() set stressTestResults(value: Array<StressTestAnalysis>) {
this.results = value;
this.addSeries();
}
public chartSeries: Array<ChartSeries> = [];
seriesName: string;
strategyName: string = '';
constructor(
) { super(); }
ngOnInit() {
// this.addSeries();
}
private addSeries() {
if (this.results === null) {
return;
}
this.results.forEach(element => {
if (element !== null) {
this.chartSeries.push({ data: element.graphData, name: element.seriesName, color: element.color });
// if (this.stressSplineChart) this.stressSplineChart.redraw();
}
});
}
}
父组件html
您可以在这里看到我已经将压力策略初始化为儿童组成部分的atspertestestresults
<div class="container-fluid mt-3 mb-3 test-feasibility--details">
<app-assumptions-summary></app-assumptions-summary>
</div>
<form #pageForm="ngForm">
<div class="container-fluid base_strategy p-0 m-0">
<div class="tb-container col-md-12 p-0 m-0 scroll-auto">
<app-strategies [strategies]="run.strategies" [linesOfBusinessInput]="run.linesOfBusinessInput" [redraw]="forceRedraw" (applyChange)="applyChange($event)" (save)="save()"></app-strategies>
<div class="col-12 test_feasibility--accordion">
<!-- Accordion -->
<div id="accordion" role="tablist">
<app-net-present-value-analysis [npvResults]="npvResults"></app-net-present-value-analysis>
<app-economic-value-analysis [evResults]="evResults"></app-economic-value-analysis>
<app-stress-test-analysis [stressTestResults]="stressTestResults"></app-stress-test-analysis>
<app-ending-surplus-analysis [results]="endingSurplusResults"></app-ending-surplus-analysis>
</div>
<!-- Accordion End -->
</div>
</div>
</div>
</form>
图表组件
import { Component, Input, OnChanges } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
@Component({
selector: 'splinechart',
template: '<chart [options]="options" (load)="getInstance($event.context)"></chart>',
styles: [`
chart {
display: block;
width: 100% !important;
padding:0;
}`]
})
export class SplineChartComponent implements OnChanges {
public options: any;
chart: any;
@Input() public series: any;
@Input() public yaxisdata: any;
@Input() public selectedRating: string = '';
constructor(private _translate: TranslateService) {
this.options = {
credits: {
enabled: false
},
chart: {
type: 'spline'
},
title: {
text: ''
},
subtitle: {
text: ''
},
legend: {
layout: 'horizontal',
margin: 25,
itemMarginTop: 0,
symbolRadius: 0,
symbolHeight: 20,
symbolWidth: 20,
useHTML: true,
title: {
text: this._translate.instant('CAPTIVES.RESULTS.COMMON.GRAPH_LEGEND_TITLE'),
margin: 50,
style: {
fontStyle: 'italic',
fontWeight: 'normal'
}
},
align: 'right',
verticalAlign: 'bottom',
},
xAxis: {
title: {
text: this._translate.instant('CAPTIVES.RESULTS.STA.GRAPH_XAXIS')
}
},
yAxis: {
title: {
text: this._translate.instant('CAPTIVES.RESULTS.STA.GRAPH_YAXIS')
}
},
tooltip: {
},
plotOptions: {
series: {
cursor: 'pointer',
events: {
legendItemClick: function() {
const elements = document.querySelectorAll('.highcharts-legend-item path');
for (let i = 0; i < elements.length; i++) {
elements[i].setAttribute('stroke-width', '20');
elements[i].setAttribute('stroke-height', '20');
}
this.chart.redraw();
}
},
allowPointSelect: true,
},
spline: {
lineWidth: 2,
states: {
hover: {
lineWidth: 3
}
},
marker: {
enabled: true,
symbol: 'circle'
},
}
},
series: [
{
showInLegend: false
}
]
};
}
getInstance(chartInstance): void {
this.chart = chartInstance;
this.redraw();
}
ngOnChanges(data: any) {
if (!data.series.currentValue || !this.chart) return;
var seriesLength = this.chart.series.length;
for(var i = seriesLength -1; i > -1; i--) {
this.chart.series[i].remove();
}
data.series.currentValue.map(s => {
this.chart.addSeries(s);
});
this.chart.reflow();
}
public redraw() {
if (!this.chart) return;
// var seriesLength = this.chart.series.length;
// for(var i = seriesLength -1; i > -1; i--) {
// this.chart.series[i].remove();
// }
this.series.map(s => {
if (s !== null)
this.chart.addSeries(s);
});
const elements = document.querySelectorAll('.highcharts-legend-item path');
for (let i = 0; i < elements.length; i++) {
elements[i].setAttribute('stroke-width', '20');
elements[i].setAttribute('stroke-height', '20');
}
this.chart.redraw();
}
}
父组件代码
import { Component, OnInit } from '@angular/core';
import { TranslateService } from '@ngx-translate/core';
import { RunService, NavBarService } from '@wtw/platform/services';
import { Base } from '@wtw/toolkit';
import { NpvAnalysis, EvAnalysis } from '../../../shared/models/results';
import { Dto } from '@wtw/platform/api';
import { Strategy, StressTestAnalysis, CaptivesRun, EndingSurplus } from '../../../api/dtos';
import { RunModel } from '@wtw/platform/api/dtos';
@Component({
selector: 'app-results',
templateUrl: './results.component.html'
})
export class ResultsComponent extends Base.ReactiveComponent implements OnInit {
run: CaptivesRun;
npvResults: Array<NpvAnalysis> = [];
evResults: Array<EvAnalysis> = [];
stressTestResults: Array<StressTestAnalysis> = [];
endingSurplusResults: Array<EndingSurplus> = [];
forceRedraw: { value: number };
private _baseRun: Dto.RunModel;
constructor(
private _runService: RunService,
private _navBarService: NavBarService,
private _translate: TranslateService,
) {
super();
}
ngOnInit() {
this._subscriptions = [
this._runService.activeRun.subscribe((r: any) => {
this._processRun(r);
}),
this._runService.currencyConverted.subscribe(r => {
this._processRun(r);
this.save();
this.forceRedraw = { value: Math.random() * 10000 };
}),
this._navBarService.downloadReportEvent.subscribe(x => {
this.downloadReport();
})
];
}
downloadReport() {
console.log('download report');
}
applyChange(event: any) {
this.run.strategies.splice(event.index, 1, event.strategy);
this._baseRun.data = this.run;
this._runTrigger2(this._baseRun, event.index);
}
save() {
this._baseRun.data = this.run;
this._runService.persist(this._baseRun.runId, this.run, this._baseRun.currencyInfo).uiSignal('save').subscribe(x => {
this._processResults(this.run.strategies);
});
}
private _runTrigger2(r: Dto.RunModel, strategyIndex: number) {
this._runService.executeTrigger(r.runId, this.run, { number: 2, param: strategyIndex.toString() }, r.currencyInfo)
.uiSignal('trigger 2')
.subscribe(x => {
this.run = x.data;
this._processResults(x.data.strategies);
});
}
private _processRun(r: RunModel) {
this._baseRun = r;
this.run = r.data as CaptivesRun;
// Initialising the data
if (this.run.strategies) {
if (!this.run.strategies[0].results) {
this._runTrigger2(this._baseRun, 0);
} else {
this._processResults(this.run.strategies);
}
}
}
private _processResults(strategies: Array<Strategy>) {
this.npvResults = new Array();
this.evResults = new Array();
this.endingSurplusResults = new Array();
this.stressTestResults = new Array();
const strategyTranslation = this._translate.instant('CAPTIVES.RESULTS.COMMON.STRATEGY');
const getStrategyName = (strategy: Strategy, index: number) => {
let name = this._translate.instant('CAPTIVES.RESULTS.COMMON.BASE_STRATEGY');
if (index > 0) {
name = strategyTranslation + ' ' + index;
}
return name;
};
strategies.forEach((strategy, index) => {
const strategyName = getStrategyName(strategy, index);
const results = strategy.results;
this.npvResults.push(Object.assign(results.npvResult, { strategyName }));
this.evResults.push(Object.assign(results.evaResult, { strategyName }));
this.endingSurplusResults.push(Object.assign(results.endingSurplus));
this.stressTestResults.push(Object.assign(results.stressResult));
});
}
}
我会尝试在@Input
中设置数组(并且仅设置数据,请勿调用addSeries()
(。然后实现onChanges
,然后在ngOnChanges
中调用您的addSeries
方法。我认为正在发生的事情是将@Input
设置为CTOR链的一部分,但是它在addSeries
中返回,因为数据还不存在,并且再也没有被调用。
所以类似:
@Component({
selector: 'app-stress-test-analysis',
templateUrl: './stress-test-analysis.component.html'
})
export class StressTestAnalysisComponent extends ReactiveComponent implements OnChanges {
isExpanded = false;
showTable = true;
private results: Array<StressTestAnalysis> = [];
@ViewChild(SplineChartComponent) public stressSplineChart: SplineChartComponent;
@Input() results: Array<StressTestAnalysis>;
public chartSeries: Array<ChartSeries> = [];
seriesName: string;
strategyName: string = '';
constructor(
) { super(); }
ngOnChanges() {
this.addSeries();
}
private addSeries() {
if (!this.results) {
return;
}
this.results.forEach(element => {
if (element !== null) {
this.chartSeries.push({ data: element.graphData, name: element.seriesName, color: element.color });
// if (this.stressSplineChart) this.stressSplineChart.redraw();
}
});
}
}