Skip to content

Commit

Permalink
viz responds to music playing
Browse files Browse the repository at this point in the history
  • Loading branch information
sxywu committed Dec 5, 2016
1 parent cb1f9be commit f5153fd
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 31 deletions.
22 changes: 13 additions & 9 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ var App = React.createClass({
prevTop: null,
top: null,
hovered: null,
playing: null,
random: false,
update: true,
useForce: true,
Expand Down Expand Up @@ -158,18 +159,21 @@ var App = React.createClass({
positions.section = PositionGraph.updateSectionWithHeight(this.state.section, positions.linePositions);
},

selectLines(lineIds) {
var linePositions = PositionGraph.positionSelectLines(
lineIds, this.state.linePositions, 2, width, vizWidth);
if (!lineIds) {
linePositions = this.positionByVizType(this.state.vizType);
};
this.setState({linePositions});
playLines(playing) {
if (playing && this.state.playing) {
// if already playing, just modify the current time
playing = Object.assign(this.state.playing, {currentTime: playing.currentTime});
} else if (playing) {
// if it just started playing
var lines = _.filter(this.state.linePositions, line =>
_.includes(playing.lineIds, line.id));
playing = Object.assign(playing, {lines});
}
this.setState({playing, update: false});
},

hoverLine(hoveredLine) {
if (hoveredLine === this.state.hovered) return;
if (!hoveredLine) console.log(hoveredLine)
this.setState({hovered: hoveredLine, update: false});
},

Expand Down Expand Up @@ -282,7 +286,7 @@ var App = React.createClass({
bodyFont: 'Libre Baskerville',
};
var eventProps = {
selectLines: this.selectLines,
playLines: this.playLines,
hoverLine: this.hoverLine,
onSelectCharacter: this.filterByCharacter,
onSelectConversation: this.filterByConversation,
Expand Down
12 changes: 8 additions & 4 deletions src/Section.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,13 @@ var Section = React.createClass({
.style('background', 'linear-gradient(to right,' +
color + ' ' + percent + '%,' +
chroma(color).alpha(0.5).css() + ' ' + (percent + 0.5) + '%)');

// highlight the right line being played
this.props.playLines({
lineIds: this.clip.lineIds,
currentTime: this.currentTime,
duration: this.duration,
});
}

// if it's still playing, and current time is less than duration
Expand All @@ -61,7 +68,7 @@ var Section = React.createClass({
}
if (!playing) {
this.setPlay();
this.props.selectLines(null);
this.props.playLines(null);
clearInterval(intervalId);
}
}, 50);
Expand Down Expand Up @@ -115,9 +122,6 @@ var Section = React.createClass({

d3.select(this).select('.control')
.html('  ❙ ❙  ');

// when starting song, highlight the right lines
that.props.selectLines(that.clip.lineIds);
});
},

Expand Down
49 changes: 31 additions & 18 deletions src/visualizations/Lines.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,21 +14,38 @@ var Lines = {
});
},

calculatePositions(line, interpolate, top) {
// line.x and line.y are center, so x1 won't change
// but y1 will go from full radius to just radius
// x2 will be current x + length
// y2 will also go from full radius to just radius
// also interpolate arc between full radius to radius
var x1 = d3.interpolateNumber(line.x, line.focusX - (line.fullRadius - line.radius))(interpolate);
var y1 = d3.interpolateNumber(line.y - line.fullRadius + top,
line.focusY - line.radius + top)(interpolate);
var x2 = d3.interpolateNumber(line.x,
line.focusX + line.length - 2 * line.radius - (line.fullRadius - line.radius))(interpolate);
var y2 = d3.interpolateNumber(line.y + line.fullRadius + top,
line.focusY + line.radius + top)(interpolate);
var radius = d3.interpolateNumber(line.fullRadius, line.radius)(interpolate);

return {x1, y1, x2, y2, radius};
},

calculateLength(line, interpolate, top) {
var x1 = line.focusX - (line.fullRadius - line.radius);
var y1 = line.focusY - line.radius + top;
var x2 = d3.interpolateNumber(line.focusX,
line.focusX + line.length - 2 * line.radius - (line.fullRadius - line.radius))(interpolate);
var y2 = line.focusY + line.radius + top;
var radius = line.radius;

return {x1, y1, x2, y2, radius};
},

drawPaths(ctx, lines, interpolate, props) {
_.each(lines, line => {
// line.x and line.y are center, so x1 won't change
// but y1 will go from full radius to just radius
// x2 will be current x + length
// y2 will also go from full radius to just radius
// also interpolate arc between full radius to radius
var x1 = d3.interpolateNumber(line.x, line.focusX - (line.fullRadius - line.radius))(interpolate);
var y1 = d3.interpolateNumber(line.y - line.fullRadius + props.top,
line.focusY - line.radius + props.top)(interpolate);
var x2 = d3.interpolateNumber(line.x,
line.focusX + line.length - 2 * line.radius - (line.fullRadius - line.radius))(interpolate);
var y2 = d3.interpolateNumber(line.y + line.fullRadius + props.top,
line.focusY + line.radius + props.top)(interpolate);
var radius = d3.interpolateNumber(line.fullRadius, line.radius)(interpolate);
var {x1, y1, x2, y2, radius} = this.calculatePositions(line, interpolate, props.top);
var opacity = d3.interpolateNumber(1, line.selected ? 1 : 0.15)(interpolate);

ctx.beginPath();
Expand All @@ -50,11 +67,7 @@ var Lines = {
// x2 will be current x + length
// y2 will also go from full radius to just radius
// also interpolate arc between full radius to radius
var x1 = line.focusX - (line.fullRadius - line.radius);
var y1 = line.focusY - line.radius + top;
var x2 = line.focusX + line.length - 2 * line.radius - (line.fullRadius - line.radius);
var y2 = line.focusY + line.radius + top;
var radius = line.radius;
var {x1, y1, x2, y2, radius} = this.calculatePositions(line, 1, top);
var opacity = line.selected ? 1 : 0.15;

ctx.beginPath();
Expand Down
83 changes: 83 additions & 0 deletions src/visualizations/Visualization.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import React from 'react';
import * as d3 from "d3";
import _ from 'lodash';
import textures from 'textures';

import Lines from './Lines';
import Diamonds from './Diamonds';
Expand All @@ -15,6 +17,10 @@ var simulation = d3.forceSimulation()
var Visualization = React.createClass({

shouldComponentUpdate(nextProps) {
if (!nextProps.update) {
this.playMusic(nextProps);
}

return nextProps.update;
},

Expand All @@ -27,6 +33,9 @@ var Visualization = React.createClass({
this.crispyCanvas(this.refs.hiddenCanvas, sf);
this.hiddenCtx = this.refs.hiddenCanvas.getContext('2d');
this.hiddenCtx.scale(sf, sf);
// and svg
this.svg = d3.select(this.refs.interactions);
this.setupInteractions();

// add mousemove
d3.select(this.refs.canvas)
Expand Down Expand Up @@ -56,6 +65,71 @@ var Visualization = React.createClass({
}
},

setupInteractions() {
var texture = textures.paths()
.d("woven")
.lighter()
.thicker();
this.svg.call(texture);

// append music group
this.svg.append('g')
.classed('music', true);

// append hover group
this.svg.append('g')
.classed('hover', true);
},

playMusic(props) {
var music = this.svg.select('.music');
music.selectAll('*').remove();

if (!props.playing) return;

music.append('rect')
.attr('width', props.width)
.attr('height', props.height)
.attr('fill', '#fff')
.attr('opacity', 0.75);
var lines = props.playing.lines;
_.each(lines, line => {
var data = [
{interpolate: 1, fill: props.gray},
{interpolate: props.playing.currentTime / props.playing.duration, fill: line.fill},
];
data = _.map(data, d => {
return Object.assign(d, Lines.calculateLength(line, d.interpolate, props.top));
});
music.append('g').selectAll('rect')
.data(data).enter().append('rect')
.attr('x', d => d.x1 - d.radius)
.attr('y', d => d.y1)
.attr('width', d => d.x2 - d.x1 + 2 * d.radius)
.attr('height', d => d.y2 - d.y1)
.attr('rx', d => d.radius)
.attr('ry', d => d.radius)
.attr('fill', d => d.fill);
});
// var music = this.svg.select('.music')
// .selectAll('.line').data(lines || [], d => d.id);
//
// music.exit().remove();
// if (!props.playing) return;
//
// var enter = music.enter().append('g')
// .classed('line', true);
// enter.append('rect')
// .classed('gray', true);
//
// music = enter.merge(music)
// .attr('fill', d => d.fill)
// .attr('stroke', d => d.fill)
// .attr('transform', d => 'translate(' + [d.focusX, d.focusY + props.top] + ')');
//
// music.select('.gray')
},

crispyCanvas(canvas, sf) {
canvas.width = this.props.width * sf;
canvas.height = this.props.height * sf;
Expand Down Expand Up @@ -132,11 +206,20 @@ var Visualization = React.createClass({
// left: 0,
// zIndex: -1,
};
var svgStyle = {
position: 'absolute',
top: 0,
left: 0,
width: this.props.width,
height: this.props.height,
pointerEvents: 'none',
};

return (
<div style={style}>
<canvas ref='canvas' />
<canvas ref='hiddenCanvas' style={hiddenCanvasStyle} />
<svg ref='interactions' style={svgStyle} />
</div>
);
}
Expand Down

0 comments on commit f5153fd

Please sign in to comment.