diff --git a/src/app/pages/dashboard/electricity/electricity-chart/electricity-chart.component.ts b/src/app/pages/dashboard/electricity/electricity-chart/electricity-chart.component.ts new file mode 100644 index 00000000..f0f3f4cc --- /dev/null +++ b/src/app/pages/dashboard/electricity/electricity-chart/electricity-chart.component.ts @@ -0,0 +1,197 @@ +import { delay, takeWhile } from 'rxjs/operators'; +import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { LayoutService } from '../../../../@core/utils'; +import { ElectricityChart } from '../../../../@core/data/electricity'; + +@Component({ + selector: 'ngx-electricity-chart', + styleUrls: ['./electricity-chart.component.scss'], + template: ` +
+
+ `, +}) +export class ElectricityChartComponent implements AfterViewInit, OnDestroy { + + private alive = true; + + @Input() data: ElectricityChart[]; + + option: any; + echartsIntance: any; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit(): void { + this.theme.getJsTheme() + .pipe( + takeWhile(() => this.alive), + delay(1), + ) + .subscribe(config => { + const eTheme: any = config.variables.electricity; + + this.option = { + grid: { + left: 0, + top: 0, + right: 0, + bottom: 80, + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'line', + lineStyle: { + color: eTheme.tooltipLineColor, + width: eTheme.tooltipLineWidth, + }, + }, + textStyle: { + color: eTheme.tooltipTextColor, + fontSize: 20, + fontWeight: eTheme.tooltipFontWeight, + }, + position: 'top', + backgroundColor: eTheme.tooltipBg, + borderColor: eTheme.tooltipBorderColor, + borderWidth: 1, + formatter: '{c0} kWh', + extraCssText: eTheme.tooltipExtraCss, + }, + xAxis: { + type: 'category', + boundaryGap: false, + offset: 25, + data: this.data.map(i => i.label), + axisTick: { + show: false, + }, + axisLabel: { + color: eTheme.xAxisTextColor, + fontSize: 18, + }, + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + width: '2', + }, + }, + }, + yAxis: { + boundaryGap: [0, '5%'], + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + splitLine: { + show: true, + lineStyle: { + color: eTheme.yAxisSplitLine, + width: '1', + }, + }, + }, + series: [ + { + type: 'line', + smooth: true, + symbolSize: 20, + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + color: '#ffffff', + borderColor: eTheme.itemBorderColor, + borderWidth: 2, + opacity: 1, + }, + }, + lineStyle: { + normal: { + width: eTheme.lineWidth, + type: eTheme.lineStyle, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.lineGradFrom, + }, { + offset: 1, + color: eTheme.lineGradTo, + }]), + shadowColor: eTheme.lineShadow, + shadowBlur: 6, + shadowOffsetY: 12, + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.areaGradFrom, + }, { + offset: 1, + color: eTheme.areaGradTo, + }]), + }, + }, + data: this.data.map(i => i.value), + }, + + { + type: 'line', + smooth: true, + symbol: 'none', + lineStyle: { + normal: { + width: eTheme.lineWidth, + type: eTheme.lineStyle, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.lineGradFrom, + }, { + offset: 1, + color: eTheme.lineGradTo, + }]), + shadowColor: eTheme.shadowLineDarkBg, + shadowBlur: 14, + opacity: 1, + }, + }, + data: this.data.map(i => i.value), + }, + ], + }; + }); + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + this.echartsIntance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } +} diff --git a/src/app/pages/dashboard/traffic/traffic-chart.component.ts b/src/app/pages/dashboard/traffic/traffic-chart.component.ts new file mode 100644 index 00000000..e4e3e38a --- /dev/null +++ b/src/app/pages/dashboard/traffic/traffic-chart.component.ts @@ -0,0 +1,174 @@ +import { delay, takeWhile } from 'rxjs/operators'; +import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { LayoutService } from '../../../@core/utils'; + +@Component({ + selector: 'ngx-traffic-chart', + template: ` +
+
+ `, +}) +export class TrafficChartComponent implements AfterViewInit, OnDestroy { + + private alive = true; + + @Input() points: number[]; + + type = 'month'; + types = ['week', 'month', 'year']; + option: any = {}; + echartsIntance: any; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe( + delay(1), + takeWhile(() => this.alive), + ) + .subscribe(config => { + const trafficTheme: any = config.variables.traffic; + + this.option = Object.assign({}, { + grid: { + left: 0, + top: 0, + right: 0, + bottom: 0, + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: this.points, + }, + yAxis: { + boundaryGap: [0, '5%'], + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + splitLine: { + show: true, + lineStyle: { + color: trafficTheme.yAxisSplitLine, + width: '1', + }, + }, + }, + tooltip: { + axisPointer: { + type: 'shadow', + }, + textStyle: { + color: trafficTheme.tooltipTextColor, + fontWeight: trafficTheme.tooltipFontWeight, + fontSize: 16, + }, + position: 'top', + backgroundColor: trafficTheme.tooltipBg, + borderColor: trafficTheme.tooltipBorderColor, + borderWidth: 1, + formatter: '{c0} MB', + extraCssText: trafficTheme.tooltipExtraCss, + }, + series: [ + { + type: 'line', + symbol: 'circle', + symbolSize: 8, + sampling: 'average', + silent: true, + itemStyle: { + normal: { + color: trafficTheme.shadowLineDarkBg, + }, + emphasis: { + color: 'rgba(0,0,0,0)', + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + }, + }, + lineStyle: { + normal: { + width: 2, + color: trafficTheme.shadowLineDarkBg, + }, + }, + data: this.points.map(p => p - 15), + }, + { + type: 'line', + symbol: 'circle', + symbolSize: 6, + sampling: 'average', + itemStyle: { + normal: { + color: trafficTheme.itemColor, + borderColor: trafficTheme.itemBorderColor, + borderWidth: 2, + }, + emphasis: { + color: 'white', + borderColor: trafficTheme.itemEmphasisBorderColor, + borderWidth: 2, + }, + }, + lineStyle: { + normal: { + width: 2, + color: trafficTheme.lineBg, + shadowColor: trafficTheme.lineBg, + shadowBlur: trafficTheme.lineShadowBlur, + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: trafficTheme.gradFrom, + }, { + offset: 1, + color: trafficTheme.gradTo, + }]), + opacity: 1, + }, + }, + data: this.points, + }, + ], + }); + }); + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + this.echartsIntance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/charts-panel/charts/orders-chart.component.ts b/src/app/pages/e-commerce/charts-panel/charts/orders-chart.component.ts new file mode 100644 index 00000000..d6e4939b --- /dev/null +++ b/src/app/pages/e-commerce/charts-panel/charts/orders-chart.component.ts @@ -0,0 +1,307 @@ +import { AfterViewInit, Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { delay, takeWhile } from 'rxjs/operators'; + +import { OrdersChart } from '../../../../@core/data/orders-chart'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + +@Component({ + selector: 'ngx-orders-chart', + styleUrls: ['./charts-common.component.scss'], + template: ` +
+
+ `, +}) +export class OrdersChartComponent implements AfterViewInit, OnDestroy, OnChanges { + + @Input() + ordersChartData: OrdersChart; + + private alive = true; + + echartsIntance: any; + option: any; + + ngOnChanges(): void { + if (this.option) { + this.updateOrdersChartOptions(this.ordersChartData); + } + } + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit(): void { + this.theme.getJsTheme() + .pipe( + takeWhile(() => this.alive), + delay(1), + ) + .subscribe(config => { + const eTheme: any = config.variables.orders; + + this.setOptions(eTheme); + this.updateOrdersChartOptions(this.ordersChartData); + }); + } + + setOptions(eTheme) { + this.option = { + grid: { + left: 40, + top: 20, + right: 0, + bottom: 40, + }, + tooltip: { + trigger: 'item', + axisPointer: { + type: 'line', + lineStyle: { + color: eTheme.tooltipLineColor, + width: eTheme.tooltipLineWidth, + }, + }, + textStyle: { + color: eTheme.tooltipTextColor, + fontSize: eTheme.tooltipFontSize, + fontWeight: eTheme.tooltipFontWeight, + }, + position: 'top', + backgroundColor: eTheme.tooltipBg, + borderColor: eTheme.tooltipBorderColor, + borderWidth: 1, + formatter: (params) => { + return Math.round(parseInt(params.value, 10)); + }, + extraCssText: eTheme.tooltipExtraCss, + }, + xAxis: { + type: 'category', + boundaryGap: false, + offset: 5, + data: [], + axisTick: { + show: false, + }, + axisLabel: { + color: eTheme.axisTextColor, + fontSize: eTheme.axisFontSize, + }, + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + width: '2', + }, + }, + }, + yAxis: { + type: 'value', + boundaryGap: false, + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + width: '1', + }, + }, + axisLabel: { + color: eTheme.axisTextColor, + fontSize: eTheme.axisFontSize, + }, + axisTick: { + show: false, + }, + splitLine: { + + lineStyle: { + color: eTheme.yAxisSplitLine, + width: '1', + }, + }, + }, + series: [ + this.getFirstLine(eTheme), + this.getSecondLine(eTheme), + this.getThirdLine(eTheme), + ], + }; + } + + getFirstLine(eTheme) { + return { + type: 'line', + smooth: true, + symbolSize: 20, + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + opacity: 0, + }, + }, + lineStyle: { + normal: { + width: 0, + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.firstAreaGradFrom, + }, { + offset: 1, + color: eTheme.firstAreaGradTo, + }]), + opacity: 1, + }, + }, + data: [], + }; + } + + getSecondLine(eTheme) { + return { + type: 'line', + smooth: true, + symbolSize: 20, + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + color: '#ffffff', + borderColor: eTheme.itemBorderColor, + borderWidth: 2, + opacity: 1, + }, + }, + lineStyle: { + normal: { + width: eTheme.lineWidth, + type: eTheme.lineStyle, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.secondLineGradFrom, + }, { + offset: 1, + color: eTheme.secondLineGradTo, + }]), + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.secondAreaGradFrom, + }, { + offset: 1, + color: eTheme.secondAreaGradTo, + }]), + }, + }, + data: [], + }; + } + + getThirdLine(eTheme) { + return { + type: 'line', + smooth: true, + symbolSize: 20, + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + color: '#ffffff', + borderColor: eTheme.itemBorderColor, + borderWidth: 2, + opacity: 1, + }, + }, + lineStyle: { + normal: { + width: eTheme.lineWidth, + type: eTheme.lineStyle, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.thirdLineGradFrom, + }, { + offset: 1, + color: eTheme.thirdLineGradTo, + }]), + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.thirdAreaGradFrom, + }, { + offset: 1, + color: eTheme.thirdAreaGradTo, + }]), + }, + }, + data: [], + }; + } + + updateOrdersChartOptions(ordersChartData: OrdersChart) { + const options = this.option; + const series = this.getNewSeries(options.series, ordersChartData.linesData); + const xAxis = this.getNewXAxis(options.xAxis, ordersChartData.chartLabel); + + this.option = { + ...options, + xAxis, + series, + }; + } + + getNewSeries(series, linesData: number[][]) { + return series.map((line, index) => { + return { + ...line, + data: linesData[index], + }; + }); + } + + getNewXAxis(xAxis, chartLabel: string[]) { + return { + ...xAxis, + data: chartLabel, + }; + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + // Fix recalculation chart size + // TODO: investigate more deeply + setTimeout(() => { + this.echartsIntance.resize(); + }, 0); + } + } + + ngOnDestroy() { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/charts-panel/charts/profit-chart.component.ts b/src/app/pages/e-commerce/charts-panel/charts/profit-chart.component.ts new file mode 100644 index 00000000..65cb017f --- /dev/null +++ b/src/app/pages/e-commerce/charts-panel/charts/profit-chart.component.ts @@ -0,0 +1,200 @@ +import { AfterViewInit, Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { takeWhile } from 'rxjs/operators'; + +import { ProfitChart } from '../../../../@core/data/profit-chart'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + +@Component({ + selector: 'ngx-profit-chart', + styleUrls: ['./charts-common.component.scss'], + template: ` +
+ `, +}) +export class ProfitChartComponent implements AfterViewInit, OnDestroy, OnChanges { + + @Input() + profitChartData: ProfitChart; + + private alive = true; + + echartsIntance: any; + options: any = {}; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngOnChanges(): void { + if (this.echartsIntance) { + this.updateProfitChartOptions(this.profitChartData); + } + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe(takeWhile(() => this.alive)) + .subscribe(config => { + const eTheme: any = config.variables.profit; + + this.setOptions(eTheme); + }); + } + + setOptions(eTheme) { + this.options = { + backgroundColor: eTheme.bg, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'shadow', + shadowStyle: { + color: 'rgba(0, 0, 0, 0.3)', + }, + }, + }, + grid: { + left: '3%', + right: '4%', + bottom: '3%', + containLabel: true, + }, + xAxis: [ + { + type: 'category', + data: this.profitChartData.chartLabel, + axisTick: { + alignWithLabel: true, + }, + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + }, + }, + axisLabel: { + color: eTheme.axisTextColor, + fontSize: eTheme.axisFontSize, + }, + }, + ], + yAxis: [ + { + type: 'value', + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + }, + }, + splitLine: { + lineStyle: { + color: eTheme.splitLineColor, + }, + }, + axisLabel: { + color: eTheme.axisTextColor, + fontSize: eTheme.axisFontSize, + }, + }, + ], + series: [ + { + name: 'Canceled', + type: 'bar', + barGap: 0, + barWidth: '20%', + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.firstLineGradFrom, + }, { + offset: 1, + color: eTheme.firstLineGradTo, + }]), + }, + }, + data: this.profitChartData.data[0], + }, + { + name: 'Payment', + type: 'bar', + barWidth: '20%', + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.secondLineGradFrom, + }, { + offset: 1, + color: eTheme.secondLineGradTo, + }]), + }, + }, + data: this.profitChartData.data[1], + }, + { + name: 'All orders', + type: 'bar', + barWidth: '20%', + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.thirdLineGradFrom, + }, { + offset: 1, + color: eTheme.thirdLineGradTo, + }]), + }, + }, + data: this.profitChartData.data[2], + }, + ], + }; + } + + updateProfitChartOptions(profitChartData: ProfitChart) { + const options = this.options; + const series = this.getNewSeries(options.series, profitChartData.data); + + this.echartsIntance.setOption({ + series: series, + xAxis: { + data: this.profitChartData.chartLabel, + }, + }); + } + + getNewSeries(series, data: number[][]) { + return series.map((line, index) => { + return { + ...line, + data: data[index], + }; + }); + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + // Fix recalculation chart size + // TODO: investigate more deeply + setTimeout(() => { + this.echartsIntance.resize(); + }, 0); + } + } + + ngOnDestroy(): void { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/country-orders/chart/country-orders-chart.component.ts b/src/app/pages/e-commerce/country-orders/chart/country-orders-chart.component.ts new file mode 100644 index 00000000..826a7fe0 --- /dev/null +++ b/src/app/pages/e-commerce/country-orders/chart/country-orders-chart.component.ts @@ -0,0 +1,181 @@ +import { AfterViewInit, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { takeWhile } from 'rxjs/operators'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + + +@Component({ + selector: 'ngx-country-orders-chart', + styleUrls: ['./country-orders-chart.component.scss'], + template: ` +
+ Selected Country/Region +

{{ countryName }}

+
+
+
+ `, +}) +export class CountryOrdersChartComponent implements AfterViewInit, OnDestroy, OnChanges { + + @Input() countryName: string; + @Input() data: number[]; + @Input() maxValue: number; + @Input() labels: string[]; + + private alive = true; + + option: any = {}; + echartsInstance; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.data && !changes.data.isFirstChange()) { + this.echartsInstance.setOption({ + series: [ + { + data: this.data.map(v => this.maxValue), + }, + { + data: this.data, + }, + { + data: this.data, + }, + ], + }); + } + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe(takeWhile(() => this.alive)) + .subscribe(config => { + const countriesTheme: any = config.variables.countryOrders; + + this.option = Object.assign({}, { + grid: { + left: '3%', + right: '3%', + bottom: '3%', + top: '3%', + containLabel: true, + }, + xAxis: { + axisLabel: { + color: countriesTheme.chartAxisTextColor, + fontSize: countriesTheme.chartAxisFontSize, + }, + axisLine: { + lineStyle: { + color: countriesTheme.chartAxisLineColor, + width: '2', + }, + }, + axisTick: { + show: false, + }, + splitLine: { + lineStyle: { + color: countriesTheme.chartAxisSplitLine, + width: '1', + }, + }, + }, + yAxis: { + data: this.labels, + axisLabel: { + color: countriesTheme.chartAxisTextColor, + fontSize: countriesTheme.chartAxisFontSize, + }, + axisLine: { + lineStyle: { + color: countriesTheme.chartAxisLineColor, + width: '2', + }, + }, + axisTick: { + show: false, + }, + }, + series: [ + { // For shadow + type: 'bar', + data: this.data.map(v => this.maxValue), + cursor: 'default', + itemStyle: { + normal: { + color: countriesTheme.chartInnerLineColor, + }, + opacity: 1, + }, + barWidth: '40%', + barGap: '-100%', + barCategoryGap: '30%', + animation: false, + z: 1, + }, + { // For bottom line + type: 'bar', + data: this.data, + cursor: 'default', + itemStyle: { + normal: { + color: countriesTheme.chartLineBottomShadowColor, + }, + opacity: 1, + }, + barWidth: '40%', + barGap: '-100%', + barCategoryGap: '30%', + z: 2, + }, + { + type: 'bar', + barWidth: '35%', + data: this.data, + cursor: 'default', + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(1, 0, 0, 0, [{ + offset: 0, + color: countriesTheme.chartGradientFrom, + }, { + offset: 1, + color: countriesTheme.chartGradientTo, + }]), + }, + }, + z: 3, + }, + ], + }); + }); + } + + onChartInit(ec) { + this.echartsInstance = ec; + } + + resizeChart() { + if (this.echartsInstance) { + this.echartsInstance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } + +} diff --git a/src/app/pages/e-commerce/earning-card/front-side/earning-live-update-chart.component.ts b/src/app/pages/e-commerce/earning-card/front-side/earning-live-update-chart.component.ts new file mode 100644 index 00000000..0b7c7474 --- /dev/null +++ b/src/app/pages/e-commerce/earning-card/front-side/earning-live-update-chart.component.ts @@ -0,0 +1,164 @@ +import { delay, takeWhile } from 'rxjs/operators'; +import { AfterViewInit, Component, Input, OnChanges, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + +@Component({ + selector: 'ngx-earning-live-update-chart', + styleUrls: ['earning-card-front.component.scss'], + template: ` +
+ `, +}) +export class EarningLiveUpdateChartComponent implements AfterViewInit, OnDestroy, OnChanges { + private alive = true; + + @Input() liveUpdateChartData: { value: [string, number] }[]; + + option: any; + echartsInstance; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngOnChanges(): void { + if (this.option) { + this.updateChartOptions(this.liveUpdateChartData); + } + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe( + delay(1), + takeWhile(() => this.alive), + ) + .subscribe(config => { + const earningLineTheme: any = config.variables.earningLine; + + this.setChartOption(earningLineTheme); + }); + } + + setChartOption(earningLineTheme) { + this.option = { + grid: { + left: 0, + top: 0, + right: 0, + bottom: 0, + }, + xAxis: { + type: 'time', + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + splitLine: { + show: false, + }, + }, + yAxis: { + boundaryGap: [0, '5%'], + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + splitLine: { + show: false, + }, + }, + tooltip: { + axisPointer: { + type: 'shadow', + }, + textStyle: { + color: earningLineTheme.tooltipTextColor, + fontWeight: earningLineTheme.tooltipFontWeight, + fontSize: earningLineTheme.tooltipFontSize, + }, + position: 'top', + backgroundColor: earningLineTheme.tooltipBg, + borderColor: earningLineTheme.tooltipBorderColor, + borderWidth: earningLineTheme.tooltipBorderWidth, + formatter: params => `$ ${Math.round(parseInt(params.value[1], 10))}`, + extraCssText: earningLineTheme.tooltipExtraCss, + }, + series: [ + { + type: 'line', + symbol: 'circle', + sampling: 'average', + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + opacity: 0, + }, + }, + lineStyle: { + normal: { + width: 0, + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: earningLineTheme.gradFrom, + }, { + offset: 1, + color: earningLineTheme.gradTo, + }]), + opacity: 1, + }, + }, + data: this.liveUpdateChartData, + }, + ], + animation: true, + }; + } + + updateChartOptions(chartData: { value: [string, number] }[]) { + this.echartsInstance.setOption({ + series: [{ + data: chartData, + }], + }); + } + + onChartInit(ec) { + this.echartsInstance = ec; + } + + resizeChart() { + if (this.echartsInstance) { + this.echartsInstance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/profit-card/back-side/stats-area-chart.component.ts b/src/app/pages/e-commerce/profit-card/back-side/stats-area-chart.component.ts new file mode 100644 index 00000000..2f0e9d06 --- /dev/null +++ b/src/app/pages/e-commerce/profit-card/back-side/stats-area-chart.component.ts @@ -0,0 +1,172 @@ +import { delay, takeWhile } from 'rxjs/operators'; +import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { LayoutService } from '../../../../@core/utils'; + +@Component({ + selector: 'ngx-stats-ares-chart', + styleUrls: ['stats-card-back.component.scss'], + template: ` +
+
+ `, +}) +export class StatsAreaChartComponent implements AfterViewInit, OnDestroy { + + private alive = true; + + @Input() points: number[]; + + echartsIntance: any; + option: any = {}; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe( + delay(1), + takeWhile(() => this.alive), + ) + .subscribe(config => { + const trafficTheme: any = config.variables.traffic; + + this.option = Object.assign({}, { + grid: { + left: 0, + top: 0, + right: 0, + bottom: 0, + }, + xAxis: { + type: 'category', + boundaryGap: false, + data: this.points, + }, + yAxis: { + boundaryGap: [0, '5%'], + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + splitLine: { + show: true, + lineStyle: { + color: trafficTheme.yAxisSplitLine, + width: '1', + }, + }, + }, + tooltip: { + axisPointer: { + type: 'shadow', + }, + textStyle: { + color: trafficTheme.tooltipTextColor, + fontWeight: trafficTheme.tooltipFontWeight, + fontSize: 16, + }, + position: 'top', + backgroundColor: trafficTheme.tooltipBg, + borderColor: trafficTheme.tooltipBorderColor, + borderWidth: 1, + formatter: '$ {c0}', + extraCssText: trafficTheme.tooltipExtraCss, + }, + series: [ + { + type: 'line', + symbol: 'circle', + symbolSize: 8, + sampling: 'average', + silent: true, + itemStyle: { + normal: { + color: trafficTheme.shadowLineDarkBg, + }, + emphasis: { + color: 'rgba(0,0,0,0)', + borderColor: 'rgba(0,0,0,0)', + borderWidth: 0, + }, + }, + lineStyle: { + normal: { + width: 2, + color: trafficTheme.shadowLineDarkBg, + }, + }, + data: this.points.map(p => p - 15), + }, + { + type: 'line', + symbol: 'circle', + symbolSize: 6, + sampling: 'average', + itemStyle: { + normal: { + color: trafficTheme.itemColor, + borderColor: trafficTheme.itemBorderColor, + borderWidth: 2, + }, + emphasis: { + color: 'white', + borderColor: trafficTheme.itemEmphasisBorderColor, + borderWidth: 2, + }, + }, + lineStyle: { + normal: { + width: 2, + color: trafficTheme.lineBg, + shadowColor: trafficTheme.lineBg, + shadowBlur: trafficTheme.lineShadowBlur, + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: trafficTheme.gradFrom, + }, { + offset: 1, + color: trafficTheme.gradTo, + }]), + opacity: 1, + }, + }, + data: this.points, + }, + ], + }); + }); + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + this.echartsIntance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/profit-card/front-side/stats-bar-animation-chart.component.ts b/src/app/pages/e-commerce/profit-card/front-side/stats-bar-animation-chart.component.ts new file mode 100644 index 00000000..339cd160 --- /dev/null +++ b/src/app/pages/e-commerce/profit-card/front-side/stats-bar-animation-chart.component.ts @@ -0,0 +1,153 @@ +import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { takeWhile } from 'rxjs/operators'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + +@Component({ + selector: 'ngx-stats-bar-animation-chart', + template: ` +
+
+ `, +}) +export class StatsBarAnimationChartComponent implements AfterViewInit, OnDestroy { + + private alive = true; + + @Input() linesData: { firstLine: number[]; secondLine: number[] } = { + firstLine: [], + secondLine: [], + }; + + echartsIntance: any; + options: any = {}; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe(takeWhile(() => this.alive)) + .subscribe(config => { + const profitBarAnimationEchart: any = config.variables.profitBarAnimationEchart; + + this.setChartOption(profitBarAnimationEchart); + }); + } + + setChartOption(chartVariables) { + this.options = { + color: [ + chartVariables.firstAnimationBarColor, + chartVariables.secondAnimationBarColor, + ], + grid: { + left: 0, + top: 0, + right: 0, + bottom: 0, + }, + legend: { + data: ['transactions', 'orders'], + borderWidth: 0, + borderRadius: 0, + itemWidth: 15, + itemHeight: 15, + textStyle: { + color: chartVariables.textColor, + }, + }, + tooltip: { + axisPointer: { + type: 'shadow', + }, + textStyle: { + color: chartVariables.tooltipTextColor, + fontWeight: chartVariables.tooltipFontWeight, + fontSize: chartVariables.tooltipFontSize, + }, + position: 'top', + backgroundColor: chartVariables.tooltipBg, + borderColor: chartVariables.tooltipBorderColor, + borderWidth: chartVariables.tooltipBorderWidth, + formatter: params => `$ ${Math.round(parseInt(params.value, 10))}`, + extraCssText: chartVariables.tooltipExtraCss, + }, + xAxis: [ + { + data: this.linesData.firstLine.map((_, index) => index), + silent: false, + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + }, + ], + yAxis: [ + { + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + splitLine: { + show: true, + lineStyle: { + color: chartVariables.splitLineStyleColor, + opacity: chartVariables.splitLineStyleOpacity, + width: chartVariables.splitLineStyleWidth, + }, + }, + }, + ], + series: [ + { + name: 'transactions', + type: 'bar', + data: this.linesData.firstLine, + animationDelay: idx => idx * 10, + }, + { + name: 'orders', + type: 'bar', + data: this.linesData.secondLine, + animationDelay: idx => idx * 10 + 100, + }, + ], + animationEasing: 'elasticOut', + animationDelayUpdate: idx => idx * 5, + }; + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + this.echartsIntance.resize(); + } + } + + ngOnDestroy(): void { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/traffic-reveal-card/back-side/traffic-bar-chart.component.ts b/src/app/pages/e-commerce/traffic-reveal-card/back-side/traffic-bar-chart.component.ts new file mode 100644 index 00000000..f2a55b7f --- /dev/null +++ b/src/app/pages/e-commerce/traffic-reveal-card/back-side/traffic-bar-chart.component.ts @@ -0,0 +1,150 @@ +import { AfterViewInit, Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { takeWhile } from 'rxjs/operators'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + +declare const echarts: any; + +@Component({ + selector: 'ngx-traffic-bar-chart', + template: ` +
+
+ `, +}) +export class TrafficBarChartComponent implements AfterViewInit, OnDestroy, OnChanges { + + @Input() data: number[]; + @Input() labels: string[]; + @Input() formatter: string; + + private alive = true; + + option: any = {}; + echartsInstance: any; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + onChartInit(ec) { + this.echartsInstance = ec; + } + + resizeChart() { + if (this.echartsInstance) { + this.echartsInstance.resize(); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (!changes.data.isFirstChange() && !changes.labels.isFirstChange()) { + this.echartsInstance.setOption({ + series: [{ + data: this.data, + }], + xAxis: { + data: this.labels, + }, + tooltip: { + formatter: this.formatter, + }, + }); + } + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe(takeWhile(() => this.alive)) + .subscribe(config => { + const trafficTheme: any = config.variables.trafficBarEchart; + + this.option = Object.assign({}, { + grid: { + left: 0, + top: 0, + right: 0, + bottom: 0, + containLabel: true, + }, + xAxis: { + type : 'category', + data : this.labels, + axisLabel: { + color: trafficTheme.axisTextColor, + fontSize: trafficTheme.axisFontSize, + }, + axisLine: { + show: false, + }, + axisTick: { + show: false, + }, + }, + yAxis: { + show: false, + axisLine: { + show: false, + }, + axisLabel: { + show: false, + }, + axisTick: { + show: false, + }, + boundaryGap: [0, '5%'], + }, + tooltip: { + axisPointer: { + type: 'shadow', + }, + textStyle: { + color: trafficTheme.tooltipTextColor, + fontWeight: trafficTheme.tooltipFontWeight, + fontSize: 16, + }, + position: 'top', + backgroundColor: trafficTheme.tooltipBg, + borderColor: trafficTheme.tooltipBorderColor, + borderWidth: 1, + formatter: this.formatter, + extraCssText: trafficTheme.tooltipExtraCss, + }, + series: [ + { + type: 'bar', + barWidth: '40%', + data: this.data, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: trafficTheme.gradientFrom, + }, { + offset: 1, + color: trafficTheme.gradientTo, + }]), + opacity: 1, + shadowColor: trafficTheme.gradientFrom, + shadowBlur: trafficTheme.shadowBlur, + }, + }, + }, + ], + }); + }); + } + + ngOnDestroy() { + this.alive = false; + } + +} diff --git a/src/app/pages/e-commerce/visitors-analytics/visitors-analytics-chart/visitors-analytics-chart.component.ts b/src/app/pages/e-commerce/visitors-analytics/visitors-analytics-chart/visitors-analytics-chart.component.ts new file mode 100644 index 00000000..48329905 --- /dev/null +++ b/src/app/pages/e-commerce/visitors-analytics/visitors-analytics-chart/visitors-analytics-chart.component.ts @@ -0,0 +1,234 @@ +import { delay, takeWhile } from 'rxjs/operators'; +import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { LayoutService } from '../../../../@core/utils'; +import { OutlineData } from '../../../../@core/data/visitors-analytics'; + +@Component({ + selector: 'ngx-visitors-analytics-chart', + styleUrls: ['./visitors-analytics-chart.component.scss'], + template: ` +
+
+ `, +}) +export class ECommerceVisitorsAnalyticsChartComponent implements AfterViewInit, OnDestroy { + + private alive = true; + + @Input() chartData: { + innerLine: number[]; + outerLine: OutlineData[]; + }; + + option: any; + themeSubscription: any; + echartsIntance: any; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit(): void { + this.theme.getJsTheme() + .pipe( + delay(1), + takeWhile(() => this.alive), + ) + .subscribe(config => { + const eTheme: any = config.variables.visitors; + + this.setOptions(eTheme); + }); + } + + setOptions(eTheme) { + this.option = { + grid: { + left: 40, + top: 20, + right: 0, + bottom: 60, + }, + tooltip: { + trigger: 'axis', + axisPointer: { + type: 'line', + lineStyle: { + color: eTheme.tooltipLineColor, + width: eTheme.tooltipLineWidth, + }, + }, + textStyle: { + color: eTheme.tooltipTextColor, + fontSize: 20, + fontWeight: eTheme.tooltipFontWeight, + }, + position: 'top', + backgroundColor: eTheme.tooltipBg, + borderColor: eTheme.tooltipBorderColor, + borderWidth: 1, + formatter: (params) => { + return Math.round(parseInt(params[0].value, 10)); + }, + extraCssText: eTheme.tooltipExtraCss, + }, + xAxis: { + type: 'category', + boundaryGap: false, + offset: 25, + data: this.chartData.outerLine.map(i => i.label), + axisTick: { + show: false, + }, + axisLabel: { + color: eTheme.axisTextColor, + fontSize: eTheme.axisFontSize, + }, + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + width: '2', + }, + }, + }, + yAxis: { + type: 'value', + boundaryGap: false, + axisLine: { + lineStyle: { + color: eTheme.axisLineColor, + width: '1', + }, + }, + axisLabel: { + color: eTheme.axisTextColor, + fontSize: eTheme.axisFontSize, + }, + axisTick: { + show: false, + }, + splitLine: { + + lineStyle: { + color: eTheme.yAxisSplitLine, + width: '1', + }, + }, + }, + series: [ + this.getInnerLine(eTheme), + this.getOuterLine(eTheme), + ], + }; + } + + getOuterLine(eTheme) { + return { + type: 'line', + smooth: true, + symbolSize: 20, + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + color: '#ffffff', + borderColor: eTheme.itemBorderColor, + borderWidth: 2, + opacity: 1, + }, + }, + lineStyle: { + normal: { + width: eTheme.lineWidth, + type: eTheme.lineStyle, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.lineGradFrom, + }, { + offset: 1, + color: eTheme.lineGradTo, + }]), + shadowColor: eTheme.lineShadow, + shadowBlur: 6, + shadowOffsetY: 12, + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.areaGradFrom, + }, { + offset: 1, + color: eTheme.areaGradTo, + }]), + }, + }, + data: this.chartData.outerLine.map(i => i.value), + }; + } + + getInnerLine(eTheme) { + return { + type: 'line', + smooth: true, + symbolSize: 20, + tooltip: { + show: false, + extraCssText: '', + }, + itemStyle: { + normal: { + opacity: 0, + }, + emphasis: { + opacity: 0, + }, + }, + lineStyle: { + normal: { + width: eTheme.innerLineWidth, + type: eTheme.innerLineStyle, + color: new echarts.graphic.LinearGradient(0, 0, 0, 1), + }, + }, + areaStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [{ + offset: 0, + color: eTheme.innerAreaGradFrom, + }, { + offset: 1, + color: eTheme.innerAreaGradTo, + }]), + opacity: 1, + }, + }, + data: this.chartData.innerLine, + }; + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + this.echartsIntance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } +} diff --git a/src/app/pages/e-commerce/visitors-analytics/visitors-statistics/visitors-statistics.component.ts b/src/app/pages/e-commerce/visitors-analytics/visitors-statistics/visitors-statistics.component.ts new file mode 100644 index 00000000..3ba87388 --- /dev/null +++ b/src/app/pages/e-commerce/visitors-analytics/visitors-statistics/visitors-statistics.component.ts @@ -0,0 +1,215 @@ +import { AfterViewInit, Component, Input, OnDestroy } from '@angular/core'; +import { NbThemeService } from '@nebular/theme'; +import { delay, takeWhile } from 'rxjs/operators'; +import { LayoutService } from '../../../../@core/utils/layout.service'; + + +@Component({ + selector: 'ngx-visitors-statistics', + styleUrls: ['./visitors-statistics.component.scss'], + templateUrl: './visitors-statistics.component.html', +}) +export class ECommerceVisitorsStatisticsComponent implements AfterViewInit, OnDestroy { + + private alive = true; + + @Input() value: number; + + option: any = {}; + chartLegend: { iconColor: string; title: string }[]; + echartsIntance: any; + + constructor(private theme: NbThemeService, + private layoutService: LayoutService) { + this.layoutService.onSafeChangeLayoutSize() + .pipe( + takeWhile(() => this.alive), + ) + .subscribe(() => this.resizeChart()); + } + + ngAfterViewInit() { + this.theme.getJsTheme() + .pipe( + takeWhile(() => this.alive), + delay(1), + ) + .subscribe(config => { + const variables: any = config.variables; + const visitorsPieLegend: any = config.variables.visitorsPieLegend; + + this.setOptions(variables); + this.setLegendItems(visitorsPieLegend); + }); + } + + setLegendItems(visitorsPieLegend) { + this.chartLegend = [ + { + iconColor: visitorsPieLegend.firstSection, + title: 'New Visitors', + }, + { + iconColor: visitorsPieLegend.secondSection, + title: 'Return Visitors', + }, + ]; + } + + setOptions(variables) { + const visitorsPie: any = variables.visitorsPie; + + this.option = { + tooltip: { + trigger: 'item', + formatter: '', + }, + series: [ + { + name: ' ', + clockWise: true, + hoverAnimation: false, + type: 'pie', + center: ['50%', '50%'], + radius: visitorsPie.firstPieRadius, + data: [ + { + value: this.value, + name: ' ', + label: { + normal: { + position: 'center', + formatter: '', + textStyle: { + fontSize: '22', + fontFamily: variables.fontSecondary, + fontWeight: '600', + color: variables.fgHeading, + }, + }, + }, + tooltip: { + show: false, + }, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: visitorsPie.firstPieGradientLeft, + }, + { + offset: 1, + color: visitorsPie.firstPieGradientRight, + }, + ]), + shadowColor: visitorsPie.firstPieShadowColor, + shadowBlur: 0, + shadowOffsetX: 0, + shadowOffsetY: 3, + }, + }, + hoverAnimation: false, + }, + { + value: 100 - this.value, + name: ' ', + tooltip: { + show: false, + }, + label: { + normal: { + position: 'inner', + }, + }, + itemStyle: { + normal: { + color: variables.layoutBg, + }, + }, + }, + ], + }, + { + name: ' ', + clockWise: true, + hoverAnimation: false, + type: 'pie', + center: ['50%', '50%'], + radius: visitorsPie.secondPieRadius, + data: [ + { + value: this.value, + name: ' ', + label: { + normal: { + position: 'center', + formatter: '', + textStyle: { + fontSize: '22', + fontFamily: variables.fontSecondary, + fontWeight: '600', + color: variables.fgHeading, + }, + }, + }, + tooltip: { + show: false, + }, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1), + }, + }, + hoverAnimation: false, + }, + { + value: 100 - this.value, + name: ' ', + tooltip: { + show: false, + }, + label: { + normal: { + position: 'inner', + }, + }, + itemStyle: { + normal: { + color: new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { + offset: 0, + color: visitorsPie.secondPieGradientLeft, + }, + { + offset: 1, + color: visitorsPie.secondPieGradientRight, + }, + ]), + shadowColor: visitorsPie.secondPieShadowColor, + shadowBlur: 0, + shadowOffsetX: visitorsPie.shadowOffsetX, + shadowOffsetY: visitorsPie.shadowOffsetY, + }, + }, + }, + ], + }, + ], + }; + } + + onChartInit(echarts) { + this.echartsIntance = echarts; + } + + resizeChart() { + if (this.echartsIntance) { + this.echartsIntance.resize(); + } + } + + ngOnDestroy() { + this.alive = false; + } +}