First stab at spline line for equalizer

This commit is contained in:
Jordan Eldredge 2016-08-29 20:17:38 -07:00
parent 1f5e7503b0
commit 99e9e70ce6
4 changed files with 120 additions and 39 deletions

View file

@ -0,0 +1,29 @@
jest.unmock('../components/EqGraph.jsx');
import {
roundToEven,
getY
} from '../components/EqGraph.jsx';
describe('roundToEven', () => {
it('leaves even numbers as is', () => {
const actual = roundToEven(4);
const expected = 4;
expect(actual).toEqual(expected);
});
it('handles zero', () => {
const actual = roundToEven(0);
const expected = 0;
expect(actual).toEqual(expected);
});
it('handles odd numbers', () => {
const actual = roundToEven(3);
const expected = 4;
expect(actual).toEqual(expected);
});
});
describe('getY', () => {
it('gives the first sprite', () => {
});
});

View file

@ -1,13 +1,21 @@
import React from 'react';
import {connect} from 'react-redux';
import {getCurvePoints} from 'cardinal-spline-js';
import {BANDS} from '../constants';
export const roundToEven = (value) => (
2 * Math.round(value / 2)
);
export const getY = (value) => (
32 - ((value / 100) * 32)
roundToEven(32 - ((value / 100) * 32))
);
class EqGraph extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
componentDidMount() {
@ -15,64 +23,91 @@ class EqGraph extends React.Component {
this.canvasCtx.imageSmoothingEnabled = false;
this.width = this.refs.canvas.width * 1; // Cast to int
this.height = this.refs.canvas.height * 1; // Cast to int
this.bgImage = new Image();
this.bgImage.onload = () => {
this.createColorPattern();
this.componentDidUpdate();
};
this.bgImage.src = 'bg.png';
}
componentDidUpdate() {
this.canvasCtx.clearRect(0, 0, this.width, this.height);
//this.createColorPattern();
this.drawPreampLine();
this.drawEqLine(); // This should paint on top of the preamp line
}
createColorPattern() {
const colorsCanvas = document.createElement('canvas');
const colorsCtx = colorsCanvas.getContext('2d');
colorsCanvas.width = this.bgImage.width * 2;
colorsCanvas.height = this.bgImage.height * 2;
colorsCtx.drawImage(this.bgImage, 0, 0, colorsCanvas.width, colorsCanvas.height);
this.colorPattern = this.canvasCtx.createPattern(colorsCanvas, 'repeat-x');
shouldComponentUpdate(nextProps) {
if (this.props.lineColorsImage !== nextProps.lineColorsImage) {
this.createColorPattern(nextProps.lineColorsImage);
}
if (this.props.preampLineUrl !== nextProps.preampLineUrl) {
this.createPreampLineImage(nextProps.preampLineUrl);
}
return true;
}
createPreampLineImage(preampLineUrl) {
const preampLineImg = new Image();
preampLineImg.onload = () => {
this.setState({preampLineImg});
};
preampLineImg.src = preampLineUrl;
}
createColorPattern(lineColorsImage) {
const bgImage = new Image();
bgImage.onload = () => {
const colorsCanvas = document.createElement('canvas');
const colorsCtx = colorsCanvas.getContext('2d');
colorsCanvas.width = bgImage.width * 2;
colorsCanvas.height = bgImage.height * 2;
colorsCtx.drawImage(bgImage, 0, 0, colorsCanvas.width, colorsCanvas.height);
this.setState({
colorPattern: this.canvasCtx.createPattern(colorsCanvas, 'repeat-x')
});
};
bgImage.src = lineColorsImage;
}
drawEqLine() {
if (!this.state.colorPattern) {
// The skin has not finished loading yet
return;
}
const {props} = this;
const values = [
props[60],
props[170],
props[310],
props[600],
props[1000],
props[3000],
props[6000],
props[12000],
props[14000],
props[16000]
];
const amplitudes = BANDS.map((band) => props[band]);
this.canvasCtx.strokeStyle = this.colorPattern;
this.canvasCtx.strokeStyle = this.state.colorPattern;
this.canvasCtx.lineWidth = 2;
this.canvasCtx.beginPath();
const paddingLeft = 4;
// TODO: Curve these lines
values.forEach((value, i) => {
this.canvasCtx.lineTo(paddingLeft + (i * 16), getY(value));
let points = [];
amplitudes.forEach((value, i) => {
points = points.concat(paddingLeft + (i * 16), getY(value));
});
// Spline between points in order to create nice curves
const tension = 0.5;
const resolution = 4; // Points in each segment
const smoothPoints = getCurvePoints(points, tension, resolution);
for (let i = 0; i < smoothPoints.length; i += 2) {
this.canvasCtx.lineTo(smoothPoints[i], smoothPoints[i + 1]);
}
this.canvasCtx.stroke();
}
drawPreampLine() {
// TODO: Use the line from the skin image
const preampValue = getY(this.props.preamp);
this.canvasCtx.lineWidth = 2;
this.canvasCtx.strokeStyle = 'white';
this.canvasCtx.beginPath();
this.canvasCtx.moveTo(0, preampValue);
this.canvasCtx.lineTo(this.width, preampValue);
this.canvasCtx.stroke();
const {preampLineImg} = this.state;
if (!preampLineImg) {
// The skin has not finished loading yet
return;
}
const preampValue = getY(100 - this.props.preamp);
this.canvasCtx.drawImage(
this.state.preampLineImg,
0,
preampValue,
preampLineImg.width * 2,
preampLineImg.height * 2
);
}
render() {
@ -85,4 +120,8 @@ class EqGraph extends React.Component {
}
}
export default connect((state) => state.equalizer.sliders)(EqGraph);
export default connect((state) => ({
...state.equalizer.sliders,
lineColorsImage: state.display.skinImages.EQ_GRAPH_LINE_COLORS,
preampLineUrl: state.display.skinImages.EQ_PREAMP_LINE
}))(EqGraph);

12
js/constants.js Normal file
View file

@ -0,0 +1,12 @@
export const BANDS = [
60,
170,
310,
600,
1000,
3000,
6000,
12000,
14000,
16000
];

View file

@ -50,6 +50,7 @@
"dependencies": {
"babel-plugin-transform-object-rest-spread": "^6.8.0",
"babel-plugin-transform-react-jsx": "^6.8.0",
"cardinal-spline-js": "^2.3.6",
"classnames": "^2.2.5",
"jszip": "^2.6.0",
"react": "^15.2.0",