├── 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 |
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 |
17 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/app/header/header.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
46 |
47 |
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)}();
--------------------------------------------------------------------------------