无法使用角度4加载高清图上没有重复的系列

我已经在角度4应用程序中实现了高图 . 我的高图似乎加载了两次相同的系列 . 有一个名为addseries的方法,我使用@Input()设置stressTestResults声明来调用它 . 我可以看到断点在那里击中两次并且两次调用addseries . 我不知道如何防止这次被调用两次 . 如果我将addseries移动到ngOnInit,它在图表加载时没有得到值,并且在刷新页面时,我可以看到值通过 . 这一次它正确地显示了一个系列 . 如果Init是正确的位置,则存在更改检测或检索数据滞后的问题 . 有人能告诉我哪里出错了

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();
      }
    });
  }

}

Parent component html

你可以在这里看到我已经将stressTestResults初始化为子组件的stressTestResults属性

<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));
    });
  }
}

回答(1)

2 years ago

我会尝试在 @Input 中设置数组(并且只设置数据,不要调用 addSeries() ) . 然后实现 onChanges ,并在 ngOnChanges 中调用 addSeries 方法 . 我认为正在发生的事情是 @Input 被设置为ctor链的一部分,但它在 addSeries 中返回,因为数据's not there yet, and it'永远不会被再次调用 .

所以类似于:

@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();
      }
    });
  }

}