@sourcetoad/react-native-sketch-canvas
Version:
react-native-sketch-canvas allows you to draw / sketch on both iOS and Android devices and sync the drawing data between users. Of course you can save as image.
284 lines (278 loc) • 11.7 kB
JavaScript
'use strict';
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _memoizeOne = _interopRequireDefault(require("memoize-one"));
var _react = _interopRequireDefault(require("react"));
var _reactNative = require("react-native");
var _handlePermissions = require("./handlePermissions.js");
var _types = require("./types.js");
var _SketchCanvasNativeComponent = _interopRequireWildcard(require("./specs/SketchCanvasNativeComponent.js"));
var _NativeSketchCanvasModule = _interopRequireDefault(require("./specs/NativeSketchCanvasModule.js"));
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && {}.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
class SketchCanvas extends _react.default.Component {
ref = /*#__PURE__*/_react.default.createRef();
static defaultProps = {
style: null,
strokeColor: '#000000',
strokeWidth: 3,
onPathsChange: () => {},
onStrokeStart: (_x, _y) => {},
onStrokeChanged: () => {},
onStrokeEnd: () => {},
onSketchSaved: () => {},
onGenerateBase64: () => {},
user: null,
touchEnabled: true,
text: null,
localSourceImage: null,
permissionDialogTitle: '',
permissionDialogMessage: ''
};
state = {
text: null
};
constructor(props) {
super(props);
this._pathsToProcess = [];
this._paths = [];
this._path = null;
this._handle = null;
this._screenScale = _reactNative.Platform.OS === 'ios' ? 1 : _reactNative.PixelRatio.get();
this._offset = {
x: 0,
y: 0
};
this._size = {
width: 0,
height: 0
};
this._initialized = false;
this.panResponder = _reactNative.PanResponder.create({
// Ask to be the responder:
onStartShouldSetPanResponder: (_evt, _gestureState) => true,
onStartShouldSetPanResponderCapture: (_evt, _gestureState) => true,
onMoveShouldSetPanResponder: (_evt, _gestureState) => true,
onMoveShouldSetPanResponderCapture: (_evt, _gestureState) => true,
onPanResponderGrant: (evt, gestureState) => {
if (!this.props.touchEnabled) {
return;
}
const e = evt.nativeEvent;
this._offset = {
x: e.pageX - e.locationX,
y: e.pageY - e.locationY
};
this._path = {
id: parseInt(String(Math.random() * 100000000), 10),
color: this.props.strokeColor,
width: this.props.strokeWidth,
data: []
};
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.newPath(this.ref.current, this._path.id, (0, _reactNative.processColor)(this._path.color), this._path.width ? this._path.width * this._screenScale : 0);
_SketchCanvasNativeComponent.Commands.addPoint(this.ref.current, parseFloat((Number((gestureState.x0 - this._offset.x).toFixed(2)) * this._screenScale).toString()), parseFloat((Number((gestureState.y0 - this._offset.y).toFixed(2)) * this._screenScale).toString()));
}
const x = parseFloat((gestureState.x0 - this._offset.x).toFixed(2)),
y = parseFloat((gestureState.y0 - this._offset.y).toFixed(2));
this._path.data.push(`${x},${y}`);
this.props.onStrokeStart?.(x, y);
},
onPanResponderMove: (_evt, gestureState) => {
if (!this.props.touchEnabled) {
return;
}
if (this._path && this.ref.current) {
_SketchCanvasNativeComponent.Commands.addPoint(this.ref.current, parseFloat((Number((gestureState.moveX - this._offset.x).toFixed(2)) * this._screenScale).toString()), parseFloat((Number((gestureState.moveY - this._offset.y).toFixed(2)) * this._screenScale).toString()));
const x = parseFloat((gestureState.moveX - this._offset.x).toFixed(2)),
y = parseFloat((gestureState.moveY - this._offset.y).toFixed(2));
this._path.data.push(`${x},${y}`);
this.props.onStrokeChanged?.(x, y);
}
},
onPanResponderRelease: (_evt, _gestureState) => {
this._handleStrokeEnd();
},
onPanResponderTerminate: (_evt, _gestureState) => {
this._handleStrokeEnd();
},
onShouldBlockNativeResponder: (_evt, _gestureState) => {
return true;
}
});
}
_handleStrokeEnd = () => {
if (!this.props.touchEnabled) {
return;
}
if (this._path) {
this.props.onStrokeEnd?.({
path: this._path,
size: this._size,
drawer: this.props.user
});
this._paths.push({
path: this._path,
size: this._size,
drawer: this.props.user
});
}
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.endPath(this.ref.current);
}
};
_processText(text) {
text && text.forEach(t => t.fontColor = (0, _reactNative.processColor)(t.fontColor));
return text;
}
getProcessedText = (0, _memoizeOne.default)(text => {
const textCopy = text ? text.map(t => Object.assign({}, t)) : null;
return this._processText(textCopy);
});
clear() {
this._paths = [];
this._path = null;
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.clear(this.ref.current);
}
}
undo() {
let lastId = -1;
this._paths.forEach(d => lastId = d.drawer === this.props.user ? d.path.id : lastId);
if (lastId >= 0) {
this.deletePath(lastId);
}
return lastId;
}
addPath(data) {
if (this._initialized) {
if (this._paths.filter(p => p.path.id === data.path.id).length === 0) {
this._paths.push(data);
}
const pathData = data.path.data.map(p => {
const coor = p.split(',').map(pp => parseFloat(pp).toFixed(2));
return `${coor[0] * this._screenScale * this._size.width / data.size.width},${coor[1] * this._screenScale * this._size.height / data.size.height}`;
});
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.addPath(this.ref.current, data.path.id, (0, _reactNative.processColor)(data.path.color), data.path.width ? data.path.width * this._screenScale : 0, pathData);
}
} else {
this._pathsToProcess.filter(p => p.path.id === data.path.id).length === 0 && this._pathsToProcess.push(data);
}
}
setInitialPaths(initialPaths) {
if (!this._initialized || !this.ref.current || !initialPaths || initialPaths.length === 0) {
return;
}
// Convert paths to the format expected by native addInitialPaths command
const pathsArray = initialPaths.map(data => {
const pathData = data.path.data.map(p => {
const coor = p.split(',').map(pp => parseFloat(pp).toFixed(2));
return `${coor[0] * this._screenScale * this._size.width / data.size.width},${coor[1] * this._screenScale * this._size.height / data.size.height}`;
});
return {
pathId: data.path.id,
color: (0, _reactNative.processColor)(data.path.color),
width: data.path.width ? data.path.width * this._screenScale : 0,
points: pathData
};
});
// Add valid paths to internal tracking
initialPaths.forEach(data => {
if (this._paths.filter(p => p.path.id === data.path.id).length === 0) {
this._paths.push(data);
}
});
// Call native batch operation
_SketchCanvasNativeComponent.Commands.addInitialPaths(this.ref.current, pathsArray);
}
deletePath(id) {
this._paths = this._paths.filter(p => p.path.id !== id);
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.deletePath(this.ref.current, id);
}
}
save(imageType, transparent, folder, filename, includeImage, includeText, cropToImageSize) {
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.save(this.ref.current, imageType, folder, filename, transparent, includeImage, includeText, cropToImageSize);
}
}
getPaths() {
return this._paths;
}
getBase64(imageType, transparent, includeImage, includeText, cropToImageSize) {
if (_reactNative.Platform.OS === 'ios') {
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.transferToBase64(this.ref.current, imageType, transparent, includeImage, includeText, cropToImageSize);
}
} else {
if (this.ref.current) {
_SketchCanvasNativeComponent.Commands.transferToBase64(this.ref.current, imageType, transparent, includeImage, includeText, cropToImageSize);
}
}
}
async componentDidMount() {
await (0, _handlePermissions.requestPermissions)(this.props.permissionDialogTitle || '', this.props.permissionDialogMessage || '');
}
render() {
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_SketchCanvasNativeComponent.default, {
ref: this.ref,
style: this.props.style,
onLayout: e => {
this._size = {
width: e.nativeEvent.layout.width,
height: e.nativeEvent.layout.height
};
this._initialized = true;
// Handle any queued paths using individual operations
this._pathsToProcess.length > 0 && this._pathsToProcess.forEach(p => this.addPath(p));
},
...this.panResponder.panHandlers,
onChange: e => {
const {
eventType,
pathsUpdate,
success,
path
} = e.nativeEvent || {};
const isSuccess = success !== undefined;
const isSave = eventType === _types.OnChangeEventType.Save;
const isPathsUpdate = eventType === _types.OnChangeEventType.PathsUpdate;
if (!isSave && isPathsUpdate) {
this.props.onPathsChange?.(pathsUpdate);
} else if (isSave) {
this.props.onSketchSaved?.(success, path);
} else if (isSuccess) {
this.props.onSketchSaved?.(success, '');
}
},
onGenerateBase64: e => {
this.props.onGenerateBase64?.(e.nativeEvent || {});
},
onCanvasReady: () => {
this.props.onCanvasReady?.();
// Handle initial paths prop using batch operation
if (this.props.initialPaths && this.props.initialPaths.length > 0) {
this.setInitialPaths(this.props.initialPaths);
}
},
onInitialPathsLoaded: e => {
this.props.onInitialPathsLoaded?.(e.nativeEvent || {});
},
localSourceImage: this.props.localSourceImage,
permissionDialogTitle: this.props.permissionDialogTitle,
permissionDialogMessage: this.props.permissionDialogMessage,
text: this.getProcessedText(this.props.text)
});
}
}
SketchCanvas.MAIN_BUNDLE = _NativeSketchCanvasModule.default.getConstants().MainBundlePath;
SketchCanvas.DOCUMENT = _NativeSketchCanvasModule.default.getConstants().NSDocumentDirectory;
SketchCanvas.LIBRARY = _NativeSketchCanvasModule.default.getConstants().NSLibraryDirectory;
SketchCanvas.CACHES = _NativeSketchCanvasModule.default.getConstants().NSCachesDirectory;
var _default = exports.default = SketchCanvas;
//# sourceMappingURL=SketchCanvas.js.map