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

module.exports = GLCanvas;