2
0

prepared animations and added central arithmetic service

This commit is contained in:
2018-08-07 18:22:51 +02:00
parent cafc27e2e9
commit 798da6bd4b
7 changed files with 151 additions and 88 deletions

View File

@@ -1,4 +1,4 @@
<app-graphs [config]="config" [restoredHistory]="restoredHistory" (svgChange)="prepareSvgExport($event)"></app-graphs> <app-graphs [config]="config" [restoredHistory]="restoredHistory" (svgChange)="prepareSvgExport($event)" [animationActive]="animationActive"></app-graphs>
<aside class="col-sm-4 col-lg-3 col-xl-3"> <aside class="col-sm-4 col-lg-3 col-xl-3">
<div class="aside-inner"> <div class="aside-inner">

View File

@@ -1,3 +1,4 @@
import { AnimationService } from './services/animation.service';
/** /**
* Copyright (C) 2018 Michael Czechowski <mail@dailysh.it> * Copyright (C) 2018 Michael Czechowski <mail@dailysh.it>
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it

View File

@@ -25,6 +25,7 @@ import { GuillocheDirective } from './directives/guilloche.directive';
import { CanvasService } from './services/canvas.service'; import { CanvasService } from './services/canvas.service';
import { HistoryService } from './services/history.service'; import { HistoryService } from './services/history.service';
import { AnimationService } from './services/animation.service'; import { AnimationService } from './services/animation.service';
import { ArithmeticService } from './services/arithmetic.service';
@NgModule({ @NgModule({
declarations: [ declarations: [
@@ -41,7 +42,8 @@ import { AnimationService } from './services/animation.service';
providers: [ providers: [
CanvasService, CanvasService,
HistoryService, HistoryService,
AnimationService AnimationService,
ArithmeticService,
], ],
bootstrap: [AppComponent] bootstrap: [AppComponent]
}) })

View File

@@ -14,16 +14,19 @@
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import { ViewChild, QueryList, Component, Input, Output, SimpleChanges, OnChanges, HostListener, EventEmitter } from '@angular/core'; import { ViewChild, QueryList, Component, Input, Output, SimpleChanges, OnChanges, HostListener, EventEmitter, OnInit } from '@angular/core';
import { Observable, interval, Subscription } from 'rxjs';
import * as Selection from 'd3-selection'; import * as Selection from 'd3-selection';
import * as Shape from 'd3-shape'; import * as Shape from 'd3-shape';
import * as Random from 'd3-random'; import * as Random from 'd3-random';
import * as Drag from 'd3-drag'; import * as Drag from 'd3-drag';
import { environment as env } from '../../environments/environment'; import { environment as env } from '../../environments/environment';
import { GuillocheDirective } from './../directives/guilloche.directive';
import { CanvasService } from './../services/canvas.service'; import { CanvasService } from './../services/canvas.service';
import { HistoryService } from './../services/history.service'; import { HistoryService } from './../services/history.service';
import { AnimationService } from '../services/animation.service';
import { ArithmeticService } from '../services/arithmetic.service';
import { GuillocheDirective } from './../directives/guilloche.directive';
import { Graph } from '../models/graph.model'; import { Graph } from '../models/graph.model';
import { Point } from '../models/point.model'; import { Point } from '../models/point.model';
@@ -32,7 +35,7 @@ import { Point } from '../models/point.model';
templateUrl: './graphs.component.html', templateUrl: './graphs.component.html',
styleUrls: ['./graphs.component.scss'] styleUrls: ['./graphs.component.scss']
}) })
export class GraphsComponent implements OnChanges { export class GraphsComponent implements OnChanges, OnInit {
public canvas: any | null; public canvas: any | null;
public matrix: any | null; public matrix: any | null;
@@ -41,34 +44,60 @@ export class GraphsComponent implements OnChanges {
private genShiftPoint: any | null; private genShiftPoint: any | null;
private genLoadedAllGraphs: any | null; private genLoadedAllGraphs: any | null;
private hash: string; private hash: string;
private animation: Observable<Graph[]>;
private timer: Observable<number>;
private animationSteps: Subscription;
@Input() config: any; @Input() config: any;
@Input() restoredHistory: any; @Input() restoredHistory: any;
@Input() animationActive: boolean;
@Output() svgChange = new EventEmitter(); @Output() svgChange = new EventEmitter();
@Output() graphChange = new EventEmitter(); @Output() graphChange = new EventEmitter();
@ViewChild('svg') svgElementRef; @ViewChild('svg') svgElementRef;
constructor( constructor(
private canvasService: CanvasService, private canvasService: CanvasService,
private historyService: HistoryService private historyService: HistoryService,
private animationService: AnimationService,
private arithmetics: ArithmeticService
) { ) {
this.genLoadedAllGraphs = this.countLoadedGraphs(); this.genLoadedAllGraphs = this.countLoadedGraphs();
this.timer = interval(500);
}
ngOnInit() {
this.updateGraphs();
} }
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
this.updateCanvas(); this.updateCanvas();
this.updateMatrix(); this.updateMatrix();
if (changes.restoredHistory) { if (changes.config && !changes.config.firstChange) {
if (changes.restoredHistory.currentValue) { this.updateGraphs();
if (this.restoredHistory.hash !== this.hash) { return;
this.graphs = this.restoredHistory.graphs; }
this.hash = this.restoredHistory.hash;
if (this.restoredHistory && this.restoredHistory.hash !== this.hash) {
this.graphs = this.restoredHistory.graphs;
this.hash = this.restoredHistory.hash;
}
if (changes.animationActive) {
if (this.animationActive) {
this.animationSteps = this.timer.subscribe(n => {
console.log('Animation step', n);
this.graphs = this.animationService.animate(this.graphs);
// this.graphs = this.graphs;
this.hash = this.historyService.hash(this.graphs);
this.saveHistory();
});
} else {
if (this.animationSteps) {
this.animationSteps.unsubscribe();
} }
return;
} }
} }
this.updateGraphs();
} }
private saveHistory() { private saveHistory() {
@@ -112,7 +141,7 @@ export class GraphsComponent implements OnChanges {
const generatedPoints = []; const generatedPoints = [];
for (let i = 0; i < this.config.nodes; i++) { for (let i = 0; i < this.config.nodes; i++) {
generatedPoints.push(this.randomPoint); generatedPoints.push(this.arithmetics.randomPoint(this.matrix, this.config.overlap));
} }
return generatedPoints; return generatedPoints;
@@ -127,22 +156,15 @@ export class GraphsComponent implements OnChanges {
this.canvasService.set(this.canvas); this.canvasService.set(this.canvas);
} }
private centerPoint(width, height): Point {
return {
x: width * 0.5,
y: height * 0.5
};
}
private updateMatrix() { private updateMatrix() {
const totalArea = Math.abs(this.canvas.clientWidth * this.canvas.clientHeight); const totalArea = Math.abs(this.canvas.clientWidth * this.canvas.clientHeight);
const totalCenter = this.centerPoint(this.canvas.clientWidth, this.canvas.clientHeight); const totalCenter = this.arithmetics.centerPoint(this.canvas.clientWidth, this.canvas.clientHeight);
const baseArea = Math.abs(this.config.width * this.config.height); const baseArea = Math.abs(this.config.width * this.config.height);
const baseScale = Math.pow(totalArea / baseArea * this.config.scale, 0.5); const baseScale = Math.pow(totalArea / baseArea * this.config.scale, 0.5);
const baseWidthScaled = baseScale * this.config.width; const baseWidthScaled = baseScale * this.config.width;
const baseHeightScaled = baseScale * this.config.height; const baseHeightScaled = baseScale * this.config.height;
const baseCenter = this.centerPoint(baseWidthScaled, baseHeightScaled); const baseCenter = this.arithmetics.centerPoint(baseWidthScaled, baseHeightScaled);
this.matrix = { this.matrix = {
start: { start: {
@@ -160,7 +182,7 @@ export class GraphsComponent implements OnChanges {
} }
private genVectorPoint(point: Point, vector: number) { private genVectorPoint(point: Point, vector: number) {
const range = this.Δ(this.matrix.start, this.matrix.end) * this.config.vectors.range; const range = this.arithmetics.Δ(this.matrix.start, this.matrix.end) * this.config.vectors.range;
return { return {
x: range * Math.sin(Math.PI * vector) + point.x, x: range * Math.sin(Math.PI * vector) + point.x,
@@ -168,32 +190,6 @@ export class GraphsComponent implements OnChanges {
}; };
} }
private get randomPoint() {
const overlap = this.config.overlap;
const x = {
min: this.matrix.center.x - this.matrix.width * overlap,
max: this.matrix.center.x + this.matrix.width * overlap
};
const y = {
min: this.matrix.center.y - this.matrix.height * overlap,
max: this.matrix.center.y + this.matrix.height * overlap
};
return {
x: Random.randomUniform(x.min, x.max)(),
y: Random.randomUniform(y.min, y.max)()
};
}
/**
* Calculate distance between to points with coordinates.
* @param a
* @param b
*/
private Δ(a: Point, b: Point) {
return Math.pow(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2), 0.5);
}
private *shiftPoint(point: Point, vector) { private *shiftPoint(point: Point, vector) {
const genShiftX = this.shiftNumber(this.config.space, vector); const genShiftX = this.shiftNumber(this.config.space, vector);
const genShiftY = this.shiftNumber(this.config.space, vector); const genShiftY = this.shiftNumber(this.config.space, vector);

View File

@@ -26,6 +26,7 @@ import { Graph } from './../models/graph.model';
import { Point } from './../models/point.model'; import { Point } from './../models/point.model';
import { Param } from './../models/param.model'; import { Param } from './../models/param.model';
import { CanvasService } from './../services/canvas.service'; import { CanvasService } from './../services/canvas.service';
import { ArithmeticService } from './../services/arithmetic.service';
@Directive({ @Directive({
selector: '[guilloche]' selector: '[guilloche]'
@@ -43,7 +44,8 @@ export class GuillocheDirective implements OnChanges {
constructor( constructor(
private canvasService: CanvasService, private canvasService: CanvasService,
private el: ElementRef private el: ElementRef,
private arithmetics: ArithmeticService
) { ) {
this.group = Selection.select(el.nativeElement); this.group = Selection.select(el.nativeElement);
this.canvas = Selection.select(this.canvasService.get); this.canvas = Selection.select(this.canvasService.get);
@@ -81,8 +83,8 @@ export class GuillocheDirective implements OnChanges {
private spreadLines(points: Point[]) { private spreadLines(points: Point[]) {
const indexMiddle = Math.floor(points.length * 0.5); const indexMiddle = Math.floor(points.length * 0.5);
const pointMiddle = points[indexMiddle]; const pointMiddle = points[indexMiddle];
const closestCenter = this.getClosestCenter(pointMiddle); const closestCenter = this.arithmetics.getClosestCenter(pointMiddle, this.matrix);
const radius = this.Δ(pointMiddle, closestCenter); const radius = this.arithmetics.Δ(pointMiddle, closestCenter);
const spreadPoints = []; const spreadPoints = [];
const pies = 80; const pies = 80;
@@ -95,7 +97,7 @@ export class GuillocheDirective implements OnChanges {
spreadPoints.sort((a, b) => { spreadPoints.sort((a, b) => {
// Good possibility to align orientation points outsite // Good possibility to align orientation points outsite
return this.Δ(b, pointMiddle) - this.Δ(a, pointMiddle); return this.arithmetics.Δ(b, pointMiddle) - this.arithmetics.Δ(a, pointMiddle);
}); });
spreadPoints.some((point, index) => { spreadPoints.some((point, index) => {
@@ -108,31 +110,6 @@ export class GuillocheDirective implements OnChanges {
} }
private getClosestCenter(point: Point) {
if (this.Δ(point, this.matrix.start) < this.Δ(point, this.matrix.end)) {
return this.matrix.start;
} else {
return this.matrix.end;
}
}
private getFarestCenter(point: Point) {
if (this.Δ(point, this.matrix.start) > this.Δ(point, this.matrix.end)) {
return this.matrix.start;
} else {
return this.matrix.end;
}
}
/**
* Calculate distance between to points with coordinates.
* @param a
* @param b
*/
private Δ(a: Point, b: Point) {
return Math.pow(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2), 0.5);
}
private showGrid() { private showGrid() {
this.graph.nodes.forEach(point => { this.graph.nodes.forEach(point => {
this.group.append('circle') this.group.append('circle')

View File

@@ -15,6 +15,7 @@
*/ */
import { Inject, Injectable, Optional, ViewChild } from '@angular/core'; import { Inject, Injectable, Optional, ViewChild } from '@angular/core';
import { interval, Observable } from 'rxjs';
import * as Selection from 'd3-selection'; import * as Selection from 'd3-selection';
import { Graph } from '../models/graph.model'; import { Graph } from '../models/graph.model';
@@ -26,8 +27,11 @@ export class AnimationService {
public speed: number; public speed: number;
public range: number; public range: number;
public genAnimation: any; public genAnimation: any;
private timer: Observable<number>;
private subscribtion: any;
constructor() { constructor() {
this.timer = interval(500);
this.resetAnimation(); this.resetAnimation();
} }
@@ -35,22 +39,32 @@ export class AnimationService {
this.genAnimation = this.animateNextStep(); this.genAnimation = this.animateNextStep();
} }
private animateNextStep() { private *animateNextStep() {
while (this.graphs) { while (this.graphs) {
return true; yield this.graphs = this.graphs.map(graph => {
console.log(graph);
return graph;
});
} }
} }
public init(initialGraphs: Graph[]) { // public start(initialGraphs: Graph[]): Observable<Graph[]> {
// // this.graphs = initialGraphs.map(graph => {
// // console.log(graph);
// // return graph;
// // });
// // return this.timer.subscribe(n => this.graphs);
// }
// public animate(): Graph[] {
// return this.genAnimation.next().value;
// }
public animate(initialGraphs: Graph[]) {
this.graphs = initialGraphs; this.graphs = initialGraphs;
}
public animate(): Graph[] {
return this.genAnimation.next().value; return this.genAnimation.next().value;
} }
public stop() {
this.graphs = null;
}
} }

View File

@@ -0,0 +1,73 @@
/**
* Copyright (C) 2018 Michael Czechowski <mail@dailysh.it>
* 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 } from '@angular/core';
import * as Selection from 'd3-selection';
import * as Random from 'd3-random';
import { Point } from './../models/point.model';
@Injectable()
export class ArithmeticService {
/**
* Calculate distance between to points with coordinates.
* @param a
* @param b
*/
public Δ(a: Point, b: Point) {
return Math.pow(Math.pow(a.x - b.x, 2) + Math.pow(a.y - b.y, 2), 0.5);
}
public getClosestCenter(point: Point, matrix: any) {
if (this.Δ(point, matrix.start) < this.Δ(point, matrix.end)) {
return matrix.start;
} else {
return matrix.end;
}
}
public getFarestCenter(point: Point, matrix: any) {
if (this.Δ(point, matrix.start) > this.Δ(point, matrix.end)) {
return matrix.start;
} else {
return matrix.end;
}
}
public randomPoint(matrix: any, overlap: number) {
const x = {
min: matrix.center.x - matrix.width * overlap,
max: matrix.center.x + matrix.width * overlap
};
const y = {
min: matrix.center.y - matrix.height * overlap,
max: matrix.center.y + matrix.height * overlap
};
return {
x: Random.randomUniform(x.min, x.max)(),
y: Random.randomUniform(y.min, y.max)()
};
}
public centerPoint(width, height): Point {
return {
x: width * 0.5,
y: height * 0.5
};
}
}