animation smooth
This commit is contained in:
@@ -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() {
|
||||||
|
|||||||
@@ -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 |
@@ -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,48 +122,48 @@ 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 drawGraph(points: Point[]): void {
|
private updateGraph(points: Point[], index: number): void {
|
||||||
this.group.append('path')
|
this.pathElements[index]
|
||||||
.attr('d', Shape.line()
|
.attr('d', Shape.line()
|
||||||
.x(p => p.x)
|
.x(p => p.x)
|
||||||
.y(p => p.y)
|
.y(p => p.y)
|
||||||
.curve(Shape.curveBasis)(points))
|
.curve(Shape.curveBasis)(points));
|
||||||
.attr('stroke', this.graph.color)
|
|
||||||
.attr('stroke-width', this.graph.stroke)
|
if (env.debug) {
|
||||||
.attr('fill', 'none');
|
this.group.selectAll('circle').remove();
|
||||||
|
this.group.selectAll('text').remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private drawGraph(points: Point[]): void {
|
||||||
|
this.pathElements.push(
|
||||||
|
this.group.append('path')
|
||||||
|
.attr('d', Shape.line()
|
||||||
|
.x(p => p.x)
|
||||||
|
.y(p => p.y)
|
||||||
|
.curve(Shape.curveBasis)(points))
|
||||||
|
.attr('stroke', this.graph.color)
|
||||||
|
.attr('stroke-width', this.graph.stroke)
|
||||||
|
.attr('fill', 'none'));
|
||||||
|
|
||||||
if (env.debug) {
|
if (env.debug) {
|
||||||
this.debugGraph(points);
|
this.debugGraph(points);
|
||||||
|
|||||||
@@ -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 });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user