Google 图表 (jsapi) 到 angular2 组件

Google charts (jsapi) into angular2 component

我正在努力创建一个 angular2 组件,它会调用 google 图表 api 并显示 google-图表 (https://developers.google.com/chart/interactive/docs/quick_start)。这通常会导致无法解释的错误或浏览器永远加载。

编辑:在下面添加了完整的更新测试文件

另见 plnkr here

更具体地说,这些是我用来确定事情开始出错的点的测试文件:

index.html

<html>
<head>
<title>Angular 2 QuickStart</title>
<script src="https://code.angularjs.org/tools/system.js"></script>
<script src="https://code.angularjs.org/tools/typescript.js"></script>
<script src="https://code.angularjs.org/2.0.0-alpha.46/angular2.dev.js">    </script>

<!--Load the AJAX API-->
<script type="text/javascript" src="https://www.google.com/jsapi"></script>


<script>
  System.config({
    transpiler: 'typescript',
    typescriptOptions: { emitDecoratorMetadata: true }
  });
  System.import('./app.ts');
</script>
</head>
<body>
<my-app>loading...</my-app>
</body>
</html>

然后,app.ts

import {bootstrap, Component} from 'angular2/angular2';


@Component({
selector: 'my-app',
template:`
<h1>Demo component my-app</h1>
<div id="cc" (click)="test($event)">Click me</div>
`
})
class AppComponent {

constructor() {
console.log("Constructor was called");
}

test(event) {
console.log("Event :",event);
console.log("Test :", google);
console.log("Document object by id",document.getElementById("cc"));

// Callback that creates and populates a data table,
// instantiates the pie chart, passes in the data and
// draws it.
function drawChart() {

  console.log("Callback is entered ");

  // Create the data table.
  var data = new google.visualization.DataTable();
  data.addColumn('string', 'Topping');
  data.addColumn('number', 'Slices');
  data.addRows([
    ['Mushrooms', 3],
    ['Onions', 1],
    ['Olives', 1],
    ['Zucchini', 1],
    ['Pepperoni', 2]
  ]);

  // Set chart options
  var options = {'title':'How Much Pizza I Ate Last Night',
                 'width':400,
                 'height':300};

  // Instantiate and draw our chart, passing in some options.
  var chart = new   google.visualization.PieChart(document.getElementById('cc'));
  chart.draw(data, options);
}



  console.log("Google object : ", google);
  console.log("Now, loading visualization api");
  // Load the Visualization API and the piechart package.
  google.load('visualization', '1.0', {'packages':['corechart']});
  console.log("Now, setting callback");
  // Set a callback to run when the Google Visualization API is loaded.
  google.setOnLoadCallback(drawChart);
  console.log("Callback was set");
  }

}



bootstrap(AppComponent);

这是控制台显示的内容,当我单击时:

Constructor was called
app.ts:18 Event : MouseEvent {isTrusted: true}
app.ts:19 Test : Object {loader: Object}
app.ts:20 Document object by id <div id=​"cc">​Click me​</div>​
app.ts:53 Google object :  Object {loader: Object}
app.ts:54 Now, loading visualization api
app.ts:57 Now, setting callback
app.ts:60 Callback was set

显然,回调永远不会进入 ?!

谁能帮我解决这个问题?非常感谢!

我在尝试将 google 图表实施到 ionic2 中时遇到了同样的问题。我不确定到底是什么问题,但似乎

  google.load('visualization', '1.0', {'packages':['corechart']});

加载时间过长

  google.setOnLoadCallback(drawChart);

永远不会执行。您可以通过将回调直接添加到 google.load() 来绕过此问题,如下所示:

    google.load('visualization', '1.0', {'packages':['corechart'], callback: drawChart});

对我有用!并且图表正在根据需要加载。此解决方案的所有功劳归功于@davidkonrad:

希望有用!

最后,通过使用图表组件调用图表指令解决了这个问题。该指令的 setter 触发绘图。不再需要直接 capture/manage 绘图事件。

  1. 从顶部 index.html 文件加载 google 脚本

    <script type="text/javascript" src="https://www.google.com/jsapi">
    </script>
    <script type="text/javascript">        
      google.load('visualization', '1.0', {
        'packages': ['corechart']
      });
    </script>
    
  2. 创建一个 "chart" 指令来绘制 google 图表 (chart.directive.ts)

    /**
    *      This directive will draw a chart from the array of records provided
    *
    *           Note : the relevant jsapi scripts should be already available
    *                  globally in the window.google object (see index.html)
    **/
    
    import {Directive, ElementRef, Input} from "angular2/core";
    import {CORE_DIRECTIVES } from "angular2/common";
    
    @Directive({
      selector: "chart",
    })
    export class ChartDirective {
    
      el: HTMLElement; 
      w: any;  // To store the window, without generating errors in typescript on window.google
      private _content: any[] = [];         
    
      // Setter for content will trigger drawing (or refreshing)
      @Input()
      set content(c: any[]) {
        console.log("Setting content ...");
        this._content = c;
        this.draw();
      }
    
      get content() { return this._content; }
    
    
    
      // Constructor inject a ref to the element
      constructor(elementRef: ElementRef) {
      console.log("Constructing chart directive");
      this.w = window;
      this.el = elementRef.nativeElement; // You cannot use elementRef directly !
      // console.log("Native HTML :", this.el);
      if (!this.w.google) { console.error("Hey ! It seems the needed google script was not loaded ?"); };
      }
    
    // Do the actual drawing
    draw() {
      // Create the data table.
      let data = new this.w.google.visualization.DataTable();
      data.addColumn("date", "Quand");
      data.addColumn("number", "KG");
      let rows = [];
      for (let c in this._content) {
        let d: Date = new Date(this._content[c].quand);
        let k: number = +(this._content[c].kg); // Plus sign to force conversion sting -> number
        // Only take into account records after the 'notBefore date'
        if (d >= this._nbd) rows.push([d, k]);
      }
      data.addRows(rows);
      // Create options
      let options: any = {
        // "width": 600,
        "height": 300,
        "curveType": "function"
      };
    
    
      // Instantiate and draw our chart, passing in some options.
      (new this.w.google.visualization.LineChart(this.el))
        .draw(data, options);
    }
    

    }

  3. 在图表组件中使用指令 (chart.component) ...

    import {Component } from "angular2/core";
    import {CORE_DIRECTIVES } from "angular2/common";
    
    import {MyModel} from "./mymodel.service.ts";
    import {ChartDirective} from "./chart.directive.ts";
    
    
    @Component({
    selector: "chartPage",
    templateUrl: "/components/chart.template.html",
    directives: [CORE_DIRECTIVES, ChartDirective]        
    })
    export class ChartComponent {     
    
    }
    
    // Injecting my data model into chart component ...
    constructor(private model: MyModel) {
      console.log("Constructing chart component");
    };
    

    }

  4. ...使用以下图表模板

    <chart [content]="model.content" ></chart>