prepared animations and added central arithmetic service
This commit is contained in:
@@ -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">
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]
|
||||
})
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
73
src/app/services/arithmetic.service.ts
Normal file
73
src/app/services/arithmetic.service.ts
Normal 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
|
||||
};
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user