Added the sample into the repository
This commit is contained in:
Коммит
af5eb5ef8f
|
@ -0,0 +1,60 @@
|
|||
{
|
||||
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
|
||||
"project": {
|
||||
"name": "ej2-ng-loan-calculator"
|
||||
},
|
||||
"apps": [
|
||||
{
|
||||
"root": "src",
|
||||
"outDir": "dist",
|
||||
"assets": [
|
||||
"assets",
|
||||
"favicon.ico"
|
||||
],
|
||||
"index": "index.html",
|
||||
"main": "main.ts",
|
||||
"polyfills": "polyfills.ts",
|
||||
"test": "test.ts",
|
||||
"tsconfig": "tsconfig.app.json",
|
||||
"testTsconfig": "tsconfig.spec.json",
|
||||
"prefix": "app",
|
||||
"styles": [
|
||||
"styles.css"
|
||||
],
|
||||
"scripts": [],
|
||||
"environmentSource": "environments/environment.ts",
|
||||
"environments": {
|
||||
"dev": "environments/environment.ts",
|
||||
"prod": "environments/environment.prod.ts"
|
||||
}
|
||||
}
|
||||
],
|
||||
"e2e": {
|
||||
"protractor": {
|
||||
"config": "./protractor.conf.js"
|
||||
}
|
||||
},
|
||||
"lint": [
|
||||
{
|
||||
"project": "src/tsconfig.app.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "src/tsconfig.spec.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
},
|
||||
{
|
||||
"project": "e2e/tsconfig.e2e.json",
|
||||
"exclude": "**/node_modules/**"
|
||||
}
|
||||
],
|
||||
"test": {
|
||||
"karma": {
|
||||
"config": "./karma.conf.js"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"styleExt": "css",
|
||||
"component": {}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
dist/
|
||||
*d.ts
|
||||
*.map
|
||||
.vscode/
|
||||
src/**/*.js
|
||||
*.ngstyle.ts
|
||||
src/**/*.map
|
||||
node_modules/
|
||||
npm-debug.log
|
||||
*ngfactory.ts
|
||||
*metadata.json
|
||||
*ngsummary.json
|
||||
src/assets/index.css
|
||||
src/assets/*.css
|
||||
*.css
|
|
@ -0,0 +1,27 @@
|
|||
# Essential JS 2 for Angular - Loan Calculator
|
||||
|
||||
This Loan calculator demo application showcases the usage of several Essential JS 2 components in a real world application scenario. You can use this application to Calculates your loan payment based on your loan amount, interest and term.
|
||||
|
||||
## Deployment
|
||||
|
||||
### Install
|
||||
|
||||
To install all dependent packages, use the below command
|
||||
|
||||
```
|
||||
npm install
|
||||
```
|
||||
|
||||
### Run
|
||||
|
||||
To run the sample, use the below command
|
||||
|
||||
```
|
||||
ng serve
|
||||
```
|
||||
|
||||
## Demo
|
||||
|
||||
#### <a href="https://ej2.syncfusion.com/showcase/angular/loancalculator/" target="_blank">https://ej2.syncfusion.com/showcase/angular/loancalculator/</a>
|
||||
|
||||
Check all the showcase samples from <a href="https://ej2.syncfusion.com/home/angular.html" target="_blank">here</a>.
|
|
@ -0,0 +1,10 @@
|
|||
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.
|
||||
|
||||
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.
|
||||
|
||||
Customers who do not qualify for the community license can contact sales@syncfusion.com for commercial licensing options.
|
||||
|
||||
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.
|
||||
|
||||
The Syncfusion license that contains the terms and conditions can be found at
|
||||
https://www.syncfusion.com/content/downloads/syncfusion_license.pdf
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"name": "@syncfusion/ej2-ng-loan-calculator",
|
||||
"version": "0.0.1",
|
||||
"description": "Essential JS 2 for Angular - Loan Calculator application",
|
||||
"author": "Syncfusion Inc.",
|
||||
"license": "SEE LICENSE IN license",
|
||||
"dependencies": {
|
||||
"rxjs": "^5.0.1",
|
||||
"tslint": "4.0.2",
|
||||
"zone.js": "^0.8.4",
|
||||
"core-js": "^2.4.1",
|
||||
"systemjs": "^0.19.40",
|
||||
"gulp-print": "^2.0.1",
|
||||
"gulp-tslint": "^7.0.1",
|
||||
"browser-sync": "2.11.2",
|
||||
"gulp-sass-lint": "^1.1.1",
|
||||
"reflect-metadata": "^0.1.9",
|
||||
"tslint-microsoft-contrib": "^4.0.0",
|
||||
"@angular/core": "~5.0.0",
|
||||
"@angular/http": "~5.0.0",
|
||||
"@angular/forms": "~5.0.0",
|
||||
"@angular/router": "^5.0.0",
|
||||
"@angular/common": "~5.0.0",
|
||||
"@angular-devkit/core": "^0.4.5",
|
||||
"@angular/upgrade": "^5.0.0",
|
||||
"@angular/compiler": "~5.0.0",
|
||||
"@angular/platform-browser": "~5.0.0",
|
||||
"@angular/platform-browser-dynamic": "~5.0.0",
|
||||
"@syncfusion/ej2-ng-base": "*",
|
||||
"@syncfusion/ej2-ng-buttons": "*",
|
||||
"@syncfusion/ej2-ng-grids": "*",
|
||||
"@syncfusion/ej2-ng-inputs": "*",
|
||||
"@syncfusion/ej2-ng-charts": "*",
|
||||
"@syncfusion/ej2-ng-calendars": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular/cli": "1.5.6",
|
||||
"@angular/compiler-cli": "5.0.0",
|
||||
"@angular/platform-server": "5.0.0",
|
||||
"@types/jasmine": "^2.2.29",
|
||||
"@types/requirejs": "^2.1.26",
|
||||
"@types/node": "^6.0.46",
|
||||
"gulp": "^3.9.0",
|
||||
"webpack": "2.5.1",
|
||||
"shelljs": "^0.7.0",
|
||||
"typescript": "~2.4.2",
|
||||
"gulp-sass": "^3.1.0",
|
||||
"gulp-clean": "^0.3.2",
|
||||
"run-sequence": "2.2.0",
|
||||
"webpack-stream": "^3.2.0",
|
||||
"karma-systemjs": "^0.16.0",
|
||||
"gulp-typescript": "^2.13.0",
|
||||
"es6-module-loader": "^0.17.11",
|
||||
"systemjs-plugin-babel": "0.0.17"
|
||||
},
|
||||
"keywords": [
|
||||
"ej2",
|
||||
"samples",
|
||||
"loan-calculator",
|
||||
"syncfusion",
|
||||
"ej2-samples",
|
||||
"ej2-ng-loan-calculator",
|
||||
"ej2-showcase-samples",
|
||||
"syncfusion-samples",
|
||||
"syncfusion-loan-calculator"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "npm run scripts && gulp styles && gulp bundle",
|
||||
"scripts": "ngc -p tsconfig-aot.json",
|
||||
"bundle": "gulp bundle",
|
||||
"ci-publish": "gulp publish-samples"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
<h2 class="header-style">Loan Calculator</h2>
|
||||
<div class="container main-content" id="content">
|
||||
<home-section #homeSection></home-section>
|
||||
<statement-section #statementSection></statement-section>
|
||||
<chart-section #chartSection></chart-section>
|
||||
<grid-section #gridSection></grid-section>
|
||||
</div>
|
|
@ -0,0 +1,29 @@
|
|||
import { Component, OnInit, ViewChild } from '@angular/core';
|
||||
import { GridAppComponent } from './grid-app/grid-app.component';
|
||||
import { BarChartComponent } from './bar-chart/bar-chart.component';
|
||||
import { DataService } from './data-service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.css']
|
||||
})
|
||||
export class AppComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Home page */
|
||||
constructor(private data: DataService) {
|
||||
}
|
||||
|
||||
@ViewChild('chartSection')
|
||||
public chart: BarChartComponent;
|
||||
@ViewChild('gridSection')
|
||||
public grid: GridAppComponent;
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
this.data.grid = this.grid;
|
||||
this.data.chart = this.chart;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { NgModule } from '@angular/core';
|
||||
|
||||
import { NumericTextBoxModule, SliderModule } from '@syncfusion/ej2-ng-inputs';
|
||||
import { RadioButtonModule } from '@syncfusion/ej2-ng-buttons';
|
||||
import { AccumulationChartModule, ChartModule } from '@syncfusion/ej2-ng-charts';
|
||||
import { DatePickerModule } from '@syncfusion/ej2-ng-calendars';
|
||||
import { GridModule } from '@syncfusion/ej2-ng-grids';
|
||||
|
||||
import { AppComponent } from './app.component';
|
||||
import { HomeComponent } from './home/home.component';
|
||||
import { InputComponent } from './home/input/input.component';
|
||||
import { DashboardComponent } from './home/dashboard/dashboard.component';
|
||||
import { StatementComponent } from './statement/statement.component';
|
||||
import { BarChartComponent } from './bar-chart/bar-chart.component';
|
||||
import { GridAppComponent } from './grid-app/grid-app.component';
|
||||
|
||||
import { DataService } from './data-service';
|
||||
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
AppComponent,
|
||||
HomeComponent,
|
||||
InputComponent,
|
||||
DashboardComponent,
|
||||
StatementComponent,
|
||||
BarChartComponent,
|
||||
GridAppComponent
|
||||
],
|
||||
imports: [
|
||||
BrowserModule,
|
||||
NumericTextBoxModule,
|
||||
SliderModule,
|
||||
RadioButtonModule,
|
||||
AccumulationChartModule,
|
||||
DatePickerModule,
|
||||
ChartModule,
|
||||
GridModule
|
||||
],
|
||||
providers: [DataService],
|
||||
bootstrap: [AppComponent]
|
||||
})
|
||||
export class AppModule { }
|
|
@ -0,0 +1,8 @@
|
|||
<div class="row top-space loan-content max-content">
|
||||
<h6 class="center-heading">Amortization Chart</h6>
|
||||
<div class="col-lg-12 graph-container">
|
||||
<ejs-chart #paymentGraph style='display:block; height: 100%' id='paymentGraph' [primaryXAxis]='primaryXAxis' [primaryYAxis]='primaryYAxis' [axes]='axes' [tooltip]='tooltip' [chartArea]="chartArea" enableSideBySidePlacement='false'
|
||||
[height]='height' useGroupingSeparator='true' [palettes]='palettes' [legendSettings]='legendSettings' border='#27304c' background="#27304c" [series]="barSeries" (chartMouseUp)='onChartMouseUp($event)' (axisLabelRender)='axisLabelRender($event)'>
|
||||
</ejs-chart>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,216 @@
|
|||
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
|
||||
import { AccumulationChart, AccumulationLegend, PieSeries, AccumulationTooltip,
|
||||
AccumulationDataLabel, IAxisLabelRenderEventArgs,
|
||||
Chart, LineSeries, DateTime, Legend, Tooltip, IAccLoadedEventArgs, AccumulationTheme, IAccPointRenderEventArgs,
|
||||
StackingColumnSeries, DataLabel, ColumnSeries, IMouseEventArgs, Series
|
||||
} from '@syncfusion/ej2-charts';
|
||||
import { DataService } from '../data-service';
|
||||
|
||||
Chart.Inject(LineSeries, StackingColumnSeries, DataLabel, ColumnSeries, DateTime, Legend, Tooltip);
|
||||
|
||||
|
||||
@Component({
|
||||
selector: 'chart-section',
|
||||
templateUrl: './bar-chart.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class BarChartComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Chart page */
|
||||
constructor(private data: DataService) {
|
||||
}
|
||||
|
||||
@ViewChild('paymentGraph')
|
||||
public chartObj: Chart;
|
||||
|
||||
// Chart component binding properties
|
||||
public primaryXAxis: Object = {
|
||||
title: 'Years',
|
||||
valueType: 'DateTime',
|
||||
labelFormat: 'y',
|
||||
intervalType: 'Years',
|
||||
majorGridLines: { width: 0 },
|
||||
minorGridLines: { width: 0 },
|
||||
majorTickLines: { width: 0 },
|
||||
minorTickLines: { width: 0 },
|
||||
lineStyle: { width: 1, dashArray: '2', color: 'rgba(255,255,255,0.2)' },
|
||||
labelStyle: {
|
||||
color: '#989CA9',
|
||||
fontFamily: 'Roboto',
|
||||
fontWeight: '400',
|
||||
size: '12px',
|
||||
},
|
||||
titleStyle: {
|
||||
color: '#FFFFFF',
|
||||
fontFamily: 'Raleway, sans-serif',
|
||||
fontWeight: '600',
|
||||
opacity: 0.62,
|
||||
size: '16px',
|
||||
}
|
||||
};
|
||||
public primaryYAxis: Object = {
|
||||
title: 'Balance',
|
||||
labelFormat: 'c0',
|
||||
rangePadding: 'None',
|
||||
lineStyle: { width: 0 },
|
||||
majorTickLines: { width: 0 },
|
||||
majorGridLines: { width: 1, dashArray: '2', color: 'rgba(255,255,255,0.2)' },
|
||||
minorGridLines: { width: 0 },
|
||||
minorTickLines: { width: 0 },
|
||||
labelStyle: {
|
||||
color: '#989CA9',
|
||||
fontFamily: 'Roboto',
|
||||
fontWeight: '400',
|
||||
size: '16px',
|
||||
},
|
||||
titleStyle: {
|
||||
color: '#FFFFFF',
|
||||
fontFamily: 'Raleway, sans-serif',
|
||||
fontWeight: '600',
|
||||
opacity: 0.62,
|
||||
size: '16px',
|
||||
}
|
||||
};
|
||||
public axes: Object[] = [
|
||||
{
|
||||
majorGridLines: { width: 0 },
|
||||
minorGridLines: { width: 0 },
|
||||
majorTickLines: { width: 0 },
|
||||
minorTickLines: { width: 0 },
|
||||
rowIndex: 0, opposedPosition: true,
|
||||
lineStyle: { width: 0 },
|
||||
name: 'yAxis',
|
||||
title: 'Payment',
|
||||
labelFormat: 'c0',
|
||||
labelStyle: {
|
||||
color: '#989CA9',
|
||||
fontFamily: 'Roboto',
|
||||
fontWeight: '400',
|
||||
size: '16px',
|
||||
},
|
||||
titleStyle: {
|
||||
color: '#FFFFFF',
|
||||
fontFamily: 'Raleway, sans-serif',
|
||||
fontWeight: '600',
|
||||
opacity: 0.62,
|
||||
size: '16px',
|
||||
}
|
||||
}
|
||||
];
|
||||
public tooltip: Object = {
|
||||
enable: true, shared: true,
|
||||
format: '${series.name} : ${point.y}',
|
||||
header: '<b>${point.x}<b>',
|
||||
fill: '#FFFFFF',
|
||||
opacity: 1,
|
||||
textStyle: {
|
||||
color: '#555555',
|
||||
fontFamily: 'Roboto',
|
||||
size: '12px',
|
||||
fontWeight: '400',
|
||||
},
|
||||
};
|
||||
public palettes: string[] = ['#FB6589', '#3AC8DC', '#FFFFFF'];
|
||||
public legendSettings: Object = {
|
||||
textStyle: {
|
||||
color: '#FFFFFF',
|
||||
fontFamily: 'Raleway, sans-serif',
|
||||
fontWeight: '600',
|
||||
opacity: 0.62,
|
||||
size: '16px',
|
||||
}
|
||||
};
|
||||
public chartArea: Object = {
|
||||
border: {
|
||||
width: 0
|
||||
}
|
||||
};
|
||||
public height: string = '500px';
|
||||
public yearWiseData: Object[] = this.data.yearWiseData;
|
||||
public barSeries: Object[] = [
|
||||
// {
|
||||
// type: 'Column',
|
||||
// columnWidth: 0.7,
|
||||
// dataSource: this.yearWiseData,
|
||||
// xName: 'yearN', width: 2, marker: {
|
||||
// visible: true,
|
||||
// width: 10,
|
||||
// height: 10,
|
||||
// },
|
||||
// yName: 'yearTotal', name: 'Total Amount Paid', yAxisName: 'yAxis', visible: false
|
||||
// },
|
||||
{
|
||||
type: 'StackingColumn',
|
||||
columnWidth: 0.425,
|
||||
dataSource: this.yearWiseData,
|
||||
xName: 'yearN', width: 2, marker: {
|
||||
visible: true,
|
||||
width: 10,
|
||||
height: 10
|
||||
},
|
||||
yName: 'yearPrincipal', name: 'Principal Paid', yAxisName: 'yAxis'
|
||||
},
|
||||
{
|
||||
type: 'StackingColumn',
|
||||
columnWidth: 0.425,
|
||||
dataSource: this.yearWiseData,
|
||||
xName: 'yearN', width: 2, marker: {
|
||||
visible: true,
|
||||
width: 10,
|
||||
height: 10
|
||||
},
|
||||
yName: 'yearInterest', name: 'Interest Paid', yAxisName: 'yAxis'
|
||||
},
|
||||
{
|
||||
type: 'Line',
|
||||
dataSource: this.yearWiseData,
|
||||
xName: 'yearN', width: 2, marker: {
|
||||
visible: true,
|
||||
width: 10,
|
||||
height: 10,
|
||||
fill: '#60448D',
|
||||
},
|
||||
yName: 'endingBalance', name: 'Balance',
|
||||
}
|
||||
];
|
||||
|
||||
public onChartMouseUp(args: IMouseEventArgs): void {
|
||||
if (args.target.indexOf('_chart_legend_') > -1 && (args.target.indexOf('shape') > -1 || args.target.indexOf('text') > -1)) {
|
||||
let id: string[] = [args.target];
|
||||
id = (args.target.indexOf('shape') > -1) ? id[0].split('chart_legend_shape_') : id[0].split('chart_legend_text_');
|
||||
let index: number = parseInt(id[1], 10);
|
||||
let series: Series = this.chartObj.visibleSeries[index];
|
||||
let yName: string = series.yAxisName;
|
||||
let ySName: string;
|
||||
let visibility: boolean = false;
|
||||
if (series.visible) {
|
||||
for (let i: number = 0, len: number = this.chartObj.series.length; i < len; i++) {
|
||||
ySName = this.chartObj.series[i].yAxisName;
|
||||
if (len === 1 || (this.chartObj.series[i].visible &&
|
||||
(<Series>this.chartObj.series[i]).index !== series.index && yName === ySName)) {
|
||||
visibility = true;
|
||||
}
|
||||
}
|
||||
series.yAxis.visible = visibility;
|
||||
} else {
|
||||
series.yAxis.visible = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public axisLabelRender(args: IAxisLabelRenderEventArgs): void {
|
||||
if (window.innerWidth < 576) {
|
||||
if (args.axis.name === 'primaryYAxis' || args.axis.name === 'yAxis') {
|
||||
let value: number = Number(args.value) / 1000;
|
||||
args.text = value === 0 ? String(value) : (String(value) + 'K');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,253 @@
|
|||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { Internationalization } from '@syncfusion/ej2-base';
|
||||
import {
|
||||
AccumulationChart, AccumulationLegend, PieSeries, AccumulationTooltip,
|
||||
AccumulationDataLabel, SeriesModel, Chart, LineSeries, DateTime, Legend, Tooltip, IAccLoadedEventArgs, AccumulationTheme, IAccPointRenderEventArgs,
|
||||
StackingColumnSeries, Crosshair, DataLabel, ColumnSeries, IMouseEventArgs, Series
|
||||
} from '@syncfusion/ej2-charts';
|
||||
import { Grid, DetailRow } from '@syncfusion/ej2-grids';
|
||||
|
||||
import { GridAppComponent } from './grid-app/grid-app.component';
|
||||
import { BarChartComponent } from './bar-chart/bar-chart.component';
|
||||
import { DashboardComponent } from './home/dashboard/dashboard.component';
|
||||
|
||||
@Injectable()
|
||||
|
||||
export class DataService {
|
||||
constructor() {
|
||||
this.initialize();
|
||||
}
|
||||
|
||||
public emi: number = 0;
|
||||
public princ: number = 0;
|
||||
public tent: number = 0;
|
||||
public principalValue: number = 300000;
|
||||
public interestValue: number = 5.5;
|
||||
public loanValue: number = 15;
|
||||
public dateValue: Date = new Date();
|
||||
public yearWiseData: Object[] = [];
|
||||
public emiAmt: string = '';
|
||||
public principalAmt: string = '';
|
||||
public interestAmt: string = '';
|
||||
public totalAmt: string = '';
|
||||
public dashboard: DashboardComponent;
|
||||
|
||||
public yearTenure: boolean = true;
|
||||
public chart: BarChartComponent;
|
||||
public grid: GridAppComponent;
|
||||
public totalPrincipalYear: number = 0;
|
||||
public totalInterestYear: number = 0;
|
||||
public inter: number;
|
||||
public dataUnits: [Object] = <[Object]>[];
|
||||
public dateObj: Date = new Date();
|
||||
public totalInterest: number = 0;
|
||||
public totalAmount: number = 0;
|
||||
public totalPrincipal: number = 0;
|
||||
public endBalance: number;
|
||||
public beginBalance: number;
|
||||
public yearTotal: number = 0;
|
||||
public monthNames: [string] = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sept', 'Oct', 'Nov', 'Dec'];
|
||||
public intl: Internationalization = new Internationalization();
|
||||
|
||||
public getCurrencyVal(value: number): string {
|
||||
return this.intl.formatNumber(value, { format: 'C0' });
|
||||
}
|
||||
|
||||
public refreshUI1(): void {
|
||||
this.setInitValues();
|
||||
let interestPercent: number = parseFloat((Math.round((this.emi * this.tent) - this.princ) / Math.round((this.emi * this.tent)) * 100).toFixed(2));
|
||||
this.dashboard.pieChart.series = [
|
||||
{
|
||||
dataSource: [
|
||||
{
|
||||
'x': 'Principal Amount',
|
||||
y: this.princ,
|
||||
text: parseFloat(((this.princ) / Math.round((this.emi * this.tent)) * 100).toFixed(2)) + '%'
|
||||
},
|
||||
{
|
||||
'x': 'Interest Amount',
|
||||
y: (this.tent ? Math.round((this.emi * this.tent) - this.princ) : 0),
|
||||
text: interestPercent ? interestPercent + '%' : ' '
|
||||
}
|
||||
],
|
||||
radius: '80%', xName: 'x',
|
||||
animation: { enable: true },
|
||||
yName: 'y',
|
||||
startAngle: 290,
|
||||
endAngle: 290, innerRadius: '60%',
|
||||
explode: true, explodeOffset: '10%', explodeIndex: 3
|
||||
}
|
||||
];
|
||||
this.dashboard.pieChart.refresh();
|
||||
this.updateTotalAmt();
|
||||
}
|
||||
|
||||
public refreshUI(): void {
|
||||
this.refreshUI1();
|
||||
this.calRangeValues();
|
||||
this.renderControls();
|
||||
this.chart.chartObj.refresh();
|
||||
}
|
||||
|
||||
public updateTotalAmt(): void {
|
||||
this.dashboard.emiAmt = this.emiAmt;
|
||||
this.dashboard.interestAmt = this.interestAmt;
|
||||
this.dashboard.totalAmt = this.totalAmt;
|
||||
this.dashboard.principalAmt = this.principalAmt;
|
||||
}
|
||||
|
||||
public renderControls(): void {
|
||||
this.grid.yearWiseData = this.yearWiseData;
|
||||
this.grid.childGrid = {
|
||||
created: this.grid.childCreated,
|
||||
dataBound: this.grid.childDataBound,
|
||||
queryString: 'year',
|
||||
columns: [
|
||||
{ field: 'month', headerText: 'Month', textAlign: 'center', minWidth: '80px' },
|
||||
{
|
||||
field: 'emi', format: 'C0',
|
||||
hideAtMedia: '(min-width: 480px)', headerText: 'Payment', minWidth: '80px', textAlign: 'center'
|
||||
},
|
||||
{ field: 'pricipalPaid', format: 'C0', headerText: 'Pricipal Paid', minWidth: '80px', textAlign: 'center' },
|
||||
{ field: 'interest', format: 'C0', headerText: 'Interest Paid', minWidth: '80px', textAlign: 'center' },
|
||||
{ field: 'endingBalance', format: 'C0', headerText: 'Balance', minWidth: '80px', textAlign: 'center' }
|
||||
],
|
||||
dataSource: this.dataUnits
|
||||
};
|
||||
this.chart.chartObj.series = [
|
||||
// {
|
||||
// type: 'Column',
|
||||
// columnWidth: 0.7,
|
||||
// dataSource: this.yearWiseData,
|
||||
// xName: 'yearN', width: 2, marker: {
|
||||
// visible: true,
|
||||
// width: 10,
|
||||
// height: 10,
|
||||
// },
|
||||
// yName: 'yearTotal', name: 'Total Amount Paid', yAxisName: 'yAxis',
|
||||
// },
|
||||
{
|
||||
type: 'StackingColumn',
|
||||
columnWidth: 0.425,
|
||||
dataSource: this.yearWiseData,
|
||||
xName: 'yearN', width: 2, marker: {
|
||||
visible: true,
|
||||
width: 10,
|
||||
height: 10
|
||||
},
|
||||
yName: 'yearPrincipal', name: 'Principal Paid', yAxisName: 'yAxis'
|
||||
},
|
||||
{
|
||||
type: 'StackingColumn',
|
||||
columnWidth: 0.425,
|
||||
dataSource: this.yearWiseData,
|
||||
xName: 'yearN', width: 2, marker: {
|
||||
visible: true,
|
||||
width: 10,
|
||||
height: 10
|
||||
},
|
||||
yName: 'yearInterest', name: 'Interest Paid', yAxisName: 'yAxis'
|
||||
},
|
||||
{
|
||||
type: 'Line',
|
||||
dataSource: this.yearWiseData,
|
||||
xName: 'yearN', width: 2, marker: {
|
||||
visible: true,
|
||||
width: 10,
|
||||
height: 10,
|
||||
fill: '#60448D',
|
||||
},
|
||||
yName: 'endingBalance', name: 'Balance',
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
public getInterest(): number {
|
||||
return this.interestValue ? parseFloat('' + this.interestValue / 12 / 100) : 0;
|
||||
}
|
||||
|
||||
public calculateEMI(): number {
|
||||
let interestValue: number = this.getInterest();
|
||||
let tent: number = this.yearTenure ? (this.loanValue * 12) : this.loanValue;
|
||||
if (interestValue) {
|
||||
return this.principalValue * interestValue *
|
||||
(Math.pow((1 + interestValue), tent)) / ((Math.pow((1 + interestValue), tent)) - 1);
|
||||
|
||||
}
|
||||
return this.principalValue / tent;
|
||||
}
|
||||
|
||||
public setInitValues(): void {
|
||||
this.emi = this.calculateEMI();
|
||||
this.princ = this.principalValue;
|
||||
this.tent = this.yearTenure ? (this.loanValue * 12) : this.loanValue;
|
||||
this.dataUnits = <[Object]>[];
|
||||
this.yearWiseData = <[Object]>[];
|
||||
this.dateObj = new Date(this.dateValue.getTime());
|
||||
this.totalInterest = 0;
|
||||
this.totalAmount = 0;
|
||||
this.totalPrincipal = 0;
|
||||
this.totalPrincipalYear = 0;
|
||||
this.totalInterestYear = 0;
|
||||
this.emiAmt = this.getCurrencyVal(this.tent ? Math.round(this.emi) : 0);
|
||||
this.interestAmt = this.getCurrencyVal(this.tent ? Math.round((this.emi * this.tent) - this.princ) : 0);
|
||||
this.totalAmt = this.getCurrencyVal(this.tent ? Math.round((this.emi * this.tent)) : 0);
|
||||
this.principalAmt = this.getCurrencyVal(this.princ);
|
||||
}
|
||||
|
||||
public calRangeValues(): void {
|
||||
for (let i: number = 0; i < this.tent; i++) {
|
||||
this.inter = this.getInterest ? (this.princ * this.getInterest()) : this.princ;
|
||||
this.totalInterest += this.inter;
|
||||
this.totalAmount += this.emi;
|
||||
this.totalPrincipal += parseFloat((this.emi - this.inter).toFixed(2));
|
||||
this.endBalance = this.princ - (this.emi - this.inter);
|
||||
this.yearTotal += this.emi;
|
||||
this.totalPrincipalYear += parseFloat((this.emi - this.inter).toFixed(2));
|
||||
this.totalInterestYear += this.inter;
|
||||
this.dataUnits.push({
|
||||
month: this.monthNames[this.dateObj.getMonth()],
|
||||
index: (i + 1),
|
||||
totalInterest: Math.round(this.totalInterest),
|
||||
totalAmount: this.totalAmount,
|
||||
emi: Math.round(this.emi),
|
||||
year: this.dateObj.getFullYear(),
|
||||
beginningBalance: Math.round(this.princ),
|
||||
interest: Math.round(this.inter),
|
||||
pricipalPaid: Math.round((this.emi - this.inter)),
|
||||
endingBalance: Math.round(this.endBalance)
|
||||
});
|
||||
if (i === 0 || this.dateObj.getMonth() === 0) {
|
||||
this.beginBalance = this.princ;
|
||||
}
|
||||
if (this.dateObj.getMonth() === 11 || (i === this.tent - 1)) {
|
||||
this.yearWiseData.push({
|
||||
beginningBalance: Math.round(this.beginBalance),
|
||||
totalInterest: Math.round(this.totalInterest),
|
||||
totalPrincipal: Math.round(this.totalPrincipal),
|
||||
totalAmount: Math.round(this.totalAmount),
|
||||
yearTotal: Math.round(this.yearTotal),
|
||||
endingBalance: Math.round(this.endBalance),
|
||||
yearN: new Date(this.dateObj.getFullYear(), 0, 1),
|
||||
year: this.dateObj.getFullYear(),
|
||||
yearPrincipal: this.totalPrincipalYear,
|
||||
yearInterest: this.totalInterestYear
|
||||
});
|
||||
this.yearTotal = 0;
|
||||
this.totalPrincipalYear = 0;
|
||||
this.totalInterestYear = 0;
|
||||
}
|
||||
this.princ = this.endBalance;
|
||||
if (i < this.tent - 1) {
|
||||
this.dateObj.setMonth(this.dateObj.getMonth() + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public initialize(): void {
|
||||
this.setInitValues();
|
||||
this.calRangeValues();
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
<div class="row top-space loan-content max-content">
|
||||
<h6 class="center-heading">Amortization Schedule</h6>
|
||||
<ejs-grid #scheduleGrid id='scheduleGrid' [dataSource]='yearWiseData' [childGrid]='childGrid' width="100%" (click)='onClick($event)'>
|
||||
<e-columns>
|
||||
<e-column field='year' headerText='Year' minWidth='80px' textAlign="center">
|
||||
<ng-template #template let-data>
|
||||
<div class="e-icons e-icon-grightarrow e-row-toggle"></div>
|
||||
<span style="padding-left: 12px;">{{data.year}}</span>
|
||||
</ng-template>
|
||||
</e-column>
|
||||
<e-column field='yearTotal' headerText='Payment' minWidth='80px' textAlign="center" [format]="format" [hideAtMedia]="paymentHideAtMedia"></e-column>
|
||||
<e-column field='yearPrincipal' headerText='Principal Paid' minWidth='80px' textAlign="center" [format]="format"></e-column>
|
||||
<e-column field='yearInterest' headerText='Interest Paid' minWidth='80px' textAlign="center" [format]="format"></e-column>
|
||||
<e-column field='endingBalance' headerText='Balance' minWidth='80px' textAlign="center" [format]="format"></e-column>
|
||||
</e-columns>
|
||||
</ejs-grid>
|
||||
</div>
|
|
@ -0,0 +1,74 @@
|
|||
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
|
||||
import { closest } from '@syncfusion/ej2-base';
|
||||
import { GridComponent } from '@syncfusion/ej2-ng-grids';
|
||||
import { Grid, DetailRow, DetailDataBoundEventArgs } from '@syncfusion/ej2-grids';
|
||||
import { DataService } from '../data-service';
|
||||
Grid.Inject(DetailRow);
|
||||
|
||||
@Component({
|
||||
selector: 'grid-section',
|
||||
templateUrl: './grid-app.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class GridAppComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Grid page */
|
||||
constructor(private data: DataService) {
|
||||
}
|
||||
|
||||
@ViewChild('scheduleGrid')
|
||||
public grid: Grid;
|
||||
|
||||
public yearWiseData: Object[] = this.data.yearWiseData;
|
||||
public childGrid: Object = {
|
||||
created: this.childCreated,
|
||||
dataBound: this.childDataBound,
|
||||
queryString: 'year',
|
||||
columns: [
|
||||
{ field: 'month', headerText: 'Month', textAlign: 'center', minWidth: '80px' },
|
||||
{
|
||||
field: 'emi', format: 'C0',
|
||||
hideAtMedia: '(min-width: 480px)', headerText: 'Payment', minWidth: '80px', textAlign: 'center'
|
||||
},
|
||||
{ field: 'pricipalPaid', format: 'C0', headerText: 'Pricipal Paid', minWidth: '80px', textAlign: 'center' },
|
||||
{ field: 'interest', format: 'C0', headerText: 'Interest Paid', minWidth: '80px', textAlign: 'center' },
|
||||
{ field: 'endingBalance', format: 'C0', headerText: 'Balance', minWidth: '80px', textAlign: 'center' }
|
||||
],
|
||||
dataSource: this.data.dataUnits
|
||||
};
|
||||
public format: string = 'c0';
|
||||
public balanceHideAtMedia: string = '(min-width: 750px)';
|
||||
public paymentHideAtMedia: string = '(min-width: 480px)';
|
||||
|
||||
/* tslint:disable */
|
||||
public childCreated(args: Object): void {
|
||||
// (this.getHeaderContent() as HTMLElement).style.display = 'none';
|
||||
// this.element.style.display = 'none';
|
||||
}
|
||||
public childDataBound(args: Object): void {
|
||||
// this.element.style.display = '';
|
||||
}
|
||||
/* tslint:enable */
|
||||
public onClick(args: MouseEvent): void {
|
||||
let target: Element = args.target as Element;
|
||||
if (target.classList.contains('e-row-toggle') || target.parentElement.querySelector('.e-row-toggle')) {
|
||||
target = target.parentElement.querySelector('.e-row-toggle') ? target.parentElement.querySelector('.e-row-toggle') : target;
|
||||
if (target.classList.contains('e-icon-gdownarrow')) {
|
||||
target.classList.remove('e-icon-gdownarrow');
|
||||
target.classList.add('e-icon-grightarrow');
|
||||
this.grid.detailRowModule.collapse(parseInt((closest(target, 'tr') as HTMLElement).getAttribute('aria-rowindex'), 10));
|
||||
} else {
|
||||
target.classList.remove('e-icon-grightarrow');
|
||||
target.classList.add('e-icon-gdownarrow');
|
||||
this.grid.detailRowModule.expand(parseInt((closest(target, 'tr') as HTMLElement).getAttribute('aria-rowindex'), 10));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
<div class="col-lg-12 emi-content">
|
||||
<div>
|
||||
<h6 class="emi-header">Break-up of Total Payment</h6>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-lg-7">
|
||||
<ejs-accumulationchart style="display: block;" #pieChart id="payment_pieChart" enableSmartLabels="true" [legendSettings]="legendSettings" height="365px" [width]="width" [tooltip]="tooltip" border="#27304c" background="#27304c" [series]='pieSeries' (load)='onLoad($event)' (pointRender)="pointRender($event)"></ejs-accumulationchart>
|
||||
</div>
|
||||
<div class="col-lg-5 pie-content" id="pieContent">
|
||||
<div>
|
||||
<p><span class="pie-icon pie-principal"></span>Principal Amount</p>
|
||||
<h5 id="loan_principal">{{principalAmt}}</h5>
|
||||
</div>
|
||||
<div>
|
||||
<p><span class="pie-icon pie-interest"></span>Total Interest</p>
|
||||
<h5 id="loan_interest">{{interestAmt}}</h5>
|
||||
</div>
|
||||
<div class="pie-total">
|
||||
<span>
|
||||
<p>Total Payment</p>
|
||||
<p>(Principal + Interest)</p>
|
||||
</span>
|
||||
<h5 id="loan_total_payment">{{totalAmt}}</h5>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h6 class="emi-footer">Your Monthly Payment</h6>
|
||||
<h1 id="loan_emi">{{emiAmt}}</h1>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<svg style="height: 0; display: block; width: 0;">
|
||||
<defs>
|
||||
<linearGradient id="principal_svg" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0"></stop>
|
||||
<stop offset="1"></stop>
|
||||
</linearGradient>
|
||||
<linearGradient id="interest_svg" x1="0" x2="0" y1="0" y2="1">
|
||||
<stop offset="0"></stop>
|
||||
<stop offset="1"></stop>
|
||||
</linearGradient>
|
||||
</defs>
|
||||
</svg>
|
|
@ -0,0 +1,71 @@
|
|||
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
|
||||
import { AccumulationChart, AccumulationLegend, PieSeries, AccumulationTooltip,
|
||||
AccumulationDataLabel,
|
||||
Chart, LineSeries, DateTime, Legend, Tooltip, IAccLoadedEventArgs, AccumulationTheme, IAccPointRenderEventArgs,
|
||||
StackingColumnSeries, Crosshair, DataLabel, ColumnSeries, IMouseEventArgs, Series
|
||||
} from '@syncfusion/ej2-charts';
|
||||
import { AccumulationChartComponent } from '@syncfusion/ej2-ng-charts';
|
||||
import { DataService } from '../../data-service';
|
||||
AccumulationChart.Inject(AccumulationLegend, PieSeries, AccumulationTooltip, AccumulationDataLabel);
|
||||
|
||||
@Component({
|
||||
selector: 'dashboard-section',
|
||||
templateUrl: './dashboard.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class DashboardComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Dashboard page */
|
||||
constructor(private data: DataService) {
|
||||
}
|
||||
|
||||
@ViewChild('pieChart')
|
||||
public pieChart: AccumulationChartComponent;
|
||||
|
||||
// chart binding properties
|
||||
public legendSettings: Object = { visible: false };
|
||||
public width: string = '100%';
|
||||
public tooltip: Object = { enable: false };
|
||||
public pieSeries: Object[] = [
|
||||
{
|
||||
dataSource: [
|
||||
{ 'x': 'Principal Amount', y: this.data.principalValue },
|
||||
{ 'x': 'Interest Amount', y: ((this.data.emi * this.data.tent) - this.data.principalValue) }
|
||||
],
|
||||
radius: '80%', xName: 'x',
|
||||
animation: { enable: true },
|
||||
yName: 'y',
|
||||
startAngle: 290,
|
||||
endAngle: 290, innerRadius: '60%',
|
||||
explode: true, explodeOffset: '10%', explodeIndex: 3
|
||||
}
|
||||
];
|
||||
public emiAmt: string = this.data.emiAmt;
|
||||
public principalAmt: string = this.data.principalAmt;
|
||||
public interestAmt: string = this.data.interestAmt;
|
||||
public totalAmt: string = this.data.totalAmt;
|
||||
|
||||
public onLoad(args: IAccLoadedEventArgs): void {
|
||||
let selectedTheme: string = location.hash.split('/')[1];
|
||||
selectedTheme = selectedTheme ? selectedTheme : 'Material';
|
||||
args.accumulation.theme = <AccumulationTheme>(selectedTheme.charAt(0).toUpperCase() + selectedTheme.slice(1));
|
||||
}
|
||||
|
||||
public pointRender(args: IAccPointRenderEventArgs): void {
|
||||
if (args.point.index) {
|
||||
args.border.width = 7;
|
||||
args.fill = 'url(#interest_svg)';
|
||||
} else {
|
||||
args.border.width = 7;
|
||||
args.border.color = '#162036';
|
||||
args.fill = 'url(#principal_svg)';
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<div class="row left-content-wrap">
|
||||
<div class="row loan-content">
|
||||
<input-section #inputSection></input-section>
|
||||
</div>
|
||||
<div class="row loan-content">
|
||||
<dashboard-section #dashboardSection></dashboard-section>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,26 @@
|
|||
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
|
||||
import { DashboardComponent } from './dashboard/dashboard.component';
|
||||
import { DataService } from '../data-service';
|
||||
|
||||
@Component({
|
||||
selector: 'home-section',
|
||||
templateUrl: './home.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class HomeComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Home page */
|
||||
constructor(private data: DataService) {
|
||||
}
|
||||
|
||||
@ViewChild('dashboardSection')
|
||||
public dashboard: DashboardComponent;
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
this.data.dashboard = this.dashboard;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
<div class="left-content col-lg-12">
|
||||
<div class="row form-space">
|
||||
<div class="col-lg-12">
|
||||
<div class="content-space">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label class="pricipal">Loan Amount</label>
|
||||
</td>
|
||||
<td>
|
||||
<div class="editor-space">
|
||||
<ejs-numerictextbox id="principal_txt" [(value)]="principalValue" [min]="principalNumMinValue" [max]="principalNumMaxValue" [step]="principalNumStep" [format]="principalNumFormat" [width]="principalNumWidth" (change)="principalNumChange($event)"></ejs-numerictextbox>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<ejs-slider id='pricipal' [(value)]="principalValue" [min]="principalMinValue" [max]="principalMaxValue" [step]="principalStep" [type]="principalType" [ticks]="principalTicks" (change)="principalChange($event)" (changed)="principalChanged($event)" (renderedTicks)="principalRenderedTicks($event)"></ejs-slider>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-space">
|
||||
<div class="col-lg-12">
|
||||
<div class="content-space">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label class="interestrate">Interest Rate</label>
|
||||
</td>
|
||||
<td>
|
||||
<div class="editor-space">
|
||||
<ejs-numerictextbox id="interest_txt" [(value)]="interestValue" [min]="interestNumMinValue" [max]="interestNumMaxValue" [step]="interestNumStep" [format]="interestNumFormat" [width]="interestNumWidth" (change)="interestNumChange($event)"></ejs-numerictextbox>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<ejs-slider id='interestrate' [(value)]="interestValue" [min]="interestMinValue" [max]="interestMaxValue" [step]="interestStep" [type]="interestType" [ticks]="interestTicks" (change)="interestChange($event)" (changed)="interestChanged($event)"></ejs-slider>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row form-space">
|
||||
<div class="col-lg-12">
|
||||
<div class="content-space">
|
||||
<table>
|
||||
<tr>
|
||||
<td>
|
||||
<label class="loantenure">Loan Term</label>
|
||||
<ul class="tenure-value" style="float: left;">
|
||||
<li>
|
||||
<ejs-radiobutton id="radio1" label="Month" name="tenure" value="month" (change)="monthChanged()"></ejs-radiobutton>
|
||||
</li>
|
||||
<li>
|
||||
<ejs-radiobutton id="radio2" label="Year" name="tenure" value="year" checked="true" [checked]="yearTenure" (change)="yearChanged()"></ejs-radiobutton>
|
||||
</li>
|
||||
</ul>
|
||||
</td>
|
||||
<td>
|
||||
<div class="editor-space">
|
||||
<ejs-numerictextbox id="loan_txt" [(value)]="loanValue" [min]="loanNumMinValue" [max]="loanNumMaxValue" [step]="loanNumStep" [format]="loanNumFormat" [width]="loanNumWidth" (change)="loanNumChange($event)"></ejs-numerictextbox>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<ejs-slider id='loantenure' [(value)]="loanValue" [min]="loanMinValue" [max]="loanMaxValue" [step]="loanStep" [type]="loanType" [ticks]="loanTicks" (change)="loanChange($event)" (changed)="loanChanged($event)"></ejs-slider>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,156 @@
|
|||
import { Component, ViewEncapsulation, OnInit, ViewChild } from '@angular/core';
|
||||
import { NumericTextBoxComponent, SliderTickRenderedEventArgs } from '@syncfusion/ej2-ng-inputs';
|
||||
import { ChangeEventArgs } from '@syncfusion/ej2-inputs';
|
||||
import { DataService } from '../../data-service';
|
||||
|
||||
@Component({
|
||||
selector: 'input-section',
|
||||
templateUrl: './input.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class InputComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Input page */
|
||||
constructor(private data: DataService) {
|
||||
this.principalValue = this.data.principalValue;
|
||||
this.interestValue = this.data.interestValue;
|
||||
this.loanValue = this.data.loanValue;
|
||||
}
|
||||
|
||||
// The principal NumericTextBox binding properties
|
||||
public principalNumMinValue: number = 1000;
|
||||
public principalNumMaxValue: number = 5000000;
|
||||
public principalNumStep: number = 10000;
|
||||
public principalNumFormat: string = 'c0';
|
||||
public principalNumWidth: string = '200px';
|
||||
|
||||
public principalNumChange(args: ChangeEventArgs): void {
|
||||
this.data.principalValue = this.principalValue;
|
||||
if (args.isInteraction) {
|
||||
this.data.refreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
// The interest NumericTextBox binding properties
|
||||
public interestNumMinValue: number = 0;
|
||||
public interestNumMaxValue: number = 20;
|
||||
public interestNumStep: number = .25;
|
||||
public interestNumFormat: string = '#.##\' %\'';
|
||||
public interestNumWidth: string = '165px';
|
||||
|
||||
public interestNumChange(args: ChangeEventArgs): void {
|
||||
this.data.interestValue = this.interestValue;
|
||||
if (args.isInteraction) {
|
||||
this.data.refreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
// The loan NumericTextBox binding properties
|
||||
public loanNumMinValue: number = 1;
|
||||
public loanNumMaxValue: number = 40;
|
||||
public loanNumStep: number = 1;
|
||||
public loanNumFormat: string = '#.##';
|
||||
public loanNumWidth: string = '150px';
|
||||
|
||||
public loanNumChange(args: ChangeEventArgs): void {
|
||||
this.data.loanValue = this.loanValue;
|
||||
if (args.isInteraction) {
|
||||
this.data.refreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
// The principal Slider binding properties
|
||||
public principalValue: number = 0;
|
||||
public principalMinValue: number = 0;
|
||||
public principalMaxValue: number = 500000;
|
||||
public principalStep: number = 10000;
|
||||
public principalType: string = 'MinRange';
|
||||
public principalTicks: Object = { placement: 'After', largeStep: 100000, smallStep: 10000, showSmallTicks: false, format: 'c0' };
|
||||
|
||||
public principalChange(args: ChangeEventArgs): void {
|
||||
this.data.principalValue = this.principalValue;
|
||||
this.data.setInitValues();
|
||||
this.data.updateTotalAmt();
|
||||
}
|
||||
|
||||
public principalChanged(args: ChangeEventArgs): void {
|
||||
this.data.refreshUI();
|
||||
}
|
||||
|
||||
public principalRenderedTicks(args: SliderTickRenderedEventArgs): void {
|
||||
let li: NodeListOf<Element> = args.ticksWrapper.getElementsByClassName('e-large');
|
||||
for (let i: number = 0; i < li.length; ++i) {
|
||||
let ele: HTMLElement = (li[i].querySelectorAll('.e-tick-value')[0] as HTMLElement);
|
||||
let num: number = parseInt(ele.innerText.substring(1).replace(/,/g , ''), 10) / 1000;
|
||||
ele.innerText = num === 0 ? ('' + num) : (num + 'K');
|
||||
}
|
||||
}
|
||||
|
||||
// The interest Slider binding properties
|
||||
public interestValue: number = 0;
|
||||
public interestMinValue: number = 0;
|
||||
public interestMaxValue: number = 20;
|
||||
public interestStep: number = .25;
|
||||
public interestType: string = 'MinRange';
|
||||
public interestTicks: Object = { placement: 'After', largeStep: 5, smallStep: 1, showSmallTicks: false };
|
||||
|
||||
public interestChange(args: ChangeEventArgs): void {
|
||||
this.data.interestValue = this.interestValue;
|
||||
this.data.setInitValues();
|
||||
this.data.updateTotalAmt();
|
||||
}
|
||||
|
||||
public interestChanged(args: ChangeEventArgs): void {
|
||||
this.data.refreshUI();
|
||||
}
|
||||
|
||||
// The loan Slider binding properties
|
||||
public loanValue: number = 0;
|
||||
public loanMinValue: number = 0;
|
||||
public loanMaxValue: number = 40;
|
||||
public loanStep: number = 1;
|
||||
public loanType: string = 'MinRange';
|
||||
public loanTicks: Object = { placement: 'After', largeStep: 10, smallStep: 1, showSmallTicks: false };
|
||||
|
||||
public loanChange(args: ChangeEventArgs): void {
|
||||
this.data.loanValue = this.loanValue;
|
||||
this.data.setInitValues();
|
||||
this.data.updateTotalAmt();
|
||||
}
|
||||
|
||||
public loanChanged(args: ChangeEventArgs): void {
|
||||
this.data.refreshUI();
|
||||
}
|
||||
|
||||
// Radio button binding properties
|
||||
public yearTenure: boolean = this.data.yearTenure;
|
||||
|
||||
public monthChanged(): void {
|
||||
this.data.yearTenure = this.yearTenure = false;
|
||||
this.loanNumMinValue = 12;
|
||||
this.loanNumMaxValue = 480;
|
||||
this.loanNumStep = 12;
|
||||
this.loanMaxValue = 480;
|
||||
this.loanValue = (this.loanValue * 12);
|
||||
this.loanStep = 12;
|
||||
this.loanTicks = { placement: 'After', largeStep: 120, smallStep: 12, showSmallTicks: false };
|
||||
}
|
||||
|
||||
public yearChanged(): void {
|
||||
this.data.yearTenure = this.yearTenure = true;
|
||||
this.loanNumMinValue = 1;
|
||||
this.loanNumMaxValue = 40;
|
||||
this.loanNumStep = 1;
|
||||
this.loanMaxValue = 40;
|
||||
this.loanValue = (this.loanValue / 12);
|
||||
this.loanStep = 1;
|
||||
this.loanTicks = { largeStep: 10, smallStep: 1, showSmallTicks: false };
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
|
||||
public ngAfterViewInit(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
<div class="row top-space loan-content" style="text-align: center">
|
||||
<div class="graph-text">Monthly payments starting from</div>
|
||||
<div class="graph-input">
|
||||
<ejs-datepicker id="monthStarter" placeholder='Enter date' start="Year" [showClearButton]="false" [strictMode]="true" [showTodayButton]="false" depth="Year" [format]="format" [value]="dateValue" [width]="width" (change)="onChange($event)"></ejs-datepicker>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,33 @@
|
|||
import { Component, ViewEncapsulation, OnInit } from '@angular/core';
|
||||
import { ChangedEventArgs } from '@syncfusion/ej2-ng-calendars';
|
||||
import { isNullOrUndefined as isNOU } from '@syncfusion/ej2-base';
|
||||
import { DataService } from '../data-service';
|
||||
|
||||
@Component({
|
||||
selector: 'statement-section',
|
||||
templateUrl: './statement.component.html',
|
||||
encapsulation: ViewEncapsulation.None
|
||||
})
|
||||
|
||||
export class StatementComponent implements OnInit {
|
||||
|
||||
/** Configurations for the Statement page */
|
||||
constructor(private data: DataService) {
|
||||
}
|
||||
|
||||
public format: string = 'MMM yyy';
|
||||
public dateValue: Date = new Date();
|
||||
public width: string = '250px';
|
||||
|
||||
public onChange(args: ChangedEventArgs): void {
|
||||
if (isNOU(args.value)) {
|
||||
this.dateValue = new Date();
|
||||
} else {
|
||||
this.data.dateValue = this.dateValue = args.value;
|
||||
this.data.refreshUI();
|
||||
}
|
||||
}
|
||||
|
||||
public ngOnInit(): void {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,901 @@
|
|||
//sass-lint:disable-all
|
||||
$border-color: #e4e2e2;
|
||||
$bg-color: #fbfbfb;
|
||||
$body-bg-color: rgb(22, 32, 54);
|
||||
$header-bg-color: #27304c;
|
||||
$header-font-color: rgb(255, 255, 255);
|
||||
$input-bg-color: #3A4360;
|
||||
$input-font-color: #fff;
|
||||
$input-icon-color: #95979c;
|
||||
$input-border-color: #475274;
|
||||
$main-bg-color: #27304c;
|
||||
$text-color: #E7E7E7;
|
||||
$text-color1: #989CA9;
|
||||
$text-color2: #F5F5F5;
|
||||
$header-color: #4a4a4a 100%;
|
||||
$range-color: #3B9ED4;
|
||||
$slider-color: #20273E;
|
||||
$row-bg-color: #27304c;
|
||||
$altrow-bg-color: #313B5A;
|
||||
$row-font-color: #fff;
|
||||
$hover-color: #404D75;
|
||||
$active-color: #5B6BC0;
|
||||
$principal-color: linear-gradient(#3AC8DC, #5B6BC0);
|
||||
$interest-color: linear-gradient(#F3A55B, #FB6589);
|
||||
$tick-color: #ABABAB;
|
||||
|
||||
@mixin Raleway-600 {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
@mixin Raleway-500 {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@mixin Raleway-400 {
|
||||
font-family: 'Raleway', sans-serif;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
@mixin Roboto-400 {
|
||||
font-family: "Roboto";
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
@mixin Roboto-500 {
|
||||
font-family: "Roboto";
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.content-space {
|
||||
display: block;
|
||||
margin-top: 25px;
|
||||
margin-bottom: 25px;
|
||||
width: 100%;
|
||||
|
||||
table {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
label {
|
||||
float: left;
|
||||
margin-top: 6px;
|
||||
color: $text-color;
|
||||
font-size: 16px;
|
||||
@include Raleway-400();
|
||||
}
|
||||
}
|
||||
|
||||
.editor-space {
|
||||
display: flex;
|
||||
justify-content: left;
|
||||
float: right;
|
||||
}
|
||||
|
||||
.form-space {
|
||||
margin-bottom: 25px;
|
||||
|
||||
&:not(:first-child) {
|
||||
margin-top: 25px;
|
||||
}
|
||||
}
|
||||
|
||||
.navbar {
|
||||
border-radius: 0;
|
||||
}
|
||||
|
||||
.component-content {
|
||||
border-radius: 3px;
|
||||
height: 300px;
|
||||
}
|
||||
|
||||
.parent {
|
||||
min-height: 85px;
|
||||
position: relative;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.child {
|
||||
left: 50%;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
|
||||
.top-space {
|
||||
margin-top: 30px;
|
||||
margin-bottom: 15px;
|
||||
|
||||
h6 {
|
||||
position: relative;
|
||||
}
|
||||
}
|
||||
|
||||
// .emi-content > div {
|
||||
// background-color: $bg-color;
|
||||
// }
|
||||
|
||||
.emi-content {
|
||||
max-width: 634px;
|
||||
max-height: 660px;
|
||||
margin: 30px 0 25px 0;
|
||||
padding: 0 44px;
|
||||
|
||||
h6 {
|
||||
@include Raleway-500();
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.emi-header {
|
||||
font-size: 20px;
|
||||
color: $text-color;
|
||||
letter-spacing: 0.7px;
|
||||
line-height: 29px;
|
||||
}
|
||||
|
||||
.emi-footer {
|
||||
font-size: 18px;
|
||||
color: $text-color1;
|
||||
margin-top: 5px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: $text-color2;
|
||||
font-size: 32px;
|
||||
@include Roboto-500();
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
> div {
|
||||
|
||||
> h6 {
|
||||
text-align: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.top-margin {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.bottom-margin {
|
||||
margin-bottom: 35px;
|
||||
}
|
||||
|
||||
.pie-content {
|
||||
height: 100%;
|
||||
padding: 0;
|
||||
|
||||
p {
|
||||
text-align: center;
|
||||
font-size: 15px;
|
||||
@include Raleway-400();
|
||||
color: $text-color1;
|
||||
}
|
||||
|
||||
.pie-icon {
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
display: inline-block;
|
||||
border-radius: 10px;
|
||||
margin: 0 14px 0 0;
|
||||
vertical-align: text-top;
|
||||
|
||||
&.pie-principal {
|
||||
background: $principal-color;
|
||||
}
|
||||
|
||||
&.pie-interest {
|
||||
background: $interest-color;
|
||||
}
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 18px;
|
||||
@include Roboto-500();
|
||||
color: $text-color2;
|
||||
padding: 5px 0 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
> div {
|
||||
margin: 35px 0;
|
||||
|
||||
&:first-child {
|
||||
margin-top: 43px;
|
||||
}
|
||||
|
||||
&.pie-total {
|
||||
|
||||
p:first-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
p + p {
|
||||
font-size: 14px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.center-heading {
|
||||
padding: 10px;
|
||||
font-size: 20px;
|
||||
text-align: center;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.border-set {
|
||||
border: 1px solid $border-color;
|
||||
}
|
||||
|
||||
.tenure-value {
|
||||
display: flex;
|
||||
padding: 4px 5px 4px 10px;
|
||||
position: relative;
|
||||
|
||||
li {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.e-radio {
|
||||
|
||||
& + label {
|
||||
|
||||
&::before {
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
border-width: 2px;
|
||||
}
|
||||
|
||||
&::before, &:hover::before {
|
||||
border-color: $range-color;
|
||||
background-color: $input-bg-color;
|
||||
}
|
||||
|
||||
&::after, &:hover::after {
|
||||
background-color: $range-color;
|
||||
}
|
||||
|
||||
.e-label {
|
||||
color: $text-color;
|
||||
font-size: 16px;
|
||||
@include Raleway-500()
|
||||
}
|
||||
}
|
||||
|
||||
&:focus + label {
|
||||
|
||||
&::before {
|
||||
border-color: $range-color;
|
||||
background-color: $input-bg-color;
|
||||
}
|
||||
|
||||
&::after{
|
||||
background-color: $range-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>li {
|
||||
padding-left: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-container {
|
||||
height: 520px;
|
||||
padding: 0 33px;
|
||||
}
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
}
|
||||
|
||||
.border-unset-left {
|
||||
border-left: 0;
|
||||
}
|
||||
|
||||
.border-unset-right {
|
||||
border-right: 0;
|
||||
}
|
||||
|
||||
.main-content {
|
||||
margin-top: 40px;
|
||||
max-width: 1300px;
|
||||
|
||||
.loan-content {
|
||||
background-color: $main-bg-color;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.e-slider-container {
|
||||
|
||||
.e-scale {
|
||||
color: $tick-color;
|
||||
|
||||
.e-tick {
|
||||
|
||||
&.e-large {
|
||||
top: 14px;
|
||||
}
|
||||
|
||||
.e-tick-value {
|
||||
@include Roboto-400();
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.e-slider {
|
||||
|
||||
.e-slider-track {
|
||||
background: $slider-color;
|
||||
border-color: $slider-color;
|
||||
}
|
||||
|
||||
.e-handle {
|
||||
height: 26px;
|
||||
width: 26px;
|
||||
top: calc(50% - 13px);
|
||||
margin-left: -13px;
|
||||
|
||||
&::before {
|
||||
content: '';
|
||||
background: $range-color;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
position: absolute;
|
||||
border-radius: 16px;
|
||||
top: 5px;
|
||||
left: 5px;
|
||||
}
|
||||
}
|
||||
|
||||
.e-range {
|
||||
background-color: $range-color;
|
||||
top: calc(50% - 5px);
|
||||
}
|
||||
|
||||
& .e-slider-track, & .e-range {
|
||||
height: 12px;
|
||||
}
|
||||
|
||||
& .e-handle, & .e-slider-track, & .e-range {
|
||||
border-radius: 15px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.e-input-group.e-control-wrapper {
|
||||
|
||||
&:not(.e-success):not(.e-warning):not(.e-error) {
|
||||
border-color: $input-border-color;
|
||||
background: $input-bg-color;
|
||||
}
|
||||
|
||||
&:not(.e-disabled):active:not(.e-success):not(.e-warning):not(.e-error):not(.e-input-focus) {
|
||||
border-color: $hover-color;
|
||||
}
|
||||
|
||||
.e-input-group-icon {
|
||||
background: $input-bg-color;
|
||||
color: $input-icon-color;
|
||||
border-color: $input-border-color;
|
||||
|
||||
&:hover {
|
||||
background: $hover-color;
|
||||
color: $input-icon-color;
|
||||
}
|
||||
}
|
||||
|
||||
.e-spin-down {
|
||||
border-right-width: 0;
|
||||
}
|
||||
|
||||
input.e-input {
|
||||
@include Roboto-400();
|
||||
font-size: 16px;
|
||||
height: 38px;
|
||||
background-color: $input-bg-color;
|
||||
color: $input-font-color;
|
||||
}
|
||||
}
|
||||
|
||||
.graph-text {
|
||||
color: $text-color;
|
||||
font-size: 20px;
|
||||
@include Raleway-500();
|
||||
letter-spacing: 0.7px;
|
||||
margin: 0 22px;
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.graph-input {
|
||||
display: inline-block;
|
||||
margin: 34px 22px;
|
||||
}
|
||||
|
||||
.e-grid {
|
||||
border-color: $main-bg-color;
|
||||
border-radius: 0;
|
||||
|
||||
.e-row {
|
||||
cursor: pointer;
|
||||
}
|
||||
.e-gridheader {
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
.e-icon-grightarrow, .e-icon-gdownarrow {
|
||||
width: 11px;
|
||||
height: 11px;
|
||||
border: 1px solid #fff;
|
||||
margin: auto;
|
||||
text-indent: 0;
|
||||
|
||||
&::before {
|
||||
position: absolute;
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
|
||||
.e-icon-grightarrow::before {
|
||||
content: '+';
|
||||
margin: -4px 0 0 -4px;
|
||||
}
|
||||
|
||||
.e-icon-gdownarrow::before {
|
||||
content: '-';
|
||||
margin: -6px 0 0 -2px;
|
||||
}
|
||||
|
||||
.e-headercelldiv {
|
||||
font-size: 14px;
|
||||
height: 55px;
|
||||
line-height: 55px;
|
||||
@include Raleway-400();
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
& .e-columnheader {
|
||||
background: linear-gradient(-90deg, #5B6BC0, #3AC8DC);
|
||||
}
|
||||
|
||||
& .e-headercell, & .e-detailheadercell {
|
||||
background: transparent;
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
& .e-rowcell, & .e-detailrowcollapse, & .e-detailrowexpand, & .e-detailindentcell, & .e-detailrow .e-altrow .e-rowcell {
|
||||
background: $row-bg-color;
|
||||
border-width: 0;
|
||||
font-size: 13px;
|
||||
@include Roboto-400();
|
||||
}
|
||||
|
||||
.e-altrow {
|
||||
|
||||
& .e-rowcell, & .e-detailrowcollapse, & .e-detailrowexpand {
|
||||
background: $altrow-bg-color;
|
||||
}
|
||||
}
|
||||
|
||||
& .e-icons, & .e-rowcell, & .e-detailrowcollapse, & .e-detailrowexpand {
|
||||
color: $row-font-color;
|
||||
}
|
||||
|
||||
.e-detailcell {
|
||||
padding: 0;
|
||||
border-width: 0;
|
||||
}
|
||||
|
||||
&.e-gridhover tr[role='row'] {
|
||||
|
||||
&:not(.e-editedrow):hover .e-rowcell:not(.e-cellselectionbackground), &:hover .e-detailrowcollapse:not(.e-cellselectionbackground), &:hover .e-detailrowexpand:not(.e-cellselectionbackground) {
|
||||
|
||||
&:not(.e-active):not(.e-updatedtd):not(.e-indentcell) {
|
||||
background: $hover-color;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.e-grid {
|
||||
|
||||
& .e-headercontent, & .e-gridcontent .e-emptyrow, & .e-spinner-pane {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
& [aria-selected] + tr .e-detailindentcell {
|
||||
border-width: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#control-container {
|
||||
padding: 0px !important;
|
||||
}
|
||||
|
||||
#principal_svg stop {
|
||||
stop-color: #3AC8DC;
|
||||
}
|
||||
|
||||
#principal_svg stop[offset="0"] {
|
||||
stop-color: #3AC8DC;
|
||||
}
|
||||
|
||||
#principal_svg stop[offset="1"] {
|
||||
stop-color: #5B6BC0;
|
||||
}
|
||||
|
||||
#interest_svg stop {
|
||||
stop-color: #F3A55B;
|
||||
}
|
||||
|
||||
#interest_svg stop[offset="0"] {
|
||||
stop-color: #e97c11;
|
||||
}
|
||||
|
||||
#interest_svg stop[offset="1"] {
|
||||
stop-color: #FB6589;
|
||||
}
|
||||
|
||||
.navbar-right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
.navbar-header {
|
||||
float: left;
|
||||
}
|
||||
|
||||
.flex-container {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.col-lg-4 {
|
||||
width: 33.33333333%;
|
||||
}
|
||||
|
||||
@media (max-width: 500px) {
|
||||
.col-lg-4 {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: $body-bg-color;
|
||||
color: $text-color;
|
||||
}
|
||||
|
||||
.left-content {
|
||||
background-color: $main-bg-color;
|
||||
max-height: 660px;
|
||||
margin: 25px 0;
|
||||
padding: 0 44px;
|
||||
border-right: 1px solid $input-border-color;
|
||||
}
|
||||
|
||||
.header-style {
|
||||
background: $header-bg-color;
|
||||
color: $header-font-color;
|
||||
margin: 0;
|
||||
padding: 15px;
|
||||
text-align: center;
|
||||
text-transform: uppercase;
|
||||
font-size: 26px;
|
||||
@include Raleway-500();
|
||||
}
|
||||
|
||||
.margin-setter {
|
||||
margin: 35px;
|
||||
}
|
||||
|
||||
.start-setter {
|
||||
margin: 17px 0;
|
||||
}
|
||||
|
||||
.e-datepicker.e-popup-wrapper {
|
||||
border-color: $input-border-color;
|
||||
}
|
||||
|
||||
.e-datepicker .e-calendar {
|
||||
background-color: $input-bg-color;
|
||||
}
|
||||
|
||||
.e-calendar .e-header .e-title, .e-calendar .e-content span, .e-calendar .e-header.e-decade .e-title,
|
||||
.e-calendar .e-header .e-title:hover {
|
||||
color: $input-font-color;
|
||||
}
|
||||
|
||||
.e-calendar .e-header .e-icon-container span, .e-calendar .e-header .e-prev:hover > span, .e-calendar .e-header .e-next:hover > span,
|
||||
.e-calendar .e-header button.e-prev:active span, .e-calendar .e-header button.e-next:active span {
|
||||
color: $input-icon-color;
|
||||
}
|
||||
|
||||
.e-calendar .e-content td.e-selected span.e-day, .e-calendar .e-header .e-prev:active, .e-calendar .e-header .e-next:active {
|
||||
background: $active-color;
|
||||
}
|
||||
|
||||
.e-calendar .e-content.e-decade tr:first-child .e-cell:first-child span.e-day, .e-calendar .e-content.e-decade tr:last-child .e-cell:last-child span.e-day {
|
||||
color: $tick-color;
|
||||
}
|
||||
|
||||
.e-calendar .e-header .e-prev:hover, .e-calendar .e-header .e-next:hover, .e-calendar .e-content td.e-focused-date span.e-day,
|
||||
.e-calendar .e-content.e-year td:hover span.e-day, .e-calendar .e-content.e-decade td:hover span.e-day,
|
||||
.e-calendar .e-content.e-year td.e-selected:hover span.e-day, .e-calendar .e-content.e-decade td.e-selected:hover span.e-day {
|
||||
background: $hover-color;
|
||||
color: $input-font-color;
|
||||
}
|
||||
|
||||
@media (max-width: 319px) {
|
||||
.container {
|
||||
min-width: 300px;
|
||||
}
|
||||
}
|
||||
@media (max-width: 576px) {
|
||||
.header-style {
|
||||
font-size: 20px;
|
||||
padding: 13px 0;
|
||||
}
|
||||
.container {
|
||||
padding: 10px;
|
||||
margin: 0;
|
||||
.e-slider-container .e-scale .e-tick .e-tick-value {
|
||||
font-size: 12px;
|
||||
}
|
||||
}
|
||||
.top-space {
|
||||
margin: 10px;
|
||||
}
|
||||
.row {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
.left-content-wrap .loan-content:first-child {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.left-content {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
border-right-width: 0;
|
||||
.col-lg-12 {
|
||||
padding: 12px 12px 18px 12px;
|
||||
}
|
||||
|
||||
.content-space {
|
||||
margin: 0 0 12px 0;
|
||||
td {
|
||||
display: block;
|
||||
}
|
||||
label {
|
||||
font-size: 15px;
|
||||
margin: 0 0 12px;
|
||||
}
|
||||
.tenure-value .e-radio + label {
|
||||
margin: 0;
|
||||
.e-label {
|
||||
font-size: 13px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.editor-space {
|
||||
float: left;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form-space {
|
||||
margin-bottom: 23px;
|
||||
&:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.e-input-group {
|
||||
width: 100% !important;
|
||||
}
|
||||
}
|
||||
.emi-content {
|
||||
padding: 0;
|
||||
margin-top: 0;
|
||||
.emi-header {
|
||||
text-align: center;
|
||||
font-size: 18px;
|
||||
}
|
||||
}
|
||||
.tenure-value {
|
||||
padding: 0;
|
||||
float: none;
|
||||
}
|
||||
.emi-content {
|
||||
h6 {
|
||||
font-size: 23px;
|
||||
}
|
||||
h1 {
|
||||
font-size: 30px;
|
||||
}
|
||||
|
||||
.col-lg-7 {
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.col-lg-5 {
|
||||
width: 100%;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
.pie-content {
|
||||
div {
|
||||
margin: 10px 0;
|
||||
text-align: center;
|
||||
&:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
}
|
||||
p {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
}
|
||||
h5 {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
}
|
||||
.pie-total {
|
||||
span {
|
||||
display: inline-block;
|
||||
}
|
||||
p {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
.main-content .loan-content {
|
||||
.graph-text {
|
||||
margin: 12px;
|
||||
font-size: 18px;
|
||||
}
|
||||
.graph-input {
|
||||
padding: 0 12px 12px;
|
||||
width: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
.center-heading {
|
||||
font-size: 18px;
|
||||
}
|
||||
.graph-container {
|
||||
padding: 0 2px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 576px) and (max-width: 991px) {
|
||||
.container {
|
||||
padding: 0 30px;
|
||||
width: 100%;
|
||||
}
|
||||
.left-content-wrap {
|
||||
.loan-content {
|
||||
width: 100%;
|
||||
float: left;
|
||||
margin: 0;
|
||||
padding-bottom: 25px;
|
||||
& + .loan-content {
|
||||
margin-top: 30px;
|
||||
padding-top: 25px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
}
|
||||
}
|
||||
.left-content {
|
||||
border-right-width: 0;
|
||||
}
|
||||
|
||||
.emi-content {
|
||||
max-width: 100%;
|
||||
|
||||
.col-lg-7 {
|
||||
width: 60%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.col-lg-5 {
|
||||
width: 40%;
|
||||
float: left;
|
||||
}
|
||||
}
|
||||
}
|
||||
@media (max-width: 700px) {
|
||||
.main-content .graph-text {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.main-content .graph-input {
|
||||
margin: 21px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) {
|
||||
.container {
|
||||
padding: 0 35px;
|
||||
width: 100%;
|
||||
}
|
||||
.left-content-wrap {
|
||||
.loan-content {
|
||||
width: 50%;
|
||||
float: left;
|
||||
margin: 0;
|
||||
& + .loan-content {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
.left-content {
|
||||
border-right-width: 1px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 992px) and (max-width: 1200px) {
|
||||
.left-content {
|
||||
min-width: 450px;
|
||||
padding: 0 20px;
|
||||
margin-bottom: 40px;
|
||||
}
|
||||
.emi-content {
|
||||
max-width: 100%;
|
||||
padding: 0 20px;
|
||||
|
||||
.col-lg-7 {
|
||||
width: 60%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.col-lg-5 {
|
||||
width: 40%;
|
||||
float: left;
|
||||
}
|
||||
|
||||
.emi-footer {
|
||||
margin-top: 15px;
|
||||
}
|
||||
}
|
||||
.graph-container {
|
||||
padding: 0 10px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1200px) and (max-width: 1329px) {
|
||||
.container {
|
||||
padding: 0 35px;
|
||||
}
|
||||
}
|
||||
@media (min-width: 1330px) {
|
||||
.container {
|
||||
width: 1300px;
|
||||
}
|
||||
}
|
||||
.e-grid#scheduleGrid > .e-gridheader .e-headercontent .e-table colgroup col:first-child,
|
||||
.e-grid .e-content .e-table#scheduleGrid_content_table > colgroup col:first-child {
|
||||
width: 0px !important;
|
||||
}
|
||||
.e-grid .e-detailrowexpand > div,
|
||||
.e-grid .e-detailrowcollapse > div {
|
||||
display: none;
|
||||
}
|
||||
.e-grid .e-row .e-row-toggle {
|
||||
display: inline-block;
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
//sass-lint:disable-all
|
||||
@import 'ej2-inputs/styles/bootstrap.scss';
|
||||
@import 'ej2-grids/styles/bootstrap.scss';
|
|
@ -0,0 +1,8 @@
|
|||
// The file contents for the current environment will overwrite these during build.
|
||||
// The build system defaults to the dev environment which uses `environment.ts`, but if you do
|
||||
// `ng build --env=prod` then `environment.prod.ts` will be used instead.
|
||||
// The list of which env maps to which file can be found in `.angular-cli.json`.
|
||||
|
||||
export const environment = {
|
||||
production: false
|
||||
};
|
Двоичный файл не отображается.
После Ширина: | Высота: | Размер: 6.4 KiB |
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title>Essential JS 2 for Angular - Loan Calculator</title>
|
||||
<meta charset="utf-8">
|
||||
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||
<meta name="description" content="Essential JS 2 for Angular - Loan Calculator">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
||||
<link rel="icon" type="image/x-icon" href="./favicon.ico">
|
||||
<link href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css?family=Roboto" rel="stylesheet">
|
||||
<link href="https://fonts.googleapis.com/css?family=Raleway:500,600" rel="stylesheet">
|
||||
<link href="./styles.css" rel="stylesheet" />
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/core-js/2.4.1/shim.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/reflect-metadata/0.1.10/Reflect.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/zone.js/0.8.18/zone.min.js"></script>
|
||||
<script type="text/javascript">
|
||||
if (/MSIE \d|Trident.*rv:/.test(navigator.userAgent)) {
|
||||
document.write('<script src="https://cdnjs.cloudflare.com/ajax/libs/bluebird/3.3.5/bluebird.min.js"><\/script>');
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<app-root></app-root>
|
||||
</body>
|
||||
<!--<script src="./dist/common.js"></script>-->
|
||||
|
||||
</html>
|
|
@ -0,0 +1,13 @@
|
|||
import { enableProdMode } from '@angular/core';
|
||||
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
|
||||
|
||||
import { AppModule } from './app/app.module';
|
||||
import { environment } from './environments/environment';
|
||||
|
||||
if (environment.production) {
|
||||
enableProdMode();
|
||||
}
|
||||
|
||||
platformBrowserDynamic().bootstrapModule(AppModule)
|
||||
.catch(err => console.log(err));
|
||||
|
|
@ -0,0 +1,66 @@
|
|||
/**
|
||||
* This file includes polyfills needed by Angular and is loaded before the app.
|
||||
* You can add your own extra polyfills to this file.
|
||||
*
|
||||
* This file is divided into 2 sections:
|
||||
* 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers.
|
||||
* 2. Application imports. Files imported after ZoneJS that should be loaded before your main
|
||||
* file.
|
||||
*
|
||||
* The current setup is for so-called "evergreen" browsers; the last versions of browsers that
|
||||
* automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera),
|
||||
* Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile.
|
||||
*
|
||||
* Learn more in https://angular.io/docs/ts/latest/guide/browser-support.html
|
||||
*/
|
||||
|
||||
/***************************************************************************************************
|
||||
* BROWSER POLYFILLS
|
||||
*/
|
||||
|
||||
/** IE9, IE10 and IE11 requires all of the following polyfills. **/
|
||||
// import 'core-js/es6/symbol';
|
||||
// import 'core-js/es6/object';
|
||||
// import 'core-js/es6/function';
|
||||
// import 'core-js/es6/parse-int';
|
||||
// import 'core-js/es6/parse-float';
|
||||
// import 'core-js/es6/number';
|
||||
// import 'core-js/es6/math';
|
||||
// import 'core-js/es6/string';
|
||||
// import 'core-js/es6/date';
|
||||
// import 'core-js/es6/array';
|
||||
// import 'core-js/es6/regexp';
|
||||
// import 'core-js/es6/map';
|
||||
// import 'core-js/es6/weak-map';
|
||||
// import 'core-js/es6/set';
|
||||
|
||||
/** IE10 and IE11 requires the following for NgClass support on SVG elements */
|
||||
// import 'classlist.js'; // Run `npm install --save classlist.js`.
|
||||
|
||||
/** IE10 and IE11 requires the following for the Reflect API. */
|
||||
// import 'core-js/es6/reflect';
|
||||
|
||||
|
||||
/** Evergreen browsers require these. **/
|
||||
// Used for reflect-metadata in JIT. If you use AOT (and only Angular decorators), you can remove.
|
||||
import 'core-js/es7/reflect';
|
||||
|
||||
|
||||
/**
|
||||
* Required to support Web Animations `@angular/platform-browser/animations`.
|
||||
* Needed for: All but Chrome, Firefox and Opera. http://caniuse.com/#feat=web-animation
|
||||
**/
|
||||
// import 'web-animations-js'; // Run `npm install --save web-animations-js`.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* Zone JS is required by default for Angular itself.
|
||||
*/
|
||||
import 'zone.js/dist/zone'; // Included with Angular CLI.
|
||||
|
||||
|
||||
|
||||
/***************************************************************************************************
|
||||
* APPLICATION IMPORTS
|
||||
*/
|
|
@ -0,0 +1,20 @@
|
|||
// This file is required by karma.conf.js and loads recursively all the .spec and framework files
|
||||
|
||||
import 'zone.js/dist/zone-testing';
|
||||
import { getTestBed } from '@angular/core/testing';
|
||||
import {
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting
|
||||
} from '@angular/platform-browser-dynamic/testing';
|
||||
|
||||
declare const require: any;
|
||||
|
||||
// First, initialize the Angular testing environment.
|
||||
getTestBed().initTestEnvironment(
|
||||
BrowserDynamicTestingModule,
|
||||
platformBrowserDynamicTesting()
|
||||
);
|
||||
// Then we find all the tests.
|
||||
const context = require.context('./', true, /\.spec\.ts$/);
|
||||
// And load the modules.
|
||||
context.keys().map(context);
|
|
@ -0,0 +1,13 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/app",
|
||||
"baseUrl": "./",
|
||||
"module": "es2015",
|
||||
"types": []
|
||||
},
|
||||
"exclude": [
|
||||
"test.ts",
|
||||
"**/*.spec.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"extends": "../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"outDir": "../out-tsc/spec",
|
||||
"baseUrl": "./",
|
||||
"module": "commonjs",
|
||||
"types": [
|
||||
"jasmine",
|
||||
"node"
|
||||
]
|
||||
},
|
||||
"files": [
|
||||
"test.ts"
|
||||
],
|
||||
"include": [
|
||||
"**/*.spec.ts",
|
||||
"**/*.d.ts"
|
||||
]
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "es2015",
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"declaration": true,
|
||||
"lib": ["es2015", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"suppressImplicitAnyIndexErrors": true,
|
||||
"types": ["requirejs"]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"files": [
|
||||
"src/app/app.module.ts",
|
||||
"src/app/main.ts"
|
||||
],
|
||||
"angularCompilerOptions": {
|
||||
"skipMetadataEmit": true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "amd",
|
||||
"declaration": true,
|
||||
"removeComments": true,
|
||||
"noLib": false,
|
||||
"lib": ["es2015", "dom"],
|
||||
"experimentalDecorators": true,
|
||||
"emitDecoratorMetadata": true,
|
||||
"sourceMap": true,
|
||||
"pretty": true,
|
||||
"allowUnreachableCode": false,
|
||||
"allowUnusedLabels": false,
|
||||
"noImplicitAny": true,
|
||||
"noImplicitReturns": true,
|
||||
"noImplicitUseStrict": false,
|
||||
"noFallthroughCasesInSwitch": true,
|
||||
"allowJs": false,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"moduleResolution": "node",
|
||||
"types": ["requirejs"]
|
||||
},
|
||||
"exclude": [
|
||||
"node_modules"
|
||||
],
|
||||
"compileOnSave": false
|
||||
}
|
Загрузка…
Ссылка в новой задаче