2
0

animation smooth

This commit is contained in:
2018-08-19 15:25:57 +02:00
parent 2e15897b8b
commit 888dcd6ef2
5 changed files with 51 additions and 50 deletions

View File

@@ -64,6 +64,7 @@ export class AppComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.configForm.reset({...this.config}); this.configForm.reset({...this.config});
this.list = this.historyService.list(); this.list = this.historyService.list();
this.startAnimation();
} }
public updateGraphs() { public updateGraphs() {

View File

@@ -1,5 +1,6 @@
<svg #svg width="100%" height="100%"> <svg #svg width="100%" height="100%" xmlns="http://www.w3.org/2000/svg"
version="1.1" shape-rendering="geometricPrecision">
<g guilloche [graph]="graphs[0]" [matrix]="matrix" [config]="config" [animate]="true" (guillocheChange)="prepareGuillocheExport($event)"></g> <g guilloche [graph]="graphs[0]" [matrix]="matrix" [config]="config" [animate]="true" (guillocheChange)="prepareGuillocheExport($event)"></g>
<!-- <g guilloche [graph]="graphs[1]" [matrix]="matrix" [config]="config" [animate]="true" (guillocheChange)="prepareGuillocheExport($event)"></g> --> <g guilloche [graph]="graphs[1]" [matrix]="matrix" [config]="config" [animate]="true" (guillocheChange)="prepareGuillocheExport($event)"></g>
<!-- <g guilloche *ngFor="let graph of graphs" [graph]="graph" [matrix]="matrix" [config]="config" [animate]="true" (guillocheChange)="prepareGuillocheExport($event)"></g> --> <!-- <g guilloche *ngFor="let graph of graphs" [graph]="graph" [matrix]="matrix" [config]="config" [animate]="true" (guillocheChange)="prepareGuillocheExport($event)"></g> -->
</svg> </svg>

Before

Width:  |  Height:  |  Size: 520 B

After

Width:  |  Height:  |  Size: 597 B

View File

@@ -14,7 +14,7 @@
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/ */
import { ElementRef, HostListener, Output, EventEmitter, Input, Directive, OnChanges, SimpleChanges } from '@angular/core'; import { ElementRef, HostListener, Output, EventEmitter, Input, Directive, OnChanges, OnDestroy, SimpleChanges } from '@angular/core';
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';
@@ -36,7 +36,7 @@ import { AnimationService } from './../services/animation.service';
@Directive({ @Directive({
selector: '[guilloche]' selector: '[guilloche]'
}) })
export class GuillocheDirective implements OnChanges { export class GuillocheDirective implements OnChanges, OnDestroy {
private canvas: any; private canvas: any;
private group: any; private group: any;
@@ -46,6 +46,7 @@ export class GuillocheDirective implements OnChanges {
private animationInterval: any; private animationInterval: any;
private medianPoint: Point; private medianPoint: Point;
private medianIndex: number; private medianIndex: number;
private pathElements: any;
@Input() graph: Graph; @Input() graph: Graph;
@Input() matrix: any; @Input() matrix: any;
@@ -65,16 +66,17 @@ export class GuillocheDirective implements OnChanges {
this.canvas = Selection.select(this.canvasService.get); this.canvas = Selection.select(this.canvasService.get);
} }
ngOnDestroy() {
this.group.selectAll('*').remove();
}
ngOnChanges(changes: SimpleChanges) { ngOnChanges(changes: SimpleChanges) {
// @todo modify graph here instead of in graphs.component.ts // @todo modify graph here instead of in graphs.component.ts
this.group.selectAll('*').remove();
this.initialNodes = this.graph.nodes.slice(); this.initialNodes = this.graph.nodes.slice();
this.medianPoint = this.math.medianOfCurve(this.initialNodes); this.medianPoint = this.math.medianOfCurve(this.initialNodes);
this.medianIndex = this.math.medianIndex(this.initialNodes); this.medianIndex = this.math.medianIndex(this.initialNodes);
if (this.graphService.isAnimated) { if (this.graphService.isAnimated) {
this.graph.nodes = this.graph.nodes.slice().map((node, i) => { this.graph.nodes = this.graph.nodes.slice().map((node, i) => {
return { return {
x: node.x, x: node.x,
@@ -88,33 +90,30 @@ export class GuillocheDirective implements OnChanges {
const bounceAmplitude = Math.round(Math.random() * 100); const bounceAmplitude = Math.round(Math.random() * 100);
return this.math.bounce(bounceStart, bounceAmplitude, 2); return this.math.bounce(bounceStart, bounceAmplitude, 2);
}); });
this.animationInterval = setInterval(() => this.animateGraph(), 120); this.animationInterval = setInterval(() => this.animateGraph(), 60);
} else { } else {
if (this.animationInterval) { if (this.animationInterval) {
this.bounce = null; this.bounce = null;
clearInterval(this.animationInterval); clearInterval(this.animationInterval);
// return;
} }
} }
this.guillocheChanged(); this.group.selectAll('*').remove();
this.spreadLines([ this.pathElements = [];
const graphs = this.spreadLines([
this.graph.start.point, this.graph.start.point,
this.graph.start.direction, this.graph.start.direction,
...this.graph.nodes, ...this.graph.nodes,
this.graph.end.point,
this.graph.end.direction, this.graph.end.direction,
]); this.graph.end.point,
]).forEach((points, index) => this.drawGraph(points));
this.guillocheChanged();
} }
private animateGraph() { private animateGraph() {
// const medianIndex = this.math.medianIndex(this.initialNodes); const graphs = this.spreadLines([
// const bouncedMedian = this.graphService.shiftPoint(medianPoint, medianPoint.ascent, this.bounce.next().value);
// this.graph.nodes.splice(medianIndex, 1, bouncedMedian);
this.group.selectAll('*').remove();
this.spreadLines([
this.graph.start.point, this.graph.start.point,
this.graph.start.direction, this.graph.start.direction,
...this.graph.nodes.map((point, i) => { ...this.graph.nodes.map((point, i) => {
@@ -123,40 +122,40 @@ export class GuillocheDirective implements OnChanges {
this.graph.end.direction, this.graph.end.direction,
this.graph.end.point, this.graph.end.point,
]); ]);
// this.debugBounce(bouncedMedian);
graphs.forEach((points, i) => this.updateGraph(points, i));
} }
private spreadLines(points: Point[]) { private spreadLines(points: Point[]) {
const shiftedMedians = []; const shiftedMedians = [];
// Alternatively use median of curve instead of center
// const medianPoint = this.math.medianOfCurve(points);
// const medianPoint = this.math.centerOfCurve(points);
// const medianIndex = this.math.medianIndex(points);
const genshiftedMedians = this.graphService.spreadOrthogonal(this.medianPoint, this.config.spread.spacing); const genshiftedMedians = this.graphService.spreadOrthogonal(this.medianPoint, this.config.spread.spacing);
for (let i = 0; i < this.config.spread.amount; i++) { for (let i = 0; i < this.config.spread.amount; i++) {
shiftedMedians.push(genshiftedMedians.next().value); shiftedMedians.push(genshiftedMedians.next().value);
} }
// if (env.debug) { return shiftedMedians.map(median => {
// [medianPoint, ...shiftedMedians].forEach((point, index) => { const shiftedPoints = points.slice();
// this.group.append('circle') shiftedPoints.splice(this.medianIndex, 1, median);
// .attr('cx', point.x) return shiftedPoints;
// .attr('cy', point.y)
// .attr('r', 10 / index)
// .attr('fill-opacity', 0.6)
// .attr('fill', 'darkgray');
// });
// }
shiftedMedians.forEach(median => {
const shiftedGraph = points.slice();
shiftedGraph.splice(this.medianIndex, 1, median);
this.drawGraph(shiftedGraph);
}); });
} }
private updateGraph(points: Point[], index: number): void {
this.pathElements[index]
.attr('d', Shape.line()
.x(p => p.x)
.y(p => p.y)
.curve(Shape.curveBasis)(points));
if (env.debug) {
this.group.selectAll('circle').remove();
this.group.selectAll('text').remove();
}
}
private drawGraph(points: Point[]): void { private drawGraph(points: Point[]): void {
this.pathElements.push(
this.group.append('path') this.group.append('path')
.attr('d', Shape.line() .attr('d', Shape.line()
.x(p => p.x) .x(p => p.x)
@@ -164,7 +163,7 @@ export class GuillocheDirective implements OnChanges {
.curve(Shape.curveBasis)(points)) .curve(Shape.curveBasis)(points))
.attr('stroke', this.graph.color) .attr('stroke', this.graph.color)
.attr('stroke-width', this.graph.stroke) .attr('stroke-width', this.graph.stroke)
.attr('fill', 'none'); .attr('fill', 'none'));
if (env.debug) { if (env.debug) {
this.debugGraph(points); this.debugGraph(points);

View File

@@ -94,7 +94,7 @@ export class MathService {
const p2 = genMedian.next().value; const p2 = genMedian.next().value;
const p3 = genMedian.next().value; const p3 = genMedian.next().value;
const radians = this.angleRadians(p2, p3); const radians = this.angleRadians(p2, p3);
// @todo if nodes are less than 5 error occures
return Object.assign(p1, { ascent: radians }); return Object.assign(p1, { ascent: radians });
} }

View File

@@ -16,11 +16,11 @@
export const environment = { export const environment = {
production: false, production: false,
debug: true, debug: false,
guilloche: { guilloche: {
colors: { colors: {
primary: '#129490', primary: '#129490',
secondary: '#004FFF' secondary: '#CE1483'
} }
}, },
formDefaults: { formDefaults: {
@@ -37,7 +37,7 @@ export const environment = {
nodes: 5, nodes: 5,
stroke: 0.7, stroke: 0.7,
spread: { spread: {
amount: 8, amount: 30,
spacing: 10 spacing: 10
} }
} }