├── src ├── assets │ ├── .gitkeep │ ├── images │ │ ├── data.png │ │ ├── Scale.png │ │ ├── Scatter.png │ │ ├── animated.png │ │ ├── axes-icon.png │ │ ├── selection.png │ │ ├── Transitions.png │ │ ├── area-chart.png │ │ ├── line-chart.png │ │ ├── Visualization.png │ │ └── General-Update-Pattern.png │ └── js │ │ └── bootstrap.min.js ├── app │ ├── data │ │ ├── data.component.css │ │ ├── data.component.html │ │ ├── data.component.spec.ts │ │ └── data.component.ts │ ├── scales │ │ ├── scales.component.css │ │ ├── scales.component.html │ │ ├── scales.component.spec.ts │ │ └── scales.component.ts │ ├── index.ts │ ├── area │ │ ├── area.component.html │ │ ├── area.component.css │ │ ├── area.component.spec.ts │ │ └── area.component.ts │ ├── axes │ │ ├── axes.component.html │ │ ├── axes.component.css │ │ ├── axes.component.spec.ts │ │ └── axes.component.ts │ ├── line │ │ ├── line.component.html │ │ ├── line.component.css │ │ ├── line.component.spec.ts │ │ └── line.component.ts │ ├── animate │ │ ├── animate.component.html │ │ ├── animate.component.css │ │ ├── animate.component.ts │ │ └── animate.component.spec.ts │ ├── scatter │ │ ├── scatter.component.html │ │ ├── scatter.component.css │ │ ├── scatter.component.spec.ts │ │ └── scatter.component.ts │ ├── selections │ │ ├── selections.component.css │ │ ├── selections.component.html │ │ ├── selections.component.spec.ts │ │ └── selections.component.ts │ ├── general-update-pattern │ │ ├── general-update-pattern.component.css │ │ ├── general-update-pattern.component.html │ │ ├── general-update-pattern.component.spec.ts │ │ └── general-update-pattern.component.ts │ ├── transitions │ │ ├── transitions.component.css │ │ ├── transitions.component.html │ │ ├── transitions.component.spec.ts │ │ └── transitions.component.ts │ ├── app.component.html │ ├── visualization │ │ ├── visualization.component.html │ │ ├── visualization.component.css │ │ ├── visualization.component.spec.ts │ │ └── visualization.component.ts │ ├── header │ │ ├── header.component.ts │ │ ├── header.component.spec.ts │ │ ├── header.component.css │ │ └── header.component.html │ ├── Dashboard │ │ ├── dashboard.component.ts │ │ ├── dashboard.component.spec.ts │ │ ├── dashboard.component.css │ │ └── dashboard.component.html │ ├── app.component.ts │ ├── app.component.css │ ├── app.component.spec.ts │ ├── app.module.ts │ └── app.routing.ts ├── demo_data │ ├── names.csv │ ├── names.tsv │ ├── names.json │ ├── country.json │ └── stocks.json ├── favicon.ico ├── styles.css ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── typings.d.ts ├── tsconfig.app.json ├── main.ts ├── tsconfig.spec.json ├── index.html ├── test.ts └── polyfills.ts ├── e2e ├── app.po.ts ├── tsconfig.e2e.json └── app.e2e-spec.ts ├── .editorconfig ├── tsconfig.json ├── .gitignore ├── README.md ├── protractor.conf.js ├── .angular-cli.json ├── karma.conf.js ├── package.json └── tslint.json /src/assets/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/data/data.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/scales/scales.component.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/app/data/data.component.html: -------------------------------------------------------------------------------- 1 |

2 | Check console 3 |

4 | -------------------------------------------------------------------------------- /src/app/index.ts: -------------------------------------------------------------------------------- 1 | export * from './app.component'; 2 | export * from './app.module'; 3 | -------------------------------------------------------------------------------- /src/demo_data/names.csv: -------------------------------------------------------------------------------- 1 | age,name 2 | 44,Ginger 3 | 32,Miriam 4 | 14,Flipper 5 | 95,Mario 6 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/app/area/area.component.html: -------------------------------------------------------------------------------- 1 |

2 | area works! 3 |

4 |
5 | -------------------------------------------------------------------------------- /src/app/axes/axes.component.html: -------------------------------------------------------------------------------- 1 |

2 | axes works! 3 |

4 |
5 | -------------------------------------------------------------------------------- /src/app/line/line.component.html: -------------------------------------------------------------------------------- 1 |

2 | line works! 3 |

4 |
5 | -------------------------------------------------------------------------------- /src/demo_data/names.tsv: -------------------------------------------------------------------------------- 1 | age name 2 | 44 Ginger 3 | 32 Miriam 4 | 14 Flipper 5 | 95 Mario 6 | -------------------------------------------------------------------------------- /src/styles.css: -------------------------------------------------------------------------------- 1 | /* You can add global styles to this file, and also import other style files */ 2 | -------------------------------------------------------------------------------- /src/app/animate/animate.component.html: -------------------------------------------------------------------------------- 1 |

2 | animate works! 3 |

4 |
5 | -------------------------------------------------------------------------------- /src/app/scales/scales.component.html: -------------------------------------------------------------------------------- 1 |

2 | Check console 3 |

4 | 5 |
xxx
6 | -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/app/scatter/scatter.component.html: -------------------------------------------------------------------------------- 1 |

2 | scatter works! 3 |

4 |
5 | -------------------------------------------------------------------------------- /src/assets/images/data.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/data.png -------------------------------------------------------------------------------- /src/assets/images/Scale.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/Scale.png -------------------------------------------------------------------------------- /src/app/selections/selections.component.css: -------------------------------------------------------------------------------- 1 | .title { 2 | font-weight: bold; 3 | } 4 | .red { 5 | color: red; 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/images/Scatter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/Scatter.png -------------------------------------------------------------------------------- /src/assets/images/animated.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/animated.png -------------------------------------------------------------------------------- /src/assets/images/axes-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/axes-icon.png -------------------------------------------------------------------------------- /src/assets/images/selection.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/selection.png -------------------------------------------------------------------------------- /src/assets/images/Transitions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/Transitions.png -------------------------------------------------------------------------------- /src/assets/images/area-chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/area-chart.png -------------------------------------------------------------------------------- /src/assets/images/line-chart.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/line-chart.png -------------------------------------------------------------------------------- /src/assets/images/Visualization.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/Visualization.png -------------------------------------------------------------------------------- /src/typings.d.ts: -------------------------------------------------------------------------------- 1 | /* SystemJS module definition */ 2 | declare var module: NodeModule; 3 | interface NodeModule { 4 | id: string; 5 | } 6 | -------------------------------------------------------------------------------- /src/app/line/line.component.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | background: lightgrey; 3 | border: 1px solid black; 4 | width: 425px; 5 | height: 625px; 6 | } 7 | -------------------------------------------------------------------------------- /src/assets/images/General-Update-Pattern.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gp187/angular2-d3v4-graph/HEAD/src/assets/images/General-Update-Pattern.png -------------------------------------------------------------------------------- /src/app/animate/animate.component.css: -------------------------------------------------------------------------------- 1 | #block { 2 | background: lightgray; 3 | border: 1px solid black; 4 | width: 100px; 5 | height: 100px; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/scatter/scatter.component.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | background: lightgrey; 3 | border: 1px solid black; 4 | width: 425px; 5 | height: 625px; 6 | } 7 | -------------------------------------------------------------------------------- /src/app/area/area.component.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | background: lightgrey; 3 | border: 1px solid black; 4 | /*width: 425px;*/ 5 | /*height: 625px;*/ 6 | } 7 | -------------------------------------------------------------------------------- /src/app/axes/axes.component.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | background: lightgrey; 3 | border: 1px solid black; 4 | /*width: 425px;*/ 5 | /*height: 625px;*/ 6 | } 7 | -------------------------------------------------------------------------------- /src/app/general-update-pattern/general-update-pattern.component.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | background: lightgrey; 3 | border: 1px solid black; 4 | } 5 | rect { 6 | fill: steelblue; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/transitions/transitions.component.css: -------------------------------------------------------------------------------- 1 | .block { 2 | background: lightgray; 3 | border: 1px solid block; 4 | width: 50px; 5 | height: 50px; 6 | margin-bottom: 1em; 7 | } 8 | -------------------------------------------------------------------------------- /src/app/app.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 |
7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /src/app/transitions/transitions.component.html: -------------------------------------------------------------------------------- 1 |

2 | transitions works! 3 |

4 | 5 | 6 |
7 | 8 | -------------------------------------------------------------------------------- /src/app/visualization/visualization.component.html: -------------------------------------------------------------------------------- 1 |

2 | visualization works! 3 |

4 | 5 |
6 | 7 | 8 | 9 | 10 |
11 | -------------------------------------------------------------------------------- /e2e/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, element, by } from 'protractor'; 2 | 3 | export class D34Page { 4 | navigateTo() { 5 | return browser.get('/'); 6 | } 7 | 8 | getParagraphText() { 9 | return element(by.css('app-root h1')).getText(); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/e2e", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types":[ 8 | "jasmine", 9 | "node" 10 | ] 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "es2015", 6 | "baseUrl": "", 7 | "types": [] 8 | }, 9 | "exclude": [ 10 | "test.ts", 11 | "**/*.spec.ts" 12 | ] 13 | } 14 | -------------------------------------------------------------------------------- /src/app/general-update-pattern/general-update-pattern.component.html: -------------------------------------------------------------------------------- 1 |

2 | general-update-pattern works! 3 |

4 |
5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /src/app/selections/selections.component.html: -------------------------------------------------------------------------------- 1 |

2 | Selections 3 |

4 | 5 |
xxx 6 | About 7 | Product 8 | Contact 9 | Buy now 10 |
11 | asasa 12 |
13 | -------------------------------------------------------------------------------- /src/demo_data/names.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "age": 44, 4 | "name": "Ginger" 5 | }, 6 | { 7 | "age": 32, 8 | "name": "Miriam" 9 | }, 10 | { 11 | "age": 14, 12 | "name": "Flipper" 13 | }, 14 | { 15 | "age": 95, 16 | "name": "Mario" 17 | }, 18 | { 19 | "age": 95, 20 | "name": "Mirel" 21 | } 22 | ] 23 | -------------------------------------------------------------------------------- /e2e/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { D34Page } from './app.po'; 2 | 3 | describe('d3-4 App', function() { 4 | let page: D34Page; 5 | 6 | beforeEach(() => { 7 | page = new D34Page(); 8 | }); 9 | 10 | it('should display message saying app works', () => { 11 | page.navigateTo(); 12 | expect(page.getParagraphText()).toEqual('app works!'); 13 | }); 14 | }); 15 | -------------------------------------------------------------------------------- /src/app/visualization/visualization.component.css: -------------------------------------------------------------------------------- 1 | .chart { 2 | background: white; 3 | border: 1px solid black; 4 | min-height: 350px; 5 | min-width: 200px; 6 | } 7 | .bar { 8 | height: 30px; 9 | fill: #fff; 10 | stroke: black; 11 | stroke-width: 2; 12 | } 13 | 14 | .bar:hover { 15 | fill: lightblue; 16 | 17 | } 18 | .barOn { 19 | fill: lightblue; 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import './polyfills.ts'; 2 | 3 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 4 | import { enableProdMode } from '@angular/core'; 5 | import { environment } from './environments/environment'; 6 | import { AppModule } from './app/'; 7 | 8 | if (environment.production) { 9 | enableProdMode(); 10 | } 11 | 12 | platformBrowserDynamic().bootstrapModule(AppModule); 13 | -------------------------------------------------------------------------------- /src/app/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-header', 6 | templateUrl: './header.component.html', 7 | styleUrls: ['./header.component.css'] 8 | }) 9 | export class HeaderComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "baseUrl": "", 8 | "types": [ 9 | "jasmine", 10 | "node" 11 | ] 12 | }, 13 | "files": [ 14 | "test.ts" 15 | ], 16 | "include": [ 17 | "**/*.spec.ts", 18 | "**/*.d.ts" 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // The file contents for the current environment will overwrite these during build. 2 | // The build system defaults to the dev environment which uses `environment.ts`, but if you do 3 | // `ng build --env=prod` then `environment.prod.ts` will be used instead. 4 | // The list of which env maps to which file can be found in `angular-cli.json`. 5 | 6 | export const environment = { 7 | production: false 8 | }; 9 | -------------------------------------------------------------------------------- /src/app/Dashboard/dashboard.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-dashbord', 6 | templateUrl: './dashboard.component.html', 7 | styleUrls: ['./dashboard.component.css'] 8 | }) 9 | export class DashboardComponent implements OnInit { 10 | title = 'Loaded D3 v'+d3.version; 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | } 15 | 16 | } 17 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "outDir": "./dist/out-tsc", 5 | "baseUrl": "src", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "moduleResolution": "node", 9 | "emitDecoratorMetadata": true, 10 | "experimentalDecorators": true, 11 | "target": "es5", 12 | "typeRoots": [ 13 | "node_modules/@types" 14 | ], 15 | "lib": [ 16 | "es2016", 17 | "dom" 18 | ] 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/app/app.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | import { log } from 'util'; 4 | import { HeaderComponent } from './header/header.component'; 5 | 6 | @Component({ 7 | selector: 'app-root', 8 | templateUrl: './app.component.html', 9 | styleUrls: ['./app.component.css'] 10 | }) 11 | export class AppComponent implements OnInit { 12 | title = 'Loaded D3 v' + d3.version; 13 | 14 | ngOnInit() { 15 | 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/demo_data/country.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "country": "US", 4 | "population": 323500000, 5 | "expectancy": 78.94, 6 | "cost": 9024.21, 7 | "code": "US" 8 | }, 9 | { 10 | "country": "Switzerland", 11 | "population": 8306200, 12 | "expectancy": 82.85, 13 | "cost": 6786.57, 14 | "code": "CH" 15 | }, 16 | { 17 | "country": "Norway", 18 | "population": 5213985, 19 | "expectancy": 81.75, 20 | "cost": 6081, 21 | "code": "NO" 22 | } 23 | ] 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | 7 | # dependencies 8 | /node_modules 9 | /bower_components 10 | 11 | # IDEs and editors 12 | /.idea 13 | /.vscode 14 | .project 15 | .classpath 16 | .c9/ 17 | *.launch 18 | .settings/ 19 | 20 | # misc 21 | /.sass-cache 22 | /connect.lock 23 | /coverage/* 24 | /libpeerconnection.log 25 | npm-debug.log 26 | testem.log 27 | /typings 28 | 29 | # e2e 30 | /e2e/*.js 31 | /e2e/*.map 32 | 33 | #System Files 34 | .DS_Store 35 | Thumbs.db 36 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | D34 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | Loading... 17 | 18 | 19 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # Angular2 D3 v4: charts, animations, view porting etc 5 | 6 | ## Clone the repo 7 | `npm install` 8 | 9 | 10 | ## Development server 11 | Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. 12 | 13 | ## Code scaffolding 14 | 15 | Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive/pipe/service/class`. 16 | 17 | ## Build 18 | 19 | Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `-prod` flag for a production build. 20 | 21 | ## Running unit tests 22 | 23 | Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). 24 | -------------------------------------------------------------------------------- /src/app/animate/animate.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | 5 | @Component({ 6 | selector: 'app-animate', 7 | templateUrl: './animate.component.html', 8 | styleUrls: ['./animate.component.css'] 9 | }) 10 | export class AnimateComponent implements OnInit { 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | d3 16 | .select('#block') 17 | .transition() 18 | .duration(500) 19 | .delay(500) 20 | .ease(d3.easeElasticOut) 21 | .style('width', '400px') 22 | .transition() 23 | .duration(500) 24 | .ease(d3.easeElasticOut) 25 | .style('height', '400px') 26 | .transition() 27 | .duration(500) 28 | .ease(d3.easeQuadOut) 29 | .style('background-color', 'purple') 30 | } 31 | 32 | } 33 | -------------------------------------------------------------------------------- /protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './e2e/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | beforeLaunch: function() { 23 | require('ts-node').register({ 24 | project: 'e2e/tsconfig.e2e.json' 25 | }); 26 | }, 27 | onPrepare() { 28 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /src/app/area/area.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { AreaComponent } from './area.component'; 7 | 8 | describe('AreaComponent', () => { 9 | let component: AreaComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ AreaComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(AreaComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/axes/axes.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { AxesComponent } from './axes.component'; 7 | 8 | describe('AxesComponent', () => { 9 | let component: AxesComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ AxesComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(AxesComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/data/data.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { DataComponent } from './data.component'; 7 | 8 | describe('DataComponent', () => { 9 | let component: DataComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ DataComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(DataComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/line/line.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { LineComponent } from './line.component'; 7 | 8 | describe('LineComponent', () => { 9 | let component: LineComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ LineComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(LineComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/scales/scales.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { ScalesComponent } from './scales.component'; 7 | 8 | describe('ScalesComponent', () => { 9 | let component: ScalesComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ ScalesComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(ScalesComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/animate/animate.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { AnimateComponent } from './animate.component'; 7 | 8 | describe('AnimateComponent', () => { 9 | let component: AnimateComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ AnimateComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(AnimateComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/scatter/scatter.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { ScatterComponent } from './scatter.component'; 7 | 8 | describe('ScatterComponent', () => { 9 | let component: ScatterComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ ScatterComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(ScatterComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/header/header.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { HeaderComponent } from './header.component'; 7 | 8 | describe('AxesComponent', () => { 9 | let component: HeaderComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ HeaderComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(HeaderComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/selections/selections.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { SelectionsComponent } from './selections.component'; 7 | 8 | describe('SelectionsComponent', () => { 9 | let component: SelectionsComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ SelectionsComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(SelectionsComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/transitions/transitions.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { TransitionsComponent } from './transitions.component'; 7 | 8 | describe('TransitionsComponent', () => { 9 | let component: TransitionsComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ TransitionsComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(TransitionsComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/Dashboard/dashboard.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { DashboardComponent } from './dashboard.component'; 7 | 8 | describe('AxesComponent', () => { 9 | let component: DashboardComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ DashboardComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(DashboardComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/visualization/visualization.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { VisualizationComponent } from './visualization.component'; 7 | 8 | describe('VisualizationComponent', () => { 9 | let component: VisualizationComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ VisualizationComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(VisualizationComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/general-update-pattern/general-update-pattern.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | import { async, ComponentFixture, TestBed } from '@angular/core/testing'; 3 | import { By } from '@angular/platform-browser'; 4 | import { DebugElement } from '@angular/core'; 5 | 6 | import { GeneralUpdatePatternComponent } from './general-update-pattern.component'; 7 | 8 | describe('GeneralUpdatePatternComponent', () => { 9 | let component: GeneralUpdatePatternComponent; 10 | let fixture: ComponentFixture; 11 | 12 | beforeEach(async(() => { 13 | TestBed.configureTestingModule({ 14 | declarations: [ GeneralUpdatePatternComponent ] 15 | }) 16 | .compileComponents(); 17 | })); 18 | 19 | beforeEach(() => { 20 | fixture = TestBed.createComponent(GeneralUpdatePatternComponent); 21 | component = fixture.componentInstance; 22 | fixture.detectChanges(); 23 | }); 24 | 25 | it('should create', () => { 26 | expect(component).toBeTruthy(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /src/app/app.component.css: -------------------------------------------------------------------------------- 1 | .navbar { 2 | background:rgba(0, 65, 194,.8); 3 | padding:5px 0; 4 | border-radius:0px; 5 | } 6 | .nav ul{ 7 | padding:0; 8 | margin: 0; 9 | } 10 | .nav ul li{ 11 | padding:5px 15px; 12 | } 13 | .nav ul li:first-child{ 14 | padding:5px 0px; 15 | } 16 | .nav ul li a{ 17 | color:#fff; 18 | text-transform: capitalize; 19 | text-decoration: none; 20 | } 21 | .content-box 22 | { 23 | margin-top:20px; 24 | } 25 | .scale 26 | { 27 | background:rgba(0, 65, 194,.8); 28 | padding: 20px; 29 | margin:15px 0; 30 | text-align: center; 31 | } 32 | .scale a{ 33 | color:#fff; 34 | } 35 | .content-route 36 | { 37 | margin-top:30px; 38 | } 39 | .window-10-box .col-md-3 40 | { 41 | width:24%; 42 | margin-right:1%; 43 | } 44 | .route-class 45 | { 46 | margin-top:20px; 47 | border-top:1px solid #ccc; 48 | padding-top:20px; 49 | } 50 | 51 | @media only screen and (max-width: 768px) { 52 | .window-10-box .col-md-3 53 | { 54 | width:100%; 55 | margin-right:1%; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/app/transitions/transitions.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-transitions', 6 | templateUrl: './transitions.component.html', 7 | styleUrls: ['./transitions.component.css'] 8 | }) 9 | export class TransitionsComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | 15 | } 16 | 17 | go(): void { 18 | const t = d3.transition(null) 19 | .delay(1000) 20 | .duration(1000) 21 | d3.selectAll('.block') 22 | .transition(t) 23 | .style('width', '400px') 24 | 25 | d3.select('.a') 26 | .transition(t) 27 | .style('background-color', 'blue') 28 | 29 | d3.select('.b') 30 | .transition(t) 31 | .style('background-color', 'red') 32 | } 33 | 34 | configure(t: any, delay: number, duration: number): any { 35 | return t.delay(delay).duration(duration); 36 | } 37 | 38 | goNow(): void { 39 | d3.selectAll('.block') 40 | .transition() 41 | .call(this.configure, 1000, 1000) 42 | .style('height', '300px') 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/app/app.component.spec.ts: -------------------------------------------------------------------------------- 1 | /* tslint:disable:no-unused-variable */ 2 | 3 | import { TestBed, async } from '@angular/core/testing'; 4 | import { AppComponent } from './app.component'; 5 | 6 | describe('AppComponent', () => { 7 | beforeEach(() => { 8 | TestBed.configureTestingModule({ 9 | declarations: [ 10 | AppComponent 11 | ], 12 | }); 13 | }); 14 | 15 | it('should create the app', async(() => { 16 | let fixture = TestBed.createComponent(AppComponent); 17 | let app = fixture.debugElement.componentInstance; 18 | expect(app).toBeTruthy(); 19 | })); 20 | 21 | it(`should have as title 'app works!'`, async(() => { 22 | let fixture = TestBed.createComponent(AppComponent); 23 | let app = fixture.debugElement.componentInstance; 24 | expect(app.title).toEqual('app works!'); 25 | })); 26 | 27 | it('should render title in a h1 tag', async(() => { 28 | let fixture = TestBed.createComponent(AppComponent); 29 | fixture.detectChanges(); 30 | let compiled = fixture.debugElement.nativeElement; 31 | expect(compiled.querySelector('h1').textContent).toContain('app works!'); 32 | })); 33 | }); 34 | -------------------------------------------------------------------------------- /src/app/data/data.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | import { log } from 'util'; 4 | 5 | @Component({ 6 | selector: 'app-data', 7 | templateUrl: './data.component.html', 8 | styleUrls: ['./data.component.css'] 9 | }) 10 | export class DataComponent implements OnInit { 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | // d3.csv('demo_data/names.csv', function (data) { 16 | // log(data); 17 | // }) 18 | // d3.tsv('demo_data/names.tsv', function (data) { 19 | // log(data); 20 | // }) 21 | d3.json('../demo_data/names.json', function (data) { 22 | const min = d3.min(data, (d: any) => d.age); 23 | const max = d3.max(data, (d: any) => d.age); 24 | log(min + ' >> ' + max); 25 | 26 | const extent = d3.extent(data, (d: any) => +d.age); 27 | log(extent.toString()); 28 | 29 | // -->Scale: using min/max 30 | const scale = d3.scaleLinear().domain(extent).range([0, 100]) 31 | log(scale(24)); 32 | 33 | // -->Unique: pull unique values 34 | const ages = d3.set(data, (d: any) => d.age); 35 | log(ages.values()) 36 | }) 37 | 38 | } 39 | 40 | } 41 | -------------------------------------------------------------------------------- /src/app/Dashboard/dashboard.component.css: -------------------------------------------------------------------------------- 1 | .navbar { 2 | background:rgba(0, 65, 194,.8); 3 | padding:5px 0; 4 | border-radius:0px; 5 | } 6 | .nav ul{ 7 | padding:0; 8 | margin: 0; 9 | } 10 | .nav ul li{ 11 | padding:5px 15px; 12 | } 13 | .nav ul li:first-child{ 14 | padding:5px 0px; 15 | } 16 | .nav ul li a{ 17 | color:#fff; 18 | text-transform: capitalize; 19 | text-decoration: none; 20 | } 21 | .content-box 22 | { 23 | margin-top:20px; 24 | } 25 | .scale 26 | { 27 | background:rgba(0, 65, 194,.8); 28 | padding: 20px; 29 | margin:15px 0; 30 | text-align: center; 31 | } 32 | .scale a{ 33 | color:#fff; 34 | } 35 | .window-10-box .col-md-3 36 | { 37 | width:24%; 38 | margin-right:1%; 39 | } 40 | .route-class 41 | { 42 | margin-top:20px; 43 | border-top:1px solid #ccc; 44 | padding-top:20px; 45 | } 46 | @media only screen and (max-width: 1024px) { 47 | .navbar-toggler 48 | { 49 | display: block !important; 50 | } 51 | } 52 | @media (min-width: 576px) and (max-width: 1024px) { 53 | .collapse 54 | { 55 | display: none !important; 56 | } 57 | } 58 | @media only screen and (max-width: 768px) { 59 | .window-10-box .col-md-3 60 | { 61 | width:100%; 62 | margin-right:1%; 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/long-stack-trace-zone'; 4 | import 'zone.js/dist/proxy.js'; 5 | import 'zone.js/dist/sync-test'; 6 | // tslint:disable-next-line:ordered-imports 7 | import 'zone.js/dist/jasmine-patch'; 8 | import 'zone.js/dist/async-test'; 9 | import 'zone.js/dist/fake-async-test'; 10 | // tslint:disable-next-line:ordered-imports 11 | import { getTestBed } from '@angular/core/testing'; 12 | import { 13 | BrowserDynamicTestingModule, 14 | platformBrowserDynamicTesting 15 | } from '@angular/platform-browser-dynamic/testing'; 16 | 17 | // Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. 18 | declare var __karma__: any; 19 | declare var require: any; 20 | 21 | // Prevent Karma from running prematurely. 22 | __karma__.loaded = function () {}; 23 | 24 | // First, initialize the Angular testing environment. 25 | getTestBed().initTestEnvironment( 26 | BrowserDynamicTestingModule, 27 | platformBrowserDynamicTesting() 28 | ); 29 | // Then we find all the tests. 30 | const context = require.context('./', true, /\.spec\.ts$/); 31 | // And load the modules. 32 | context.keys().map(context); 33 | // Finally, start Karma to run the tests. 34 | __karma__.start(); 35 | -------------------------------------------------------------------------------- /.angular-cli.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "project": { 4 | "name": "d3-v4" 5 | }, 6 | "apps": [{ 7 | "root": "src", 8 | "outDir": "dist", 9 | "assets": [ 10 | "assets", 11 | "demo_data", 12 | "favicon.ico" 13 | ], 14 | "index": "index.html", 15 | "main": "main.ts", 16 | "polyfills": "polyfills.ts", 17 | "test": "test.ts", 18 | "tsconfig": "tsconfig.app.json", 19 | "testTsconfig": "tsconfig.spec.json", 20 | "prefix": "app", 21 | "styles": [ 22 | "styles.css" 23 | ], 24 | "scripts": [], 25 | "environmentSource": "environments/environment.ts", 26 | "environments": { 27 | "dev": "environments/environment.ts", 28 | "prod": "environments/environment.prod.ts" 29 | } 30 | }], 31 | "e2e": { 32 | "protractor": { 33 | "config": "./protractor.conf.js" 34 | } 35 | }, 36 | "lint": [{ 37 | "project": "src/tsconfig.app.json" 38 | }, 39 | { 40 | "project": "src/tsconfig.spec.json" 41 | }, 42 | { 43 | "project": "e2e/tsconfig.e2e.json" 44 | } 45 | ], 46 | "test": { 47 | "karma": { 48 | "config": "./karma.conf.js" 49 | } 50 | }, 51 | "defaults": { 52 | "styleExt": "css", 53 | "component": {} 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/0.13/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular/cli'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular/cli/plugins/karma') 14 | ], 15 | client:{ 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | files: [ 19 | { pattern: './src/test.ts', watched: false } 20 | ], 21 | preprocessors: { 22 | './src/test.ts': ['@angular/cli'] 23 | }, 24 | mime: { 25 | 'text/x-typescript': ['ts','tsx'] 26 | }, 27 | coverageIstanbulReporter: { 28 | reports: [ 'html', 'lcovonly' ], 29 | fixWebpackSourcePaths: true 30 | }, 31 | angularCli: { 32 | environment: 'dev' 33 | }, 34 | reporters: config.angularCli && config.angularCli.codeCoverage 35 | ? ['progress', 'coverage-istanbul'] 36 | : ['progress', 'kjhtml'], 37 | port: 9876, 38 | colors: true, 39 | logLevel: config.LOG_INFO, 40 | autoWatch: true, 41 | browsers: ['Chrome'], 42 | singleRun: false 43 | }); 44 | }; 45 | -------------------------------------------------------------------------------- /src/app/header/header.component.css: -------------------------------------------------------------------------------- 1 | .navbar { 2 | background:rgba(0, 65, 194,.8); 3 | padding:5px 0; 4 | border-radius:0px; 5 | } 6 | .nav ul{ 7 | padding:0; 8 | margin: 0; 9 | } 10 | .nav ul li{ 11 | padding:5px 15px; 12 | } 13 | .nav ul li:first-child{ 14 | padding:5px 0px; 15 | } 16 | .nav ul li a{ 17 | color:#fff; 18 | text-transform: capitalize; 19 | text-decoration: none; 20 | } 21 | .content-box 22 | { 23 | margin-top:20px; 24 | } 25 | .scale 26 | { 27 | background:rgba(0, 65, 194,.8); 28 | padding: 20px; 29 | margin:15px 0; 30 | text-align: center; 31 | } 32 | .scale a{ 33 | color:#fff; 34 | } 35 | .window-10-box .col-md-3 36 | { 37 | width:24%; 38 | margin-right:1%; 39 | } 40 | .route-class 41 | { 42 | margin-top:20px; 43 | border-top:1px solid #ccc; 44 | padding-top:20px; 45 | } 46 | @media only screen and (max-width: 1024px) { 47 | .navbar-toggler 48 | { 49 | display: block !important; 50 | } 51 | } 52 | @media (min-width: 576px) and (max-width: 1024px) { 53 | .navbar-toggleable-xs 54 | { 55 | display: none !important; 56 | } 57 | .collapsing, .in{ 58 | display: block !important; 59 | } 60 | .collapsing ul li, .in ul li{ 61 | float: none; 62 | } 63 | } 64 | @media only screen and (max-width: 768px) { 65 | .window-10-box .col-md-3 66 | { 67 | width:100%; 68 | margin-right:1%; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/app/scales/scales.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | import { log } from 'util'; 4 | 5 | @Component({ 6 | selector: 'app-scales', 7 | templateUrl: './scales.component.html', 8 | styleUrls: ['./scales.component.css'] 9 | }) 10 | export class ScalesComponent implements OnInit { 11 | 12 | title = 'app works! D3 v' + d3.version; 13 | 14 | ngOnInit() { 15 | // -->Find: linear scale between 2 numbers 16 | const linearScale = d3.scaleLinear().domain([0, 100]).range([0, 1]).clamp(true); 17 | log(linearScale(50).toString()) 18 | 19 | // -->Find: time scale between 2 dates 20 | const timeScale = d3.scaleTime().domain([new Date(2016, 0, 1), new Date()]).range([0, 100]); 21 | log(timeScale(new Date(2016, 3, 15)).toString()) 22 | log(timeScale.invert(50).toString()); 23 | log('------'); 24 | 25 | // -->Map: scale to colors 26 | const red = 0xFF0000; 27 | const white = 0xFFFFFF; 28 | const green = 0x00FF00; 29 | const quantizeScale = d3.scaleQuantize().domain([0, 100]).range([red, white, green]); 30 | log(quantizeScale(22)); 31 | log(quantizeScale(50)); 32 | log(quantizeScale(88)); 33 | log(quantizeScale.invertExtent(0xFFFFFF /*white*/)); 34 | 35 | // -->Map: scale to colors 36 | const ordinalScale = d3.scaleOrdinal().domain(['poor', 'good', 'great']).range([red, white, green]); 37 | log(ordinalScale('poor').toString()); 38 | 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "d3-4", 3 | "version": "0.0.0", 4 | "license": "MIT", 5 | "angular-cli": {}, 6 | "scripts": { 7 | "start": "ng serve", 8 | "lint": "tslint \"src/**/*.ts\"", 9 | "test": "ng test", 10 | "pree2e": "webdriver-manager update", 11 | "e2e": "protractor" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/common": "4.4.6", 16 | "@angular/compiler": "4.4.6", 17 | "@angular/core": "4.4.6", 18 | "@angular/forms": "4.4.6", 19 | "@angular/http": "4.4.6", 20 | "@angular/platform-browser": "4.4.6", 21 | "@angular/platform-browser-dynamic": "4.4.6", 22 | "@angular/router": "4.4.6", 23 | "core-js": "^2.4.1", 24 | "d3": "^4.4.0", 25 | "rxjs": "5.5.1", 26 | "ts-helpers": "^1.1.1", 27 | "zone.js": "^0.8.18" 28 | }, 29 | "devDependencies": { 30 | "@angular/cli": "^1.4.9", 31 | "@angular/compiler-cli": "4.4.6", 32 | "@types/d3": "^4.3.0", 33 | "@types/jasmine": "2.6.1", 34 | "@types/node": "^8.0.47", 35 | "codelyzer": "~3.2.2", 36 | "jasmine-core": "2.8.0", 37 | "jasmine-spec-reporter": "4.2.1", 38 | "karma": "1.7.1", 39 | "karma-chrome-launcher": "^2.0.0", 40 | "karma-cli": "^1.0.1", 41 | "karma-jasmine": "^1.0.2", 42 | "karma-remap-istanbul": "^0.6.0", 43 | "protractor": "5.2.0", 44 | "ts-node": "3.3.0", 45 | "tslint": "5.8.0", 46 | "typescript": ">=2.1.0 <2.4.0", 47 | "webdriver-manager": "12.0.6" 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/app/selections/selections.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | import {log} from "util"; 4 | 5 | @Component({ 6 | selector: 'app-selections', 7 | templateUrl: './selections.component.html', 8 | styleUrls: ['./selections.component.css'] 9 | }) 10 | export class SelectionsComponent implements OnInit { 11 | 12 | constructor() { } 13 | 14 | ngOnInit() { 15 | // -->Selecting: same as css 16 | let div = d3.selectAll('div'); 17 | console.log(div.nodes()); 18 | 19 | let divLinks = div.selectAll('a'); 20 | console.log(divLinks.nodes()); 21 | 22 | console.log(d3.selectAll('div.title a').nodes()); 23 | 24 | // -->Modifying: selected links 25 | let secondLink = d3.selectAll('a:nth-child(2)'); 26 | secondLink.attr('href','http://google.com'); 27 | console.log(secondLink.nodes()); 28 | console.log(secondLink.attr('href')); 29 | 30 | secondLink.style('color','red'); // change style 31 | secondLink.classed('red',true); // change class 32 | secondLink.text('Inventory SALE'); // change text 33 | secondLink.html('Inventory SALE'); // change text 34 | 35 | 36 | // -->Create: DOM elements 37 | d3.select('.title').append('button').style('color','red').html('Inventory2') 38 | d3.select('.title').insert('button','a:first-child').html('Inventory3') 39 | 40 | d3.select('.action').remove(); 41 | 42 | 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/app.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { FormsModule } from '@angular/forms'; 3 | import { HttpModule } from '@angular/http'; 4 | import { BrowserModule } from '@angular/platform-browser'; 5 | 6 | import { RouterModule } from '@angular/router'; 7 | import { AnimateComponent } from './animate/animate.component'; 8 | import { AppComponent } from './app.component'; 9 | import { routes } from './app.routing'; 10 | import { AreaComponent } from './area/area.component'; 11 | import { AxesComponent } from './axes/axes.component'; 12 | import { DashboardComponent } from './Dashboard/dashboard.component'; 13 | import { DataComponent } from './data/data.component'; 14 | import { GeneralUpdatePatternComponent } from './general-update-pattern/general-update-pattern.component'; 15 | import { HeaderComponent } from './header/header.component'; 16 | import { LineComponent } from './line/line.component'; 17 | import { ScalesComponent } from './scales/scales.component'; 18 | import { ScatterComponent } from './scatter/scatter.component'; 19 | import { SelectionsComponent } from './selections/selections.component'; 20 | import { TransitionsComponent } from './transitions/transitions.component'; 21 | import { VisualizationComponent } from './visualization/visualization.component'; 22 | 23 | @NgModule({ 24 | declarations: [ 25 | AppComponent, 26 | ScalesComponent, 27 | DataComponent, 28 | SelectionsComponent, 29 | VisualizationComponent, 30 | AxesComponent, 31 | ScatterComponent, 32 | LineComponent, 33 | AreaComponent, 34 | AnimateComponent, 35 | TransitionsComponent, 36 | GeneralUpdatePatternComponent, 37 | HeaderComponent, 38 | DashboardComponent 39 | ], 40 | imports: [ 41 | BrowserModule, 42 | FormsModule, 43 | HttpModule, 44 | RouterModule.forRoot(routes) 45 | ], 46 | providers: [], 47 | bootstrap: [AppComponent] 48 | }) 49 | export class AppModule { } 50 | -------------------------------------------------------------------------------- /src/app/Dashboard/dashboard.component.html: -------------------------------------------------------------------------------- 1 |
2 |

3 | {{title}} 4 |

5 | 11 |
12 | 13 | 14 | 15 | 16 |
17 | 22 |
23 |
24 |
25 | -------------------------------------------------------------------------------- /src/app/header/header.component.html: -------------------------------------------------------------------------------- 1 | 48 | -------------------------------------------------------------------------------- /src/app/app.routing.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { Routes, RouterModule } from '@angular/router'; 3 | import { ScalesComponent } from "./scales/scales.component"; 4 | import { DataComponent } from "./data/data.component"; 5 | import { SelectionsComponent } from "./selections/selections.component"; 6 | import { VisualizationComponent } from "./visualization/visualization.component"; 7 | import { AxesComponent } from "./axes/axes.component"; 8 | import { ScatterComponent } from "./scatter/scatter.component"; 9 | import { LineComponent } from "./line/line.component"; 10 | import {AreaComponent} from "./area/area.component"; 11 | import {AnimateComponent} from "./animate/animate.component"; 12 | import {TransitionsComponent} from "./transitions/transitions.component"; 13 | import {GeneralUpdatePatternComponent} from "./general-update-pattern/general-update-pattern.component"; 14 | import {DashboardComponent} from "./Dashboard/dashboard.component"; 15 | 16 | export const routes: Routes = [ 17 | { 18 | 19 | path: '', 20 | pathMatch: 'full', 21 | component: DashboardComponent 22 | }, 23 | { 24 | path: 'dashboard', 25 | pathMatch: 'full', 26 | component: DashboardComponent 27 | }, 28 | { 29 | path: 'scales', 30 | component: ScalesComponent 31 | }, 32 | { 33 | path: 'data', 34 | component: DataComponent 35 | }, 36 | { 37 | path: 'selections', 38 | component: SelectionsComponent 39 | }, 40 | { 41 | path: 'visualization', 42 | component: VisualizationComponent 43 | }, 44 | { 45 | path: 'axes', 46 | component: AxesComponent 47 | }, 48 | { 49 | path: 'scatter', 50 | component: ScatterComponent 51 | }, 52 | { 53 | path: 'line', 54 | component: LineComponent 55 | }, 56 | { 57 | path: 'area', 58 | component: AreaComponent 59 | }, 60 | { 61 | path: 'animate', 62 | component: AnimateComponent 63 | }, 64 | { 65 | path: 'transitions', 66 | component: TransitionsComponent 67 | }, 68 | { 69 | path: 'general', 70 | component: GeneralUpdatePatternComponent 71 | } 72 | 73 | ]; 74 | 75 | @NgModule({ 76 | imports: [ RouterModule.forRoot(routes) ], 77 | exports: [ RouterModule ] 78 | }) 79 | export class AppRoutingModule {} 80 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE9, IE10 and IE11 requires all of the following polyfills. **/ 22 | // import 'core-js/es6/symbol'; 23 | // import 'core-js/es6/object'; 24 | // import 'core-js/es6/function'; 25 | // import 'core-js/es6/parse-int'; 26 | // import 'core-js/es6/parse-float'; 27 | // import 'core-js/es6/number'; 28 | // import 'core-js/es6/math'; 29 | // import 'core-js/es6/string'; 30 | // import 'core-js/es6/date'; 31 | // import 'core-js/es6/array'; 32 | // import 'core-js/es6/regexp'; 33 | // import 'core-js/es6/map'; 34 | // import 'core-js/es6/set'; 35 | 36 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 37 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 38 | 39 | /** IE10 and IE11 requires the following to support `@angular/animation`. */ 40 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 41 | 42 | /** Evergreen browsers require these. **/ 43 | import 'core-js/es6/reflect'; 44 | import 'core-js/es7/reflect'; 45 | 46 | /** ALL Firefox browsers require the following to support `@angular/animation`. **/ 47 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 48 | 49 | /*************************************************************************************************** 50 | * Zone JS is required by Angular itself. 51 | */ 52 | import 'zone.js/dist/zone'; // Included with Angular CLI. 53 | 54 | /*************************************************************************************************** 55 | * APPLICATION IMPORTS 56 | */ 57 | 58 | /** 59 | * Date, currency, decimal and percent pipes. 60 | * Needed for: All but Chrome, Firefox, Edge, IE11 and Safari 10 61 | */ 62 | // import 'intl'; // Run `npm install --save intl`. 63 | -------------------------------------------------------------------------------- /src/app/line/line.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-line', 6 | templateUrl: './line.component.html', 7 | styleUrls: ['./line.component.css'] 8 | }) 9 | export class LineComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | const margin = { top: 10, right: 20, left: 40, bottom: 50 } 15 | const width = 425 - margin.left - margin.right; 16 | const height = 625 - margin.top - margin.bottom; 17 | 18 | function responsify(chart) { 19 | const container = d3.select(chart.node().parentNode), 20 | w = parseInt(chart.style('width'), 10), 21 | h = parseInt(chart.style('height'), 10), 22 | aspect = w / h; 23 | 24 | chart.attr('viewBox', '0 0 ' + w + ' ' + h) 25 | .attr('preserveAspectRatio', 'xMinYMid') 26 | .call(resize); 27 | 28 | d3.select(window).on('resize.' + container.attr('id'), resize); 29 | 30 | function resize() { 31 | const targetWidth = parseInt(container.style('width'), 10); 32 | chart.attr('width', targetWidth); 33 | chart.attr('height', Math.round(targetWidth / aspect)); 34 | } 35 | } 36 | 37 | const svg = d3.select('.chart') 38 | .append('svg') 39 | .attr('width', width + margin.left + margin.right) 40 | .attr('height', height + margin.top + margin.bottom) 41 | .call(responsify) 42 | .append('g') 43 | .attr('transform', `translate(${margin.left}, ${margin.top})`) 44 | 45 | d3.json('../demo_data/stocks.json', function (err, data: any) { 46 | 47 | const parseTime = d3.timeParse('%Y/%m/%d'); 48 | data.forEach(company => { 49 | company.values.forEach(d => { 50 | d.date = parseTime(d.date); 51 | d.close = +d.close; 52 | }); 53 | }); 54 | 55 | const xScale = d3.scaleTime() 56 | .domain([ 57 | +d3.min(data, (co: any) => d3.min(co.values, (d: any) => d.date)), 58 | +d3.max(data, (co: any) => d3.max(co.values, (d: any) => d.date)) 59 | ]) 60 | .range([0, width]); 61 | svg 62 | .append('g') 63 | .attr('transform', `translate(0, ${height})`) 64 | .call(d3.axisBottom(xScale).ticks(5)); 65 | 66 | const yScale = d3.scaleLinear() 67 | .domain([ 68 | +d3.min(data, (co: any) => d3.min(co.values, (d: any) => d.close)), 69 | +d3.max(data, (co: any) => d3.max(co.values, (d: any) => d.close)) 70 | ]) 71 | .range([height, 0]) 72 | svg 73 | .append('g') 74 | .call(d3.axisLeft(yScale)); 75 | 76 | const line = d3.line() 77 | .x((d: any) => xScale(d.date)) 78 | .y((d: any) => yScale(d.close)) 79 | .curve(d3.curveCatmullRom.alpha(0.1)); 80 | 81 | svg.selectAll('.line') 82 | .data(data) 83 | .enter() 84 | .append('path') 85 | .attr('class', 'line') 86 | .attr('d', (d: any) => line(d.values)) 87 | .style('stroke', (d, i) => ['#FF9900', '#3369E8'][i]) 88 | .style('stroke-width', 2) 89 | .style('fill', 'none') 90 | 91 | }) 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/app/area/area.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-area', 6 | templateUrl: './area.component.html', 7 | styleUrls: ['./area.component.css'] 8 | }) 9 | export class AreaComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | const margin = { top: 10, right: 20, left: 40, bottom: 50 } 15 | const width = 425 - margin.left - margin.right; 16 | const height = 625 - margin.top - margin.bottom; 17 | 18 | function responsify(chart) { 19 | const container = d3.select(chart.node().parentNode), 20 | w = parseInt(chart.style('width'), 10), 21 | h = parseInt(chart.style('height'), 10), 22 | aspect = w / h; 23 | 24 | chart.attr('viewBox', '0 0 ' + w + ' ' + h) 25 | .attr('preserveAspectRatio', 'xMinYMid') 26 | .call(resize); 27 | 28 | d3.select(window).on('resize.' + container.attr('id'), resize); 29 | 30 | function resize() { 31 | const targetWidth = parseInt(container.style('width'), 10); 32 | chart.attr('width', targetWidth); 33 | chart.attr('height', Math.round(targetWidth / aspect)); 34 | } 35 | } 36 | 37 | const svg = d3.select('.chart') 38 | .append('svg') 39 | .attr('width', width + margin.left + margin.right) 40 | .attr('height', height + margin.top + margin.bottom) 41 | .call(responsify) 42 | .append('g') 43 | .attr('transform', `translate(${margin.left}, ${margin.top})`) 44 | 45 | d3.json('../demo_data/stocks.json', function (err, data: any) { 46 | 47 | const parseTime = d3.timeParse('%Y/%m/%d'); 48 | data.forEach(company => { 49 | company.values.forEach(d => { 50 | d.date = parseTime(d.date); 51 | d.close = +d.close; 52 | }); 53 | }); 54 | 55 | const xScale = d3.scaleTime() 56 | .domain([ 57 | +d3.min(data, (co: any) => d3.min(co.values, (d: any) => d.date)), 58 | +d3.max(data, (co: any) => d3.max(co.values, (d: any) => d.date)) 59 | ]) 60 | .range([0, width]); 61 | svg 62 | .append('g') 63 | .attr('transform', `translate(0, ${height})`) 64 | .call(d3.axisBottom(xScale).ticks(5)); 65 | 66 | const yScale = d3.scaleLinear() 67 | .domain([ 68 | +d3.min(data, (co: any) => d3.min(co.values, (d: any) => d.close)), 69 | +d3.max(data, (co: any) => d3.max(co.values, (d: any) => d.close)) 70 | ]) 71 | .range([height, 0]) 72 | svg 73 | .append('g') 74 | .call(d3.axisLeft(yScale)); 75 | 76 | // ******************* 77 | // Until here is identical to line chart. 78 | // ******************* 79 | 80 | const area = d3.area() 81 | .x((d: any) => xScale(d.date)) 82 | .y0(yScale(yScale.domain()[0])) // pass the bottom of the scale, the 0 val 83 | .y1((d: any) => yScale(d.close)) 84 | .curve(d3.curveCatmullRom.alpha(0.5)) 85 | svg 86 | .selectAll('.area') 87 | .data(data) 88 | .enter() 89 | .append('path') 90 | .attr('class', 'area') 91 | .attr('d', (d: any) => area(d.values)) 92 | .style('stroke', (d, i) => ['#FF9900', '#3369E8'][i]) 93 | .style('stroke-width', 2) 94 | .style('fill', (d, i) => ['#FF9900', '#3369E8'][i]) 95 | .style('fill-opacity', 0.5) 96 | 97 | }) 98 | } 99 | 100 | } 101 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "rules": { 6 | "callable-types": true, 7 | "class-name": true, 8 | "comment-format": [ 9 | true, 10 | "check-space" 11 | ], 12 | "curly": true, 13 | "eofline": true, 14 | "forin": true, 15 | "import-blacklist": [ 16 | true, 17 | "rxjs" 18 | ], 19 | "ordered-imports": [ 20 | true 21 | ], 22 | "import-spacing": true, 23 | "indent": [ 24 | true, 25 | "spaces" 26 | ], 27 | "interface-over-type-literal": true, 28 | "label-position": true, 29 | "max-line-length": [ 30 | true, 31 | 140 32 | ], 33 | "member-access": false, 34 | "member-ordering": [ 35 | true, 36 | "static-before-instance", 37 | "variables-before-functions" 38 | ], 39 | "no-arg": true, 40 | "no-bitwise": true, 41 | "no-console": [ 42 | true, 43 | "debug", 44 | "info", 45 | "time", 46 | "timeEnd", 47 | "trace" 48 | ], 49 | "no-construct": true, 50 | "no-consecutive-blank-lines": [ 51 | true 52 | ], 53 | "no-debugger": true, 54 | "no-empty": false, 55 | "no-empty-interface": true, 56 | "no-eval": true, 57 | "no-inferrable-types": [ 58 | true, 59 | "ignore-params" 60 | ], 61 | "no-shadowed-variable": true, 62 | "no-string-literal": false, 63 | "no-string-throw": true, 64 | "no-switch-case-fall-through": true, 65 | "no-trailing-whitespace": true, 66 | "no-unused-expression": true, 67 | "no-unused-variable": [ 68 | true 69 | ], 70 | "no-use-before-declare": true, 71 | "no-var-keyword": true, 72 | "object-literal-sort-keys": false, 73 | "one-line": [ 74 | true, 75 | "check-open-brace", 76 | "check-catch", 77 | "check-else", 78 | "check-whitespace" 79 | ], 80 | "prefer-const": true, 81 | "quotemark": [ 82 | true, 83 | "single" 84 | ], 85 | "radix": true, 86 | "semicolon": [ 87 | "always" 88 | ], 89 | "triple-equals": [ 90 | true, 91 | "allow-null-check" 92 | ], 93 | "typedef-whitespace": [ 94 | true, 95 | { 96 | "call-signature": "nospace", 97 | "index-signature": "nospace", 98 | "parameter": "nospace", 99 | "property-declaration": "nospace", 100 | "variable-declaration": "nospace" 101 | } 102 | ], 103 | "typeof-compare": true, 104 | "unified-signatures": true, 105 | "variable-name": false, 106 | "whitespace": [ 107 | true, 108 | "check-branch", 109 | "check-decl", 110 | "check-operator", 111 | "check-separator", 112 | "check-type" 113 | ], 114 | "directive-selector": [ 115 | true, 116 | "attribute", 117 | "app", 118 | "camelCase" 119 | ], 120 | "component-selector": [ 121 | true, 122 | "element", 123 | "app", 124 | "kebab-case" 125 | ], 126 | "use-input-property-decorator": true, 127 | "use-output-property-decorator": true, 128 | "use-host-property-decorator": true, 129 | "no-input-rename": true, 130 | "no-output-rename": true, 131 | "use-life-cycle-interface": true, 132 | "use-pipe-transform-interface": true, 133 | "component-class-suffix": true, 134 | "directive-class-suffix": true, 135 | "no-access-missing-member": true, 136 | "templates-use-public": true, 137 | "invoke-injectable": true 138 | } 139 | } 140 | -------------------------------------------------------------------------------- /src/app/scatter/scatter.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-scatter', 6 | templateUrl: './scatter.component.html', 7 | styleUrls: ['./scatter.component.css'] 8 | }) 9 | export class ScatterComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | const margin = { top: 10, right: 20, left: 40, bottom: 50 } 15 | const width = 425 - margin.left - margin.right; 16 | const height = 625 - margin.top - margin.bottom; 17 | 18 | function responsify(chart) { 19 | const container = d3.select(chart.node().parentNode), 20 | w = parseInt(chart.style('width'), 10), 21 | h = parseInt(chart.style('height'), 10), 22 | aspect = w / h; 23 | 24 | chart.attr('viewBox', '0 0 ' + w + ' ' + h) 25 | .attr('preserveAspectRatio', 'xMinYMid') 26 | .call(resize); 27 | 28 | d3.select(window).on('resize.' + container.attr('id'), resize); 29 | 30 | function resize() { 31 | const targetWidth = parseInt(container.style('width'), 10); 32 | chart.attr('width', targetWidth); 33 | chart.attr('height', Math.round(targetWidth / aspect)); 34 | } 35 | } 36 | 37 | const svg = d3.select('.chart') 38 | .append('svg') 39 | .attr('width', width + margin.left + margin.right) 40 | .attr('height', height + margin.top + margin.bottom) 41 | .call(responsify) 42 | .append('g') 43 | .attr('transform', `translate(${margin.left}, ${margin.top})`) 44 | 45 | d3.json('../demo_data/country.json', function (err, data: any) { 46 | // -->Generate: scales [from,to] where you want 47 | const yScale = d3.scaleLinear() 48 | .domain(d3.extent(data, (d: any) => +d.expectancy)) 49 | .range([height, 0]) 50 | .nice(); 51 | const yAxes = d3.axisLeft(yScale) 52 | svg.call(yAxes); 53 | 54 | const xScale = d3.scaleLinear() 55 | .domain(d3.extent(data, (d: any) => +d.cost)) 56 | .range([0, width]) 57 | .nice(); 58 | const xAxes = d3 59 | .axisBottom(xScale) 60 | .ticks(5) 61 | 62 | svg.append('g') 63 | .attr('transform', `translate(0, ${height})`) // set to bottom 64 | .call(xAxes) 65 | 66 | const rScale = d3.scaleSqrt() 67 | .domain([0, d3.max(data, (d: any) => +d.population)]) 68 | .range([0, 40]); 69 | 70 | // svg.selectAll("circle") 71 | // .data(data) 72 | // .enter() 73 | // .append('circle') 74 | // .attr('cx', d => xScale(d.cost)) 75 | // .attr('cy', d => yScale(d.expectancy)) 76 | // .attr('r', d => rScale(d.population)) 77 | // .style('fill-opacity', 0.5) 78 | // .style('fill', 'steelblue') 79 | 80 | // -->G: make all the circle containors within graphic containors to separate 81 | const circles = svg.selectAll('.ball') 82 | .data(data) 83 | .enter() 84 | .append('g') 85 | .attr('class', 'ball') 86 | .attr('transform', (d: any) => { 87 | return `translate(${xScale(d.cost)}, ${yScale(d.expectancy)})` 88 | }); 89 | 90 | circles 91 | .append('circle') 92 | .attr('cx', 0) 93 | .attr('cy', 0) 94 | .attr('r', (d: any) => rScale(d.population)) 95 | .style('fill-opacity', 0.5) 96 | .style('fill', 'steelblue') 97 | 98 | circles 99 | .append('text') 100 | .style('text-anchor', 'middle') 101 | .style('fill', 'black') 102 | .attr('y', 4) 103 | .text((d: any) => d.code) 104 | }) 105 | 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/app/general-update-pattern/general-update-pattern.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-general-update-pattern', 6 | templateUrl: './general-update-pattern.component.html', 7 | styleUrls: ['./general-update-pattern.component.css'] 8 | }) 9 | export class GeneralUpdatePatternComponent implements OnInit { 10 | public svg; 11 | public data; 12 | public opts: any = {}; 13 | public xScale; 14 | public yScale; 15 | constructor() { } 16 | 17 | ngOnInit() { 18 | this.data = [ 19 | { name: 'Alice', math: 37, science: 62, language: 54 }, 20 | { name: 'Billy', math: null, science: 34, language: 85 }, 21 | { name: 'Cindy', math: 86, science: 48, language: null }, 22 | { name: 'David', math: 44, science: null, language: 65 }, 23 | { name: 'Emily', math: 59, science: 73, language: 29 } 24 | ]; 25 | this.opts = { margin: { top: 10, right: 10, bottom: 30, left: 30 } } 26 | this.opts.width = 400 - this.opts.margin.left - this.opts.margin.right, 27 | this.opts.height = 535 - this.opts.margin.top - this.opts.margin.bottom; 28 | 29 | function responsify(svg) { 30 | const container = d3.select(svg.node().parentNode), 31 | width = parseInt(svg.style('width'), 10), 32 | height = parseInt(svg.style('height'), 10), 33 | aspect = width / height; 34 | 35 | svg.attr('viewBox', '0 0 ' + width + ' ' + height) 36 | .attr('preserveAspectRatio', 'xMinYMid') 37 | .call(resize); 38 | 39 | d3.select(window).on('resize.' + container.attr('id'), resize); 40 | 41 | function resize() { 42 | const targetWidth = parseInt(container.style('width'), 10); 43 | svg.attr('width', targetWidth); 44 | svg.attr('height', Math.round(targetWidth / aspect)); 45 | } 46 | } 47 | 48 | this.svg = d3.select('.chart') 49 | .append('svg') 50 | .attr('width', this.opts.width + this.opts.margin.left + this.opts.margin.right) 51 | .attr('height', this.opts.height + this.opts.margin.top + this.opts.margin.bottom) 52 | .call(responsify) 53 | .append('g') 54 | .attr('transform', `translate(${this.opts.margin.left}, ${this.opts.margin.top})`); 55 | 56 | this.xScale = d3.scaleBand() 57 | .domain(this.data.map(d => d.name)) 58 | .range([0, this.opts.width]) 59 | .padding(0.2); 60 | this.svg 61 | .append('g') 62 | .attr('transform', `translate(0, ${this.opts.height})`) 63 | .call(d3.axisBottom(this.xScale)); 64 | 65 | this.yScale = d3.scaleLinear() 66 | .domain([0, 100]) 67 | .range([this.opts.height, 0]); 68 | this.svg 69 | .append('g') 70 | .call(d3.axisLeft(this.yScale)); 71 | 72 | // ****************************************************** 73 | 74 | } 75 | 76 | render(subject = 'math'): void { 77 | const t = d3.transition(null).duration(1000); 78 | 79 | const update = this.svg.selectAll('rect') 80 | .data(this.data.filter(d => d[subject]), d => d.name); 81 | 82 | update 83 | .exit() 84 | .transition(t) 85 | .attr('y', this.opts.height) 86 | .attr('height', 0) 87 | .remove(); 88 | 89 | update 90 | .transition(t) 91 | .delay(1000) 92 | .attr('y', d => this.yScale(d[subject])) 93 | .attr('height', d => this.opts.height - this.yScale(d[subject])) 94 | 95 | const enter = update 96 | .enter() 97 | .append('rect') 98 | .attr('y', this.opts.height) 99 | .attr('height', 0) 100 | .attr('x', d => this.xScale(d.name)) 101 | .attr('width', d => this.xScale.bandwidth()) 102 | .transition(t) 103 | .delay(2000) 104 | .attr('y', d => this.yScale(d[subject])) 105 | .attr('height', d => this.opts.height - this.yScale(d[subject])) 106 | } 107 | 108 | } 109 | -------------------------------------------------------------------------------- /src/app/visualization/visualization.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-visualization', 6 | templateUrl: './visualization.component.html', 7 | styleUrls: ['./visualization.component.css'] 8 | }) 9 | export class VisualizationComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | const scores: Array = [ 15 | { name: 'Alice', score: 96 }, 16 | { name: 'Billy', score: 88 }, 17 | { name: 'Cindy', score: 21 }, 18 | { name: 'Emily', score: 91 }, 19 | { name: 'David', score: 33 }, 20 | { name: 'Trump', score: 65 }, 21 | ]; 22 | // ************************* 23 | // USING CSS 24 | // ************************* 25 | 26 | // // -->Match: DOM elements with data and correlate 27 | // let update = d3.select('.chart').selectAll('div').data(scores, (d) => d ? d.name : this.innerText).style('color','blue'); 28 | // // -->Update: this method handles the matching process 29 | // let enter = update.enter().append('div').text((d) => d.name).style('color','green') 30 | // // -->Exist: this method handles the exit stage of matching 31 | // let exit = update.exit().remove(); 32 | // 33 | // // -->Merge: 2 selections 34 | // update.merge(enter) 35 | // .style('width', (d) => d.score+'px') 36 | // .style('height','50px') 37 | // .style('background','black') 38 | 39 | // ************************* 40 | // USING SVG 41 | // ************************* 42 | // -->Do: all in a single step (same thing) 43 | const bar = d3.select('.chart') 44 | .append('svg') 45 | .attr('width', 225) 46 | .attr('height', 300) 47 | .selectAll('g') 48 | .data(scores) 49 | .enter() 50 | .append('g') 51 | .attr('transform', (d, i) => 'translate(0, ' + i * 33 + ')') 52 | 53 | function scaleBar(selection, scale) { 54 | selection.style('transform', 'scaleX(' + scale + ')'); 55 | } 56 | function setFill(selection, color) { 57 | selection.style('fill', color) 58 | } 59 | function fade(selection, opacity) { 60 | selection.style('fill-opacity', 0.5) 61 | } 62 | 63 | bar.append('rect') 64 | .style('width', (d) => d.score) 65 | .style('height', 30) 66 | .style('fill', 'lightgreen') 67 | .attr('class', 'bar') 68 | // -->Simple: class attribution 69 | // .on('mouseover', function(){ 70 | // d3.select(this).classed("barOn",true) 71 | // }) 72 | // .on('mouseout', function(){ 73 | // d3.select(this).classed("barOn",false) 74 | // }) 75 | // -->Simple: sexy scale and hover 76 | // .on('mouseover', function(d,i,elements){ 77 | // d3.select(this).style('transform','scaleX(2)') 78 | // d3.selectAll(elements) 79 | // .filter(':not(:hover)') 80 | // .style('fill-opacity', 0.5) 81 | // }) 82 | // .on('mouseout', function(d,i, elements){ 83 | // d3.select(this).style('transform','scaleX(1)') 84 | // d3.selectAll(elements) 85 | // .style('fill-opacity', 1) 86 | // }) 87 | // -->Code: better code structure 88 | .on('mouseover', function (d, i, elements: any) { 89 | d3.select(this).call(scaleBar, 2).call(setFill, 'teal') 90 | d3.selectAll(elements) 91 | .filter(':not(:hover)') 92 | .call(fade, 0.5) 93 | }) 94 | .on('mouseout', function (d, i, elements: any) { 95 | d3.select(this).call(scaleBar, 1).call(setFill, 'lightgreen') 96 | d3.selectAll(elements) 97 | .filter(':not(:hover)') 98 | .call(fade, 1) 99 | }) 100 | 101 | bar.append('text') 102 | .attr('y', 20) 103 | .text((d) => d.name) 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/app/axes/axes.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | import * as d3 from 'd3'; 3 | 4 | @Component({ 5 | selector: 'app-axes', 6 | templateUrl: './axes.component.html', 7 | styleUrls: ['./axes.component.css'] 8 | }) 9 | export class AxesComponent implements OnInit { 10 | 11 | constructor() { } 12 | 13 | ngOnInit() { 14 | let data = [ 15 | {score: 63, subject: "Math"}, 16 | {score: 33, subject: "Geography"}, 17 | {score: 91, subject: "Spelling"}, 18 | {score: 21, subject: "Reading"}, 19 | {score: 12, subject: "Science"}, 20 | {score: 48, subject: "Doing"}, 21 | {score: 88, subject: "Thinking"}, 22 | {score: 92, subject: "Waling"}, 23 | ] 24 | 25 | let margin = { top: 10, right: 20, left: 40, bottom: 50} 26 | let width = 425 - margin.left - margin.right; 27 | let height = 625 - margin.top - margin.bottom; 28 | 29 | let fullWidth = width + margin.left + margin.right; 30 | let fullHeight = height + margin.top + margin.bottom; 31 | 32 | 33 | function responsify(svg) { 34 | let container = d3.select(svg.node().parentNode), 35 | width = parseInt(svg.style("width")), 36 | height = parseInt(svg.style("height")), 37 | aspect = width / height; 38 | 39 | svg.attr("viewBox", "0 0 " + width + " " + height) 40 | .attr("preserveAspectRatio","xMinYMid") 41 | .call(resize); 42 | 43 | d3.select(window).on("resize." + container.attr("id"), resize); 44 | 45 | function resize() { 46 | let targetWidth = parseInt(container.style("width")); 47 | svg.attr("width", targetWidth); 48 | svg.attr("height", Math.round(targetWidth / aspect)); 49 | } 50 | } 51 | 52 | 53 | let svg = d3.select('.chart') 54 | .append('svg') 55 | .attr('width', width + margin.left + margin.right) 56 | .attr('height', height + margin.top + margin.bottom) 57 | .call(responsify) 58 | // .attr('viewBox', `0 0 ${fullWidth * 2} ${fullHeight * 2}`) // automatic responsive svg 59 | .append('g') 60 | .attr('transform', `translate(${margin.left}, ${margin.top})`) 61 | 62 | 63 | // svg.append('rect') 64 | // .attr('width', width) 65 | // // .attr('width', width/2) 66 | // .attr('height', height) 67 | // .style('fill', 'lightblue') 68 | // .style('stroke','green') 69 | // 70 | // svg.append('rect') 71 | // .attr('x', width /2 ) 72 | // .attr('width', width /2 ) 73 | // .attr('height', height) 74 | // .style('fill', 'lightblue') 75 | // .style('stroke','green') 76 | 77 | // -->Generate: scales [from,to] where you want 78 | let yScale = d3.scaleLinear() 79 | .domain([0,100]) 80 | .range([height, 0]); 81 | let yAxes = d3.axisLeft(yScale) 82 | //.ticks(5) 83 | //.tickValues([8,19,25,77,100]) 84 | svg.call(yAxes); 85 | 86 | // -->Generate: time scale for X 87 | // let xScale = d3.scaleTime() 88 | // .domain([new Date(2016,0,1,6), new Date(2016,0,1,9)]).range([0, width]) 89 | 90 | // -->ScaleBand: specially used for bar charts 91 | let xScale = d3.scaleBand() 92 | // .paddingInner(0.2) 93 | // .paddingOuter(0.5) 94 | .padding(0.2) 95 | // .align(0) 96 | .domain(data.map(d => d.subject)).range([0, width]) 97 | 98 | 99 | 100 | let xAxis = d3.axisBottom(xScale) 101 | .ticks(5).tickSize(10).tickPadding(15) 102 | //.ticks(d3.timeMinute.every(45)) 103 | 104 | svg 105 | .append('g') 106 | .attr('transform',`translate(0, ${height})`) 107 | .call(xAxis) 108 | .selectAll('text') 109 | .style('text-anchor','end') 110 | .style('transform', 'rotate(-45deg)') 111 | 112 | 113 | // ****************************************************** 114 | svg.selectAll('rect') 115 | .data(data) 116 | .enter() 117 | .append('rect') 118 | .attr('x', d => xScale(d.subject)) 119 | .attr('y', d => yScale(d.score)) 120 | .attr('width', xScale.bandwidth()) 121 | .attr('height', d => height - yScale(d.score)) 122 | .style("fill","steelblue") 123 | 124 | } 125 | 126 | } 127 | -------------------------------------------------------------------------------- /src/demo_data/stocks.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "ticker": "AMZN", 4 | "values": [ 5 | { 6 | "date": "2016/09/30", 7 | "close": 837.31 8 | }, 9 | { 10 | "date": "2016/09/29", 11 | "close": 829.05 12 | }, 13 | { 14 | "date": "2016/09/28", 15 | "close": 828.72 16 | }, 17 | { 18 | "date": "2016/09/27", 19 | "close": 816.11 20 | }, 21 | { 22 | "date": "2016/09/26", 23 | "close": 799.16 24 | }, 25 | { 26 | "date": "2016/09/23", 27 | "close": 805.75 28 | }, 29 | { 30 | "date": "2016/09/22", 31 | "close": 804.7 32 | }, 33 | { 34 | "date": "2016/09/21", 35 | "close": 789.74 36 | }, 37 | { 38 | "date": "2016/09/20", 39 | "close": 780.22 40 | }, 41 | { 42 | "date": "2016/09/19", 43 | "close": 775.1 44 | }, 45 | { 46 | "date": "2016/09/16", 47 | "close": 778.52 48 | }, 49 | { 50 | "date": "2016/09/15", 51 | "close": 769.69 52 | }, 53 | { 54 | "date": "2016/09/14", 55 | "close": 761.09 56 | }, 57 | { 58 | "date": "2016/09/13", 59 | "close": 761.01 60 | }, 61 | { 62 | "date": "2016/09/12", 63 | "close": 771.49 64 | }, 65 | { 66 | "date": "2016/09/09", 67 | "close": 760.14 68 | }, 69 | { 70 | "date": "2016/09/08", 71 | "close": 784.06 72 | }, 73 | { 74 | "date": "2016/09/07", 75 | "close": 784.48 76 | }, 77 | { 78 | "date": "2016/09/06", 79 | "close": 788.87 80 | }, 81 | { 82 | "date": "2016/09/02", 83 | "close": 772.44 84 | }, 85 | { 86 | "date": "2016/09/01", 87 | "close": 770.62 88 | }, 89 | { 90 | "date": "2016/08/31", 91 | "close": 769.16 92 | }, 93 | { 94 | "date": "2016/08/30", 95 | "close": 767.58 96 | }, 97 | { 98 | "date": "2016/08/29", 99 | "close": 771.29 100 | }, 101 | { 102 | "date": "2016/08/26", 103 | "close": 769 104 | }, 105 | { 106 | "date": "2016/08/25", 107 | "close": 759.22 108 | }, 109 | { 110 | "date": "2016/08/24", 111 | "close": 757.25 112 | }, 113 | { 114 | "date": "2016/08/23", 115 | "close": 762.45 116 | }, 117 | { 118 | "date": "2016/08/22", 119 | "close": 759.48 120 | }, 121 | { 122 | "date": "2016/08/19", 123 | "close": 757.31 124 | }, 125 | { 126 | "date": "2016/08/18", 127 | "close": 764.46 128 | }, 129 | { 130 | "date": "2016/08/17", 131 | "close": 764.63 132 | }, 133 | { 134 | "date": "2016/08/16", 135 | "close": 764.04 136 | }, 137 | { 138 | "date": "2016/08/15", 139 | "close": 768.49 140 | }, 141 | { 142 | "date": "2016/08/12", 143 | "close": 772.56 144 | }, 145 | { 146 | "date": "2016/08/11", 147 | "close": 771.24 148 | }, 149 | { 150 | "date": "2016/08/10", 151 | "close": 768.56 152 | }, 153 | { 154 | "date": "2016/08/09", 155 | "close": 768.31 156 | }, 157 | { 158 | "date": "2016/08/08", 159 | "close": 766.56 160 | }, 161 | { 162 | "date": "2016/08/05", 163 | "close": 765.98 164 | }, 165 | { 166 | "date": "2016/08/04", 167 | "close": 760.77 168 | }, 169 | { 170 | "date": "2016/08/03", 171 | "close": 754.64 172 | }, 173 | { 174 | "date": "2016/08/02", 175 | "close": 760.58 176 | }, 177 | { 178 | "date": "2016/08/01", 179 | "close": 767.74 180 | }, 181 | { 182 | "date": "2016/07/29", 183 | "close": 758.81 184 | }, 185 | { 186 | "date": "2016/07/28", 187 | "close": 752.61 188 | }, 189 | { 190 | "date": "2016/07/27", 191 | "close": 736.67 192 | }, 193 | { 194 | "date": "2016/07/26", 195 | "close": 735.59 196 | }, 197 | { 198 | "date": "2016/07/25", 199 | "close": 739.61 200 | }, 201 | { 202 | "date": "2016/07/22", 203 | "close": 744.86 204 | }, 205 | { 206 | "date": "2016/07/21", 207 | "close": 744.43 208 | }, 209 | { 210 | "date": "2016/07/20", 211 | "close": 745.72 212 | }, 213 | { 214 | "date": "2016/07/19", 215 | "close": 739.95 216 | }, 217 | { 218 | "date": "2016/07/18", 219 | "close": 736.07 220 | }, 221 | { 222 | "date": "2016/07/15", 223 | "close": 735.44 224 | }, 225 | { 226 | "date": "2016/07/14", 227 | "close": 741.2 228 | }, 229 | { 230 | "date": "2016/07/13", 231 | "close": 742.63 232 | }, 233 | { 234 | "date": "2016/07/12", 235 | "close": 748.21 236 | }, 237 | { 238 | "date": "2016/07/11", 239 | "close": 753.78 240 | }, 241 | { 242 | "date": "2016/07/08", 243 | "close": 745.81 244 | }, 245 | { 246 | "date": "2016/07/07", 247 | "close": 736.57 248 | }, 249 | { 250 | "date": "2016/07/06", 251 | "close": 737.61 252 | }, 253 | { 254 | "date": "2016/07/05", 255 | "close": 728.1 256 | }, 257 | { 258 | "date": "2016/07/01", 259 | "close": 725.68 260 | } 261 | ] 262 | }, 263 | { 264 | "ticker": "GOOG", 265 | "values": [ 266 | { 267 | "date": "2016/09/30", 268 | "close": 777.29 269 | }, 270 | { 271 | "date": "2016/09/29", 272 | "close": 775.01 273 | }, 274 | { 275 | "date": "2016/09/28", 276 | "close": 781.56 277 | }, 278 | { 279 | "date": "2016/09/27", 280 | "close": 783.01 281 | }, 282 | { 283 | "date": "2016/09/26", 284 | "close": 774.21 285 | }, 286 | { 287 | "date": "2016/09/23", 288 | "close": 786.9 289 | }, 290 | { 291 | "date": "2016/09/22", 292 | "close": 787.21 293 | }, 294 | { 295 | "date": "2016/09/21", 296 | "close": 776.22 297 | }, 298 | { 299 | "date": "2016/09/20", 300 | "close": 771.41 301 | }, 302 | { 303 | "date": "2016/09/19", 304 | "close": 765.7 305 | }, 306 | { 307 | "date": "2016/09/16", 308 | "close": 768.88 309 | }, 310 | { 311 | "date": "2016/09/15", 312 | "close": 771.76 313 | }, 314 | { 315 | "date": "2016/09/14", 316 | "close": 762.49 317 | }, 318 | { 319 | "date": "2016/09/13", 320 | "close": 759.69 321 | }, 322 | { 323 | "date": "2016/09/12", 324 | "close": 769.02 325 | }, 326 | { 327 | "date": "2016/09/09", 328 | "close": 759.66 329 | }, 330 | { 331 | "date": "2016/09/08", 332 | "close": 775.32 333 | }, 334 | { 335 | "date": "2016/09/07", 336 | "close": 780.35 337 | }, 338 | { 339 | "date": "2016/09/06", 340 | "close": 780.08 341 | }, 342 | { 343 | "date": "2016/09/02", 344 | "close": 771.46 345 | }, 346 | { 347 | "date": "2016/09/01", 348 | "close": 768.78 349 | }, 350 | { 351 | "date": "2016/08/31", 352 | "close": 767.05 353 | }, 354 | { 355 | "date": "2016/08/30", 356 | "close": 769.09 357 | }, 358 | { 359 | "date": "2016/08/29", 360 | "close": 772.15 361 | }, 362 | { 363 | "date": "2016/08/26", 364 | "close": 769.54 365 | }, 366 | { 367 | "date": "2016/08/25", 368 | "close": 769.41 369 | }, 370 | { 371 | "date": "2016/08/24", 372 | "close": 769.64 373 | }, 374 | { 375 | "date": "2016/08/23", 376 | "close": 772.08 377 | }, 378 | { 379 | "date": "2016/08/22", 380 | "close": 772.15 381 | }, 382 | { 383 | "date": "2016/08/19", 384 | "close": 775.42 385 | }, 386 | { 387 | "date": "2016/08/18", 388 | "close": 777.5 389 | }, 390 | { 391 | "date": "2016/08/17", 392 | "close": 779.91 393 | }, 394 | { 395 | "date": "2016/08/16", 396 | "close": 777.14 397 | }, 398 | { 399 | "date": "2016/08/15", 400 | "close": 782.44 401 | }, 402 | { 403 | "date": "2016/08/12", 404 | "close": 783.22 405 | }, 406 | { 407 | "date": "2016/08/11", 408 | "close": 784.85 409 | }, 410 | { 411 | "date": "2016/08/10", 412 | "close": 784.68 413 | }, 414 | { 415 | "date": "2016/08/09", 416 | "close": 784.26 417 | }, 418 | { 419 | "date": "2016/08/08", 420 | "close": 781.76 421 | }, 422 | { 423 | "date": "2016/08/05", 424 | "close": 782.22 425 | }, 426 | { 427 | "date": "2016/08/04", 428 | "close": 771.61 429 | }, 430 | { 431 | "date": "2016/08/03", 432 | "close": 773.18 433 | }, 434 | { 435 | "date": "2016/08/02", 436 | "close": 771.07 437 | }, 438 | { 439 | "date": "2016/08/01", 440 | "close": 772.88 441 | }, 442 | { 443 | "date": "2016/07/29", 444 | "close": 768.79 445 | }, 446 | { 447 | "date": "2016/07/28", 448 | "close": 745.91 449 | }, 450 | { 451 | "date": "2016/07/27", 452 | "close": 741.77 453 | }, 454 | { 455 | "date": "2016/07/26", 456 | "close": 738.42 457 | }, 458 | { 459 | "date": "2016/07/25", 460 | "close": 739.77 461 | }, 462 | { 463 | "date": "2016/07/22", 464 | "close": 742.74 465 | }, 466 | { 467 | "date": "2016/07/21", 468 | "close": 738.63 469 | }, 470 | { 471 | "date": "2016/07/20", 472 | "close": 741.19 473 | }, 474 | { 475 | "date": "2016/07/19", 476 | "close": 736.96 477 | }, 478 | { 479 | "date": "2016/07/18", 480 | "close": 733.78 481 | }, 482 | { 483 | "date": "2016/07/15", 484 | "close": 719.85 485 | }, 486 | { 487 | "date": "2016/07/14", 488 | "close": 720.95 489 | }, 490 | { 491 | "date": "2016/07/13", 492 | "close": 716.98 493 | }, 494 | { 495 | "date": "2016/07/12", 496 | "close": 720.64 497 | }, 498 | { 499 | "date": "2016/07/11", 500 | "close": 715.09 501 | }, 502 | { 503 | "date": "2016/07/08", 504 | "close": 705.63 505 | }, 506 | { 507 | "date": "2016/07/07", 508 | "close": 695.36 509 | }, 510 | { 511 | "date": "2016/07/06", 512 | "close": 697.77 513 | }, 514 | { 515 | "date": "2016/07/05", 516 | "close": 694.49 517 | }, 518 | { 519 | "date": "2016/07/01", 520 | "close": 699.21 521 | } 522 | ] 523 | } 524 | ] 525 | -------------------------------------------------------------------------------- /src/assets/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v4.0.0-alpha.5 (https://getbootstrap.com) 3 | * Copyright 2011-2016 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors) 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}(jQuery),+function(){function a(a,b){if(!a)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!b||"object"!=typeof b&&"function"!=typeof b?a:b}function b(a,b){if("function"!=typeof b&&null!==b)throw new TypeError("Super expression must either be null or a function, not "+typeof b);a.prototype=Object.create(b&&b.prototype,{constructor:{value:a,enumerable:!1,writable:!0,configurable:!0}}),b&&(Object.setPrototypeOf?Object.setPrototypeOf(a,b):a.__proto__=b)}function c(a,b){if(!(a instanceof b))throw new TypeError("Cannot call a class as a function")}var d="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(a){return typeof a}:function(a){return a&&"function"==typeof Symbol&&a.constructor===Symbol&&a!==Symbol.prototype?"symbol":typeof a},e=function(){function a(a,b){for(var c=0;cthis._items.length-1||b<0)){if(this._isSliding)return void a(this._element).one(r.SLID,function(){return c.to(b)});if(d===b)return this.pause(),void this.cycle();var e=b>d?q.NEXT:q.PREVIOUS;this._slide(e,this._items[b])}},j.prototype.dispose=function(){a(this._element).off(i),a.removeData(this._element,h),this._items=null,this._config=null,this._element=null,this._interval=null,this._isPaused=null,this._isSliding=null,this._activeElement=null,this._indicatorsElement=null},j.prototype._getConfig=function(c){return c=a.extend({},o,c),f.typeCheckConfig(b,c,p),c},j.prototype._addEventListeners=function(){this._config.keyboard&&a(this._element).on(r.KEYDOWN,a.proxy(this._keydown,this)),"hover"!==this._config.pause||"ontouchstart"in document.documentElement||a(this._element).on(r.MOUSEENTER,a.proxy(this.pause,this)).on(r.MOUSELEAVE,a.proxy(this.cycle,this))},j.prototype._keydown=function(a){if(a.preventDefault(),!/input|textarea/i.test(a.target.tagName))switch(a.which){case m:this.prev();break;case n:this.next();break;default:return}},j.prototype._getItemIndex=function(b){return this._items=a.makeArray(a(b).parent().find(t.ITEM)),this._items.indexOf(b)},j.prototype._getItemByDirection=function(a,b){var c=a===q.NEXT,d=a===q.PREVIOUS,e=this._getItemIndex(b),f=this._items.length-1,g=d&&0===e||c&&e===f;if(g&&!this._config.wrap)return b;var h=a===q.PREVIOUS?-1:1,i=(e+h)%this._items.length;return i===-1?this._items[this._items.length-1]:this._items[i]},j.prototype._triggerSlideEvent=function(b,c){var d=a.Event(r.SLIDE,{relatedTarget:b,direction:c});return a(this._element).trigger(d),d},j.prototype._setActiveIndicatorElement=function(b){if(this._indicatorsElement){a(this._indicatorsElement).find(t.ACTIVE).removeClass(s.ACTIVE);var c=this._indicatorsElement.children[this._getItemIndex(b)];c&&a(c).addClass(s.ACTIVE)}},j.prototype._slide=function(b,c){var d=this,e=a(this._element).find(t.ACTIVE_ITEM)[0],g=c||e&&this._getItemByDirection(b,e),h=Boolean(this._interval),i=b===q.NEXT?s.LEFT:s.RIGHT;if(g&&a(g).hasClass(s.ACTIVE))return void(this._isSliding=!1);var j=this._triggerSlideEvent(g,i);if(!j.isDefaultPrevented()&&e&&g){this._isSliding=!0,h&&this.pause(),this._setActiveIndicatorElement(g);var k=a.Event(r.SLID,{relatedTarget:g,direction:i});f.supportsTransitionEnd()&&a(this._element).hasClass(s.SLIDE)?(a(g).addClass(b),f.reflow(g),a(e).addClass(i),a(g).addClass(i),a(e).one(f.TRANSITION_END,function(){a(g).removeClass(i).removeClass(b),a(g).addClass(s.ACTIVE),a(e).removeClass(s.ACTIVE).removeClass(b).removeClass(i),d._isSliding=!1,setTimeout(function(){return a(d._element).trigger(k)},0)}).emulateTransitionEnd(l)):(a(e).removeClass(s.ACTIVE),a(g).addClass(s.ACTIVE),this._isSliding=!1,a(this._element).trigger(k)),h&&this.cycle()}},j._jQueryInterface=function(b){return this.each(function(){var c=a(this).data(h),e=a.extend({},o,a(this).data());"object"===("undefined"==typeof b?"undefined":d(b))&&a.extend(e,b);var f="string"==typeof b?b:e.slide;if(c||(c=new j(this,e),a(this).data(h,c)),"number"==typeof b)c.to(b);else if("string"==typeof f){if(void 0===c[f])throw new Error('No method named "'+f+'"');c[f]()}else e.interval&&(c.pause(),c.cycle())})},j._dataApiClickHandler=function(b){var c=f.getSelectorFromElement(this);if(c){var d=a(c)[0];if(d&&a(d).hasClass(s.CAROUSEL)){var e=a.extend({},a(d).data(),a(this).data()),g=this.getAttribute("data-slide-to");g&&(e.interval=!1),j._jQueryInterface.call(a(d),e),g&&a(d).data(h).to(g),b.preventDefault()}}},e(j,null,[{key:"VERSION",get:function(){return g}},{key:"Default",get:function(){return o}}]),j}();return a(document).on(r.CLICK_DATA_API,t.DATA_SLIDE,u._dataApiClickHandler),a(window).on(r.LOAD_DATA_API,function(){a(t.DATA_RIDE).each(function(){var b=a(this);u._jQueryInterface.call(b,b.data())})}),a.fn[b]=u._jQueryInterface,a.fn[b].Constructor=u,a.fn[b].noConflict=function(){return a.fn[b]=k,u._jQueryInterface},u}(jQuery),function(a){var b="collapse",g="4.0.0-alpha.5",h="bs.collapse",i="."+h,j=".data-api",k=a.fn[b],l=600,m={toggle:!0,parent:""},n={toggle:"boolean",parent:"string"},o={SHOW:"show"+i,SHOWN:"shown"+i,HIDE:"hide"+i,HIDDEN:"hidden"+i,CLICK_DATA_API:"click"+i+j},p={IN:"in",COLLAPSE:"collapse",COLLAPSING:"collapsing",COLLAPSED:"collapsed"},q={WIDTH:"width",HEIGHT:"height"},r={ACTIVES:".card > .in, .card > .collapsing",DATA_TOGGLE:'[data-toggle="collapse"]'},s=function(){function i(b,d){c(this,i),this._isTransitioning=!1,this._element=b,this._config=this._getConfig(d),this._triggerArray=a.makeArray(a('[data-toggle="collapse"][href="#'+b.id+'"],'+('[data-toggle="collapse"][data-target="#'+b.id+'"]'))),this._parent=this._config.parent?this._getParent():null,this._config.parent||this._addAriaAndCollapsedClass(this._element,this._triggerArray),this._config.toggle&&this.toggle()}return i.prototype.toggle=function(){a(this._element).hasClass(p.IN)?this.hide():this.show()},i.prototype.show=function(){var b=this;if(!this._isTransitioning&&!a(this._element).hasClass(p.IN)){var c=void 0,d=void 0;if(this._parent&&(c=a.makeArray(a(r.ACTIVES)),c.length||(c=null)),!(c&&(d=a(c).data(h),d&&d._isTransitioning))){var e=a.Event(o.SHOW);if(a(this._element).trigger(e),!e.isDefaultPrevented()){c&&(i._jQueryInterface.call(a(c),"hide"),d||a(c).data(h,null));var g=this._getDimension();a(this._element).removeClass(p.COLLAPSE).addClass(p.COLLAPSING),this._element.style[g]=0,this._element.setAttribute("aria-expanded",!0),this._triggerArray.length&&a(this._triggerArray).removeClass(p.COLLAPSED).attr("aria-expanded",!0),this.setTransitioning(!0);var j=function(){a(b._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).addClass(p.IN),b._element.style[g]="",b.setTransitioning(!1),a(b._element).trigger(o.SHOWN)};if(!f.supportsTransitionEnd())return void j();var k=g[0].toUpperCase()+g.slice(1),m="scroll"+k;a(this._element).one(f.TRANSITION_END,j).emulateTransitionEnd(l),this._element.style[g]=this._element[m]+"px"}}}},i.prototype.hide=function(){var b=this;if(!this._isTransitioning&&a(this._element).hasClass(p.IN)){var c=a.Event(o.HIDE);if(a(this._element).trigger(c),!c.isDefaultPrevented()){var d=this._getDimension(),e=d===q.WIDTH?"offsetWidth":"offsetHeight";this._element.style[d]=this._element[e]+"px",f.reflow(this._element),a(this._element).addClass(p.COLLAPSING).removeClass(p.COLLAPSE).removeClass(p.IN),this._element.setAttribute("aria-expanded",!1),this._triggerArray.length&&a(this._triggerArray).addClass(p.COLLAPSED).attr("aria-expanded",!1),this.setTransitioning(!0);var g=function(){b.setTransitioning(!1),a(b._element).removeClass(p.COLLAPSING).addClass(p.COLLAPSE).trigger(o.HIDDEN)};return this._element.style[d]="",f.supportsTransitionEnd()?void a(this._element).one(f.TRANSITION_END,g).emulateTransitionEnd(l):void g()}}},i.prototype.setTransitioning=function(a){this._isTransitioning=a},i.prototype.dispose=function(){a.removeData(this._element,h),this._config=null,this._parent=null,this._element=null,this._triggerArray=null,this._isTransitioning=null},i.prototype._getConfig=function(c){return c=a.extend({},m,c),c.toggle=Boolean(c.toggle),f.typeCheckConfig(b,c,n),c},i.prototype._getDimension=function(){var b=a(this._element).hasClass(q.WIDTH);return b?q.WIDTH:q.HEIGHT},i.prototype._getParent=function(){var b=this,c=a(this._config.parent)[0],d='[data-toggle="collapse"][data-parent="'+this._config.parent+'"]';return a(c).find(d).each(function(a,c){b._addAriaAndCollapsedClass(i._getTargetFromElement(c),[c])}),c},i.prototype._addAriaAndCollapsedClass=function(b,c){if(b){var d=a(b).hasClass(p.IN);b.setAttribute("aria-expanded",d),c.length&&a(c).toggleClass(p.COLLAPSED,!d).attr("aria-expanded",d)}},i._getTargetFromElement=function(b){var c=f.getSelectorFromElement(b);return c?a(c)[0]:null},i._jQueryInterface=function(b){return this.each(function(){var c=a(this),e=c.data(h),f=a.extend({},m,c.data(),"object"===("undefined"==typeof b?"undefined":d(b))&&b);if(!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||(e=new i(this,f),c.data(h,e)),"string"==typeof b){if(void 0===e[b])throw new Error('No method named "'+b+'"');e[b]()}})},e(i,null,[{key:"VERSION",get:function(){return g}},{key:"Default",get:function(){return m}}]),i}();return a(document).on(o.CLICK_DATA_API,r.DATA_TOGGLE,function(b){b.preventDefault();var c=s._getTargetFromElement(this),d=a(c).data(h),e=d?"toggle":a(this).data();s._jQueryInterface.call(a(c),e)}),a.fn[b]=s._jQueryInterface,a.fn[b].Constructor=s,a.fn[b].noConflict=function(){return a.fn[b]=k,s._jQueryInterface},s}(jQuery),function(a){var b="dropdown",d="4.0.0-alpha.5",g="bs.dropdown",h="."+g,i=".data-api",j=a.fn[b],k=27,l=38,m=40,n=3,o={HIDE:"hide"+h,HIDDEN:"hidden"+h,SHOW:"show"+h,SHOWN:"shown"+h,CLICK:"click"+h,CLICK_DATA_API:"click"+h+i,KEYDOWN_DATA_API:"keydown"+h+i},p={BACKDROP:"dropdown-backdrop",DISABLED:"disabled",OPEN:"open"},q={BACKDROP:".dropdown-backdrop",DATA_TOGGLE:'[data-toggle="dropdown"]',FORM_CHILD:".dropdown form",ROLE_MENU:'[role="menu"]',ROLE_LISTBOX:'[role="listbox"]',NAVBAR_NAV:".navbar-nav",VISIBLE_ITEMS:'[role="menu"] li:not(.disabled) a, [role="listbox"] li:not(.disabled) a'},r=function(){function b(a){c(this,b),this._element=a,this._addEventListeners()}return b.prototype.toggle=function(){if(this.disabled||a(this).hasClass(p.DISABLED))return!1;var c=b._getParentFromElement(this),d=a(c).hasClass(p.OPEN);if(b._clearMenus(),d)return!1;if("ontouchstart"in document.documentElement&&!a(c).closest(q.NAVBAR_NAV).length){var e=document.createElement("div");e.className=p.BACKDROP,a(e).insertBefore(this),a(e).on("click",b._clearMenus)}var f={relatedTarget:this},g=a.Event(o.SHOW,f);return a(c).trigger(g),!g.isDefaultPrevented()&&(this.focus(),this.setAttribute("aria-expanded","true"),a(c).toggleClass(p.OPEN),a(c).trigger(a.Event(o.SHOWN,f)),!1)},b.prototype.dispose=function(){a.removeData(this._element,g),a(this._element).off(h),this._element=null},b.prototype._addEventListeners=function(){a(this._element).on(o.CLICK,this.toggle)},b._jQueryInterface=function(c){return this.each(function(){var d=a(this).data(g);if(d||a(this).data(g,d=new b(this)),"string"==typeof c){if(void 0===d[c])throw new Error('No method named "'+c+'"');d[c].call(this)}})},b._clearMenus=function(c){if(!c||c.which!==n){var d=a(q.BACKDROP)[0];d&&d.parentNode.removeChild(d);for(var e=a.makeArray(a(q.DATA_TOGGLE)),f=0;f0&&h--,c.which===m&&hdocument.documentElement.clientHeight;!this._isBodyOverflowing&&a&&(this._element.style.paddingLeft=this._scrollbarWidth+"px"),this._isBodyOverflowing&&!a&&(this._element.style.paddingRight=this._scrollbarWidth+"px")},j.prototype._resetAdjustments=function(){this._element.style.paddingLeft="",this._element.style.paddingRight=""},j.prototype._checkScrollbar=function(){this._isBodyOverflowing=document.body.clientWidth=c){var d=this._targets[this._targets.length-1];this._activeTarget!==d&&this._activate(d)}if(this._activeTarget&&a=this._offsets[e]&&(void 0===this._offsets[e+1]||a .nav-item .fade, > .fade",ACTIVE:".active",ACTIVE_CHILD:"> .nav-item > .active, > .active",DATA_TOGGLE:'[data-toggle="tab"], [data-toggle="pill"]', 7 | DROPDOWN_TOGGLE:".dropdown-toggle",DROPDOWN_ACTIVE_CHILD:"> .dropdown-menu .active"},o=function(){function b(a){c(this,b),this._element=a}return b.prototype.show=function(){var b=this;if(!this._element.parentNode||this._element.parentNode.nodeType!==Node.ELEMENT_NODE||!a(this._element).hasClass(m.ACTIVE)){var c=void 0,d=void 0,e=a(this._element).closest(n.UL)[0],g=f.getSelectorFromElement(this._element);e&&(d=a.makeArray(a(e).find(n.ACTIVE)),d=d[d.length-1]);var h=a.Event(l.HIDE,{relatedTarget:this._element}),i=a.Event(l.SHOW,{relatedTarget:d});if(d&&a(d).trigger(h),a(this._element).trigger(i),!i.isDefaultPrevented()&&!h.isDefaultPrevented()){g&&(c=a(g)[0]),this._activate(this._element,e);var j=function(){var c=a.Event(l.HIDDEN,{relatedTarget:b._element}),e=a.Event(l.SHOWN,{relatedTarget:d});a(d).trigger(c),a(b._element).trigger(e)};c?this._activate(c,c.parentNode,j):j()}}},b.prototype.dispose=function(){a.removeClass(this._element,g),this._element=null},b.prototype._activate=function(b,c,d){var e=a(c).find(n.ACTIVE_CHILD)[0],g=d&&f.supportsTransitionEnd()&&(e&&a(e).hasClass(m.FADE)||Boolean(a(c).find(n.FADE_CHILD)[0])),h=a.proxy(this._transitionComplete,this,b,e,g,d);e&&g?a(e).one(f.TRANSITION_END,h).emulateTransitionEnd(k):h(),e&&a(e).removeClass(m.IN)},b.prototype._transitionComplete=function(b,c,d,e){if(c){a(c).removeClass(m.ACTIVE);var g=a(c).find(n.DROPDOWN_ACTIVE_CHILD)[0];g&&a(g).removeClass(m.ACTIVE),c.setAttribute("aria-expanded",!1)}if(a(b).addClass(m.ACTIVE),b.setAttribute("aria-expanded",!0),d?(f.reflow(b),a(b).addClass(m.IN)):a(b).removeClass(m.FADE),b.parentNode&&a(b.parentNode).hasClass(m.DROPDOWN_MENU)){var h=a(b).closest(n.DROPDOWN)[0];h&&a(h).find(n.DROPDOWN_TOGGLE).addClass(m.ACTIVE),b.setAttribute("aria-expanded",!0)}e&&e()},b._jQueryInterface=function(c){return this.each(function(){var d=a(this),e=d.data(g);if(e||(e=e=new b(this),d.data(g,e)),"string"==typeof c){if(void 0===e[c])throw new Error('No method named "'+c+'"');e[c]()}})},e(b,null,[{key:"VERSION",get:function(){return d}}]),b}();return a(document).on(l.CLICK_DATA_API,n.DATA_TOGGLE,function(b){b.preventDefault(),o._jQueryInterface.call(a(this),"show")}),a.fn[b]=o._jQueryInterface,a.fn[b].Constructor=o,a.fn[b].noConflict=function(){return a.fn[b]=j,o._jQueryInterface},o}(jQuery),function(a){if(void 0===window.Tether)throw new Error("Bootstrap tooltips require Tether (http://tether.io/)");var b="tooltip",g="4.0.0-alpha.5",h="bs.tooltip",i="."+h,j=a.fn[b],k=150,l="bs-tether",m={animation:!0,template:'',trigger:"hover focus",title:"",delay:0,html:!1,selector:!1,placement:"top",offset:"0 0",constraints:[]},n={animation:"boolean",template:"string",title:"(string|element|function)",trigger:"string",delay:"(number|object)",html:"boolean",selector:"(string|boolean)",placement:"(string|function)",offset:"string",constraints:"array"},o={TOP:"bottom center",RIGHT:"middle left",BOTTOM:"top center",LEFT:"middle right"},p={IN:"in",OUT:"out"},q={HIDE:"hide"+i,HIDDEN:"hidden"+i,SHOW:"show"+i,SHOWN:"shown"+i,INSERTED:"inserted"+i,CLICK:"click"+i,FOCUSIN:"focusin"+i,FOCUSOUT:"focusout"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i},r={FADE:"fade",IN:"in"},s={TOOLTIP:".tooltip",TOOLTIP_INNER:".tooltip-inner"},t={element:!1,enabled:!1},u={HOVER:"hover",FOCUS:"focus",CLICK:"click",MANUAL:"manual"},v=function(){function j(a,b){c(this,j),this._isEnabled=!0,this._timeout=0,this._hoverState="",this._activeTrigger={},this._tether=null,this.element=a,this.config=this._getConfig(b),this.tip=null,this._setListeners()}return j.prototype.enable=function(){this._isEnabled=!0},j.prototype.disable=function(){this._isEnabled=!1},j.prototype.toggleEnabled=function(){this._isEnabled=!this._isEnabled},j.prototype.toggle=function(b){if(b){var c=this.constructor.DATA_KEY,d=a(b.currentTarget).data(c);d||(d=new this.constructor(b.currentTarget,this._getDelegateConfig()),a(b.currentTarget).data(c,d)),d._activeTrigger.click=!d._activeTrigger.click,d._isWithActiveTrigger()?d._enter(null,d):d._leave(null,d)}else{if(a(this.getTipElement()).hasClass(r.IN))return void this._leave(null,this);this._enter(null,this)}},j.prototype.dispose=function(){clearTimeout(this._timeout),this.cleanupTether(),a.removeData(this.element,this.constructor.DATA_KEY),a(this.element).off(this.constructor.EVENT_KEY),this.tip&&a(this.tip).remove(),this._isEnabled=null,this._timeout=null,this._hoverState=null,this._activeTrigger=null,this._tether=null,this.element=null,this.config=null,this.tip=null},j.prototype.show=function(){var b=this,c=a.Event(this.constructor.Event.SHOW);if(this.isWithContent()&&this._isEnabled){a(this.element).trigger(c);var d=a.contains(this.element.ownerDocument.documentElement,this.element);if(c.isDefaultPrevented()||!d)return;var e=this.getTipElement(),g=f.getUID(this.constructor.NAME);e.setAttribute("id",g),this.element.setAttribute("aria-describedby",g),this.setContent(),this.config.animation&&a(e).addClass(r.FADE);var h="function"==typeof this.config.placement?this.config.placement.call(this,e,this.element):this.config.placement,i=this._getAttachment(h);a(e).data(this.constructor.DATA_KEY,this).appendTo(document.body),a(this.element).trigger(this.constructor.Event.INSERTED),this._tether=new Tether({attachment:i,element:e,target:this.element,classes:t,classPrefix:l,offset:this.config.offset,constraints:this.config.constraints,addTargetClasses:!1}),f.reflow(e),this._tether.position(),a(e).addClass(r.IN);var k=function(){var c=b._hoverState;b._hoverState=null,a(b.element).trigger(b.constructor.Event.SHOWN),c===p.OUT&&b._leave(null,b)};if(f.supportsTransitionEnd()&&a(this.tip).hasClass(r.FADE))return void a(this.tip).one(f.TRANSITION_END,k).emulateTransitionEnd(j._TRANSITION_DURATION);k()}},j.prototype.hide=function(b){var c=this,d=this.getTipElement(),e=a.Event(this.constructor.Event.HIDE),g=function(){c._hoverState!==p.IN&&d.parentNode&&d.parentNode.removeChild(d),c.element.removeAttribute("aria-describedby"),a(c.element).trigger(c.constructor.Event.HIDDEN),c.cleanupTether(),b&&b()};a(this.element).trigger(e),e.isDefaultPrevented()||(a(d).removeClass(r.IN),f.supportsTransitionEnd()&&a(this.tip).hasClass(r.FADE)?a(d).one(f.TRANSITION_END,g).emulateTransitionEnd(k):g(),this._hoverState="")},j.prototype.isWithContent=function(){return Boolean(this.getTitle())},j.prototype.getTipElement=function(){return this.tip=this.tip||a(this.config.template)[0]},j.prototype.setContent=function(){var b=a(this.getTipElement());this.setElementContent(b.find(s.TOOLTIP_INNER),this.getTitle()),b.removeClass(r.FADE).removeClass(r.IN),this.cleanupTether()},j.prototype.setElementContent=function(b,c){var e=this.config.html;"object"===("undefined"==typeof c?"undefined":d(c))&&(c.nodeType||c.jquery)?e?a(c).parent().is(b)||b.empty().append(c):b.text(a(c).text()):b[e?"html":"text"](c)},j.prototype.getTitle=function(){var a=this.element.getAttribute("data-original-title");return a||(a="function"==typeof this.config.title?this.config.title.call(this.element):this.config.title),a},j.prototype.cleanupTether=function(){this._tether&&this._tether.destroy()},j.prototype._getAttachment=function(a){return o[a.toUpperCase()]},j.prototype._setListeners=function(){var b=this,c=this.config.trigger.split(" ");c.forEach(function(c){if("click"===c)a(b.element).on(b.constructor.Event.CLICK,b.config.selector,a.proxy(b.toggle,b));else if(c!==u.MANUAL){var d=c===u.HOVER?b.constructor.Event.MOUSEENTER:b.constructor.Event.FOCUSIN,e=c===u.HOVER?b.constructor.Event.MOUSELEAVE:b.constructor.Event.FOCUSOUT;a(b.element).on(d,b.config.selector,a.proxy(b._enter,b)).on(e,b.config.selector,a.proxy(b._leave,b))}}),this.config.selector?this.config=a.extend({},this.config,{trigger:"manual",selector:""}):this._fixTitle()},j.prototype._fixTitle=function(){var a=d(this.element.getAttribute("data-original-title"));(this.element.getAttribute("title")||"string"!==a)&&(this.element.setAttribute("data-original-title",this.element.getAttribute("title")||""),this.element.setAttribute("title",""))},j.prototype._enter=function(b,c){var d=this.constructor.DATA_KEY;return c=c||a(b.currentTarget).data(d),c||(c=new this.constructor(b.currentTarget,this._getDelegateConfig()),a(b.currentTarget).data(d,c)),b&&(c._activeTrigger["focusin"===b.type?u.FOCUS:u.HOVER]=!0),a(c.getTipElement()).hasClass(r.IN)||c._hoverState===p.IN?void(c._hoverState=p.IN):(clearTimeout(c._timeout),c._hoverState=p.IN,c.config.delay&&c.config.delay.show?void(c._timeout=setTimeout(function(){c._hoverState===p.IN&&c.show()},c.config.delay.show)):void c.show())},j.prototype._leave=function(b,c){var d=this.constructor.DATA_KEY;if(c=c||a(b.currentTarget).data(d),c||(c=new this.constructor(b.currentTarget,this._getDelegateConfig()),a(b.currentTarget).data(d,c)),b&&(c._activeTrigger["focusout"===b.type?u.FOCUS:u.HOVER]=!1),!c._isWithActiveTrigger())return clearTimeout(c._timeout),c._hoverState=p.OUT,c.config.delay&&c.config.delay.hide?void(c._timeout=setTimeout(function(){c._hoverState===p.OUT&&c.hide()},c.config.delay.hide)):void c.hide()},j.prototype._isWithActiveTrigger=function(){for(var a in this._activeTrigger)if(this._activeTrigger[a])return!0;return!1},j.prototype._getConfig=function(c){return c=a.extend({},this.constructor.Default,a(this.element).data(),c),c.delay&&"number"==typeof c.delay&&(c.delay={show:c.delay,hide:c.delay}),f.typeCheckConfig(b,c,this.constructor.DefaultType),c},j.prototype._getDelegateConfig=function(){var a={};if(this.config)for(var b in this.config)this.constructor.Default[b]!==this.config[b]&&(a[b]=this.config[b]);return a},j._jQueryInterface=function(b){return this.each(function(){var c=a(this).data(h),e="object"===("undefined"==typeof b?"undefined":d(b))?b:null;if((c||!/dispose|hide/.test(b))&&(c||(c=new j(this,e),a(this).data(h,c)),"string"==typeof b)){if(void 0===c[b])throw new Error('No method named "'+b+'"');c[b]()}})},e(j,null,[{key:"VERSION",get:function(){return g}},{key:"Default",get:function(){return m}},{key:"NAME",get:function(){return b}},{key:"DATA_KEY",get:function(){return h}},{key:"Event",get:function(){return q}},{key:"EVENT_KEY",get:function(){return i}},{key:"DefaultType",get:function(){return n}}]),j}();return a.fn[b]=v._jQueryInterface,a.fn[b].Constructor=v,a.fn[b].noConflict=function(){return a.fn[b]=j,v._jQueryInterface},v}(jQuery));(function(f){var h="popover",i="4.0.0-alpha.5",j="bs.popover",k="."+j,l=f.fn[h],m=f.extend({},g.Default,{placement:"right",trigger:"click",content:"",template:''}),n=f.extend({},g.DefaultType,{content:"(string|element|function)"}),o={FADE:"fade",IN:"in"},p={TITLE:".popover-title",CONTENT:".popover-content"},q={HIDE:"hide"+k,HIDDEN:"hidden"+k,SHOW:"show"+k,SHOWN:"shown"+k,INSERTED:"inserted"+k,CLICK:"click"+k,FOCUSIN:"focusin"+k,FOCUSOUT:"focusout"+k,MOUSEENTER:"mouseenter"+k,MOUSELEAVE:"mouseleave"+k},r=function(g){function l(){return c(this,l),a(this,g.apply(this,arguments))}return b(l,g),l.prototype.isWithContent=function(){return this.getTitle()||this._getContent()},l.prototype.getTipElement=function(){return this.tip=this.tip||f(this.config.template)[0]},l.prototype.setContent=function(){var a=f(this.getTipElement());this.setElementContent(a.find(p.TITLE),this.getTitle()),this.setElementContent(a.find(p.CONTENT),this._getContent()),a.removeClass(o.FADE).removeClass(o.IN),this.cleanupTether()},l.prototype._getContent=function(){return this.element.getAttribute("data-content")||("function"==typeof this.config.content?this.config.content.call(this.element):this.config.content)},l._jQueryInterface=function(a){return this.each(function(){var b=f(this).data(j),c="object"===("undefined"==typeof a?"undefined":d(a))?a:null;if((b||!/destroy|hide/.test(a))&&(b||(b=new l(this,c),f(this).data(j,b)),"string"==typeof a)){if(void 0===b[a])throw new Error('No method named "'+a+'"');b[a]()}})},e(l,null,[{key:"VERSION",get:function(){return i}},{key:"Default",get:function(){return m}},{key:"NAME",get:function(){return h}},{key:"DATA_KEY",get:function(){return j}},{key:"Event",get:function(){return q}},{key:"EVENT_KEY",get:function(){return k}},{key:"DefaultType",get:function(){return n}}]),l}(g);return f.fn[h]=r._jQueryInterface,f.fn[h].Constructor=r,f.fn[h].noConflict=function(){return f.fn[h]=l,r._jQueryInterface},r})(jQuery)}(); --------------------------------------------------------------------------------