156 lines
3.5 KiB
JavaScript
156 lines
3.5 KiB
JavaScript
/* global window, performance */
|
|
|
|
const React = require('react');
|
|
|
|
const r = require('r-dom');
|
|
|
|
const PIXI = require('pixi.js');
|
|
|
|
const theme = require('../../utils/theme');
|
|
|
|
PIXI.Ticker.shared.autoStart = false;
|
|
|
|
class Peaks extends React.Component {
|
|
constructor(props) {
|
|
super(props);
|
|
|
|
this.state = {};
|
|
|
|
this.containerRef = React.createRef();
|
|
|
|
this.handleTick = this.handleTick.bind(this);
|
|
this.handlePeak = this.handlePeak.bind(this);
|
|
this.handleResize = this.handleResize.bind(this);
|
|
this.handleAnimationFrame = this.handleAnimationFrame.bind(this);
|
|
}
|
|
|
|
componentDidMount() {
|
|
this.app = new PIXI.Application({
|
|
autoStart: false,
|
|
transparent: true,
|
|
});
|
|
this.app.ticker.add(this.handleTick);
|
|
|
|
this.trailTexture = PIXI.Texture.from('assets/trail.png');
|
|
this.points = [
|
|
new PIXI.Point(0, 0),
|
|
new PIXI.Point(100, 100),
|
|
];
|
|
this.rope = new PIXI.SimpleRope(this.trailTexture, this.points);
|
|
this.rope.blendmode = PIXI.BLEND_MODES.ADD;
|
|
this.app.stage.addChild(this.rope);
|
|
|
|
this.ropes = {};
|
|
|
|
this.containerRef.current.append(this.app.view);
|
|
|
|
this.peaks = {};
|
|
this.props.peaks.on('peak', this.handlePeak);
|
|
|
|
this.graph = window.document.querySelector('#graph .graph');
|
|
this.view = this.graph.querySelector('.view');
|
|
|
|
window.addEventListener('resize', this.handleResize);
|
|
this.handleResize();
|
|
|
|
this.lastAnimationFrameTimeStamp = 0;
|
|
this.requestAnimationFrame();
|
|
}
|
|
|
|
componentWillUnmount() {
|
|
this.app.destroy();
|
|
|
|
this.props.peaks.off('peak', this.handlePeak);
|
|
|
|
window.removeEventListener('resize', this.handleResize);
|
|
|
|
window.cancelAnimationFrame(this.animationFrameRequest);
|
|
}
|
|
|
|
requestAnimationFrame() {
|
|
this.animationFrameRequest = window.requestAnimationFrame(this.handleAnimationFrame);
|
|
}
|
|
|
|
get targetDelay() {
|
|
if (window.document.hidden) {
|
|
return 2 * 1000;
|
|
}
|
|
|
|
if (this.props.accommodateGraphAnimation) {
|
|
return 1000 / 70;
|
|
}
|
|
|
|
return 1000 / 25;
|
|
}
|
|
|
|
handleAnimationFrame(timeStamp) {
|
|
if (timeStamp < this.lastAnimationFrameTimeStamp + this.targetDelay) {
|
|
this.requestAnimationFrame();
|
|
return;
|
|
}
|
|
|
|
this.lastAnimationFrameTimeStamp = timeStamp;
|
|
|
|
this.app.ticker.update(timeStamp);
|
|
|
|
this.requestAnimationFrame();
|
|
}
|
|
|
|
handleTick() {
|
|
const matrix = this.view.getScreenCTM();
|
|
const point = this.graph.createSVGPoint();
|
|
|
|
const p = ({ x = 0, y = 0 }) => {
|
|
point.x = x;
|
|
point.y = y;
|
|
|
|
const p = point.matrixTransform(matrix);
|
|
|
|
return new PIXI.Point(p.x, p.y);
|
|
};
|
|
|
|
const ropes = this.props.edges
|
|
.filter(edge => {
|
|
return edge.type === 'sinkInput' || edge.type === 'sourceOutput';
|
|
})
|
|
.map(edge => {
|
|
const source = this.props.nodes.find(n => n.id === edge.source);
|
|
const target = this.props.nodes.find(n => n.id === edge.target);
|
|
|
|
const peak = this.peaks[target.target] || this.peaks[target.edge];
|
|
|
|
const points = [
|
|
p(target),
|
|
p(source),
|
|
];
|
|
const rope = new PIXI.SimpleRope(this.trailTexture, points);
|
|
rope.blendmode = PIXI.BLEND_MODES.ADD;
|
|
rope.alpha = peak === undefined ? 0 : peak ** (1 / 3);
|
|
rope.tint = Number.parseInt(theme.colors.themeSelectedBgColor.replace(/#/g, ''), 16);
|
|
|
|
return rope;
|
|
});
|
|
|
|
this.app.stage.removeChildren();
|
|
ropes.forEach(r => this.app.stage.addChild(r));
|
|
}
|
|
|
|
handlePeak(type, id, peak) {
|
|
this.peaks[`${type}-${id}`] = peak;
|
|
}
|
|
|
|
handleResize() {
|
|
this.app.renderer.resize(window.innerWidth, window.innerHeight);
|
|
this.app.ticker.update(performance.now());
|
|
}
|
|
|
|
render() {
|
|
return r.div({
|
|
className: 'peaks',
|
|
ref: this.containerRef,
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports = Peaks;
|