diff --git a/.gitignore b/.gitignore index ee5c9d8..3cf8af6 100644 --- a/.gitignore +++ b/.gitignore @@ -33,6 +33,7 @@ npm-debug.log yarn-error.log testem.log /typings +package-lock.json # System Files .DS_Store diff --git a/package-lock.json b/package-lock.json index e3b7690..562667e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,6 +71,7 @@ "webpack-merge": "^4.1.2", "webpack-sources": "^1.1.0", "webpack-subresource-integrity": "^1.1.0-rc.4" +<<<<<<< HEAD } }, "@angular-devkit/build-ng-packagr": { @@ -107,6 +108,8 @@ "source-map": "^0.5.6" } } +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "@angular-devkit/build-optimizer": { @@ -1221,6 +1224,7 @@ "dev": true, "requires": { "hoek": "4.x.x" +<<<<<<< HEAD } }, "boxen": { @@ -1275,6 +1279,8 @@ "ansi-regex": "^3.0.0" } } +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "brace-expansion": { @@ -1892,6 +1898,7 @@ "inherits": "^2.0.3", "readable-stream": "^2.2.2", "typedarray": "^0.0.6" +<<<<<<< HEAD } }, "configstore": { @@ -1906,6 +1913,8 @@ "unique-string": "^1.0.0", "write-file-atomic": "^2.0.0", "xdg-basedir": "^3.0.0" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "connect": { @@ -2078,6 +2087,7 @@ "requires": { "bn.js": "^4.1.0", "elliptic": "^6.0.0" +<<<<<<< HEAD } }, "create-error-class": { @@ -2087,6 +2097,8 @@ "dev": true, "requires": { "capture-stack-trace": "^1.0.0" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "create-hash": { @@ -2855,6 +2867,7 @@ "requires": { "dom-serializer": "0", "domelementtype": "1" +<<<<<<< HEAD } }, "dot-prop": { @@ -2864,6 +2877,8 @@ "dev": true, "requires": { "is-obj": "^1.0.0" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "duplexer3": { @@ -3840,6 +3855,7 @@ "dev": true, "requires": { "null-check": "^1.0.0" +<<<<<<< HEAD } }, "fs-extra": { @@ -3851,6 +3867,8 @@ "graceful-fs": "^4.1.2", "jsonfile": "^4.0.0", "universalify": "^0.1.0" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "fs-write-stream-atomic": { @@ -3912,12 +3930,14 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, + "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -3932,17 +3952,20 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "core-util-is": { "version": "1.0.2", @@ -4059,7 +4082,8 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "ini": { "version": "1.3.5", @@ -4071,6 +4095,7 @@ "version": "1.0.0", "bundled": true, "dev": true, + "optional": true, "requires": { "number-is-nan": "1.0.1" } @@ -4085,6 +4110,7 @@ "version": "3.0.4", "bundled": true, "dev": true, + "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4092,12 +4118,14 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, + "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4116,6 +4144,7 @@ "version": "0.5.1", "bundled": true, "dev": true, + "optional": true, "requires": { "minimist": "0.0.8" } @@ -4196,7 +4225,8 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true + "dev": true, + "optional": true }, "object-assign": { "version": "4.1.1", @@ -4208,6 +4238,7 @@ "version": "1.4.0", "bundled": true, "dev": true, + "optional": true, "requires": { "wrappy": "1" } @@ -4329,6 +4360,7 @@ "version": "1.0.2", "bundled": true, "dev": true, + "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", @@ -4600,6 +4632,7 @@ "glob": "~7.1.1", "lodash": "~4.17.4", "minimatch": "~3.0.2" +<<<<<<< HEAD } }, "got": { @@ -4619,6 +4652,8 @@ "timed-out": "^4.0.0", "unzip-response": "^2.0.1", "url-parse-lax": "^1.0.0" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "graceful-fs": { @@ -6509,6 +6544,7 @@ "requires": { "pseudomap": "^1.0.2", "yallist": "^2.1.2" +<<<<<<< HEAD } }, "magic-string": { @@ -6518,6 +6554,8 @@ "dev": true, "requires": { "vlq": "^0.2.2" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "make-dir": { @@ -6796,6 +6834,11 @@ "minimist": "0.0.8" } }, + "moment": { + "version": "2.22.2", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.22.2.tgz", + "integrity": "sha1-PCV/mDn8DpP/UxSWMiOeuQeD/2Y=" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -6876,6 +6919,7 @@ "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", "dev": true }, +<<<<<<< HEAD "ng-packagr": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/ng-packagr/-/ng-packagr-3.0.6.tgz", @@ -6969,6 +7013,14 @@ "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", "dev": true } +======= + "ngx-moment": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/ngx-moment/-/ngx-moment-3.1.0.tgz", + "integrity": "sha512-liX6iTfOY0XyI3rUuWNgGpgxoeD+DFaAl7UJ/ejl9Ama5cXzw8L1Eft6UQLUo1d80kjNMc6AL+L19CPMvUQ/BA==", + "requires": { + "tslib": "^1.9.0" +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "no-case": { @@ -8577,6 +8629,7 @@ "regenerate": "^1.2.1", "regjsgen": "^0.2.0", "regjsparser": "^0.1.4" +<<<<<<< HEAD } }, "registry-auth-token": { @@ -8596,6 +8649,8 @@ "dev": true, "requires": { "rc": "^1.0.1" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "regjsgen": { @@ -8797,6 +8852,7 @@ "requires": { "hash-base": "^3.0.0", "inherits": "^2.0.1" +<<<<<<< HEAD } }, "rollup": { @@ -8949,6 +9005,8 @@ "regex-cache": "^0.4.2" } } +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "run-queue": { @@ -10043,6 +10101,7 @@ "block-stream": "*", "fstream": "^1.0.2", "inherits": "2" +<<<<<<< HEAD } }, "term-size": { @@ -10052,6 +10111,8 @@ "dev": true, "requires": { "execa": "^0.7.0" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "through": { @@ -10673,6 +10734,7 @@ "requires": { "querystringify": "^2.0.0", "requires-port": "^1.0.0" +<<<<<<< HEAD } }, "url-parse-lax": { @@ -10682,6 +10744,8 @@ "dev": true, "requires": { "prepend-http": "^1.0.1" +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "use": { @@ -11207,6 +11271,7 @@ "dev": true, "requires": { "string-width": "^1.0.2" +<<<<<<< HEAD } }, "widest-line": { @@ -11249,6 +11314,8 @@ "ansi-regex": "^3.0.0" } } +======= +>>>>>>> c982aba19a25a34015fca143901c097fe45b2c8b } }, "window-size": { diff --git a/package.json b/package.json index c3e7e06..ce92a21 100644 --- a/package.json +++ b/package.json @@ -37,10 +37,10 @@ }, "private": false, "dependencies": { - "@angular/common": "^6.0.0", - "@angular/core": "^6.0.0", - "@angular/compiler": "^6.0.0", "@angular/animations": "^6.0.0", + "@angular/common": "^6.0.0", + "@angular/compiler": "^6.0.0", + "@angular/core": "^6.0.0", "@angular/forms": "^6.0.0", "@angular/http": "^6.0.0", "@angular/platform-browser": "^6.0.0", @@ -48,6 +48,8 @@ "@angular/router": "^6.0.0", "core-js": "^2.5.4", "d3": "^5.3.0", + "moment": "^2.22.2", + "ngx-moment": "^3.1.0", "rxjs": "^6.0.0", "zone.js": "^0.8.26" }, diff --git a/src/app/app.component.html b/src/app/app.component.html index 47d5a9e..f0b2742 100644 --- a/src/app/app.component.html +++ b/src/app/app.component.html @@ -1,4 +1,4 @@ - + diff --git a/src/app/app.component.scss b/src/app/app.component.scss index 8c56685..5965217 100644 --- a/src/app/app.component.scss +++ b/src/app/app.component.scss @@ -23,30 +23,8 @@ opacity: 0.2; } -ul { - display: flex; - flex-direction: column; - position: absolute; - top: 0; - right: auto; - bottom: 0; - left: 0; - justify-content: center; - margin: 0; - padding: 3rem; - background: rgba(0,0,0,0.3); - transition: all 360ms 120ms ease-out; +.list-group-item { cursor: pointer; - list-style-type: none; - - &:hover { - opacity: 1; - } - - li { - display: flex; - align-items: center; - } } aside { @@ -57,7 +35,7 @@ aside { right: 0; bottom: 0; left: auto; - justify-content: center; + // justify-content: center; padding: 0; margin: 0; background: rgba(251, 252, 253, 0.9); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index d1d4be7..f290615 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -18,10 +18,16 @@ import { ConfigForm } from './forms/config.form'; import { Component, OnInit, HostListener } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; +// import { Moment } from 'moment'; +import * as moment from 'moment'; +import 'moment/min/locales'; import { environment as env } from '../environments/environment'; import { Param } from './models/param.model'; import { Config } from './models/config.model'; +import { CanvasService } from './services/canvas.service'; +import { HistoryService } from './services/history.service'; +import { Graph } from './models/graph.model'; @Component({ selector: 'app-root', @@ -34,18 +40,31 @@ export class AppComponent implements OnInit { public config: any | null; public configForm: FormGroup; public url: any; + public list: any[]; + public showList: boolean; + public restoredHistory: any; + + constructor( + private canvasService: CanvasService, + private historyService: HistoryService, + ) { + moment.locale('de'); - constructor(private sanitizer: DomSanitizer) { this.config = env.formDefaults; this.configForm = ConfigForm; + this.list = []; + this.showList = true; } ngOnInit() { this.configForm.reset({...this.config}); + this.list = this.historyService.list(); + // console.log(this.graphs); } public updateGraphs() { this.config = {...this.configForm.value}; + this.list = this.historyService.list(); } public prepareSvgExport(svg) { @@ -58,11 +77,24 @@ export class AppComponent implements OnInit { public exportSvg() { const link = document.createElement('a'); - + // const blob = new Blob( + // [this.canvasService.get], + // {type: 'image/svg+xml;charset=utf-8'} + // ); + // link.href = URL.createObjectURL(blob); link.href = this.url; link.download = 'guilloche.svg'; document.body.appendChild(link); link.click(); document.body.removeChild(link); } + + public toggleList() { + this.showList = !this.showList; + } + + public restoreGraph(history) { + this.configForm.reset({...history.config}); + this.restoredHistory = history; + } } diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 998c8a2..9811fd9 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -17,11 +17,13 @@ import { BrowserModule } from '@angular/platform-browser'; import { NgModule } from '@angular/core'; import { ReactiveFormsModule, FormsModule } from '@angular/forms'; +import { MomentModule } from 'ngx-moment'; import { AppComponent } from './app.component'; import { GraphsComponent } from './components/graphs.component'; import { GuillocheDirective } from './directives/guilloche.directive'; import { CanvasService } from './services/canvas.service'; +import { HistoryService } from './services/history.service'; @NgModule({ declarations: [ @@ -33,10 +35,12 @@ import { CanvasService } from './services/canvas.service'; BrowserModule, ReactiveFormsModule, FormsModule, + MomentModule, ], providers: [ - CanvasService + CanvasService, + HistoryService ], bootstrap: [AppComponent] }) -export class AppModule { } +export class AppModule {} diff --git a/src/app/components/graphs.component.html b/src/app/components/graphs.component.html index f8ee281..37a7bbd 100644 --- a/src/app/components/graphs.component.html +++ b/src/app/components/graphs.component.html @@ -1,3 +1,3 @@ - + diff --git a/src/app/components/graphs.component.ts b/src/app/components/graphs.component.ts index cb1e057..94ad20e 100644 --- a/src/app/components/graphs.component.ts +++ b/src/app/components/graphs.component.ts @@ -23,6 +23,7 @@ import * as Drag from 'd3-drag'; import { environment as env } from '../../environments/environment'; import { GuillocheDirective } from './../directives/guilloche.directive'; import { CanvasService } from './../services/canvas.service'; +import { HistoryService } from './../services/history.service'; import { Graph } from '../models/graph.model'; import { Point } from '../models/point.model'; @@ -33,60 +34,45 @@ import { Point } from '../models/point.model'; }) export class GraphsComponent implements OnChanges { - public graphs: Graph[]; public canvas: any | null; public matrix: any | null; + public graphs: Graph[]; private genShiftPoint: any | null; private genLoadedAllGraphs: any | null; + private hash: string; @Input() config: any; - + @Input() restoredHistory: any; + @Output() svgChange = new EventEmitter(); + @Output() graphChange = new EventEmitter(); @ViewChild('svg') svgElementRef; - @Output() svgChange = new EventEmitter(); - - @HostListener('window:resize', ['$event']) - private onResize(event) { - this.init(); - } - constructor( - private canvasService: CanvasService + private canvasService: CanvasService, + private historyService: HistoryService ) { this.genLoadedAllGraphs = this.countLoadedGraphs(); } ngOnChanges(changes: SimpleChanges) { - this.init(); - } - - private init() { this.updateCanvas(); this.updateMatrix(); + + if (changes.restoredHistory) { + if (changes.restoredHistory.currentValue) { + if (this.restoredHistory.hash !== this.hash) { + this.graphs = this.restoredHistory.graphs; + this.hash = this.restoredHistory.hash; + } + return; + } + } this.updateGraphs(); } - public prepareGuillocheExport(guillocheElement) { - const item = this.genLoadedAllGraphs.next().value; - console.log(item); - if (item) { - this.svgChange.emit(this.svgElementRef); - } - } - - private *countLoadedGraphs() { - let cycles = 1; - - while (true) { - if (cycles < this.graphs.length) { - yield false; - cycles++; - } else { - yield true; - cycles = 1; - } - } + private saveHistory() { + this.historyService.save(this.graphs, this.config); } private updateGraphs(): void { @@ -107,6 +93,8 @@ export class GraphsComponent implements OnChanges { ]; this.graphs = curveList.map(curve => this.adjustGraph(curve)); + this.hash = this.historyService.hash(this.graphs); + this.saveHistory(); } private adjustGraph(curve) { @@ -239,4 +227,24 @@ export class GraphsComponent implements OnChanges { yield sign = sign * (-1); } } + + public prepareGuillocheExport(guillocheElement) { + if (this.genLoadedAllGraphs.next().value) { + this.svgChange.emit(this.svgElementRef); + } + } + + private *countLoadedGraphs() { + let cycles = 1; + + while (true) { + if (cycles < this.graphs.length) { + yield false; + cycles++; + } else { + yield true; + cycles = 1; + } + } + } } diff --git a/src/app/services/history.service.ts b/src/app/services/history.service.ts new file mode 100644 index 0000000..8a2a4e5 --- /dev/null +++ b/src/app/services/history.service.ts @@ -0,0 +1,53 @@ +/** + * Copyright (C) 2018 Michael Czechowski + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; version 2. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 51 + * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import { Inject, Injectable, Optional, ViewChild } from '@angular/core'; +import * as Selection from 'd3-selection'; + +import { Graph } from '../models/graph.model'; + +@Injectable() +export class HistoryService { + + public history: any[]; + + constructor() { + this.history = []; + } + + public save(graphs: Graph[], config) { + this.history.push({ + date: new Date(), + graphs: graphs, + config: config, + hash: this.hash(graphs) + }); + } + + public hash(graphs) { + return btoa(JSON.stringify([graphs])); + } + + public list() { + return this.history; + } + + public restore(graphs: Graph[]) { + console.log(graphs); + } + +} +