GLCanvas.js 3.65 KB
Newer Older
1
import invariant from "invariant";
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
2 3
import React, {Component} from "react";
import {requireNativeComponent, findNodeHandle} from "react-native";
4 5
import defer from "promise-defer";
import captureFrame from "./GLCanvas.captureFrame";
6

7 8 9
const serializeOption = config =>
config.format + ":" + config.type + ":" + config.quality;

10 11 12 13 14
const GLCanvasNative = requireNativeComponent("GLCanvas", GLCanvas, {
  nativeOnly: {
    onGLChange: true,
    onGLProgress: true,
    onGLCaptureFrame: true
15
  }
16 17 18
});

class GLCanvas extends Component {
19 20 21 22 23 24 25 26 27 28 29

  componentWillMount () {
    this._pendingCaptureFrame = {};
  }

  componentWillUnmount () {
    Object.keys(this._pendingCaptureFrame).forEach(key =>
      this._pendingCaptureFrame[key].reject(new Error("GLCanvas is unmounting")));
    this._pendingCaptureFrame = null;
  }

30 31 32 33 34
  setNativeProps (props) {
    this.refs.native.setNativeProps(props);
  }

  _addPendingCaptureFrame (config) {
35 36
    const key = serializeOption(config);
    return this._pendingCaptureFrame[key] || (
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
37
      (captureFrame(findNodeHandle(this.refs.native), config),
38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79
      this._pendingCaptureFrame[key] = defer())
    );
  }

  captureFrame (configArg) {
    let config;
    if (configArg) {
      invariant(typeof configArg==="object", "captureFrame takes an object option in parameter");
      let nb = 0;
      if ("format" in configArg) {
        invariant(
          typeof configArg.format === "string",
          "captureFrame({format}): format must be a string (e.g: 'base64'), Got: '%s'",
          configArg.format);
        if (configArg.format === "file") invariant(
          typeof configArg.filePath === "string" && configArg.filePath,
          "captureFrame({filePath}): filePath must be defined when using 'file' format and be an non-empty string, Got: '%s'",
          configArg.filePath);
        nb ++;
      }
      if ("type" in configArg) {
        invariant(
          typeof configArg.type === "string",
          "captureFrame({type}): type must be a string (e.g: 'png', 'jpg'), Got: '%s'",
          configArg.type);
        nb ++;
      }
      if ("quality" in configArg) {
        invariant(
          typeof configArg.quality === "number" &&
          configArg.quality >= 0 &&
          configArg.quality <= 1,
          "captureFrame({quality}): quality must be a number between 0 and 1, Got: '%s'",
          configArg.quality);
        nb ++;
      }
      if ("filePath" in configArg) {
        nb ++;
      }
      const keys = Object.keys(configArg);
      invariant(keys.length === nb, "captureFrame(config): config must be an object with {format, type, quality, filePath}, found some invalid keys in '%s'", keys);
      config = configArg;
80
    }
81
    return this._addPendingCaptureFrame({
82 83 84 85 86 87
      format: "base64",
      type: "png",
      quality: 1,
      filePath: "",
      ...config
    }).promise;
88
  }
89 90 91 92 93 94 95 96 97 98 99

  onGLCaptureFrame = ({ nativeEvent: { error, result, config } }) => {
    const key = serializeOption(config);
    invariant(key in this._pendingCaptureFrame, "capture '%s' is not scheduled in this._pendingCaptureFrame", key);
    if (error) {
      this._pendingCaptureFrame[key].reject(error);
    }
    else {
      this._pendingCaptureFrame[key].resolve(result);
    }
    delete this._pendingCaptureFrame[key];
100
  };
101

102
  render () {
103
    const {
104
      width, height,
105 106
      onLoad, onProgress, eventsThrough,
      ...restProps } = this.props;
107

108 109 110
    return <GLCanvasNative
      ref="native"
      {...restProps}
111
      style={{ width, height }}
112 113 114 115
      onGLLoad={onLoad ? onLoad : null}
      onGLProgress={onProgress ? onProgress : null}
      onGLCaptureFrame={this.onGLCaptureFrame}
      pointerEvents={eventsThrough ? "none" : "auto"}
116 117 118 119 120
    />;
  }
}

module.exports = GLCanvas;