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: `
+
+
+
+ `,
+})
+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;
+ }
+}