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

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

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

class GLCanvas extends Component {
18

19 20 21 22
  viewConfig = {
    uiViewClassName: "GLCanvas"
  };

23 24 25 26 27 28 29 30 31 32
  componentWillMount () {
    this._pendingCaptureFrame = {};
  }

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

33 34 35 36 37
  setNativeProps (props) {
    this.refs.native.setNativeProps(props);
  }

  _addPendingCaptureFrame (config) {
38 39
    const key = serializeOption(config);
    return this._pendingCaptureFrame[key] || (
Gaëtan Renaudeau's avatar
Gaëtan Renaudeau committed
40
      (captureFrame(findNodeHandle(this.refs.native), config),
Shir Levkowitz MbP's avatar
Shir Levkowitz MbP committed
41
      this._pendingCaptureFrame[key] = this._makeDeferred())
42 43 44
    );
  }

Shir Levkowitz MbP's avatar
Shir Levkowitz MbP committed
45 46 47 48
  _makeDeferred() {
    var defer = {};
    var p = new Promise(function(resolve, reject) {
      defer.resolve = resolve;
Kesha Antonov's avatar
Kesha Antonov committed
49
      defer.reject = reject;
Shir Levkowitz MbP's avatar
Shir Levkowitz MbP committed
50 51 52 53 54
    });
    defer.promise = p;
    return defer;
  }

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 80 81 82 83 84 85 86 87 88 89 90 91 92
  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;
93
    }
94
    return this._addPendingCaptureFrame({
95 96 97 98 99 100
      format: "base64",
      type: "png",
      quality: 1,
      filePath: "",
      ...config
    }).promise;
101
  }
102 103 104 105 106 107 108 109 110 111 112

  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];
113
  };
114

115
  render () {
116
    const {
117
      width, height, style,
118 119
      onLoad, onProgress, eventsThrough,
      ...restProps } = this.props;
120
    const { backgroundColor } = style;
121

122 123 124
    return <GLCanvasNative
      ref="native"
      {...restProps}
125
      backgroundColor={processColor(backgroundColor)}
126
      style={{ width, height }}
127 128 129 130
      onGLLoad={onLoad ? onLoad : null}
      onGLProgress={onProgress ? onProgress : null}
      onGLCaptureFrame={this.onGLCaptureFrame}
      pointerEvents={eventsThrough ? "none" : "auto"}
131 132 133 134 135
    />;
  }
}

module.exports = GLCanvas;