[] React VR-, |
React VR JavaScript React WebVR API. ( ) Chrome, Firefox Edge. VR.
WebVR Experiments -, WebVR. The Musical Forest, Google Creative Lab, A-Frame, - WebVR, Mozilla VR.
Musical Forest WebSockets , . - ( ). , , React VR Pusher?
React VR/Pusher-:
URL . Pusher-, , .
Node.js-, - JavaScript React. React VR VR , .
( ) React VR CLI:
npm install -g react-vr-cli
React VR-:
react-vr init musical-exp-react-vr-pusher
:
cd musical-exp-react-vr-pusher
npm start
( Firefox Nightly Windows), View in VR, VR:
.
(equirectangular image). , . 4096x2048 . .
static_assets images, . index.vr.js render :
render() {
return (
);
}
Cylinder. , . Musical Forest js/components/background-objects.js , . React- , :
import React from 'react';
import {
View,
Cylinder,
} from 'react-vr';
export default ({trees, perimeter, colors}) => {
const DEG2RAD = Math.PI / 180;
return (
{Array.apply(null, {length: trees}).map((obj, index) => {
const theta = DEG2RAD * (index / trees) * 360;
const randomSeed = Math.random();
const treeDistance = randomSeed * 5 + perimeter;
const treeColor = Math.floor(randomSeed * 3);
const x = Math.cos(theta) * treeDistance;
const z = Math.sin(theta) * treeDistance;
return (
);
})}
);
}
:
Array.apply(null, {length: trees})
, map-, , View.
Forest.js index.vr.js:
...
import Forest from './components/Forest';
export default class musical_exp_react_vr_pusher extends React.Component {
render() {
return (
);
}
};
...
3D-, . , .
VrButton, Animated.View, Box, Cylinder Sphere. , , . components/SoundShape.js:
import React from 'react';
import {
VrButton,
Animated,
} from 'react-vr';
export default class SoundShape extends React.Component {
constructor(props) {
super(props);
this.state = {
bounceValue: new Animated.Value(0),
};
}
animateEnter() {
Animated.spring(
this.state.bounceValue,
{
toValue: 1,
friction: 4,
}
).start();
}
animateExit() {
Animated.timing(
this.state.bounceValue,
{
toValue: 0,
duration: 50,
}
).start();
}
render() {
return (
this.animateEnter()}
onExit={()=>this.animateExit()}
>
{this.props.children}
);
}
};
, Animated.spring
this.state.bounceValue
0 1 . , Animated.timing
this.state.bounceValue
1 0 50 . , VrButton
Animated.View
, rotateX- View .
index.vr.js SpotLight
( ) SoundShape
, :
...
import {
AppRegistry,
asset,
Pano,
SpotLight,
View,
Cylinder,
} from 'react-vr';
import Forest from './components/Forest';
import SoundShape from './components/SoundShape';
export default class musical_exp_react_vr_pusher extends React.Component {
render() {
return (
...
);
}
};
...
, 3D-, 3D-.
( op radius ):
:
:
:
:
. :
!
, React VR wav, mp3 ogg-. .
Freesound . , , static_assets/sounds. , , , , , ( , , React VR ).
React VR :
3D/ Sound
, . SoundShape
, onClick
VrButton
:
...
import {
...
Sound,
} from 'react-vr';
export default class SoundShape extends React.Component {
...
render() {
return (
> this.props.onClick()}
...
>
...
);
}
}
index.vr.js :
...
import {
...
MediaPlayerState,
} from 'react-vr';
...
export default class musical_exp_react_vr_pusher extends React.Component {
constructor(props) {
super(props);
this.config = [
{sound: asset('sounds/bird.wav'), playerState: new MediaPlayerState({})},
{sound: asset('sounds/bird2.wav'), playerState: new MediaPlayerState({})},
{sound: asset('sounds/bird3.wav'), playerState: new MediaPlayerState({})},
{sound: asset('sounds/cat.wav'), playerState: new MediaPlayerState({})},
{sound: asset('sounds/cricket.wav'), playerState: new MediaPlayerState({})},
{sound: asset('sounds/dog.wav'), playerState: new MediaPlayerState({})},
];
}
...
}
And a method to play a sound using the MediaPlayerState object when the right index is passed:
...
export default class musical_exp_react_vr_pusher extends React.Component {
...
onShapeClicked(index) {
this.config[index].playerState.play();
}
...
}
SoundShape. 3D- map- :
...
export default class musical_exp_react_vr_pusher extends React.Component {
...
render() {
const shapes = [
,
,
,
,
,
];
return (
...
{shapes.map((shape, index) => {
return (
> this.onShapeClicked(index)}
sound={this.config[index].sound}
playerState={this.config[index].playerState}>
{shape}
);
})}
);
}
...
}
, .
Pusher React VR- .
https://pusher.com/signup. , - :
, React, Node.js. :
, , . Pusher .
ID ( , mt1), ID , , . App Keys.
React VR Web Worker ( React VR ), Pusher- index.vr.js:
...
importScripts('https://js.pusher.com/4.1/pusher.worker.min.js');
export default class musical_exp_react_vr_pusher extends React.Component {
...
}
, . -, URL ( http://localhost:8081/vr/?channel=1234), , .
URL. , React VR Location, window.location React.
, Pusher-, . , , , , . , , .
Pusher- ID . Pusher, socket_id
, ( ).
, getParameterByName
URL socketId
Pusher, :
...
import {
...
NativeModules,
} from 'react-vr';
...
const Location = NativeModules.Location;
export default class musical_exp_react_vr_pusher extends React.Component {
componentWillMount() {
const pusher = new Pusher('', {
cluster: '',
encrypted: true,
});
this.socketId = null;
pusher.connection.bind('connected', () => {
this.socketId = pusher.connection.socket_id;
});
this.channelName = 'channel-' + this.getChannelId();
const channel = pusher.subscribe(this.channelName);
channel.bind('sound_played', (data) => {
this.config[data.index].playerState.play();
});
}
getChannelId() {
let channel = this.getParameterByName('channel', Location.href);
if(!channel) {
channel = 0;
}
return channel;
}
getParameterByName(name, url) {
const regex = new RegExp("[?&]" + name + "(=([^]*)|&|#|$)");
const results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
...
}
URL , ID 0. ID Pusher-, .
, endpoint , , ID , :
...
export default class musical_exp_react_vr_pusher extends React.Component {
...
onShapeClicked(index) {
this.config[index].playerState.play();
fetch('http:///pusher/trigger', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
index: index,
socketId: this.socketId,
channelName: this.channelName,
})
});
}
...
}
React-. .
package.json:
npm init -y
:
npm install --save body-parser express pusher
:
const express = require('express');
const bodyParser = require('body-parser');
const Pusher = require('pusher');
const app = express();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
/*
, React VR . , middleware
*/
app.use((req, res, next) => {
res.header("Access-Control-Allow-Origin", "*")
res.header("Access-Control-Allow-Headers",
"Origin, X-Requested-With, Content-Type, Accept")
next();
});
const pusher = new Pusher({
appId: '',
key: '',
secret: '',
cluster: '',
encrypted: true,
});
app.post('/pusher/trigger', function(req, res) {
pusher.trigger(req.body.channelName,
'sound_played',
{ index: req.body.index },
req.body.socketId );
res.send('ok');
});
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`Running on port ${port}`));
, Express-, Pusher- route/pusher/trigger, socketID .
. .
Node.js- :
node server.js
URL index.vr.js ( IP localhost) http://localhost:8081/vr/?channel=1234. 3D- ( ):
React VR , VR-, React/React Native. Pusher, - .
production- -: https://facebook.github.io/react-vr/docs/publishing.html.
, , , Musical Forest.