@lebek/react-user-media
Version:
React components for webcam and audio
209 lines (176 loc) • 5.14 kB
JavaScript
import React, { Component, PropTypes } from "react";
class Webcam extends Component {
static propTypes = {
audio: PropTypes.bool,
width: PropTypes.number,
height: PropTypes.number,
captureFormat: PropTypes.oneOf(["image/png", "image/jpeg", "image/webp"]),
onSuccess: PropTypes.func,
onFailure: PropTypes.func
};
static defaultProps = {
audio: true,
video: true,
width: 640,
height: 480,
clockwiseRotations: 0,
zoom: 1,
focusX: 0.5,
focusY: 0.5,
captureFormat: "image/png",
onSuccess: () => {},
onFailure: error => {
console.error("An error occured while requesting user media");
throw error;
}
};
static _mediaStream = null;
static _captureCanvas = null;
//---------------------------------------------------------------------------
// Initialization
//---------------------------------------------------------------------------
constructor(props) {
super(props);
this.state = {
hasUserMedia: false,
userMediaRequested: false
};
}
//---------------------------------------------------------------------------
// Lifecycle methods
//---------------------------------------------------------------------------
componentDidMount() {
if (!this._hasGetUserMedia()) {
return false;
}
const { hasUserMedia, userMediaRequested } = this.state;
if (!hasUserMedia && !userMediaRequested) {
this._requestUserMedia();
}
}
componentWillUnmount() {
this._mediaStream &&
this._mediaStream.getTracks().forEach(track => track.stop());
}
//---------------------------------------------------------------------------
// External methods
//---------------------------------------------------------------------------
_hasGetUserMedia() {
return !!(navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia);
}
_requestUserMedia() {
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
const constraints = {
video: {
width: { min: 1280, ideal: 3840 },
height: { min: 720, ideal: 2160 }
},
audio: this.props.audio
};
navigator.getUserMedia(
constraints,
stream => {
const video = this._video;
if (window.URL) {
video.src = window.URL.createObjectURL(stream);
} else {
video.src = stream;
}
this._mediaStream = stream;
this.setState({
hasUserMedia: true,
userMediaRequested: true
});
this.props.onSuccess();
},
error => {
this.props.onFailure(error);
}
);
}
_getCanvas() {
this._captureCanvas = document.createElement("canvas");
this._captureCanvas.width = this.props.viewX;
this._captureCanvas.height = this.props.viewY;
return this._captureCanvas;
}
//---------------------------------------------------------------------------
// External methods
//---------------------------------------------------------------------------
captureCanvas() {
const { hasUserMedia, userMediaRequested } = this.state;
const {
width,
height,
viewX,
viewY,
focusX,
focusY,
clockwiseRotations
} = this.props;
if (hasUserMedia && userMediaRequested) {
const canvas = this._getCanvas();
const ctx = canvas.getContext("2d");
if (clockwiseRotations % 4 === 0) {
} else if (clockwiseRotations % 4 === 1) {
ctx.translate(canvas.width, 0);
ctx.rotate(Math.PI / 2.0);
} else if (clockwiseRotations % 4 === 2) {
ctx.translate(canvas.width, canvas.height);
ctx.rotate(Math.PI);
} else if (clockwiseRotations % 4 === 3) {
ctx.translate(0, canvas.height);
ctx.rotate(3 * Math.PI / 2.0);
}
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(
this._video,
viewX / 2.0 - focusX * width,
viewY / 2.0 - focusY * height,
width,
height
);
return canvas;
}
}
captureScreenshot() {
const { captureFormat } = this.props;
const canvas = this.captureCanvas();
if (canvas) {
return canvas.toDataURL(captureFormat);
}
}
//---------------------------------------------------------------------------
// Render
//---------------------------------------------------------------------------
render() {
const { width, height, ...props } = this.props;
const wrapperStyle = {
width,
height,
overflow: "hidden",
position: "relative"
};
const videoStyle = {
position: "absolute"
};
return (
<div style={wrapperStyle} {...props}>
<video
style={videoStyle}
width={width}
height={height}
ref={component => this._video = component}
autoPlay
/>
</div>
);
}
}
export default Webcam;