Move prop logic out of index.

This commit is contained in:
empathicqubit 2018-05-27 16:00:18 -04:00
parent 9b2618d376
commit 8469c37254
14 changed files with 313 additions and 217 deletions

View file

@ -3,5 +3,6 @@ module.exports = {
rules: {
"no-restricted-globals": "off",
"no-undef": "off",
"eqeqeq": "off",
},
};

View file

@ -0,0 +1,5 @@
function getProps () {
return {};
}
export default getProps;

View file

@ -0,0 +1,49 @@
import BufferClientBackend from '../buffer-client-backend';
import StartAudioContext from 'startaudiocontext';
function getProps(render) {
const client = {
clientName: '',
clientId: '',
sources: [],
realPosition: 0,
};
client.options = {
onTimeOffset: timeOffset => {
client.realPosition = backend.getRealPosition();
render();
},
onClientId: clientId => {
client.clientId = clientId;
render();
},
onSourcesUpdated: sources => {
client.sources = sources
render();
},
onSyncPacket: packet => {
client.realPosition = backend.getRealPosition();
render();
}
};
const backend = new BufferClientBackend(client.options);
client.onChangeName = (clientName) => {
backend.changeName(clientName);
client.clientName = clientName;
render();
};
client.onComponentMount = () => {
StartAudioContext(backend._context, '.playit')
.then(() => {
backend.afterContextStarted();
});
};
return client;
};
export default getProps;

View file

@ -0,0 +1,143 @@
import BufferClientBackend from '../buffer-client-backend';
import StartAudioContext from 'startaudiocontext';
const HOST = window.location.host.split(':')[0];
function getProps (render) {
let AudioContext = window.AudioContext || window.webkitAudioContext;
let context = new AudioContext();
const createClient = () => {
let mixerNode = null;
let options = {
context: context,
onTimeOffset: timeOffset => {
client.realPosition = backend.getRealPosition();
render();
},
onClientId: clientId => {
client.clientId = clientId;
render();
},
onSourcesUpdated: sources => {
client.sources = sources;
render();
},
onSyncPacket: packet => {
client.realPosition = backend.getRealPosition();
render();
},
onMixerNodeCreated: node => {
mixerNode = node;
mixerNode.panningModel = 'HRTF';
mixerNode.distanceModel = 'inverse';
mixerNode.refDistance = 1;
mixerNode.maxDistance = 500;
mixerNode.rolloffFactor = 0.01;
mixerNode.coneInnerAngle = 360;
mixerNode.coneOuterAngle = 0;
mixerNode.codeOuterGain = 0;
client.x = 50;
client.y = 50;
render();
},
};
let backend = new BufferClientBackend(options);
const updateX = (newX) => {
client.x = newX;
mixerNode.positionX.value = newX - 250;
};
const updateY = (newY) => {
client.y = newY;
mixerNode.positionZ.value = 250 - newY;
}
let client = {
sources: [],
realPosition: 0,
clientId: 0,
x: 0,
y: 0,
onDrag: (evt, data) => {
updateX(data.x);
updateY(data.y);
render();
},
onChangeName: (name) => {
backend.changeName(name);
client.name = name;
render();
},
};
StartAudioContext(backend._context, '.playit')
.then(() => {
backend.afterContextStarted();
});
return client;
};
let clients = [];
const doHello = (password) => {
ws.send(JSON.stringify({type: 'hello_admin', password: password }));
}
const updateX = (newX) => {
simulator.listenerX = newX;
context.listener.positionX.value = newX - 250;
};
const updateY = (newY) => {
simulator.listenerY = newY;
context.listener.positionZ.value = 250 - newY;
}
let simulator = {
clients: clients,
passwordSubmitted: false,
password: '',
listenerX: 250,
listenerY: 250,
onDrag: (evt, data) => {
updateX(data.x);
updateY(data.y);
render();
},
onNewMixerNode: () => {
clients.push(createClient());
render();
},
onSubmitPassword: (password) => doHello(password),
onChangePassword: (password) => {
simulator.password = password;
render();
},
};
let ws = new WebSocket(`ws://${HOST}:3031`);
ws.addEventListener('message', evt => {
let data = JSON.parse(evt.data);
if(data.type == 'hello_admin') {
simulator.passwordSubmitted = true;
render();
}
});
return simulator;
};
export default getProps;

View file

@ -1,231 +1,36 @@
import React from 'react';
import ReactDOM from 'react-dom';
import registerServiceWorker from './registerServiceWorker';
import BufferClientBackend from './buffer-client-backend';
import StartAudioContext from 'startaudiocontext';
import { HashRouter, Route, Switch } from 'react-router-dom';
import './index.css';
import './range.css';
import App from './app';
import Client from './client';
import Admin from './admin';
import Simulator from './simulator';
import App from './view/app';
const HOST = window.location.host.split(':')[0];
import Client from './view/client';
import getClientProps from './controller/client';
import Admin from './view/admin';
import getAdminProps from './controller/admin';
import Simulator from './view/simulator';
import getSimulatorProps from './controller/simulator';
const render = () => ReactDOM.render(router(), document.getElementById('root'));
let clientProps, adminProps, simulatorProps;
const router = () => {
return <HashRouter>
<Switch>
<Route path="/" exact component={App} />
<Route path="/client" render={(routeProps) => <Client {...routeProps} {...props.client} />} />
<Route path="/admin" render={(routeProps) => <Admin {...routeProps} {...props.admin} />} />
<Route path="/simulator" render={(routeProps) => <Simulator {...routeProps} {...props.simulator} />} />
<Route path="/client" render={(routeProps) => <Client {...routeProps} {...clientProps || (clientProps = getClientProps(render))} />} />
<Route path="/admin" render={(routeProps) => <Admin {...routeProps} {...adminProps || (adminProps = getAdminProps(render))} />} />
<Route path="/simulator" render={(routeProps) => <Simulator {...routeProps} {...simulatorProps || (simulatorProps = getSimulatorProps(render))} />} />
</Switch>
</HashRouter>
};
const getProps = () => {
const props = {
admin: {},
};
const createClient = () => {
const client = {
clientName: '',
clientId: '',
sources: [],
realPosition: 0,
};
client.options = {
onTimeOffset: timeOffset => {
client.realPosition = backend.getRealPosition();
render();
},
onClientId: clientId => {
client.clientId = clientId;
render();
},
onSourcesUpdated: sources => {
client.sources = sources
render();
},
onSyncPacket: packet => {
client.realPosition = backend.getRealPosition();
render();
}
};
const backend = new BufferClientBackend(client.options);
client.onChangeName = (clientName) => {
backend.changeName(clientName);
client.clientName = clientName;
render();
};
client.onComponentMount = () => {
StartAudioContext(backend._context, '.playit')
.then(() => {
backend.afterContextStarted();
});
};
return client;
};
props.client = createClient();
const createSimulator = () => {
let AudioContext = window.AudioContext || window.webkitAudioContext;
let context = new AudioContext();
const createClient = () => {
let mixerNode = null;
let options = {
context: context,
onTimeOffset: timeOffset => {
client.realPosition = backend.getRealPosition();
render();
},
onClientId: clientId => {
client.clientId = clientId;
render();
},
onSourcesUpdated: sources => {
client.sources = sources;
render();
},
onSyncPacket: packet => {
client.realPosition = backend.getRealPosition();
render();
},
onMixerNodeCreated: node => {
mixerNode = node;
mixerNode.panningModel = 'HRTF';
mixerNode.distanceModel = 'inverse';
mixerNode.refDistance = 1;
mixerNode.maxDistance = 500;
mixerNode.rolloffFactor = 0.01;
mixerNode.coneInnerAngle = 360;
mixerNode.coneOuterAngle = 0;
mixerNode.codeOuterGain = 0;
client.x = 50;
client.y = 50;
render();
},
};
let backend = new BufferClientBackend(options);
const updateX = (newX) => {
client.x = newX;
mixerNode.positionX.value = newX - 250;
};
const updateY = (newY) => {
client.y = newY;
mixerNode.positionZ.value = 250 - newY;
}
let client = {
sources: [],
realPosition: 0,
clientId: 0,
x: 0,
y: 0,
onDrag: (evt, data) => {
updateX(data.x);
updateY(data.y);
render();
},
onChangeName: (name) => {
backend.changeName(name);
client.name = name;
render();
},
};
StartAudioContext(backend._context, '.playit')
.then(() => {
backend.afterContextStarted();
});
return client;
};
let clients = [];
const doHello = (password) => {
ws.send(JSON.stringify({type: 'hello_admin', password: password }));
}
const updateX = (newX) => {
simulator.listenerX = newX;
context.listener.positionX.value = newX - 250;
};
const updateY = (newY) => {
simulator.listenerY = newY;
context.listener.positionZ.value = 250 - newY;
}
let simulator = {
clients: clients,
passwordSubmitted: false,
password: '',
listenerX: 250,
listenerY: 250,
onDrag: (evt, data) => {
updateX(data.x);
updateY(data.y);
render();
},
onNewMixerNode: () => {
clients.push(createClient());
render();
},
onSubmitPassword: (password) => doHello(password),
onChangePassword: (password) => {
simulator.password = password;
render();
},
};
let ws = new WebSocket(`ws://${HOST}:3031`);
ws.addEventListener('message', evt => {
let data = JSON.parse(evt.data);
if(data.type == 'hello_admin') {
simulator.passwordSubmitted = true;
render();
}
});
return simulator;
};
props.simulator = createSimulator();
return props;
}
const props = getProps();
//<Route path="/admin" component={Admin} />
//<Route path="/simulator" component={Simulator} />
render();
registerServiceWorker();

85
frontend/src/range.css Normal file
View file

@ -0,0 +1,85 @@
input[type=range] {
-webkit-appearance: none;
width: 100%;
margin: 9.95px 0;
}
input[type=range]:focus {
outline: none;
}
input[type=range]::-webkit-slider-runnable-track {
width: 100%;
height: 10.1px;
cursor: pointer;
box-shadow: 0.2px 0.2px 1.4px #000000, 0px 0px 0.2px #0d0d0d;
background: #a2f9fc;
border-radius: 11.8px;
border: 0.4px solid #010101;
}
input[type=range]::-webkit-slider-thumb {
box-shadow: 2.6px 2.6px 1.1px rgba(2, 55, 86, 0.85), 0px 0px 2.6px rgba(3, 71, 111, 0.85);
border: 3px solid #f17a6b;
height: 30px;
width: 30px;
border-radius: 15px;
background: #f0957d;
cursor: pointer;
-webkit-appearance: none;
margin-top: -10.35px;
}
input[type=range]:focus::-webkit-slider-runnable-track {
background: #e7fdfe;
}
input[type=range]::-moz-range-track {
width: 100%;
height: 10.1px;
cursor: pointer;
box-shadow: 0.2px 0.2px 1.4px #000000, 0px 0px 0.2px #0d0d0d;
background: #a2f9fc;
border-radius: 11.8px;
border: 0.4px solid #010101;
}
input[type=range]::-moz-range-thumb {
box-shadow: 2.6px 2.6px 1.1px rgba(2, 55, 86, 0.85), 0px 0px 2.6px rgba(3, 71, 111, 0.85);
border: 3px solid #f17a6b;
height: 30px;
width: 30px;
border-radius: 15px;
background: #f0957d;
cursor: pointer;
}
input[type=range]::-ms-track {
width: 100%;
height: 10.1px;
cursor: pointer;
background: transparent;
border-color: transparent;
color: transparent;
}
input[type=range]::-ms-fill-lower {
background: #5df5fa;
border: 0.4px solid #010101;
border-radius: 23.6px;
box-shadow: 0.2px 0.2px 1.4px #000000, 0px 0px 0.2px #0d0d0d;
}
input[type=range]::-ms-fill-upper {
background: #a2f9fc;
border: 0.4px solid #010101;
border-radius: 23.6px;
box-shadow: 0.2px 0.2px 1.4px #000000, 0px 0px 0.2px #0d0d0d;
}
input[type=range]::-ms-thumb {
box-shadow: 2.6px 2.6px 1.1px rgba(2, 55, 86, 0.85), 0px 0px 2.6px rgba(3, 71, 111, 0.85);
border: 3px solid #f17a6b;
height: 30px;
width: 30px;
border-radius: 15px;
background: #f0957d;
cursor: pointer;
height: 10.1px;
}
input[type=range]:focus::-ms-fill-lower {
background: #a2f9fc;
}
input[type=range]:focus::-ms-fill-upper {
background: #e7fdfe;
}

View file

@ -1,6 +1,6 @@
.clients input[type="range"] {
display: block;
float: left;
float: left;
width: 5em;
height: 10em;
-webkit-appearance: slider-vertical;
@ -52,14 +52,14 @@
}
.knobs .pan {
background-image: url('../node_modules/material-design-icons/action/svg/design/ic_pan_tool_24px.svg');
background-image: url('../../node_modules/material-design-icons/action/svg/design/ic_pan_tool_24px.svg');
background-size: 50%;
background-repeat: no-repeat;
background-position: 40% 35%;
}
.knobs .gain {
background-image: url('../node_modules/material-design-icons/av/svg/design/ic_volume_up_24px.svg');
background-image: url('../../node_modules/material-design-icons/av/svg/design/ic_volume_up_24px.svg');
background-size: 70%;
background-repeat: no-repeat;
background-position: 70% 46%;

View file

@ -170,6 +170,9 @@ class Admin extends React.Component {
<h1>
Source administrator
</h1>
<p>
This interface allows you to control the state of connected clients; which tracks are playing as well as the pan and gain for each track.
</p>
{!this.state.passwordSubmitted
? (
<div className="password-input">
@ -180,11 +183,11 @@ class Admin extends React.Component {
</div>
) : (
<div>
Current play position: {this.state.syncPacket.timecode / 1000} seconds<br />
Current play position: <strong>{this.state.syncPacket.timecode / 1000} seconds</strong><br />
<input type="range" min={0} max={370000} step={1} value={this.state.syncPacket.timecode} onChange={ evt => this.adjustTimecode(evt.target.value) } />
<div className="track-controls">
<button onClick={ () => this.restart() }>
Start over
Restart song
</button>
<button onClick={ () => this.muteAll() }>
Mute All Clients
@ -197,6 +200,7 @@ class Admin extends React.Component {
{state.clients.length
? state.clients.map((client) =>
<li key={client.id}>
<div style={{position: 'relative', display: 'inline-block' }} className="speaker"></div>
Client {client.name || client.id} <br />
<br />
Sources: <br />

View file

@ -0,0 +1,4 @@
.enabled-sources li {
margin: 0 1em;
padding: 0 0.5em;
}

View file

@ -10,6 +10,7 @@ class BufferClient extends React.Component {
let enabledSources = this.props.sources.filter(source => source.enabled);
return (
<div>
<div style={{position: 'relative', display: 'inline-block' }} className="speaker"></div>
<strong>{"Client " + (this.props.clientName || this.props.clientId)}</strong>
<br />
<div>

View file

@ -10,7 +10,7 @@
.speaker::before {
content: "";
mask-image: url('../node_modules/material-design-icons/hardware/svg/design/ic_speaker_24px.svg');
mask-image: url('../../node_modules/material-design-icons/hardware/svg/design/ic_speaker_24px.svg');
mask-repeat: none;
mask-size: contain;
background-color: #109030;
@ -37,7 +37,7 @@
.listener::before {
content: "";
mask-image: url('../node_modules/material-design-icons/av/svg/design/ic_hearing_24px.svg');
mask-image: url('../../node_modules/material-design-icons/av/svg/design/ic_hearing_24px.svg');
mask-repeat: none;
mask-size: contain;
background-color: #F17A6B;

View file

@ -1,5 +1,4 @@
import BufferClient from './buffer-client.js';
import BufferClientBackend from './buffer-client-backend.js';
import React from 'react';
import Draggable from 'react-draggable';