import { Component } from '@angular/core';
import { DataService } from './data.service';
@Component({
selector: 'my-app',
templateUrl: 'app/app.html'
})
export class AppComponent {
data: IData[];
newLabel: string;
newValue: number;
constructor(private dataService: DataService) { }
ngOnInit() {
this.dataService.$data.subscribe(data => {
this.data = data;
});
}
addData(): void {
let newData = {
label: this.newLabel,
value: this.newValue
} as IData;
this.dataService.addData(newData);
}
}
/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
import { NgModule } from '@angular/core';
import { FormsModule } from "@angular/forms";
import { BrowserModule } from '@angular/platform-browser';
import { AppComponent } from './app.component';
import { PieChartComponent } from './pie-chart.component';
import { DataService } from './data.service';
@NgModule({
imports: [ BrowserModule, FormsModule ],
declarations: [
AppComponent,
PieChartComponent
],
bootstrap: [ AppComponent ],
providers: [
DataService
]
})
export class AppModule { }
/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app/app.module';
platformBrowserDynamic().bootstrapModule(AppModule);
/*
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<!DOCTYPE html>
<html>
<head>
<title>Angular Quickstart</title>
<script>document.write('<base href="' + document.location + '" />');</script>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link data-require="bootstrap-css" data-semver="4.0.0-alpha.4" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.4/css/bootstrap.min.css" />
<link data-require="bootstrap@*" data-semver="4.0.5" rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" />
<style>
body {color:#369;font-family: Arial,Helvetica,sans-serif;}
</style>
<!-- Polyfills -->
<script src="https://d3js.org/d3.v3.min.js" charset="utf-8"></script>
<script data-require="jquery" data-semver="3.1.1" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script src="https://npmcdn.com/tether@1.2.4/dist/js/tether.min.js"></script>
<script data-require="bootstrap" data-semver="4.0.5" src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.5/js/bootstrap.min.js"></script>
<script src="https://unpkg.com/core-js/client/shim.min.js"></script>
<script src="https://unpkg.com/zone.js@0.7.4?main=browser"></script>
<script src="https://unpkg.com/systemjs@0.19.39/dist/system.src.js"></script>
<script src="systemjs.config.js"></script>
<script>
System.import('main.js').catch(function(err){ console.error(err); });
</script>
</head>
<body>
<my-app>Loading AppComponent content here ...</my-app>
</body>
</html>
<!--
Copyright 2017 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
-->
/**
* WEB ANGULAR VERSION
* (based on systemjs.config.js in angular.io)
* System configuration for Angular samples
* Adjust as necessary for your application needs.
*/
(function (global) {
System.config({
// DEMO ONLY! REAL CODE SHOULD NOT TRANSPILE IN THE BROWSER
transpiler: 'ts',
typescriptOptions: {
// Copy of compiler options in standard tsconfig.json
"target": "es5",
"module": "system",
"moduleResolution": "node",
"sourceMap": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"lib": ["es2015", "dom"],
"noImplicitAny": true,
"suppressImplicitAnyIndexErrors": true
},
meta: {
'typescript': {
"exports": "ts"
}
},
paths: {
// paths serve as alias
'npm:': 'https://unpkg.com/'
},
// map tells the System loader where to look for things
map: {
// our app is within the app folder
app: 'app',
// angular bundles
'@angular/core': 'npm:@angular/core/bundles/core.umd.js',
'@angular/common': 'npm:@angular/common/bundles/common.umd.js',
'@angular/compiler': 'npm:@angular/compiler/bundles/compiler.umd.js',
'@angular/platform-browser': 'npm:@angular/platform-browser/bundles/platform-browser.umd.js',
'@angular/platform-browser-dynamic': 'npm:@angular/platform-browser-dynamic/bundles/platform-browser-dynamic.umd.js',
'@angular/http': 'npm:@angular/http/bundles/http.umd.js',
'@angular/router': 'npm:@angular/router/bundles/router.umd.js',
'@angular/router/upgrade': 'npm:@angular/router/bundles/router-upgrade.umd.js',
'@angular/forms': 'npm:@angular/forms/bundles/forms.umd.js',
'@angular/upgrade': 'npm:@angular/upgrade/bundles/upgrade.umd.js',
'@angular/upgrade/static': 'npm:@angular/upgrade/bundles/upgrade-static.umd.js',
// other libraries
'rxjs': 'npm:rxjs@5.0.1',
'angular-in-memory-web-api': 'npm:angular-in-memory-web-api/bundles/in-memory-web-api.umd.js',
'ts': 'npm:plugin-typescript@5.2.7/lib/plugin.js',
'typescript': 'npm:typescript@2.0.10/lib/typescript.js',
'd3': 'https://d3js.org/d3.v3.min.js'
},
// packages tells the System loader how to load when no filename and/or no extension
packages: {
app: {
main: './main.ts',
defaultExtension: 'ts'
},
rxjs: {
defaultExtension: 'js'
},
'd3': {
defaultExtension: "js"
}
}
});
})(this);
/*
Copyright 2016 Google Inc. All Rights Reserved.
Use of this source code is governed by an MIT-style license that
can be found in the LICENSE file at http://angular.io/license
*/
<h1>Pie Chart with dynamic data</h1>
<div class="row">
<div class="col-md-2">
<div class="form-group">
<label for="dataLabel">Label : </label>
<input class="form-control" type="text" name="dataLabel" [(ngModel)]="newLabel" />
</div>
<div class="form-group">
<label for="dataValue">Value : </label>
<input class="form-control" type="number" name="dataValue" [(ngModel)]="newValue" />
</div>
<button (click)="addData()" class="btn btn-primary">Add data</button>
</div>
</div>
<div class="row">
<div class="col-md-5" style="width:400px; height:400px;">
<pie-chart></pie-chart>
</div>
<div class="col-md-7">
<table class="table table-striped">
<thead>
<tr>
<td>Label</td>
<td>Value</td>
</tr>
</thead>
<tbody>
<tr *ngFor="let d of data">
<td [innerHTML]="d.label"></td>
<td [innerHTML]="d.value"></td>
</tr>
</tbody>
</table>
</div>
</div>
import { Component, ElementRef, ViewChild, AfterViewInit } from "@angular/core";
import { IData } from './data.interface';
import { DataService } from './data.service';
import * as D3 from "d3";
@Component({
selector: "pie-chart",
templateUrl: "app/pie-chart.html"
})
export class PieChartComponent implements AfterViewInit {
@ViewChild("containerPieChart") element: ElementRef;
private host: D3.Selection<any>;
private svg: D3.Selection<any>;
private width: number;
private height: number;
private radius: number;
private htmlElement: HTMLElement;
private pieData: IData[];
constructor(private dataService: DataService) { }
ngAfterViewInit() {
this.htmlElement = this.element.nativeElement;
this.host = D3.select(this.htmlElement);
this.dataService.$data.subscribe(data => {
this.pieData = data;
this.setup();
this.buildSVG();
this.buildPie();
});
}
private setup(): void {
this.width = 250;
this.height = 250;
this.radius = Math.min(this.width, this.height) / 2;
}
private buildSVG(): void {
this.host.html("");
this.svg = this.host.append("svg")
.attr("viewBox", `0 0 ${this.width} ${this.height}`)
.append("g")
.attr("transform", `translate(${this.width / 2},${this.height / 2})`);
}
private buildPie(): void {
let pie = D3.layout.pie();
let values = this.pieData.map(data => data.value);
let arcSelection = this.svg.selectAll(".arc")
.data(pie(values))
.enter()
.append("g")
.attr("class", "arc");
this.populatePie(arcSelection);
}
private populatePie(arcSelection: D3.Selection<D3.layout.pie.Arc<number>>): void {
let innerRadius = this.radius - 50;
let outerRadius = this.radius - 10;
let pieColor = D3.scale.category20c();
let arc = D3.svg.arc<D3.layout.pie.Arc<number>>()
.outerRadius(outerRadius);
arcSelection.append("path")
.attr("d", arc)
.attr("fill", (datum, index) => {
return pieColor(this.pieData[index].label);
});
arcSelection.append("text")
.attr("transform", (datum: any) => {
datum.innerRadius = 0;
datum.outerRadius = outerRadius;
return "translate(" + arc.centroid(datum) + ")";
})
.text((datum, index) => this.pieData[index].label)
.style("text-anchor", "middle");
}
}
<div #containerPieChart></div>
import { Injectable } from "@angular/core";
import { BehaviorSubject } from "rxjs/BehaviorSubject";
import { IData } from './data.interface';
@Injectable()
export class DataService {
private mockData: IData[] = [
{
label: "data1",
value: 1,
},
{
label: "data2",
value: 2,
},
{
label: "data3",
value: 3,
},
{
label: "data4",
value: 4,
}
];
private dataSubject = new BehaviorSubject<IData[]>(this.mockData);
$data = this.dataSubject.asObservable();
addData(newData: IData) {
this.mockData.push(newData);
this.dataSubject.next(this.mockData);
}
}
export interface IData {
label: string,
value: number
}