diff --git a/client/package-lock.json b/client/package-lock.json index 5c58b57..00e51c8 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -275,6 +275,24 @@ "semver-intersect": "1.3.1" } }, + "@swimlane/ngx-charts": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-7.3.0.tgz", + "integrity": "sha512-vRepalGJQOiVMBiIhLSuRY0d4nAA6ORSHXGRe8Klqh808NQ9WXR7tvB8zk4MFr496v6iilG8dLIeDwXGY+asOw==", + "requires": { + "d3-array": "1.2.1", + "d3-brush": "1.0.4", + "d3-color": "1.1.0", + "d3-force": "1.1.0", + "d3-format": "1.2.2", + "d3-hierarchy": "1.1.6", + "d3-interpolate": "1.1.6", + "d3-scale": "1.0.7", + "d3-selection": "1.3.0", + "d3-shape": "1.2.0", + "d3-time-format": "2.1.1" + } + }, "abbrev": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", @@ -1122,6 +1140,39 @@ "supports-color": "4.5.0" } }, + "chart.js": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.7.2.tgz", + "integrity": "sha512-90wl3V9xRZ8tnMvMlpcW+0Yg13BelsGS9P9t0ClaDxv/hdypHDr/YAGf+728m11P5ljwyB0ZHfPKCapZFqSqYA==", + "requires": { + "chartjs-color": "2.2.0", + "moment": "2.22.1" + } + }, + "chartjs-color": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.2.0.tgz", + "integrity": "sha1-hKL7dVeH7YXDndbdjHsdiEKbrq4=", + "requires": { + "chartjs-color-string": "0.5.0", + "color-convert": "0.5.3" + }, + "dependencies": { + "color-convert": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz", + "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=" + } + } + }, + "chartjs-color-string": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.5.0.tgz", + "integrity": "sha512-amWNvCOXlOUYxZVDSa0YOab5K/lmEhbFNKI55PWc4mlv28BDzA7zaoQTGxSBgJMHIW+hGX8YUrvw/FH4LyhwSQ==", + "requires": { + "color-name": "1.1.3" + } + }, "chokidar": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", @@ -1335,8 +1386,7 @@ "color-name": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=" }, "combined-stream": { "version": "1.0.6", @@ -1699,6 +1749,149 @@ "es5-ext": "0.10.41" } }, + "d3-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-1.2.1.tgz", + "integrity": "sha512-CyINJQ0SOUHojDdFDH4JEM0552vCR1utGyLHegJHyYH0JyCpSeTPxi4OBqHMA2jJZq4NH782LtaJWBImqI/HBw==" + }, + "d3-brush": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-1.0.4.tgz", + "integrity": "sha1-AMLyOAGfJPbAoZSibUGhUw/+e8Q=", + "requires": { + "d3-dispatch": "1.0.3", + "d3-drag": "1.2.1", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-transition": "1.1.1" + } + }, + "d3-collection": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/d3-collection/-/d3-collection-1.0.4.tgz", + "integrity": "sha1-NC39EoN8kJdPM/HMCnha6lcNzcI=" + }, + "d3-color": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-1.1.0.tgz", + "integrity": "sha512-IZVcqX5yYFvR2NUBbSfIfbgNcSgAtZ7JbgQWqDXf4CywtN7agvI7Kw6+Q1ETvlHOHWJT55Kyuzt0C3I0GVtRHQ==" + }, + "d3-dispatch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-1.0.3.tgz", + "integrity": "sha1-RuFJHqqbWMNY/OW+TovtYm54cfg=" + }, + "d3-drag": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-1.2.1.tgz", + "integrity": "sha512-Cg8/K2rTtzxzrb0fmnYOUeZHvwa4PHzwXOLZZPwtEs2SKLLKLXeYwZKBB+DlOxUvFmarOnmt//cU4+3US2lyyQ==", + "requires": { + "d3-dispatch": "1.0.3", + "d3-selection": "1.3.0" + } + }, + "d3-ease": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-1.0.3.tgz", + "integrity": "sha1-aL+8NJM4o4DETYrMT7wzBKotjA4=" + }, + "d3-force": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/d3-force/-/d3-force-1.1.0.tgz", + "integrity": "sha512-2HVQz3/VCQs0QeRNZTYb7GxoUCeb6bOzMp/cGcLa87awY9ZsPvXOGeZm0iaGBjXic6I1ysKwMn+g+5jSAdzwcg==", + "requires": { + "d3-collection": "1.0.4", + "d3-dispatch": "1.0.3", + "d3-quadtree": "1.0.3", + "d3-timer": "1.0.7" + } + }, + "d3-format": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-1.2.2.tgz", + "integrity": "sha512-zH9CfF/3C8zUI47nsiKfD0+AGDEuM8LwBIP7pBVpyR4l/sKkZqITmMtxRp04rwBrlshIZ17XeFAaovN3++wzkw==" + }, + "d3-hierarchy": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-1.1.6.tgz", + "integrity": "sha512-nn4bhBnwWnMSoZgkBXD7vRyZ0xVUsNMQRKytWYHhP1I4qHw+qzApCTgSQTZqMdf4XXZbTMqA59hFusga+THA/g==" + }, + "d3-interpolate": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-1.1.6.tgz", + "integrity": "sha512-mOnv5a+pZzkNIHtw/V6I+w9Lqm9L5bG3OTXPM5A+QO0yyVMQ4W1uZhR+VOJmazaOZXri2ppbiZ5BUNWT0pFM9A==", + "requires": { + "d3-color": "1.1.0" + } + }, + "d3-path": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.5.tgz", + "integrity": "sha1-JB6xhJvZ6egCHA0KeZ+KDo5EF2Q=" + }, + "d3-quadtree": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/d3-quadtree/-/d3-quadtree-1.0.3.tgz", + "integrity": "sha1-rHmH4+I/6AWpkPKOG1DTj8uCJDg=" + }, + "d3-scale": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-1.0.7.tgz", + "integrity": "sha512-KvU92czp2/qse5tUfGms6Kjig0AhHOwkzXG0+PqIJB3ke0WUv088AHMZI0OssO9NCkXt4RP8yju9rpH8aGB7Lw==", + "requires": { + "d3-array": "1.2.1", + "d3-collection": "1.0.4", + "d3-color": "1.1.0", + "d3-format": "1.2.2", + "d3-interpolate": "1.1.6", + "d3-time": "1.0.8", + "d3-time-format": "2.1.1" + } + }, + "d3-selection": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-1.3.0.tgz", + "integrity": "sha512-qgpUOg9tl5CirdqESUAu0t9MU/t3O9klYfGfyKsXEmhyxyzLpzpeh08gaxBUTQw1uXIOkr/30Ut2YRjSSxlmHA==" + }, + "d3-shape": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.2.0.tgz", + "integrity": "sha1-RdAVOPBkuv0F6j1tLLdI/YxB93c=", + "requires": { + "d3-path": "1.0.5" + } + }, + "d3-time": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-1.0.8.tgz", + "integrity": "sha512-YRZkNhphZh3KcnBfitvF3c6E0JOFGikHZ4YqD+Lzv83ZHn1/u6yGenRU1m+KAk9J1GnZMnKcrtfvSktlA1DXNQ==" + }, + "d3-time-format": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-2.1.1.tgz", + "integrity": "sha512-8kAkymq2WMfzW7e+s/IUNAtN/y3gZXGRrdGfo6R8NKPAA85UBTxZg5E61bR6nLwjPjj4d3zywSQe1CkYLPFyrw==", + "requires": { + "d3-time": "1.0.8" + } + }, + "d3-timer": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-1.0.7.tgz", + "integrity": "sha512-vMZXR88XujmG/L5oB96NNKH5lCWwiLM/S2HyyAQLcjWJCloK5shxta4CwOFYLZoY3AWX73v8Lgv4cCAdWtRmOA==" + }, + "d3-transition": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-1.1.1.tgz", + "integrity": "sha512-xeg8oggyQ+y5eb4J13iDgKIjUcEfIOZs2BqV/eEmXm2twx80wTzJ4tB4vaZ5BKfz7XsI/DFmQL5me6O27/5ykQ==", + "requires": { + "d3-color": "1.1.0", + "d3-dispatch": "1.0.3", + "d3-ease": "1.0.3", + "d3-interpolate": "1.1.6", + "d3-selection": "1.3.0", + "d3-timer": "1.0.7" + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -4342,6 +4535,11 @@ "minimist": "0.0.8" } }, + "moment": { + "version": "2.22.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.1.tgz", + "integrity": "sha512-shJkRTSebXvsVqk56I+lkb2latjBs8I+pc2TzWc545y2iFnSjm7Wg0QMh+ZWcdSLQyGEau5jI8ocnmkyTgr9YQ==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/client/package.json b/client/package.json index a31b841..1fe8b88 100644 --- a/client/package.json +++ b/client/package.json @@ -21,6 +21,7 @@ "@angular/material": "^5.2.4", "@angular/platform-browser": "^5.2.9", "@angular/platform-browser-dynamic": "^5.2.9", + "chart.js": "^2.7.2", "ngx-electron": "^1.0.4", "rxjs": "^5.5.7", "zone.js": "^0.8.20" diff --git a/client/src/app/app.component.ts b/client/src/app/app.component.ts index 28f99e4..3905f51 100644 --- a/client/src/app/app.component.ts +++ b/client/src/app/app.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { AfterViewInit, Component } from '@angular/core'; import { UpdaterService } from './update/updater.service'; @Component({ @@ -6,10 +6,10 @@ import { UpdaterService } from './update/updater.service'; templateUrl: './app.component.html', styleUrls: ['./app.component.scss'] }) -export class AppComponent implements OnInit { +export class AppComponent implements AfterViewInit { constructor(private _updaterService: UpdaterService) {} - ngOnInit() { + ngAfterViewInit() { this._updaterService.setupHandlers(); } } diff --git a/client/src/app/app.module.ts b/client/src/app/app.module.ts index a2f89d5..092208b 100644 --- a/client/src/app/app.module.ts +++ b/client/src/app/app.module.ts @@ -5,13 +5,15 @@ import { MatButtonModule, MatCheckboxModule, MatDialogModule, + MatExpansionModule, MatIconModule, MatListModule, + MatProgressBarModule, MatProgressSpinnerModule, MatSidenavModule, MatSnackBarModule, MatTableModule, - MatToolbarModule, + MatToolbarModule } from '@angular/material'; import { BrowserModule } from '@angular/platform-browser'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; @@ -19,6 +21,8 @@ import { NgxElectronModule } from 'ngx-electron'; import { AppComponent } from './app.component'; import { CardPreviewOverlayComponent } from './card-preview/card-preview.component'; import { CardPreviewOverlayService } from './card-preview/card-preview.service'; +import { ChartsComponent } from './chart/chart.component'; +import { SeriesChartComponent } from './chart/series-chart.component'; import { HomeComponent } from './home/home.component'; import { IpcService } from './ipc.service'; import { SetItemComponent } from './set-item/set-item.component'; @@ -30,13 +34,16 @@ import { UpdaterService } from './update/updater.service'; declarations: [ AppComponent, HomeComponent, + ChartsComponent, SetItemComponent, // MenuItemComponent, UpdateAvailableDialogComponent, UpdateDownloadedDialogComponent, - CardPreviewOverlayComponent + CardPreviewOverlayComponent, + + SeriesChartComponent // SettingsDialogComponent ], imports: [ @@ -50,6 +57,8 @@ import { UpdaterService } from './update/updater.service'; MatIconModule, MatToolbarModule, MatCheckboxModule, + MatProgressBarModule, + MatExpansionModule, NgxElectronModule, BrowserModule, diff --git a/client/src/app/card-preview/card-preview.component.ts b/client/src/app/card-preview/card-preview.component.ts index 76139a4..2cc9c6c 100644 --- a/client/src/app/card-preview/card-preview.component.ts +++ b/client/src/app/card-preview/card-preview.component.ts @@ -1,4 +1,4 @@ -import { Component, Inject, OnInit } from '@angular/core'; +import { AfterViewInit, Component, Inject } from '@angular/core'; import { Subject } from 'rxjs/Subject'; import { IpcService } from '../ipc.service'; import { CardPreviewOverlayRef } from './card-preview-overlay.ref'; @@ -12,7 +12,7 @@ import { templateUrl: './card-preview.component.html', styleUrls: ['./card-preview.component.css'] }) -export class CardPreviewOverlayComponent implements OnInit { +export class CardPreviewOverlayComponent implements AfterViewInit { img$: Subject = new Subject(); constructor( @@ -21,7 +21,7 @@ export class CardPreviewOverlayComponent implements OnInit { private _ipcService: IpcService ) {} - ngOnInit() { + ngAfterViewInit() { this._ipcService.setupIpcListenerOnce( `cards:image:${this.cardData.setCode}-${this.cardData.cardNumber}`, (event, args) => { diff --git a/client/src/app/chart/chart.component.html b/client/src/app/chart/chart.component.html new file mode 100644 index 0000000..489b7c6 --- /dev/null +++ b/client/src/app/chart/chart.component.html @@ -0,0 +1,33 @@ + + + + + + + + + + + + + + + General + + + + + + {{ generalChart }} + + + + diff --git a/client/src/app/chart/chart.component.scss b/client/src/app/chart/chart.component.scss new file mode 100644 index 0000000..0b21de8 --- /dev/null +++ b/client/src/app/chart/chart.component.scss @@ -0,0 +1,12 @@ +:host { + display: block; + height: 100%; +} + +.mat-expansion-panel-header-description { + max-width: calc(50% - 17px); +} + +.mat-expansion-panel-header-title { + max-width: calc(50% - 17px); +} diff --git a/client/src/app/chart/chart.component.ts b/client/src/app/chart/chart.component.ts new file mode 100644 index 0000000..59e0d76 --- /dev/null +++ b/client/src/app/chart/chart.component.ts @@ -0,0 +1,146 @@ +import { AfterViewInit, Component } from '@angular/core'; +import { Chart } from 'chart.js'; +import { IpcService } from '../ipc.service'; + +@Component({ + selector: 'pokemon-charts', + templateUrl: './chart.component.html', + styleUrls: ['./chart.component.scss'] +}) +export class ChartsComponent implements AfterViewInit { + totalProgress = 0; + + seriesData: { + name: string; + series: { + name: string; + value: number; + }[]; + }[] = [ + { + name: 'XY', + series: [ + { + name: 'Set 1', + value: 97 + }, + { + name: 'Set 2', + value: 65 + }, + { + name: 'Set 3', + value: 23 + } + ] + } + ]; + + data: { name: string; value: number }[] = []; + + charts = [ + 'Base', + 'XY', + 'POP', + 'Black & White', + 'HeartGold & SoulSilver', + 'Platinum', + 'EX', + 'Sun & Moon', + 'Gym', + 'Diamond & Pearl', + 'Neo', + 'E-Card' + ]; + chartData = {}; + + generalChart: Chart; + + series: string[]; + + constructor(private _ipcService: IpcService) {} + + ngAfterViewInit(): void { + this._setupSeriesHandler(); + + this._setupChartingHandler(); + this._ipcService.sendMessage('chart:load'); + + // this._setupSeriesDataHandler(); + // this._ipcService.sendMessage('chart:load:series'); + } + + private _setupChartingHandler() { + this._ipcService.setupIpcListenerOnce('chart:data', (event, data) => { + this.totalProgress = data.collected / data.total * 100; + }); + } + + private _setupSeriesHandler() { + this._ipcService.setupIpcListenerOnce('series:data', (event, data) => { + this.series = data; + }); + } + + private _setupSeriesDataHandler() { + this._ipcService.setupIpcListenerOnce( + 'chart:data:series', + (event, data) => { + data.forEach(seriesSet => { + // let chartObject: { name: string; chart ?: any } = { + // name: seriesSet.name + // }; + + // this.charts.push(seriesSet.name); + + let labels = []; + let data = []; + + seriesSet.series.forEach(set => { + labels.push(set.name); + data.push(set.value); + }); + + console.log(labels, data); + + this.chartData[seriesSet.name] = new Chart(seriesSet.name, { + type: 'polarArea', + data: { + labels: labels, + datasets: [ + { + data: data + } + ] + } + }); + + console.log(this.chartData); + + // console.log(seriesChart); + + // seriesSet.series.forEach(set => { + // seriesChart.data.labels.push(set.name); + // seriesChart.data.datasets = [ + // { + + // .forEach(dataset => { + // console.log(set); + // dataset.data.push(set.value); + // }); + // seriesChart.update(); + // }); + + //this.charts.push(seriesChart); + + // this.chartData[seriesSet.name] = seriesChart; + + // chartObject.chart = seriesChart; + }); + + console.log(data); + this.seriesData = data; + } + ); + } +} diff --git a/client/src/app/chart/series-chart.component.html b/client/src/app/chart/series-chart.component.html new file mode 100644 index 0000000..aac4695 --- /dev/null +++ b/client/src/app/chart/series-chart.component.html @@ -0,0 +1,11 @@ + + + + {{ series }} + + + + + + {{ chart }} + diff --git a/client/src/app/chart/series-chart.component.scss b/client/src/app/chart/series-chart.component.scss new file mode 100644 index 0000000..9ad22a5 --- /dev/null +++ b/client/src/app/chart/series-chart.component.scss @@ -0,0 +1,11 @@ +.mat-expanded { + margin: 16px 0; +} + +.mat-expansion-panel-header-description { + max-width: calc(50% - 17px); +} + +.mat-expansion-panel-header-title { + max-width: calc(50% - 17px); +} diff --git a/client/src/app/chart/series-chart.component.ts b/client/src/app/chart/series-chart.component.ts new file mode 100644 index 0000000..f12b421 --- /dev/null +++ b/client/src/app/chart/series-chart.component.ts @@ -0,0 +1,71 @@ +import { AfterViewInit, Component, Input } from '@angular/core'; +import { Chart } from 'chart.js'; +import { IpcService } from '../ipc.service'; + +@Component({ + selector: 'pokemon-series-chart', + templateUrl: './series-chart.component.html', + styleUrls: ['./series-chart.component.scss'] +}) +export class SeriesChartComponent implements AfterViewInit { + @Input() series: string; + + chart; + + progress = 0; + + constructor(private _ipcService: IpcService) {} + + ngAfterViewInit(): void { + this._setupSeriesChartHandler(); + this._ipcService.sendMessage(`chart:series:load`, this.series); + } + + private _setupSeriesChartHandler() { + this._ipcService.setupIpcListenerOnce( + `chart:series:data:${this.series}`, + (event, data) => { + let seriesData = data.reduce( + (accumulator, currentValue) => { + accumulator.labels.push(currentValue.name); + accumulator.values.push(currentValue.value); + return accumulator; + }, + { labels: [], values: [] } + ); + + this.chart = new Chart(this.series, { + type: 'polarArea', + data: { + labels: seriesData.labels, + datasets: [ + { + data: seriesData.values, + backgroundColor: this._fillColors(seriesData.values.length) + } + ] + } + }); + + this.progress = + seriesData.values.reduce((accumulator, currentValue) => { + accumulator += parseFloat(currentValue); + return accumulator; + }, 0) / seriesData.values.length; + } + ); + } + + private _fillColors(length) { + return Array.apply(null, Array(length)).map(x => this._getRandomColor()); + } + + private _getRandomColor() { + var letters = '0123456789ABCDEF'; + var color = '#'; + for (var i = 0; i < 6; i++) { + color += letters[Math.floor(Math.random() * 16)]; + } + return color; + } +} diff --git a/client/src/app/home/home.component.html b/client/src/app/home/home.component.html index 7f2d603..06cbdd6 100644 --- a/client/src/app/home/home.component.html +++ b/client/src/app/home/home.component.html @@ -12,81 +12,84 @@ -
- -
- - - {{ selectedSet?.name }} - - + + +
+ +
+ + + {{ selectedSet?.name }} + + +
+ +
+ +
- -
- -
-
- - - -
+ + + + - - - Number - {{ element.number }} - + + + Number + {{ element.number }} + - - - - - - - - - - + + + + + + + + + + - - Name - {{ element.name }} - + + Name + {{ element.name }} + - - Rarity - {{ element.rarity }} - + + Rarity + {{ element.rarity }} + - - Supertype - {{ element.supertype }} - + + Supertype + {{ element.supertype }} + - - Collected - - - - - - {{ collection[element.id] | date }} - - - + + Collected + + + + + + {{ collection[element.id] | date }} + + + - - - + + + +
diff --git a/client/src/app/home/home.component.scss b/client/src/app/home/home.component.scss index 715d6e9..2f000d0 100644 --- a/client/src/app/home/home.component.scss +++ b/client/src/app/home/home.component.scss @@ -30,6 +30,10 @@ mat-sidenav-content { overflow: auto; height: calc(100vh - 64px); } + + pokemon-charts { + overflow: auto; + } } .spacer { diff --git a/client/src/app/home/home.component.ts b/client/src/app/home/home.component.ts index 09764ea..098da46 100644 --- a/client/src/app/home/home.component.ts +++ b/client/src/app/home/home.component.ts @@ -1,5 +1,5 @@ import { SelectionModel } from '@angular/cdk/collections'; -import { Component, OnInit } from '@angular/core'; +import { AfterViewInit, Component } from '@angular/core'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Subject } from 'rxjs/Subject'; import 'rxjs/add/observable/zip'; @@ -16,7 +16,7 @@ import { Set } from '../models/set.interface'; templateUrl: './home.component.html', styleUrls: ['./home.component.scss'] }) -export class HomeComponent implements OnInit { +export class HomeComponent implements AfterViewInit { collection = {}; defaultColumns: string[] = [ @@ -77,7 +77,7 @@ export class HomeComponent implements OnInit { ); } - ngOnInit(): void { + ngAfterViewInit(): void { this._setupSetlistHandler(); this._setupCardlistHandler(); this._setupCollectionListHandler(); diff --git a/client/src/app/set-item/set-item.component.ts b/client/src/app/set-item/set-item.component.ts index a0835d3..1a836fa 100644 --- a/client/src/app/set-item/set-item.component.ts +++ b/client/src/app/set-item/set-item.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { AfterViewInit, Component, Input } from '@angular/core'; import { BehaviorSubject } from 'rxjs/BehaviorSubject'; import { Subject } from 'rxjs/Subject'; import { IpcService } from '../ipc.service'; @@ -9,7 +9,7 @@ import { Set } from '../models/set.interface'; templateUrl: './set-item.component.html', styleUrls: ['./set-item.component.scss'] }) -export class SetItemComponent implements OnInit { +export class SetItemComponent implements AfterViewInit { @Input() set: Set; @Input() last: boolean; @@ -18,7 +18,7 @@ export class SetItemComponent implements OnInit { constructor(private _ipcService: IpcService) {} - ngOnInit() { + ngAfterViewInit() { this._ipcService.setupIpcListenerOnce( `collection:count:${this.set.code}`, (event, args) => { @@ -42,7 +42,7 @@ export class SetItemComponent implements OnInit { } ); - this._ipcService.setupIpcListener( + this._ipcService.setupIpcListenerOnce( `sets:symbol:${this.set.code}`, (event, args) => { this.img$.next(`data:image/png;base64,${args}`); diff --git a/client/src/app/update/updater.service.ts b/client/src/app/update/updater.service.ts index bc1b2e2..a266c5e 100644 --- a/client/src/app/update/updater.service.ts +++ b/client/src/app/update/updater.service.ts @@ -32,7 +32,7 @@ export class UpdaterService { } private setupNewVersionHandler(): void { - this._ipcService.setupIpcListener( + this._ipcService.setupIpcListenerOnce( 'update-available', (ev, info: UpdateInfo) => { this._dialog @@ -51,13 +51,13 @@ export class UpdaterService { } private setupUpToDateHandler(): void { - this._ipcService.setupIpcListener('up-to-date', event => { + this._ipcService.setupIpcListenerOnce('up-to-date', event => { this._openSnackbar("Hooray, you're using the latest version!"); }); } private setupDownloadStartedHandler(): void { - this._ipcService.setupIpcListener('update-download-started', () => { + this._ipcService.setupIpcListenerOnce('update-download-started', () => { this._openSnackbar( 'Update downloading, you will be prompted when it is ready to be installed.' ); @@ -65,7 +65,7 @@ export class UpdaterService { } private setupDownloadFinishedHandler(): void { - this._ipcService.setupIpcListener('update-download-finished', () => { + this._ipcService.setupIpcListenerOnce('update-download-finished', () => { this._dialog .open(UpdateDownloadedDialogComponent, { width: '500px', @@ -79,7 +79,7 @@ export class UpdaterService { } private setupDownloadProgressHandler(): void { - this._ipcService.setupIpcListener( + this._ipcService.setupIpcListenerOnce( 'update-download-progress', (event, progress) => { console.log(progress); diff --git a/electron/database/chart.js b/electron/database/chart.js new file mode 100644 index 0000000..4968617 --- /dev/null +++ b/electron/database/chart.js @@ -0,0 +1,167 @@ +const { db } = require('./database'); + +//****************// +// IPC functions // +//****************// +const { handler, notify } = require('../communicate'); + +handler('chart:load', async () => { + let collectionCall = countCollection(); + let totalCall = countTotal(); + + let results = await Promise.all([collectionCall, totalCall]); + notify('chart:data', { + collected: results[0], + total: results[1] + }); +}); + +handler('chart:series:load', async (event, args) => { + let sets = await loadSets(args); + + let setCodes = sets.map(set => { + return set.code; + }); + + let collections = await loadCollections(setCodes); + + let seriesInfo = sets.map(set => { + let setCollection = collections.filter( + collection => set.code === collection.setCode + ); + return { + name: set.name, + value: (setCollection.length / set.totalCards * 100).toFixed(2) + }; + }); + + notify(`chart:series:data:${args}`, seriesInfo); +}); + +handler('chart:load:series', async () => { + let seriesCall = loadSeries(); + let collectionCall = loadCollection(); + + let results = await Promise.all([seriesCall, collectionCall]); + + let allSeries = results[0]; + let collectionCount = results[1]; + + let seriesData = []; + + for (let series in allSeries) { + let seriesInfo = { + name: series, + series: allSeries[series].map(set => { + return { + name: set.name, + value: ( + (collectionCount[set.code] || 0) / + set.totalCards * + 100 + ).toFixed(2) + }; + }) + }; + seriesData.push(seriesInfo); + } + + notify('chart:data:series', seriesData); +}); + +function loadSets(seriesName) { + return new Promise((resolve, reject) => { + db.sets.find({ series: seriesName }, (err, sets) => { + if (err) { + reject(err); + } else { + resolve(sets); + } + }); + }); +} + +function loadCollections(setCodes) { + return new Promise((resolve, reject) => { + db.collection.find( + { + setCode: { + $in: setCodes + } + }, + (err, collection) => { + if (err) { + reject(err); + } else { + resolve(collection); + } + } + ); + }); +} + +function loadCollection() { + return new Promise((resolve, reject) => { + db.collection.find({}, (err, collection) => { + if (err) { + reject(err); + } else { + let setCount = collection.reduce((setCounts, currentCollection) => { + if (!setCounts[currentCollection.setCode]) { + setCounts[currentCollection.setCode] = 0; + } + setCounts[currentCollection.setCode]++; + return setCounts; + }, {}); + resolve(setCount); + } + }); + }); +} + +function loadSeries() { + return new Promise((resolve, reject) => { + db.sets.find({}, (err, sets) => { + if (err) { + reject(err); + } else { + let series = sets.reduce((allSeries, currentSet) => { + if (!allSeries[currentSet.series]) { + allSeries[currentSet.series] = []; + } + allSeries[currentSet.series].push(currentSet); + return allSeries; + }, {}); + + resolve(series); + } + }); + }); +} + +function countCollection() { + return new Promise((resolve, reject) => { + db.collection.count({}, (err, count) => { + if (err) { + reject(err); + } else { + resolve(count); + } + }); + }); +} + +function countTotal() { + return new Promise((resolve, reject) => { + db.sets.find({}, (err, sets) => { + if (err) { + reject(err); + } else { + let total = sets.reduce((allCards, current) => { + return allCards + current.totalCards; + }, 0); + resolve(total); + } + }); + }); +} diff --git a/electron/database/index.js b/electron/database/index.js index e19f444..b96d750 100644 --- a/electron/database/index.js +++ b/electron/database/index.js @@ -4,6 +4,7 @@ const { notify, handler } = require('../communicate'); require('./cards'); require('./collection'); +require('./chart'); module.exports = { initDatabases,