├── .angular-cli.json
├── .gitignore
├── README.md
├── license
├── package.json
├── src
├── app
│ ├── about
│ │ ├── about.component.html
│ │ └── about.component.ts
│ ├── app.component.html
│ ├── app.component.ts
│ ├── app.module.ts
│ ├── app.router.ts
│ ├── chart
│ │ ├── chart.component.html
│ │ ├── chart.component.ts
│ │ └── stock-data.ts
│ ├── main.ts
│ ├── menu
│ │ ├── menu.component.html
│ │ └── menu.component.ts
│ └── stock-data.ts
├── assets
│ ├── images
│ │ ├── About-Normal.svg
│ │ ├── About-Selection.svg
│ │ ├── Analysis-Normal.svg
│ │ ├── Analysis-Selection.svg
│ │ ├── Information.svg
│ │ ├── Stock_Analysis.png
│ │ ├── fonts
│ │ │ ├── Expense-Analysis-Sample.eot
│ │ │ ├── Expense-Analysis-Sample.svg
│ │ │ ├── Expense-Analysis-Sample.ttf
│ │ │ ├── Expense-Analysis-Sample.woff
│ │ │ ├── controls.eot
│ │ │ ├── controls.svg
│ │ │ ├── controls.ttf
│ │ │ ├── controls.woff
│ │ │ ├── icons.eot
│ │ │ ├── icons.svg
│ │ │ ├── icons.ttf
│ │ │ └── icons.woff
│ │ └── sb-icons
│ │ │ ├── Syncfusion-logo.svg
│ │ │ ├── Syncfusion-mobile-logo.svg
│ │ │ ├── fonts
│ │ │ ├── icons.eot
│ │ │ ├── icons.svg
│ │ │ ├── icons.ttf
│ │ │ └── icons.woff
│ │ │ ├── new-light.svg
│ │ │ ├── preview-light.svg
│ │ │ └── updated-light.svg
│ ├── index.css
│ └── index.scss
├── environments
│ └── environment.ts
├── favicon.ico
├── index.html
├── main.ts
├── polyfills.ts
├── styles.css
├── test.ts
├── tsconfig.app.json
└── tsconfig.spec.json
├── tsconfig-aot.json
└── tsconfig.json
/.angular-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json",
3 | "project": {
4 | "name": "ej2-ng-stock-chart"
5 | },
6 | "apps": [
7 | {
8 | "root": "src",
9 | "outDir": "dist",
10 | "assets": [
11 | "assets",
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 | ],
32 | "e2e": {
33 | "protractor": {
34 | "config": "./protractor.conf.js"
35 | }
36 | },
37 | "lint": [
38 | {
39 | "project": "src/tsconfig.app.json",
40 | "exclude": "**/node_modules/**"
41 | },
42 | {
43 | "project": "src/tsconfig.spec.json",
44 | "exclude": "**/node_modules/**"
45 | },
46 | {
47 | "project": "e2e/tsconfig.e2e.json",
48 | "exclude": "**/node_modules/**"
49 | }
50 | ],
51 | "test": {
52 | "karma": {
53 | "config": "./karma.conf.js"
54 | }
55 | },
56 | "defaults": {
57 | "styleExt": "css",
58 | "component": {}
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | dist/
2 | *d.ts
3 | *.map
4 | .vscode/
5 | src/**/*.js
6 | *.ngstyle.ts
7 | src/**/*.map
8 | node_modules/
9 | npm-debug.log
10 | *ngfactory.ts
11 | *metadata.json
12 | *ngsummary.json
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Essential JS 2 for Angular - Stock Chart
2 |
3 | This Stock Chart demo application showcases the usage of Chart and Range Navigator in a real world application scenario. You can use this application to track and visualize stock price of any company over a specific period using charting and range tools
4 |
5 | ## Deployment
6 |
7 | ### Install
8 |
9 | To install all dependent packages, use the below command
10 |
11 | ```
12 | npm install
13 | ```
14 |
15 | ### Run
16 |
17 | To run the sample, use the below command
18 |
19 | ```
20 | ng serve
21 | ```
22 |
23 | ## Demo
24 |
25 | #### https://ej2.syncfusion.com/showcase/angular/stockchart/
26 |
27 | Check all the showcase samples from here.
--------------------------------------------------------------------------------
/license:
--------------------------------------------------------------------------------
1 | Essential JS 2 library is available under the Syncfusion Essential Studio program, and can be licensed either under the Syncfusion Community License Program or the Syncfusion commercial license.
2 |
3 | To be qualified for the Syncfusion Community License Program you must have a gross revenue of less than one (1) million U.S. dollars ($1,000,000.00 USD) per year and have less than five (5) developers in your organization, and agree to be bound by Syncfusion’s terms and conditions.
4 |
5 | Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options.
6 |
7 | Under no circumstances can you use this product without (1) either a Community License or a commercial license and (2) without agreeing and abiding by Syncfusion’s license containing all terms and conditions.
8 |
9 | The Syncfusion license that contains the terms and conditions can be found at
10 | https://www.syncfusion.com/content/downloads/syncfusion_license.pdf
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@syncfusion/ej2-ng-stock-chart",
3 | "version": "0.0.1",
4 | "description": "Essential JS 2 for Angular - Stock Chart application",
5 | "author": "Syncfusion Inc.",
6 | "license": "SEE LICENSE IN license",
7 | "dependencies": {
8 | "rxjs": "^5.0.1",
9 | "tslint": "4.0.2",
10 | "zone.js": "^0.8.4",
11 | "core-js": "^2.4.1",
12 | "systemjs": "^0.19.40",
13 | "gulp-print": "^2.0.1",
14 | "gulp-tslint": "^7.0.1",
15 | "browser-sync": "2.11.2",
16 | "gulp-sass-lint": "^1.1.1",
17 | "reflect-metadata": "^0.1.9",
18 | "tslint-microsoft-contrib": "^4.0.0",
19 | "@angular/core": "10.2.5",
20 | "@angular/http": "~5.0.0",
21 | "@angular/forms": "~5.0.0",
22 | "@angular/router": "^5.0.0",
23 | "@angular/common": "~5.0.0",
24 | "@angular-devkit/core": "^0.4.5",
25 | "@angular/upgrade": "^5.0.0",
26 | "@angular/compiler": "~5.0.0",
27 | "@angular/platform-browser": "~5.0.0",
28 | "@angular/platform-browser-dynamic": "~5.0.0",
29 | "@syncfusion/ej2-ng-base": "*",
30 | "@syncfusion/ej2-ng-charts": "*",
31 | "@syncfusion/ej2-ng-popups": "*",
32 | "request": "3.0.0",
33 | "minimist": "1.2.6",
34 | "ua-parser-js": "0.7.33",
35 | "debug": "2.6.9",
36 | "ms": "2.0.0",
37 | "json5": "1.0.2",
38 | "qs": "6.5.3",
39 | "decode-uri-component": ">=0.2.1",
40 | "engine.io": ">=3.6.1",
41 | "socket.io-parser": ">=3.3.3",
42 | "loader-utils": ">=1.4.1",
43 | "minimatch": ">=3.0.5",
44 | "got": ">=11.8.5",
45 | "async": ">=2.6.4",
46 | "eventsource": ">=1.1.1",
47 | "ejs": ">=3.1.7",
48 | "axios": ">=0.21.2",
49 | "ansi-regex": ">=3.0.1",
50 | "node-forge": ">=1.3.0",
51 | "url-parse": ">=1.5.9",
52 | "follow-redirects": ">=1.14.8",
53 | "node-sass": ">=7.0.0",
54 | "shelljs": ">=0.8.5",
55 | "json-schema": ">=0.4.0",
56 | "set-value": ">=2.0.1",
57 | "jsonpointer": ">=5.0.0",
58 | "object-path": ">=0.11.8",
59 | "tar": ">=4.4.18",
60 | "path-parse": ">=1.0.7",
61 | "dns-packet": ">=1.3.2",
62 | "xmlhttprequest-ssl": ">=1.6.2",
63 | "chownr": ">=1.1.0",
64 | "ajv": ">=6.12.3",
65 | "hosted-git-info": ">=2.8.9",
66 | "sockjs": ">=0.3.20",
67 | "lodash": ">=4.17.21",
68 | "underscore": ">=1.12.1",
69 | "braces": ">=2.3.1",
70 | "merge": ">=2.1.1",
71 | "y18n": ">=4.0.1",
72 | "elliptic": ">=6.5.4",
73 | "socket.io": ">=2.4.0",
74 | "ini": ">=1.3.6",
75 | "yargs-parser": ">=13.1.2",
76 | "webpack-subresource-integrity": ">=1.5.1",
77 | "http-proxy": ">=1.18.1",
78 | "tree-kill": ">=1.2.2",
79 | "lodash.mergewith": ">=4.6.2",
80 | "lodash.merge": ">=4.6.2",
81 | "connect": ">=2.8.1",
82 | "dot-prop": ">=4.2.1",
83 | "serialize-javascript": ">=3.1.0",
84 | "acorn": ">=5.7.4",
85 | "ws": ">=1.1.5",
86 | "mixin-deep": ">=1.3.2",
87 | "underscore.string": ">=3.3.5",
88 | "js-yaml": ">=3.13.1",
89 | "fstream": ">=1.0.12",
90 | "engine.io-client": ">=1.6.9",
91 | "webpack-dev-server": ">=3.1.11",
92 | "express": ">=3.11.0",
93 | "negotiator": ">=0.6.1",
94 | "parsejson": "0.0.4",
95 | "fresh": ">=0.5.2",
96 | "mime": ">=1.4.1",
97 | "hoek": ">=4.2.1"
98 | },
99 | "devDependencies": {
100 | "@angular/cli": "1.5.6",
101 | "@angular/compiler-cli": "5.0.0",
102 | "@angular/platform-server": "5.0.0",
103 | "@types/jasmine": "^2.2.29",
104 | "@types/requirejs": "^2.1.26",
105 | "@types/node": "^6.0.46",
106 | "gulp": "^3.9.0",
107 | "webpack": "2.5.1",
108 | "shelljs": ">=0.8.5",
109 | "typescript": "~2.4.2",
110 | "gulp-sass": "^3.1.0",
111 | "gulp-clean": "^0.3.2",
112 | "run-sequence": "2.2.0",
113 | "webpack-stream": "^3.2.0",
114 | "karma-systemjs": "^0.16.0",
115 | "gulp-typescript": "^2.13.0",
116 | "es6-module-loader": "^0.17.11",
117 | "systemjs-plugin-babel": "0.0.17",
118 | "decode-uri-component": ">=0.2.1",
119 | "engine.io": ">=3.6.1",
120 | "socket.io-parser": ">=3.3.3",
121 | "loader-utils": ">=1.4.1",
122 | "minimatch": ">=3.0.5",
123 | "got": ">=11.8.5",
124 | "async": ">=2.6.4",
125 | "eventsource": ">=1.1.1",
126 | "ejs": ">=3.1.7",
127 | "axios": ">=0.21.2",
128 | "ansi-regex": ">=3.0.1",
129 | "node-forge": ">=1.3.0",
130 | "url-parse": ">=1.5.9",
131 | "follow-redirects": ">=1.14.8",
132 | "node-sass": ">=7.0.0",
133 | "json-schema": ">=0.4.0",
134 | "set-value": ">=2.0.1",
135 | "jsonpointer": ">=5.0.0",
136 | "object-path": ">=0.11.8",
137 | "tar": ">=4.4.18",
138 | "path-parse": ">=1.0.7",
139 | "dns-packet": ">=1.3.2",
140 | "xmlhttprequest-ssl": ">=1.6.2",
141 | "chownr": ">=1.1.0",
142 | "ajv": ">=6.12.3",
143 | "hosted-git-info": ">=2.8.9",
144 | "sockjs": ">=0.3.20",
145 | "lodash": ">=4.17.21",
146 | "underscore": ">=1.12.1",
147 | "braces": ">=2.3.1",
148 | "merge": ">=2.1.1",
149 | "y18n": ">=4.0.1",
150 | "elliptic": ">=6.5.4",
151 | "socket.io": ">=2.4.0",
152 | "ini": ">=1.3.6",
153 | "yargs-parser": ">=13.1.2",
154 | "webpack-subresource-integrity": ">=1.5.1",
155 | "http-proxy": ">=1.18.1",
156 | "tree-kill": ">=1.2.2",
157 | "lodash.mergewith": ">=4.6.2",
158 | "lodash.merge": ">=4.6.2",
159 | "connect": ">=2.8.1",
160 | "dot-prop": ">=4.2.1",
161 | "serialize-javascript": ">=3.1.0",
162 | "acorn": ">=5.7.4",
163 | "ws": ">=1.1.5",
164 | "mixin-deep": ">=1.3.2",
165 | "underscore.string": ">=3.3.5",
166 | "js-yaml": ">=3.13.1",
167 | "fstream": ">=1.0.12",
168 | "engine.io-client": ">=1.6.9",
169 | "webpack-dev-server": ">=3.1.11",
170 | "express": ">=3.11.0",
171 | "negotiator": ">=0.6.1",
172 | "fresh": ">=0.5.2",
173 | "mime": ">=1.4.1",
174 | "hoek": ">=4.2.1"
175 | },
176 | "keywords": [
177 | "ej2",
178 | "samples",
179 | "stock-chart",
180 | "syncfusion",
181 | "ej2-samples",
182 | "ej2-ng-stock-chart",
183 | "ej2-showcase-samples",
184 | "syncfusion-samples",
185 | "syncfusion-stock-chart"
186 | ],
187 | "scripts": {
188 | "build": "npm run scripts && gulp styles && gulp bundle",
189 | "scripts": "ngc -p tsconfig-aot.json",
190 | "bundle": "gulp bundle",
191 | "ci-publish": "gulp publish-samples"
192 | }
193 | }
194 |
--------------------------------------------------------------------------------
/src/app/about/about.component.html:
--------------------------------------------------------------------------------
1 |
2 |
{{title}}
3 |
{{description}}
4 |
{{listTitle}}
5 |
11 |
12 |
--------------------------------------------------------------------------------
/src/app/about/about.component.ts:
--------------------------------------------------------------------------------
1 | import { LowerCasePipe } from '@angular/common';
2 | import { Directive, HostListener } from '@angular/core';
3 | import { Component, ViewEncapsulation, OnInit } from '@angular/core';
4 |
5 | import { MenuComponent } from '../menu/menu.component';
6 |
7 |
8 | @Component({
9 | templateUrl: 'about.component.html',
10 | encapsulation: ViewEncapsulation.None,
11 | })
12 | export class AboutComponent implements OnInit {
13 | public title: string;
14 | public listTitle: string;
15 | public description: string;
16 | public controlList: Object[];
17 |
18 | /** Configurations for the About page */
19 | constructor(
20 | public menu: MenuComponent
21 | ) {
22 | this.title = 'About this sample';
23 | this.listTitle = 'List of EJ2 components used in this sample';
24 | this.description = 'This stock chart demo application showcases using Essential JS 2 '
25 | + 'components together in a real-world application scenario. You can further explore the source '
26 | + 'code of this application and use it as a reference for integrating Essential JS 2 components '
27 | + 'into your applications.';
28 |
29 | this.controlList = [
30 | { 'control': 'Chart', 'link': 'http://ej2.syncfusion.com/angular/documentation/chart/getting-started.html' },
31 | { 'control': 'Button', 'link': 'http://ej2.syncfusion.com/angular/documentation/button/getting-started.html' },
32 | { 'control': 'DropDownButton', 'link': 'http://ej2.syncfusion.com/angular/documentation/drop-down-button/getting-started.html' },
33 | { 'control': 'Toolbar', 'link': 'http://ej2.syncfusion.com/angular/documentation/toolbar/getting-started.html' },
34 | { 'control': 'DateRangePicker', 'link': 'http://ej2.syncfusion.com/angular/documentation/daterangepicker/getting-started.html' },
35 | { 'control': 'RangeNavigator', 'link': 'http://ej2.syncfusion.com/angular/documentation/daterangepicker/getting-started.html' },
36 | ];
37 | this.handleResize();
38 | }
39 |
40 |
41 | public ngOnInit(): void {
42 | }
43 |
44 | public handleResize(): void {
45 | setTimeout(() => {
46 | if (document.documentElement.offsetWidth > 1400) {
47 | document.getElementById('about-overall').style.minHeight = 'auto';
48 | document.getElementById('about-overall').style.minHeight = document.documentElement.offsetHeight + 'px';
49 | }
50 | }, 100);
51 | }
52 |
53 | @HostListener('window:resize', ['$event'])
54 | onResize(event: any): void {
55 | /** Document height alignment corrections for high resoultion screens */
56 | this.handleResize();
57 | }
58 |
59 | }
--------------------------------------------------------------------------------
/src/app/app.component.html:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/app/app.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, OnInit, ViewChild } from '@angular/core';
2 |
3 |
4 | @Component({
5 | selector: 'app-root',
6 | templateUrl: './app.component.html'
7 | })
8 | export class AppComponent implements OnInit {
9 |
10 | public ngOnInit(): void {
11 | }
12 | }
--------------------------------------------------------------------------------
/src/app/app.module.ts:
--------------------------------------------------------------------------------
1 | import { NgModule } from '@angular/core';
2 | import { APP_BASE_HREF, HashLocationStrategy, Location, LocationStrategy} from '@angular/common';
3 | import { BrowserModule } from '@angular/platform-browser';
4 |
5 | import { ChartAllModule, RangeNavigatorAllModule } from '@syncfusion/ej2-ng-charts';
6 |
7 | import { DialogAllModule } from '@syncfusion/ej2-ng-popups';
8 |
9 | import { routing } from './app.router';
10 | import { ChartComponent } from '../app/chart/chart.component';
11 | import { MenuComponent } from '../app/menu/menu.component';
12 | import { AboutComponent } from '../app/about/about.component';
13 | import { AppComponent } from './app.component';
14 |
15 |
16 | @NgModule({
17 | imports: [
18 | BrowserModule,
19 | ChartAllModule,
20 | DialogAllModule,
21 | RangeNavigatorAllModule,
22 | routing
23 | ],
24 | declarations: [
25 | ChartComponent,
26 | MenuComponent,
27 | AboutComponent,
28 | AppComponent
29 | ],
30 | entryComponents: [
31 | AppComponent,
32 | ChartComponent
33 | ],
34 | bootstrap: [AppComponent],
35 | providers: [ {provide: APP_BASE_HREF, useValue : '/' }, Location, {provide: LocationStrategy, useClass: HashLocationStrategy} ]
36 | })
37 | export class AppModule {
38 | private location: Location;
39 | constructor(location: Location) { this.location = location; }
40 | }
--------------------------------------------------------------------------------
/src/app/app.router.ts:
--------------------------------------------------------------------------------
1 | import { ModuleWithProviders } from '@angular/core';
2 | import { Routes, RouterModule } from '@angular/router';
3 | import { AboutComponent } from './about/about.component';
4 | import { ChartComponent } from './chart/chart.component';
5 | import { MenuComponent } from './menu/menu.component';
6 |
7 | // Route Configuration
8 | export const routes: Routes = [
9 | { path: '', redirectTo: 'stockChart', pathMatch: 'full' },
10 | { path: 'stockChart', component: ChartComponent},
11 | { path: 'about', component: AboutComponent }
12 | ];
13 |
14 | export const routing: ModuleWithProviders = RouterModule.forRoot(routes);
--------------------------------------------------------------------------------
/src/app/chart/chart.component.html:
--------------------------------------------------------------------------------
1 |
3 |
4 |
9 |
Alphabet Inc. (GOOG) 2012-2015
10 |
11 |
$534.07
12 |
+5.83 (+0.51%)
13 |
14 |
At Close: 4:00 PM EDT
17 |
18 |
19 |
20 |
23 |
24 |
25 |
26 |
31 |
32 |
34 |
35 |
36 |
37 |
38 |
39 |
41 |
43 |
44 |
45 |
46 |
47 |
49 |
51 |
53 |
54 |
56 |
57 |
59 |
60 |
61 |
62 |
63 |
64 |
--------------------------------------------------------------------------------
/src/app/chart/chart.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, ViewChild, OnInit } from '@angular/core';
2 | import { Browser, remove, EmitType } from '@syncfusion/ej2-base';
3 | import { Directive, HostListener } from '@angular/core';
4 | import { Chart, RangeNavigator, IRangeLoadedEventArgs, IRangeSelectorRenderEventArgs, ILoadEventArgs } from '@syncfusion/ej2-ng-charts';
5 | import { ChartTheme, PeriodSelectorSettingsModel, IChangedEventArgs, ChartSeriesType } from '@syncfusion/ej2-ng-charts';
6 | import { TechnicalIndicators, TechnicalIndicatorModel, TrendlineTypes, AxisModel, Axis } from '@syncfusion/ej2-charts';
7 | import { ItemModel } from '@syncfusion/ej2-navigations';
8 | import { ChartAreaModel, TooltipSettingsModel, CrosshairSettingsModel, ZoomSettingsModel, getElement } from '@syncfusion/ej2-ng-charts';
9 | import { ITooltipRenderEventArgs, IPointEventArgs, IAxisLabelRenderEventArgs, ILoadedEventArgs } from '@syncfusion/ej2-ng-charts';
10 | import { IMouseEventArgs, MarginModel, IPointRenderEventArgs, AnimationModel, withInBounds, Series } from '@syncfusion/ej2-ng-charts';
11 | import { RowModel, LegendSettingsModel, IAxisRangeCalculatedEventArgs, VisibleLabels, ExportType } from '@syncfusion/ej2-ng-charts';
12 | import { goog, googl, aapl, amzn, tsla, IVolume, IClose } from './stock-data';
13 | import { DropDownButton, MenuEventArgs } from '@syncfusion/ej2-splitbuttons';
14 | import { Button } from '@syncfusion/ej2-buttons';
15 |
16 |
17 | @Component({
18 | selector: 'stock',
19 | templateUrl: 'chart.component.html',
20 | })
21 |
22 |
23 | export class ChartComponent implements OnInit {
24 |
25 | //component initialization
26 | @ViewChild('chart')
27 | public chart: Chart;
28 | @ViewChild('range')
29 | public range: RangeNavigator;
30 |
31 | // range navigator
32 | public width: string = '90%';
33 | public selectedTheme: string = location.hash.split('/')[1] ? location.hash.split('/')[1] : 'Material';
34 | public theme: ChartTheme = (this.selectedTheme.charAt(0).toUpperCase() + this.selectedTheme.slice(1));
35 | public periods: PeriodSelectorSettingsModel;
36 | public rangeChanged: EmitType;
37 | public rangeLoaded: EmitType;
38 | public rangeLoad: EmitType;
39 | public chartLoad: EmitType;
40 | public selectorRender: EmitType;
41 | public data: Object[] = googl;
42 | public secondaryData: Object[] = aapl;
43 | public thirdData: Object[] = goog;
44 | public fourthData: Object[] = amzn;
45 | public fifthData: Object[] = tsla;
46 | public firstContent: string;
47 | public setValue: boolean = false;
48 | public setValue1: boolean = false;
49 | public setValue2: boolean = false;
50 | public setValue3: boolean = false;
51 | //chart initialization
52 | public chartArea: ChartAreaModel;
53 | public primaryXAxis: AxisModel;
54 | public primaryYAxis: AxisModel;
55 | public tooltip: TooltipSettingsModel;
56 | public crosshair: CrosshairSettingsModel;
57 | public tooltipRender: EmitType;
58 | public pointRender: EmitType;
59 | public margin: MarginModel;
60 | public zoomSettings: ZoomSettingsModel;
61 | public axisLabelRender: EmitType;
62 | public loaded: EmitType;
63 | public chartClick: EmitType;
64 | public chartMouseMove: EmitType;
65 | public chartMouseLeave: EmitType;
66 | public axes: AxisModel[];
67 | public rows: RowModel[];
68 | public legendSettings: LegendSettingsModel;
69 | public axisRangeCalculated: EmitType;
70 | public period: number;
71 | public fastPeriod: number = 8;
72 | public slowPeriod: number = 5;
73 | public macdType: string = 'Both';
74 | public annotationString: string = '';
75 | public animation: AnimationModel = { enable: false };
76 | public opacity: number;
77 | public secondaryOpacity: number;
78 | public thirdOpacity: number;
79 | public fourthOpacity: number;
80 | public fifthOpacity: number;
81 | public trendLineTooltip: boolean;
82 | public upperLine: object = {
83 | color: '#FFE200',
84 | width: 1
85 | };
86 | public periodLine: object = {
87 | width: 2
88 | };
89 | public lowerLine: object = {
90 | color: '#FAA512',
91 | width: 1
92 | };
93 |
94 | public pointColors: string[] = [];
95 |
96 |
97 |
98 | //private variables:
99 | private indicators: TechnicalIndicators[] = [];
100 | private secondayIndicators: TechnicalIndicators[] = [];
101 | private secondaryValue: string = null;
102 | private thirdValue: string = null;
103 | private fourthValue: string = null;
104 | private fifthValue: string = null;
105 | private tmaValue: string = ': $124.79';
106 | private bollingerValue: string = ': $9.979';
107 | private rsiValue: string = ': $99.279';
108 | private smaValue: string = ': $106.719';
109 | private macdValue: string = ': 2.719';
110 | public sidePlacement: boolean = false;
111 | private candleValue: string = '534.07';
112 | private content: string;
113 | public ngOnInit(): void {
114 |
115 | //range navigator
116 | this.tmaValue = ': $124.79';
117 | this.bollingerValue = ': $9.979';
118 | this.rsiValue = ': $99.279';
119 | this.smaValue = ': $106.719';
120 | this.macdValue = ': 2.719';
121 | this.content = this.candle(this.candleValue);
122 | this.firstContent = this.candle('534.07');
123 | this.periods = {
124 | position: 'Top',
125 | periods: [
126 | { text: '1M', interval: 1, intervalType: 'Months' },
127 | { text: '3M', interval: 3, intervalType: 'Months', selected: Browser.isDevice ? true : false },
128 | { text: '6M', interval: 6, intervalType: 'Months' }, { text: 'YTD' },
129 | { text: '1Y', interval: 1, intervalType: 'Years', selected: Browser.isDevice ? false : true },
130 | { text: '2Y', interval: 2, intervalType: 'Years' },
131 | { text: 'All' }
132 | ]
133 | };
134 |
135 | this.rangeChanged = (args: IChangedEventArgs) => {
136 | let returnPoint: number;
137 | if (args.selectedData.length > 2000) {
138 | returnPoint = 10;
139 | } else if (args.selectedData.length > 1000) {
140 | returnPoint = 8;
141 | } else if (args.selectedData.length > 600) {
142 | returnPoint = 6;
143 | } else if (args.selectedData.length > 100) {
144 | returnPoint = 3;
145 | } else {
146 | returnPoint = 2;
147 | }
148 | let data: IVolume[] = googl.filter((data: IVolume, index: number) => {
149 | return ((data['x'].getTime() >= (args.start as Date).getTime() &&
150 | data['x'].getTime() <= (args.end as Date).getTime()) && index % returnPoint === 0);
151 | });
152 | let data1: IVolume[] = aapl.filter((data1: IVolume, index: number) => {
153 | return ((data1['x'].getTime() >= (args.start as Date).getTime() &&
154 | data1['x'].getTime() <= (args.end as Date).getTime()) && index % returnPoint === 0);
155 | });
156 | let data2: IClose[] = goog.filter((data2: IClose, index: number) => {
157 | return ((data2['x'].getTime() >= (args.start as Date).getTime() &&
158 | data2['x'].getTime() <= (args.end as Date).getTime()) && index % returnPoint === 0);
159 | });
160 |
161 | let data3: IClose[] = amzn.filter((data3: IClose, index: number) => {
162 | /* tslint:disable:no-string-literal */
163 | return ((data3['x'].getTime() >= (args.start as Date).getTime() &&
164 | data3['x'].getTime() <= (args.end as Date).getTime()) && index % returnPoint === 0);
165 | });
166 | let data4: IClose[] = tsla.filter((data4: IClose, index: number) => {
167 | /* tslint:disable:no-string-literal */
168 | return ((data4['x'].getTime() >= (args.start as Date).getTime() &&
169 | data4['x'].getTime() <= (args.end as Date).getTime()) && index % returnPoint === 0);
170 | });
171 | let diff: number = ((args.end as Date).getTime() - (args.start as Date).getTime()) / 1000;
172 | diff /= (60 * 60 * 24 * 7 * 4);
173 | let totalMonths: number = Math.abs(Math.round(diff));
174 | if (totalMonths >= 13) {
175 | this.chart.primaryXAxis.labelFormat = 'MMM yyy';
176 | } else if (totalMonths <= 6) {
177 | this.chart.primaryXAxis.labelFormat = 'MMM dd';
178 | }
179 | this.chart.series[0].animation.enable = false; this.chart.primaryXAxis.zoomPosition = 0;
180 | this.chart.primaryXAxis.zoomFactor = 1; this.chart.series[1].animation.enable = false;
181 | this.chart.primaryXAxis.stripLines = [{ visible: true }];
182 | this.pointColors = []; this.chart.series[6].dataSource = data4;
183 | this.chart.series[0].dataSource = data; this.chart.series[1].dataSource = data; this.chart.series[2].dataSource = data;
184 | this.chart.series[3].dataSource = data1; this.chart.series[4].dataSource = data2; this.chart.series[5].dataSource = data3;
185 | this.chart.refresh(); this.chart.setAnnotationValue(0, '
');
186 | };
187 | this.chartLoad = (args: ILoadedEventArgs) => {
188 | if (document.documentElement.offsetHeight) {
189 | let height: number = (document.documentElement.offsetHeight - 245);
190 | args.chart.height = height > 450 ? (height + '') : null;
191 | } else {
192 | args.chart.height = null;
193 | }
194 | document.body.style.overflowY = args.chart.height ? 'hidden' : 'auto';
195 | if (document.documentElement.offsetHeight > 700 && document.getElementById('_dialog-content')) {
196 | document.getElementById('_dialog-content').style.overflowY = 'hidden';
197 | }
198 | document.getElementById('close').style.display = Browser.isDevice ? 'none' : 'block';
199 | document.getElementById('atClose').style.display = Browser.isDevice ? 'none' : 'block';
200 | document.getElementById('stockRange').style.paddingTop = Browser.isDevice ? '1%' : '0.5%';
201 | document.getElementById('stockRange').style.paddingBottom = Browser.isDevice ? '1%' : '0.5%';
202 | }
203 | this.rangeLoaded = (args: IRangeLoadedEventArgs) => {
204 | let calendar: Element = document.getElementById('customRange');
205 | calendar.classList.add('e-flat');
206 |
207 | let icon: Element = document.getElementById('dateIcon');
208 | icon.classList.add('e-btn-icon');
209 |
210 | let rect: ClientRect = document.getElementsByClassName('chart-element')[0].getBoundingClientRect();
211 | let size: number = rect.width > 350 ? 10 : 18;
212 | document.getElementById('range_Secondary_Element').style.transform = 'translateX(' + (rect.left - size) + 'px)';
213 | document.getElementById('range_Secondary_Element').style.width = rect.width + 'px';
214 | document.getElementById('stockRange').style.transform = 'translateX(' + (rect.left - 10) + 'px)';
215 | let seriesType: DropDownButton = new DropDownButton({
216 | items: [{ text: 'Line' }, { text: 'Hilo' }, { text: 'HiloOpenClose' },
217 | { text: 'Hollow Candle' }, { text: 'Spline' }, { text: 'Candle' }],
218 | select: (args: MenuEventArgs) => {
219 | if (args.item.text === 'Candle') {
220 | this.chart.series[1].enableSolidCandles = true;
221 | this.chart.series[1].type = 'Candle';
222 | } else if (args.item.text === 'Hollow Candle') {
223 | this.chart.series[1].enableSolidCandles = false;
224 | this.chart.series[1].type = 'Candle';
225 | } else {
226 | this.chart.series[1].type =
args.item.text;
227 | }
228 | this.chart.refresh();
229 | this.removeSecondaryElement(0);
230 | },
231 | iconCss: 'e-icons e-add', cssClass: 'e-caret-hide'
232 | });
233 | seriesType.appendTo('#seriesType');
234 | let comparision: DropDownButton = new DropDownButton({
235 | items: [{ text: 'GOOG' }, { text: 'AAPL' }, { text: 'GOOGL' }, { text: 'AMZN' }, { text: 'TSLA' }],
236 | select: (args: MenuEventArgs) => {
237 | if (args.item.text === 'AAPL' && !this.setValue) {
238 | this.secondaryValue = '467.5'
239 | this.chart.series[3].opacity = 1;
240 | this.chart.series[3].visible = true;
241 | this.setValue = true;
242 | this.chart.refresh();
243 | } else if (args.item.text === 'GOOGL' && !this.setValue1) {
244 | this.thirdValue = '467.5'
245 | this.chart.series[4].opacity = 1;
246 | this.chart.series[4].visible = true;
247 | this.setValue1 = true;
248 | this.chart.refresh();
249 | } else if (args.item.text === 'AMZN' && !this.setValue2) {
250 | this.fourthValue = '389.51'
251 | this.chart.series[5].opacity = 1;
252 | this.chart.series[5].visible = true;
253 | this.setValue2 = true;
254 | this.chart.refresh();
255 | } else if (args.item.text === 'TSLA' && !this.setValue3) {
256 | this.fifthValue = '205.27'
257 | this.chart.series[6].opacity = 1;
258 | this.chart.series[6].visible = true;
259 | this.setValue3 = true;
260 | this.chart.refresh();
261 | }
262 | this.removeSecondaryElement(0);
263 | this.renderAnnotation();
264 | },
265 | iconCss: 'e-icons e-add', cssClass: 'e-caret-hide'
266 | });
267 | comparision.appendTo('#comparision');
268 | let reset: Button = new Button({
269 | iconCss: 'e-icons e-reset', cssClass: 'e-flat'
270 | });
271 | reset.appendTo('#resetClick');
272 | let print: Button = new Button({
273 | iconCss: 'e-icons e-play-icon', cssClass: 'e-flat'
274 | });
275 | print.appendTo('#print');
276 | let exportChart: DropDownButton = new DropDownButton({
277 | items: [{ text: 'JPEG' }, { text: 'PNG' }, { text: 'SVG' }],
278 | iconCss: 'e-icons e-export', cssClass: 'e-caret-hide',
279 | select: (args: MenuEventArgs) => {
280 | let type: ExportType = args.item.text;
281 | this.chart.export(type, 'chart');
282 | }
283 | });
284 | exportChart.appendTo('#export');
285 |
286 | document.getElementById('print').onclick = () => {
287 | this.chart.print(['chartStock']);
288 | };
289 | document.getElementById('resetClick').onclick = () => {
290 | while (this.chart.indicators.length) {
291 | this.chart.indicators.pop();
292 | }
293 | this.indicators = [];
294 | this.secondayIndicators = [];
295 | this.chart.series[1].trendlines[0].width = 0;
296 | this.chart.series[1].type = 'Candle';
297 | this.secondaryValue = null;
298 | this.secondaryOpacity = 0;
299 | this.chart.series[3].opacity = 0;
300 | this.chart.series[3].visible = false;
301 | this.chart.indicatorElements = null;
302 | this.setValue = false;
303 |
304 | this.thirdValue = null;
305 | this.fourthValue = null;
306 | this.thirdOpacity = 0;
307 | this.fourthOpacity = 0;
308 | this.fifthValue = null;
309 | this.fifthOpacity = 0;
310 |
311 | this.chart.series[4].opacity = 0;
312 | this.chart.series[4].visible = false;
313 | this.setValue1 = false;
314 |
315 | this.chart.series[5].opacity = 0;
316 | this.chart.series[5].visible = false;
317 | this.setValue2 = false;
318 |
319 | this.chart.series[6].opacity = 0;
320 | this.chart.series[6].visible = false;
321 | this.setValue3 = false;
322 | this.chart.rows = [
323 | { height: '15%' },
324 | { height: '85%' }
325 | ];
326 | this.chart.axes = [{
327 | name: 'secondary', opposedPosition: true, rowIndex: 0, desiredIntervals: 2,
328 | majorGridLines: { width: 0, color: '#EDEDED' },
329 | lineStyle: { width: 1, color: 'whitesmoke' }, majorTickLines: { width: 0 }, rangePadding: 'None'
330 | }];
331 | this.chart.primaryYAxis = {
332 | crosshairTooltip: { enable: true },
333 | labelFormat: 'n0', plotOffset: 25,
334 | desiredIntervals: 5,
335 | rowIndex: 1, opposedPosition: true,
336 | lineStyle: { width: 1, color: 'whitesmoke' },
337 | rangePadding: 'None',
338 | majorGridLines: { width: 1, color: '#EDEDED' },
339 | };
340 | this.chart.refresh();
341 |
342 | if (window.innerWidth > 450) {
343 | this.range.periodSelectorModule.selectedIndex = 8;
344 | this.range.rangeSlider.performAnimation(1398105000000, 1429641000000, this.range);
345 | } else {
346 | this.range.periodSelectorModule.selectedIndex = 4;
347 | this.range.rangeSlider.performAnimation(1421971200000, 1429641000000, this.range);
348 | }
349 | this.chart.setAnnotationValue(1, this.candle(': $534.07'));
350 | };
351 | let indicatorType: DropDownButton = new DropDownButton({
352 | items: [{ text: 'TMA' }, { text: 'Bollinger Bands' }, { text: 'RSI' }, { text: 'SMA' },
353 | { text: 'MACD' }],
354 | iconCss: 'e-icons e-add', cssClass: 'e-caret-hide',
355 | select: (args: MenuEventArgs) => {
356 | let text: string = args.item.text.split(' ')[0].toLocaleLowerCase() + (args.item.text.split(' ')[1] ? args.item.text.split(' ')[1] : '');
357 | text = text.substr(0, 1).toUpperCase() + text.substr(1);
358 | let type: TechnicalIndicators = text;
359 | if (type === 'Tma' || type === 'BollingerBands' || type === 'Sma') {
360 | if (this.indicators.indexOf(type) === -1) {
361 | let indicator: TechnicalIndicatorModel[] = [{
362 | type: type, period: 3, fastPeriod: 8, slowPeriod: 5,
363 | seriesName: 'Apple Inc', macdType: 'Both', width: 2,
364 | macdPositiveColor: '#6EC992', macdNegativeColor: '#FF817F',
365 | fill: type === 'Sma' ? '#32CD32' : '#6063ff',
366 | animation: { enable: false },
367 | upperLine: { color: '#FFE200', width: 1 },
368 | periodLine: { width: 2 },
369 | bandColor: 'rgba(245, 203, 35, 0.12)',
370 | lowerLine: { color: '#FAA512', width: 1 }
371 | }];
372 |
373 | this.indicators.push(type);
374 | this.chart.indicators = this.chart.indicators.concat(indicator);
375 | this.chart.refresh();
376 | }
377 | } else {
378 | if (this.indicators.indexOf(type) === -1) {
379 | this.indicators.push(type);
380 | this.secondayIndicators.push(type);
381 | let axis: AxisModel[];
382 | let row: RowModel[]
383 | let indicator: TechnicalIndicatorModel[];
384 | let len: number = this.chart.rows.length;
385 | this.chart.rows[this.chart.rows.length - 1].height = '15%';
386 | row = [{ height: '' + (100 - len * 15) + 'px' }];
387 | this.chart.rows = this.chart.rows.concat(row);
388 | axis = [{
389 | plotOffset: 10, name: type.toString(), opposedPosition: true, rowIndex: 0, desiredIntervals: 1,
390 | majorGridLines: { width: 0, color: '#EDEDED' }, lineStyle: { width: 1, color: 'whitesmoke' },
391 | majorTickLines: { width: 0 }, rangePadding: 'None'
392 | }];
393 | for (let i: number = 0; i < this.chart.axes.length; i++) {
394 | this.chart.axes[i].rowIndex += 1;
395 | }
396 | this.chart.axes = this.chart.axes.concat(axis);
397 | this.chart.primaryYAxis.rowIndex = len + 1;
398 | indicator = [{
399 | type: type, period: 3, fastPeriod: 8, slowPeriod: 5,
400 | seriesName: 'Apple Inc', macdType: 'Both', width: 2,
401 | macdPositiveColor: '#6EC992', macdNegativeColor: '#FF817F',
402 | fill: '#6063ff', yAxisName: type.toString(), animation: { enable: false },
403 | upperLine: { color: '#FFE200', width: 1 },
404 | periodLine: { width: 2 },
405 | bandColor: 'rgba(245, 203, 35, 0.12)',
406 | lowerLine: { color: '#FAA512', width: 1 }
407 | }];
408 | this.chart.indicators = this.chart.indicators.concat(indicator);
409 | this.chart.refresh();
410 | }
411 | }
412 | this.removeSecondaryElement(0);
413 | this.renderAnnotation();
414 | },
415 | });
416 | indicatorType.appendTo('#indicatorType');
417 | let trendType: DropDownButton = new DropDownButton({
418 | items: [{ text: 'Linear' }, { text: 'Polynomial' }, { text: 'MovingAverage' }],
419 | select: (args: MenuEventArgs) => {
420 | let type: TrendlineTypes = args.item.text;
421 | this.chart.series[1].trendlines[0].animation.enable = false;
422 | this.chart.series[1].trendlines[0].width = 3;
423 | this.chart.series[1].trendlines[0].type = type;
424 | this.chart.refresh();
425 | },
426 | iconCss: 'e-icons e-add', cssClass: 'e-caret-hide'
427 | });
428 | trendType.appendTo('#trendType');
429 | args.rangeNavigator.periodSelectorModule.toolbar.refreshOverflow();
430 | };
431 | this.selectorRender = (args: IRangeSelectorRenderEventArgs) => {
432 | args.enableCustomFormat = true;
433 | args.content = 'Date Range';
434 | let seriesModel: ItemModel = {
435 | template: ' ', align: 'Left'
436 | };
437 | let indicatorModel: ItemModel = {
438 | template: ' ', align: 'Left'
439 | };
440 | let comparisionModel: ItemModel = {
441 | template: ' ', align: 'Left'
442 | };
443 | let trendLineModel: ItemModel = {
444 | template: ' ', align: 'Left'
445 | };
446 | let resetModel: ItemModel = {
447 | template: ' ', align: 'Right', tooltipText: 'Reset'
448 | };
449 | let printModel: ItemModel = {
450 | template: ' ', align: 'Right', tooltipText: 'Print'
451 | };
452 | let exportModel: ItemModel = {
453 | template: ' ', align: 'Right', tooltipText: 'Export'
454 | };
455 | args.selector.splice(0, 0, trendLineModel);
456 | args.selector.splice(0, 0, indicatorModel);
457 | args.selector.splice(0, 0, comparisionModel);
458 | args.selector.splice(0, 0, seriesModel);
459 | args.selector.push(resetModel);
460 | args.selector.push(printModel);
461 | args.selector.push(exportModel);
462 | };
463 |
464 |
465 | //chart initialization
466 | this.trendLineTooltip = false;
467 | this.opacity = 0;
468 | this.secondaryOpacity = 0;
469 | this.thirdOpacity = 0;
470 | this.fourthOpacity = 0;
471 | this.fifthOpacity = 0;
472 | this.primaryXAxis = {
473 | valueType: 'DateTime', majorGridLines: { width: 0, color: '#EDEDED' }, crosshairTooltip: { enable: true },
474 | edgeLabelPlacement: 'Hide'
475 | };
476 | this.primaryYAxis = {
477 | crosshairTooltip: { enable: true },
478 | labelFormat: 'n0', plotOffset: 25,
479 | desiredIntervals: 5,
480 | rowIndex: 1, opposedPosition: true,
481 | lineStyle: { width: 1, color: 'whitesmoke' },
482 | rangePadding: 'None',
483 | majorGridLines: { width: 1, color: '#EDEDED' },
484 | };
485 | this.rows = [
486 | { height: '15%' },
487 | { height: '85%' }
488 | ];
489 |
490 | this.axes = [{
491 | name: 'secondary', opposedPosition: true, rowIndex: 0, desiredIntervals: 2,
492 | majorGridLines: { width: 0, color: '#EDEDED' },
493 | lineStyle: { width: 1, color: 'whitesmoke' }, majorTickLines: { width: 0 }, rangePadding: 'None'
494 | }];
495 |
496 | this.axisLabelRender = (args: IAxisLabelRenderEventArgs) => {
497 | if (args.axis.name === 'secondary') {
498 | args.text = Math.round((args.value / 10000000)) + 'B';
499 | } else if (args.axis.orientation === 'Vertical') {
500 | args.text = '$' + Math.round(args.value);
501 | }
502 | };
503 | this.axisRangeCalculated = (args: IAxisRangeCalculatedEventArgs) => {
504 | this.chart.setAnnotationValue(0, '');
505 | };
506 | this.loaded = (args: ILoadedEventArgs) => {
507 | document.getElementById('stock-details').style.visibility = 'visible';
508 | document.getElementById('waitingpopup').style.display = 'none';
509 | let labels: VisibleLabels[] = (args.chart.axisCollections[0]).visibleLabels;
510 | let maxValue: number = args.chart.axisCollections[0].visibleRange.max;
511 | if (args.chart.primaryXAxis.stripLines.length === 1) {
512 | for (let i: number = 0; i < labels.length; i += 2) {
513 | args.chart.primaryXAxis.stripLines.push({
514 | start: new Date(labels[i].value), end: labels[i + 1] ? new Date(labels[i + 1].value) : new Date(maxValue),
515 | zIndex: 'Behind', border: { width: 0, color: 'transparent' }, rotation: null,
516 | opacity: 0.6, textStyle: {}, text: '', color: '#F1F5FB', visible: true
517 | });
518 | }
519 | args.chart.refresh();
520 | }
521 | this.handleResize();
522 | };
523 |
524 | this.chartClick = (args: IMouseEventArgs) => {
525 | if (args.target === 'tsla' || args.target === 'amzn' || args.target === 'aapl' || args.target === 'googl' || args.target === 'tma' || args.target === 'bollingerbands' || args.target === 'rsi' || args.target === 'sma' || args.target === 'macd') {
526 | this.removeSecondaryElement(0);
527 | if (args.target === 'aapl') {
528 | this.secondaryValue = null;
529 | this.secondaryOpacity = 0;
530 | this.chart.series[3].opacity = 0;
531 | this.chart.series[3].visible = false;
532 | this.setValue = false;
533 | }
534 | if (args.target === 'googl') {
535 | this.thirdValue = null;
536 | this.thirdOpacity = 0;
537 | this.chart.series[4].opacity = 0;
538 | this.chart.series[4].visible = false;
539 | this.setValue1 = false;
540 | }
541 |
542 | if (args.target === 'amzn') {
543 | this.fourthValue = null;
544 | this.fourthOpacity = 0;
545 | this.chart.series[5].opacity = 0;
546 | this.chart.series[5].visible = false;
547 | this.setValue2 = false;
548 | }
549 |
550 | if (args.target === 'tsla') {
551 | this.fifthValue = null;
552 | this.fifthOpacity = 0;
553 | this.chart.series[6].opacity = 0;
554 | this.chart.series[6].visible = false;
555 | this.setValue3 = false;
556 | }
557 | this.content = this.candle(this.candleValue);
558 | this.indicators = [];
559 | let removeIndex: number;
560 | this.chart.indicators.map((indicator: TechnicalIndicatorModel, index: number) => {
561 | let type: string = indicator.type.toLocaleLowerCase();
562 | if (type === args.target) {
563 | removeIndex = index;
564 | if (type === 'macd' || type === 'rsi') {
565 | this.secondayIndicators.splice(0, 1);
566 | this.chart.rows.splice(0, 1);
567 | let len: number = this.chart.rows.length;
568 | this.chart.rows[this.chart.rows.length - 1].height = '' + (100 - (len - 1) * 15) + 'px';
569 | for (let i: number = 0; i < this.chart.axes.length; i++) {
570 | if (this.chart.axes[i].name.toLowerCase() === type) {
571 | this.chart.axes.splice(i, 1);
572 | break;
573 | }
574 | }
575 | for (let i: number = 0; i < this.chart.axes.length; i++) {
576 | this.chart.axes[i].rowIndex -= 1;
577 | }
578 |
579 | this.chart.primaryYAxis.rowIndex = len - 1;
580 | }
581 | type = null;
582 | }
583 | if (type === 'tma') {
584 | this.indicators.push('Tma');
585 | this.content += this.tma(this.tmaValue);
586 | } else if (type === 'bollingerbands') {
587 | this.indicators.push('BollingerBands');
588 | this.content += this.bollinger(this.bollingerValue);
589 | } else if (type === 'rsi') {
590 | this.indicators.push('Rsi');
591 | this.content += this.rsi(this.rsiValue);
592 | } else if (type === 'sma') {
593 | this.indicators.push('Sma');
594 | this.content += this.sma(this.smaValue);
595 | } else if (type === 'macd') {
596 | this.indicators.push('Macd');
597 | this.content += this.macd(this.macdValue);
598 | }
599 | });
600 | if (removeIndex !== undefined) {
601 | this.chart.indicators.splice(removeIndex, 1);
602 | }
603 | if (this.secondaryValue) {
604 | this.content += this.compare(this.secondaryValue);
605 | }
606 | if (this.thirdValue) {
607 | this.content += this.compare1(this.thirdValue);
608 | }
609 | if (this.fourthValue) {
610 | this.content += this.compare2(this.fourthValue);
611 | }
612 | if (this.fifthValue) {
613 | this.content += this.compare3(this.fifthValue);
614 | }
615 | if (document.getElementById('chartStock_Annotation_1').childNodes.length === 1) {
616 | this.chart.indicatorElements = null;
617 | }
618 | if (this.chart.indicators.length === 0) {
619 | this.chart.indicatorElements = null;
620 | }
621 | this.chart.refresh();
622 | this.chart.setAnnotationValue(1, this.content);
623 | }
624 | };
625 | this.tooltip = {
626 | enable: true,
627 | shared: true,
628 | header: '',
629 | format: '${point.x}
High : ${point.high}
Low :' +
630 | ' ${point.low}
Open : ${point.open}
Close : ${point.close}
Volume : ${point.volume}'
631 | };
632 | this.crosshair = {
633 | enable: true, lineType: 'Both'
634 | };
635 |
636 | this.legendSettings = {
637 | visible: false
638 | };
639 | this.period = 3;
640 | this.chartArea = {
641 | border: { width: 1, color: 'whitesmoke' }
642 | };
643 | this.zoomSettings = { enableMouseWheelZooming: true, mode: 'X', toolbarItems: [] };
644 |
645 | this.tooltipRender = (args: ITooltipRenderEventArgs) => {
646 | if (args.series.name === 'Apple Inc') {
647 | this.content += this.candle(' :$' + args.text.split('
')[4].split('')[1].split('')[0]);
648 | }
649 | if (args.series.type === 'Candle') {
650 | this.chart.setAnnotationValue(0, this.annotationString + (this.getContent(args.text) + '') + ' ');
651 | } else if (args.series.name === 'AAPL' && this.setValue) {
652 | this.content += this.compare(args.text.split('
')[4].split('')[1].split('')[0]);
653 | } else if (args.series.name === 'GOOGL' && this.setValue1) {
654 | this.content += this.compare1(args.text.split('
')[4].split('')[1].split('')[0]);
655 | } else if (args.series.name === 'AMZN' && this.setValue2) {
656 | this.content += this.compare2(args.text.split('
')[4].split('')[1].split('')[0]);
657 | } else if (args.series.name === 'TSLA' && this.setValue3) {
658 | this.content += this.compare3(args.text.split('
')[4].split('')[1].split('')[0]);
659 | } else {
660 | /* tslint:disable:no-string-literal */
661 | this.setIndicatorAnnotation(args.text, (args.series as Series)['parentObj']['type']);
662 | }
663 | args.text = '';
664 | };
665 |
666 | this.pointRender = (args: IPointRenderEventArgs) => {
667 | if (args.series.type === 'Candle') {
668 | this.pointColors.push(args.fill);
669 | } else {
670 | args.fill = this.pointColors[args.point.index];
671 | }
672 | };
673 |
674 | this.chartMouseLeave = (args: IMouseEventArgs) => { this.removeSecondaryElement(); };
675 | this.chartMouseMove = (args: IMouseEventArgs) => {
676 | if (!withInBounds(this.chart.mouseX, this.chart.mouseY, this.chart.chartAxisLayoutPanel.seriesClipRect)) {
677 | this.removeSecondaryElement();
678 | }
679 | };
680 |
681 | }
682 | public renderAnnotation(): void {
683 | this.content = this.candle(this.candleValue);
684 | if (this.secondaryValue) {
685 | this.content += this.compare(this.secondaryValue);
686 | }
687 | if (this.thirdValue) {
688 | this.content += this.compare1(this.thirdValue);
689 | }
690 | if (this.fourthValue) {
691 | this.content += this.compare2(this.fourthValue);
692 | }
693 | if (this.fifthValue) {
694 | this.content += this.compare3(this.fifthValue);
695 | }
696 | this.chart.indicators.map((indicator: TechnicalIndicatorModel) => {
697 | let type: string = indicator.type.toLocaleLowerCase();
698 | if (type === 'tma') {
699 | this.content += this.tma(this.tmaValue);
700 | } else if (type === 'bollingerbands') {
701 | this.content += this.bollinger(this.bollingerValue);
702 | } else if (type === 'rsi') {
703 | this.content += this.rsi(this.rsiValue);
704 | } else if (type === 'sma') {
705 | this.content += this.sma(this.smaValue);
706 | } else if (type === 'macd') {
707 | this.content += this.macd(this.macdValue);
708 | }
709 | });
710 | this.chart.setAnnotationValue(1, this.content);
711 | }
712 | public candle(value: string): string {
713 | this.candleValue = value.indexOf('$') > -1 ? value.split('$')[1] : value;
714 | return '' +
718 | '' +
720 | 'GOOG: $' + this.candleValue + '
';
721 | }
722 |
723 | public tma(value: string): string {
724 | this.tmaValue = value.indexOf(':') > -1 ? value.split(':')[1] : value;
725 | return '' +
729 | 'TMA:' + this.tmaValue + '' +
730 | '
';
731 | };
732 | public compare(value: string): string {
733 | this.secondaryValue = value;
734 | return '' +
738 | '' +
740 | 'AAPL: $' + value + '' +
741 | '
';
742 | };
743 |
744 | public compare1(value: string): string {
745 | this.thirdValue = value;
746 | return '' +
750 | '' +
752 | 'GOOGL: $' + value + '' +
753 | '
';
754 | };
755 |
756 |
757 | public compare2(value: string): string {
758 | this.fourthValue = value;
759 | return '' +
763 | '' +
765 | 'AMZN: $' + value + '' +
766 | '
';
767 | };
768 |
769 | public compare3(value: string): string {
770 | this.fifthValue = value;
771 | return '' +
775 | '' +
777 | 'TSLA: $' + value + '' +
778 | '
';
779 | };
780 | public bollinger(value: string): string {
781 | this.bollingerValue = value.indexOf(':') > -1 ? value.split(':')[1] : value;
782 | return '' +
786 | 'Bollinger: ' + this.bollingerValue + '' +
787 | '
';
788 | };
789 | public rsi(value: string): string {
790 | this.rsiValue = value.indexOf(':') > -1 ? value.split(':')[1] : value;
791 | return '' +
795 | 'RSI:' + this.rsiValue + '' +
796 | '
';
797 | };
798 | public sma(value: string): string {
799 | this.smaValue = value.indexOf(':') > -1 ? value.split(':')[1] : value;
800 | return '' +
804 | 'SMA:' + this.smaValue + '' +
805 | '
';
806 | };
807 | public macd(value: string): string {
808 | this.macdValue = value.indexOf(':') > -1 ? value.split(':')[1] : value;
809 | return '' +
813 | 'MACD:' + this.macdValue + '' +
814 | '
';
815 | };
816 |
817 | public setIndicatorAnnotation(value: string, type: string): string {
818 | if (value.indexOf('SignalLine') > -1) {
819 | value = value.replace('SignalLine', '')
820 | if (type === 'Tma') {
821 | this.tmaValue = value.replace(' : ', ': $');
822 | } else if (type === 'Macd') {
823 | value = value;
824 | this.macdValue = value;
825 | } else if (type === 'BollingerBands') {
826 | this.bollingerValue = value.replace(' : ', ': $');
827 | } else if (type === 'Rsi') {
828 | this.rsiValue = value.replace(' : ', ': $');
829 | } else {
830 | this.smaValue = value.replace(' : ', ': $');
831 | }
832 | }
833 | this.renderAnnotation();
834 | return this.content;
835 | }
836 |
837 | public getContent(value: string): string {
838 | let text: string[] = value.split('
'); let html: string = '';
839 | for (let i: number = 1; i < text.length; i++) {
840 | let value: string[] = text[i].split(':');
841 | if (i === text.length - 1) {
842 | html += '' + value[0] + ' | ' +
843 | Math.round(((+value[1].split('')[0].split('')[1]) / 10000000)) + 'B';
844 | } else {
845 | html += '' + value[0] + ' | $' +
846 | (+value[1].split(' ')[1].split('')[0]).toFixed(2) + ' | ';
847 | }
848 | }
849 | return html;
850 | };
851 |
852 | public removeSecondaryElement = (time?: number): void => {
853 | setTimeout(() => {
854 | if (getElement('annotation')) {
855 | remove(getElement('annotation'));
856 | }
857 | },
858 | // tslint:disable-next-line:align
859 | time === 0 ? this.chart.setAnnotationValue(0, '') : 2000
860 | );
861 | }
862 |
863 | public handleResize(): void {
864 | document.getElementById('stock-details').style.minHeight = 'auto';
865 | document.getElementById('stock-details').style.minHeight = document.documentElement.offsetHeight + 'px';
866 |
867 | let elements: NodeList = document.querySelectorAll('.e-popup-open');
868 | let length: number = elements.length;
869 | for (let i: number = 0; i < length; i++) {
870 | (elements[i] as HTMLElement).classList.remove('e-popup-open');
871 | (elements[i] as HTMLElement).classList.add('e-popup-close');
872 | }
873 | }
874 |
875 | @HostListener('window:resize', ['$event'])
876 | onResize(event: any): void {
877 | /** Document height alignment corrections for high resoultions screens */
878 | this.handleResize();
879 | }
880 | }
--------------------------------------------------------------------------------
/src/app/main.ts:
--------------------------------------------------------------------------------
1 | import { platformBrowser } from '@angular/platform-browser';
2 | import { AppModule } from './app.module';
3 | platformBrowser().bootstrapModule(AppModule);
--------------------------------------------------------------------------------
/src/app/menu/menu.component.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Stock Analysis Demo
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
17 |
18 |
19 |
20 | {{description}}
21 | {{listTitle}}
22 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/app/menu/menu.component.ts:
--------------------------------------------------------------------------------
1 | import { Component, Directive, ElementRef } from '@angular/core';
2 | import { HostListener } from '@angular/core';
3 | import { Browser, rippleEffect, isNullOrUndefined as isNOU, enableRipple } from '@syncfusion/ej2-base';
4 | import { ViewChild, AfterViewInit } from '@angular/core';
5 | import { DialogComponent } from '@syncfusion/ej2-ng-popups';
6 | import { EmitType } from '@syncfusion/ej2-base';
7 | enableRipple(true);
8 |
9 |
10 | @Component({
11 | selector: 'menu',
12 | templateUrl: 'menu.component.html'
13 | })
14 |
15 | export class MenuComponent {
16 | public menu: HTMLElement;
17 | public userName: string;
18 | public filterMenu: HTMLElement;
19 | public overlay: HTMLElement;
20 | // Define Dialog properties
21 | @ViewChild('confirmDialog')
22 | public confirmDialog: DialogComponent;
23 | public confirmHeader: string = 'About';
24 | public showCloseIcon: Boolean = false;
25 | public visible: Boolean = true;
26 | public hidden: Boolean = false;
27 | public confirmCloseIcon: Boolean = true;
28 | public position: object = { X: 'center', Y: 'center' };
29 | public target: string = '.stock-details';
30 | public confirmWidth: string = '50%';
31 | public animationSettings: Object = { effect: 'None' };
32 | public hide: any;
33 | public title: string;
34 | public listTitle: string;
35 | public description: string;
36 | public controlList: Object[];
37 | public confirmHeight: string = '400px';
38 |
39 | constructor(public eleRef: ElementRef) {
40 | /** Loads the user data in the profile from the sidebar */
41 | rippleEffect(document.body, { selector: '.ripple-element', rippleFlag: true });
42 | this.title = 'About this sample';
43 | this.listTitle = 'List of EJ2 components used in this sample';
44 | this.description = ' This demo helps to track and visualize the stock price of various sectors/industries over a specific' +
45 | ' period using Essential JS 2 components. Different types of technical indicators' +
46 | ' in chart help you to track the price movement based on the past prices, and the time periods ' +
47 | 'can be selected using range navigator. In addition to this, the DateRangePicker helps you to ' +
48 | 'select custom periods to check the stock price. Different types of series help to visualize the' +
49 | ' open, high, low, and close values of the stock. You can further explore the source code of this ' +
50 | 'application and use it as a reference for integrating Essential JS 2 components into your applications.';
51 |
52 | this.controlList = [
53 | { 'control': 'Chart', 'link': 'http://ej2.syncfusion.com/angular/documentation/chart/getting-started.html' },
54 | { 'control': 'Button', 'link': 'http://ej2.syncfusion.com/angular/documentation/button/getting-started.html' },
55 | { 'control': 'DropDownButton', 'link': 'http://ej2.syncfusion.com/angular/documentation/drop-down-button/getting-started.html' },
56 | { 'control': 'Toolbar', 'link': 'http://ej2.syncfusion.com/angular/documentation/toolbar/getting-started.html' },
57 | { 'control': 'Dialog', 'link': 'https://ej2.syncfusion.com/16.1.37/angular/documentation/dialog/getting-started.html' },
58 | { 'control': 'DateRangePicker', 'link': 'http://ej2.syncfusion.com/angular/documentation/daterangepicker/getting-started.html' },
59 | { 'control': 'RangeNavigator', 'link': 'https://ej2.syncfusion.com/angular/documentation/rangenavigator/getting-started.html ' },
60 | ];
61 | }
62 |
63 | public ngAfterViewInit(): void {
64 | /** Holds the sidebar elements for later use */
65 | this.menu = this.eleRef.nativeElement.querySelector('#sidebar-wrapper');
66 | this.overlay = this.eleRef.nativeElement.querySelector('#overlay');
67 | }
68 |
69 |
70 | /** Toggles the sidebar open and close actions - for small resoultion */
71 | public toggleMenu(): void {
72 | this.confirmDialog.show();
73 | this.dialogOpen();
74 | }
75 |
76 | public confirmDlgBtnClick: EmitType |