2
0

rudimental animation running for median point

This commit is contained in:
2018-08-13 19:03:53 +02:00
parent da886fb74f
commit d9893bc6d2
4 changed files with 92 additions and 60 deletions

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, OnInit, SimpleChanges } from '@angular/core'; import { ElementRef, HostListener, Output, EventEmitter, Input, Directive, OnChanges, 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,13 +36,13 @@ import { AnimationService } from './../services/animation.service';
@Directive({ @Directive({
selector: '[guilloche]' selector: '[guilloche]'
}) })
export class GuillocheDirective implements OnChanges, OnInit { export class GuillocheDirective implements OnChanges {
private canvas: any; private canvas: any;
private group: any; private group: any;
private bounce: any | null;
private initialNodes: any;
private animationInterval: any; private animationInterval: any;
private x: any;
private y: any;
@Input() graph: Graph; @Input() graph: Graph;
@Input() matrix: any; @Input() matrix: any;
@@ -62,78 +62,42 @@ export class GuillocheDirective implements OnChanges, OnInit {
this.canvas = Selection.select(this.canvasService.get); this.canvas = Selection.select(this.canvasService.get);
} }
ngOnInit() {
// console.log('guilloche:init');
// Timer.timer(function(elapsed) {
// let t = (elapsed % 3000) / 3000;
// console.log(t);
// // dot1.attr("cx", x(t)).attr("cy", y(ease(t)));
// // dot2.attr("cy", y(ease(t)));
// });
// console.log(Ease.easeLinear(0.5));
// const t = Timer.timer(function(elapsed) {
// if (elapsed > 200) {
// t.stop();
// }
// }, 1000);
}
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.group.selectAll('*').remove();
// console.log('guilloche:changes', changes);
if (this.graphService.isAnimated) { if (this.graphService.isAnimated) {
console.log('is animated'); this.bounce = this.math.bounce(0, 600, 3);
// this.graphService.startAnimation(); this.initialNodes = this.graph.nodes.slice();
this.animationInterval = setInterval(() => this.animateGraph(), this.config.spread.spacing); this.animationInterval = setInterval(() => this.animateGraph(), 100);
} else { } else {
if (this.animationInterval) { if (this.animationInterval) {
console.log('not animated'); this.bounce = null;
// this.graphService.stopAnimation();
clearInterval(this.animationInterval); clearInterval(this.animationInterval);
} }
} }
const points = [ this.guillocheChanged();
this.spreadLines([
this.graph.start.point, this.graph.start.point,
...this.graph.nodes, ...this.graph.nodes,
this.graph.end.point this.graph.end.point
]; ]);
this.spreadLines(points);
this.guillocheChanged();
} }
private animateGraph() { private animateGraph() {
const medianIndex = this.math.medianIndex(this.initialNodes);
const medianPoint = this.math.medianOfCurve(this.initialNodes);
const bouncedMedian = this.graphService.shiftPoint(medianPoint, medianPoint.ascent, this.bounce.next().value);
this.graph.nodes.splice(medianIndex, 1, bouncedMedian);
this.group.selectAll('*').remove(); this.group.selectAll('*').remove();
this.graph = this.animationService.animate(this.graph); this.spreadLines([
const points = [
this.graph.start.point, this.graph.start.point,
...this.graph.nodes, ...this.graph.nodes,
this.graph.end.point this.graph.end.point,
]; ]);
this.spreadLines(points); this.debugBounce(bouncedMedian);
}
public guillocheChanged() {
this.guillocheChange.emit(this.el.nativeElement);
}
private drawGraph(points: Point[]): void {
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.grid) {
this.showGrid();
}
} }
private spreadLines(points: Point[]) { private spreadLines(points: Point[]) {
@@ -146,7 +110,7 @@ export class GuillocheDirective implements OnChanges, OnInit {
shiftedMedians.push(genshiftedMedians.next().value); shiftedMedians.push(genshiftedMedians.next().value);
} }
if (env.grid) { if (env.debug) {
[medianPoint, ...shiftedMedians].forEach((point, index) => { [medianPoint, ...shiftedMedians].forEach((point, index) => {
this.group.append('circle') this.group.append('circle')
.attr('cx', point.x) .attr('cx', point.x)
@@ -164,7 +128,26 @@ export class GuillocheDirective implements OnChanges, OnInit {
}); });
} }
private showGrid() { private drawGraph(points: Point[]): void {
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) {
this.debugGraph();
}
}
public guillocheChanged() {
this.guillocheChange.emit(this.el.nativeElement);
}
private debugGraph() {
this.graph.nodes.forEach((point, index) => { this.graph.nodes.forEach((point, index) => {
const circle = this.group.append('g'); const circle = this.group.append('g');
@@ -184,4 +167,15 @@ export class GuillocheDirective implements OnChanges, OnInit {
.text(index); .text(index);
}); });
} }
private debugBounce(point: Point): void {
if (env.debug) {
this.group.append('circle')
.attr('cx', point.x)
.attr('cy', point.y)
.attr('r', 2)
.attr('fill-opacity', 0.4)
.attr('fill', 'darkgray');
}
}
} }

View File

@@ -88,6 +88,16 @@ export class MathService {
return Object.assign(this.centerOfPoints(p1, p2), { ascent: radians }); return Object.assign(this.centerOfPoints(p1, p2), { ascent: radians });
} }
public medianOfCurve(curve: Point[]) {
const genMedian = this.medianPoint(curve);
const p1 = genMedian.next().value;
const p2 = genMedian.next().value;
const p3 = genMedian.next().value;
const radians = this.angleRadians(p2, p3);
return Object.assign(p1, { ascent: radians });
}
public angleRadians(p1: Point, p2: Point) { public angleRadians(p1: Point, p2: Point) {
return Math.atan2(p2.y - p1.y, p2.x - p1.x); return Math.atan2(p2.y - p1.y, p2.x - p1.x);
} }
@@ -112,6 +122,33 @@ export class MathService {
} }
} }
/**
* Generator for sine bounce
*
* @param start 0 indicates to initiate with positive numbers, 1 indicates to
* start with negative numbers first
* @param amplitude default to 1 indicates the amplitude in positive as well
* in negative range
* @param decimals amount of decimal places
*/
public *bounce(
start: number = 0,
amplitude: number = 1,
decimals: number = 1
) {
const power = Math.pow(10, decimals);
const step = 1 / (power);
let index = start;
while (true) {
const radians = Math.PI * step * index;
yield Math.round((Math.sin(radians) * amplitude) * power) / power;
index++;
}
}
public *flipSign() { public *flipSign() {
let sign = 1; let sign = 1;

View File

@@ -16,6 +16,7 @@
export const environment = { export const environment = {
production: true, production: true,
grid: false,
guilloche: { guilloche: {
colors: { colors: {
primary: '#F8485E', primary: '#F8485E',

View File

@@ -16,7 +16,7 @@
export const environment = { export const environment = {
production: false, production: false,
grid: true, debug: false,
guilloche: { guilloche: {
colors: { colors: {
primary: '#950952', primary: '#950952',
@@ -37,7 +37,7 @@ export const environment = {
nodes: 5, nodes: 5,
stroke: 0.7, stroke: 0.7,
spread: { spread: {
amount: 36, amount: 10,
spacing: 32 spacing: 32
} }
} }