【问题标题】:Dynamically updated ng2-charts动态更新的 ng2-charts
【发布时间】:2016-12-28 22:01:59
【问题描述】:

是否可以从ng2-charts 动态更新任何chart?我知道还有像angular2-highcharts 这样的其他库,但我想使用ng2-charts 来处理它。主要问题是如何在单击按钮后重绘chart?我可以调整窗口大小并更新数据,因此必须是手动执行的任何选项。

https://plnkr.co/edit/fXQTIjONhzeMDYmAWTe1?p=preview

【问题讨论】:

    标签: angular charts ng2-charts


    【解决方案1】:

    这是在 2020 年,ng2-charts 存在示意图

    npm i ng2-charts
    ng generate ng2-charts-schematics:<type> <chart-name>
    

    这会生成一个组件(例如,名为 times-bought 的条形图)

    time-bought.component.html

    <div style="display: block; width: 40vw; height:80vh">
      <canvas baseChart
        [datasets]="barChartData"
        [labels]="barChartLabels"
        [options]="barChartOptions"
        [colors]="barChartColors"
        [legend]="barChartLegend"
        [chartType]="barChartType"
        [plugins]="barChartPlugins">
      </canvas>
    </div>
    

    在组件 ts 中,您订阅了一个服务,该服务返回一个可观察的数据,在这种情况下,我们计算一个 firestore 字段值,我们将其解析为一个数字和购买的课程/产品的标题

    times-bought.component.ts

    import { Component, OnInit } from '@angular/core';
    import { ChartDataSets, ChartOptions, ChartType } from 'chart.js';
    import { Color, Label } from 'ng2-charts';
    import { AdminService } from 'src/app/services/admin.service';
    import { _COURSES, _BAR_CHART_COLORS } from  "../../../../settings/courses.config";//
    
    @Component({
     selector: 'times-bought-chart', // Name this however you want
     templateUrl: './times-bought.component.html', 
     styleUrls: ['./times-bought.component.scss']
    })
    export class TimesBoughtComponent implements OnInit {
    
    public barChartData: ChartDataSets[] = [
     { data: [0, 0, 0, 0], label: 'Times Bought', barThickness: 60, barPercentage: 0.1 }];
    public barChartLabels: Label[] = _COURSES  // Array of strings
    public barChartOptions: ChartOptions = {
      responsive: true,
      scales: { yAxes: [{ ticks: { beginAtZero: true } }] }
    };
    public barChartColors: Color[] = _BAR_CHART_COLORS // 
    public barChartLegend = true;
    public barChartType: ChartType = 'bar';
    public barChartPlugins = [];
    
    constructor(private adminService: AdminService) { }
    
    ngOnInit() {
      this.adminService.getAllCourses().subscribe(
        data =>{
          this.barChartData[0].data = data.map(v=> parseInt((v.times_bought).toString())) // parse FieldValue to Int
          this.barChartLabels = data.map(v => v.title)
      })
    }}
    

    对 firestore 执行实际查询并返回 observable 的服务 ts 文件

    import { Injectable } from '@angular/core';
    import { AngularFirestore } from '@angular/fire/firestore';
    import { Course } from '../interfaces/course.interface';
    
    @Injectable({
      providedIn: 'root'
    })
    export class AdminService {
    
    constructor(private db: AngularFirestore) { }
    
    public  getAllCourses(){
      return this.db.collection<Course>('courses', ref =>
        ref.orderBy('times_bought', 'desc')).valueChanges()
    }}
    

    以及设置/courses.config.ts

    export const _COURSES = [
     'Title1',
     'Title2',
     'Title3',
     'Title4']
    
     export const _BAR_CHART_COLORS = [
     {
       borderColor: [
         'rgba(255,0,0,0.5)',
         'rgba(54, 75, 181, 0.5)',
         'rgba(114, 155, 59, 0.5)',
         'rgba(102, 59, 155, 0.5)'
       ],
       backgroundColor: [
         'rgba(255,0,0,0.3)',
         'rgba(54, 75, 181, 0.3)',
         'rgba(114, 155, 59, 0.3)',
         'rgba(102, 59, 155, 0.3)'
       ]
     }]
    

    还要确保在 ngOnDestroy 中关闭订阅。 每次更新 times_bought 字段时,课程集合的 observable 都会发出一个新值,这将触发图表中的更新。 唯一的缺点是颜色绑定到特定的列/栏,所以如果一个标题超过另一个,只有标题会改变位置,y轴会相应更新,但颜色不会更新 还要确保将 node_modules/dist/Chart.min.js 包含到您的 Web 清单中(如果是 pwa service worker),或者作为 index.html 中的脚本

    【讨论】:

      【解决方案2】:

      我想通了,也许它不是现有的最佳选择,但它确实有效。我们无法更新现有的chart,但我们可以使用现有的chart 创建新的并添加新点。我们甚至可以得到更好的效果,关闭图表动画。

      解决问题的函数:

      updateChart(){
         let _dataSets:Array<any> = new Array(this.datasets.length);
         for (let i = 0; i < this.datasets.length; i++) {
            _dataSets[i] = {data: new Array(this.datasets[i].data.length), label: this.datasets[i].label};
            for (let j = 0; j < this.datasets[i].data.length; j++) {
              _dataSets[i].data[j] = this.datasets[i].data[j];
            }
         }
         this.datasets = _dataSets;
      }
      

      现场演示:https://plnkr.co/edit/fXQTIjONhzeMDYmAWTe1?p=preview

      @UPDATE: 正如@Raydelto Hernandez 在下面的评论中提到的,更好的解决方案是:

      updateChart(){
          this.datasets = this.dataset.slice()
      }
      

      【讨论】:

      • 您的代码有效,但同样可以通过以下方式完成:this.datasets = this.datasets.slice();
      【解决方案3】:

      **这对我有用 - 饼图:*

      Component.html:

       <canvas baseChart [colors]="chartColors" [data]="pieChartData" [labels]="pieChartLabels" [chartType]="pieChartType"></canvas>
      

      Component.ts:

      在标题部分:

      import { Component, OnInit, ViewChild, ElementRef } from '@angular/core';
      import { Chart } from 'chart.js';
      import { BaseChartDirective } from 'ng2-charts/ng2-charts';
      

      在出口类的声明部分:

      @ViewChild(BaseChartDirective) chart: BaseChartDirective;
      // for custom colors
      public chartColors: Array<any> = [{
      backgroundColor: ['rgb(87, 111, 158)', 'yellow', 'pink', 'rgb(102, 151, 185)'],
      borderColor: ['white', 'white', 'white', 'white']
      }];
      

      在更新您的饼图数据的块之后(使用服务/套接字或任何其他方式):

      this.chart.chart.update();
      

      【讨论】:

        【解决方案4】:

        最近我不得不使用 ng2-charts,我在更新数据时遇到了很大的问题,直到我找到了这个解决方案:

        <div class="chart">
                <canvas baseChart [datasets]="datasets_lines" [labels]="labels_line" [colors]="chartColors" [options]="options" [chartType]="lineChartType">
                </canvas>
        </div>
        

        这里是我的组件中的内容:

        import { Component, OnInit, Pipe, ViewChild, ElementRef } from '@angular/core';
        import { BaseChartDirective } from 'ng2-charts/ng2-charts';
        
        @Component({
            moduleId: module.id,
            selector: 'product-detail',
            templateUrl: 'product-detail.component.html'
        })
        
        export class ProductDetailComponent {
            @ViewChild(BaseChartDirective) chart: BaseChartDirective;
        
            private datasets_lines: { label: string, backgroundColor: string, borderColor: string, data: Array<any> }[] = [
                {
                    label: "Quantities",
                    data: Array<any>()
                }
            ];
        
            private labels_line = Array<any>();
        
            private options = {
                scales: {
                    yAxes: [{
                        ticks: {
                            beginAtZero: true
                        }
                    }]
                }
            };
        
        
            constructor() { }
            ngOnInit() {
        
                this.getStats();
        
            }
            getStats() {
        
                this.labels_line = this.getDates();
        
                this._statsService.getStatistics(this.startDate, this.endDate, 'comparaison')
                    .subscribe(
                    res => {
                        console.log('getStats success');
                        this.stats = res;
        
                        this.datasets_lines = [];
        
                        let arr: any[];
                        arr = [];
                        for (let stat of this.stats) {
                            arr.push(stat.quantity);
                        }
        
                        this.datasets_lines.push({
                            label: 'title',
                            data: arr
                        });
        
                        this.refresh_chart();
        
                    },
                    err => {
                        console.log("getStats failed from component");
                    },
                    () => {
                        console.log('getStats finished');
                    });
            }
        
            refresh_chart() {
                setTimeout(() => {
                    console.log(this.datasets_lines_copy);
                    console.log(this.datasets_lines);
                    if (this.chart && this.chart.chart && this.chart.chart.config) {
                        this.chart.chart.config.data.labels = this.labels_line;
                        this.chart.chart.config.data.datasets = this.datasets_lines;
                        this.chart.chart.update();
                    }
                });
            }
        
            getDates() {
                let dateArray: string[] = [];
                let currentDate: Date = new Date();
                currentDate.setTime(this.startDate.getTime());
                let pushed: string;
                for (let i = 1; i < this.daysNum; i++) {
                    pushed = currentDate == null ? '' : this._datePipe.transform(currentDate, 'dd/MM/yyyy');
                    dateArray.push(pushed);
                    currentDate.setTime(currentDate.getTime() + 24 * 60 * 60 * 1000);
                }
                return dateArray;
            }    
        }
        

        我确信这是正确的做法。

        【讨论】:

          【解决方案5】:

          一个好方法是掌握图表本身,以便使用 API 重新绘制它:

          export class MyClass {
           @ViewChild( BaseChartDirective ) chart: BaseChartDirective;
          
            private updateChart(){
             this.chart.ngOnChanges({});
            }
          
          }
          

          【讨论】:

            【解决方案6】:

            可以从ng2-charts 动态更新任何图表。 例子: http://plnkr.co/edit/m3fBiHpKuDgYG6GVdJQD?p=preview

            Angular 更新图表、变量或引用必须更改。当您仅更改数组元素的值时,变量和引用不会更改。 See also Github.

            【讨论】:

            • 完全按照问题提出。这不应该被否决。
            • @Hutch Imho,这个答案并不总是有效,尤其是在 Angular 区域被破坏的情况下。 OP 还表示他正在寻找一个手动解决方案,这个答案部分解决了这个问题。
            • 数据是动态变化的,但是如果我想改变 linechartlabels, linechartcolors 怎么办
            猜你喜欢
            • 1970-01-01
            • 2021-11-08
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-12-29
            • 2017-02-23
            • 2017-09-03
            相关资源
            最近更新 更多