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">
<div class="aside-inner">

View File

@@ -1,3 +1,4 @@
import { AnimationService } from './services/animation.service';
/**
* Copyright (C) 2018 Michael Czechowski <mail@dailysh.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 { HistoryService } from './services/history.service';
import { AnimationService } from './services/animation.service';
import { ArithmeticService } from './services/arithmetic.service';
@NgModule({
declarations: [
@@ -41,7 +42,8 @@ import { AnimationService } from './services/animation.service';
providers: [
CanvasService,
HistoryService,
AnimationService
AnimationService,
ArithmeticService,
],
bootstrap: [AppComponent]
})

View File

@@ -14,16 +14,19 @@
* 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 Shape from 'd3-shape';
import * as Random from 'd3-random';
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 { AnimationService } from '../services/animation.service';
import { ArithmeticService } from '../services/arithmetic.service';
import { GuillocheDirective } from './../directives/guilloche.directive';
import { Graph } from '../models/graph.model';
import { Point } from '../models/point.model';
@@ -32,7 +35,7 @@ import { Point } from '../models/point.model';
templateUrl: './graphs.component.html',
styleUrls: ['./graphs.component.scss']
})
export class GraphsComponent implements OnChanges {
export class GraphsComponent implements OnChanges, OnInit {
public canvas: any | null;
public matrix: any | null;
@@ -41,34 +44,60 @@ export class GraphsComponent implements OnChanges {
private genShiftPoint: any | null;
private genLoadedAllGraphs: any | null;
private hash: string;
private animation: Observable<Graph[]>;
private timer: Observable<number>;
private animationSteps: Subscription;
@Input() config: any;
@Input() restoredHistory: any;
@Input() animationActive: boolean;
@Output() svgChange = new EventEmitter();
@Output() graphChange = new EventEmitter();
@ViewChild('svg') svgElementRef;
constructor(
private canvasService: CanvasService,
private historyService: HistoryService
private historyService: HistoryService,
private animationService: AnimationService,
private arithmetics: ArithmeticService
) {
this.genLoadedAllGraphs = this.countLoadedGraphs();
this.timer = interval(500);
}
ngOnInit() {
this.updateGraphs();
}
ngOnChanges(changes: SimpleChanges) {
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;
if (changes.config && !changes.config.firstChange) {
this.updateGraphs();
return;
}
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() {
@@ -112,7 +141,7 @@ export class GraphsComponent implements OnChanges {
const generatedPoints = [];
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;
@@ -127,22 +156,15 @@ export class GraphsComponent implements OnChanges {
this.canvasService.set(this.canvas);
}
private centerPoint(width, height): Point {
return {
x: width * 0.5,
y: height * 0.5
};
}
private updateMatrix() {
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 baseScale = Math.pow(totalArea / baseArea * this.config.scale, 0.5);
const baseWidthScaled = baseScale * this.config.width;
const baseHeightScaled = baseScale * this.config.height;
const baseCenter = this.centerPoint(baseWidthScaled, baseHeightScaled);
const baseCenter = this.arithmetics.centerPoint(baseWidthScaled, baseHeightScaled);
this.matrix = {
start: {
@@ -160,7 +182,7 @@ export class GraphsComponent implements OnChanges {
}
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 {
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) {
const genShiftX = 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 { Param } from './../models/param.model';
import { CanvasService } from './../services/canvas.service';
import { ArithmeticService } from './../services/arithmetic.service';
@Directive({
selector: '[guilloche]'
@@ -43,7 +44,8 @@ export class GuillocheDirective implements OnChanges {
constructor(
private canvasService: CanvasService,
private el: ElementRef
private el: ElementRef,
private arithmetics: ArithmeticService
) {
this.group = Selection.select(el.nativeElement);
this.canvas = Selection.select(this.canvasService.get);
@@ -81,8 +83,8 @@ export class GuillocheDirective implements OnChanges {
private spreadLines(points: Point[]) {
const indexMiddle = Math.floor(points.length * 0.5);
const pointMiddle = points[indexMiddle];
const closestCenter = this.getClosestCenter(pointMiddle);
const radius = this.Δ(pointMiddle, closestCenter);
const closestCenter = this.arithmetics.getClosestCenter(pointMiddle, this.matrix);
const radius = this.arithmetics.Δ(pointMiddle, closestCenter);
const spreadPoints = [];
const pies = 80;
@@ -95,7 +97,7 @@ export class GuillocheDirective implements OnChanges {
spreadPoints.sort((a, b) => {
// 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) => {
@@ -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() {
this.graph.nodes.forEach(point => {
this.group.append('circle')

View File

@@ -15,6 +15,7 @@
*/
import { Inject, Injectable, Optional, ViewChild } from '@angular/core';
import { interval, Observable } from 'rxjs';
import * as Selection from 'd3-selection';
import { Graph } from '../models/graph.model';
@@ -26,8 +27,11 @@ export class AnimationService {
public speed: number;
public range: number;
public genAnimation: any;
private timer: Observable<number>;
private subscribtion: any;
constructor() {
this.timer = interval(500);
this.resetAnimation();
}
@@ -35,22 +39,32 @@ export class AnimationService {
this.genAnimation = this.animateNextStep();
}
private animateNextStep() {
private *animateNextStep() {
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;
}
public animate(): Graph[] {
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
};
}
}