UNPKG

roiact

Version:
299 lines (240 loc) 11.2 kB
"use strict"; function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _react = _interopRequireWildcard(require("react")); var _propTypes = _interopRequireDefault(require("prop-types")); var _reactRedux = require("react-redux"); var _semanticUiReact = require("semantic-ui-react"); var _SketchModule = _interopRequireDefault(require("./Sketch.module.scss")); var _reactSizeme = require("react-sizeme"); var _Canvas = _interopRequireDefault(require("../../Redux/Canvas")); var _EventDispatcher = _interopRequireDefault(require("../../Services/EventDispatcher")); require("fabric"); var _Canvas2 = _interopRequireDefault(require("./Canvas")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); } function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } //} from "../../node_modules/fabric/dist/fabric.js"; // OK, this is local state, something like instance properties for a class // component but for a pure functional component. It's useful because I want this state // to persist among new renders, and I don't want to use the react state because I want // the changes to be applied immediately. I'll take care of resetting it if needed. // Also this component is a pure logical component, and full of listeners callbacks. // Such functions, when registered, won't receive updates for the redux props that change, // so I'll use this object reference inside them, and I'll update this object properties // when a redux prop I need inside those functions changes. var initLocalState = function initLocalState() { return { canvas: null, canvasSize: null, ignoreSelectionCreated: false }; }; var s = initLocalState(); /** * The sketch component, the mind behind the drawing feature * EventDispatcher is used to communicate ina sync way between * different components */ var Sketch = function Sketch(props) { // redux store stuff var dispatch = (0, _reactRedux.useDispatch)(); var tools = (0, _reactRedux.useSelector)(function (state) { return state.canvas.tools; }); var shapes = (0, _reactRedux.useSelector)(function (state) { return state.canvas.shapes; }); if (s.canvas) { s.canvas.setStoreShapes(shapes); s.canvas.setShapeMode(tools.mode); s.canvas.setShapeThreshold(50); } var save = (0, _react.useCallback)(function (evtName, mshapes) { dispatch(_Canvas.default.setSaving(true)); props.save_callback(mshapes); /*request( 'saveNoTrespassingZones', [shapes], 'Si è verificato un errore nel salvare le no trespassing zones: {error}', response => { dispatch(CanvasActions.setSaving(false)) dispatch(CanvasActions.setDirty(false)) toast( 'Salvataggio effettuato con successo', { type: 'success' } ) }, error => { // eslint-disable-line dispatch(CanvasActions.setSaving(false)) } )*/ dispatch(_Canvas.default.setSaving(false)); }, []); // listeners callbacks // shape removal: notified by the objects list var handleShapeRemoval = (0, _react.useCallback)(function (evtName, id) { return s.canvas.removeShape(id); }, []); // shape selection: notified by the objects list var handleShapeSelection = (0, _react.useCallback)(function (evtName, ids, from) { if (from !== 'canvas') { // also from the canvas we trigger this event and we don't need to process it // avoid ping pong between this component and objects component s.ignoreSelectionCreated = true; s.canvas.setActiveSelection(ids[0]); } }); // shape selection: notify the objects list var handleSelectionCreation = (0, _react.useCallback)(function (e) { if (!s.ignoreSelectionCreated) { _EventDispatcher.default.emit('shapeSelected', e.selected.map(function (st) { st.lockScalingFlip = true; st.lockRotation = true; st.lockMovementX = true; st.lockMovementY = true; st.lockScalingX = true; st.lockScalingY = true; return st.id; }), 'canvas'); } s.ignoreSelectionCreated = false; }, []); // shape selection updated: notify the objects list var handleSelectionUpdate = (0, _react.useCallback)(function (e) { if (!s.ignoreSelectionCreated) { e.target.lockScalingFlip = true; e.target.lockRotation = true; e.target.lockMovementX = true; e.target.lockMovementY = true; e.target.lockScalingX = true; e.target.lockScalingY = true; _EventDispatcher.default.emit('shapeSelected', [e.target.id], 'canvas'); } s.ignoreSelectionCreated = false; }, []); // shape selection cleared: notify the objects list var handleSelectionClear = (0, _react.useCallback)(function (e) { _EventDispatcher.default.emit('shapeSelected', null, 'canvas'); }, []); // shape edit -> save to redux store var handleShapeEdit = (0, _react.useCallback)(function (e) { dispatch(_Canvas.default.editShape({ id: e.target.id, shape: s.canvas.fabric2redux(e.target) })); }, []); var handleShapeRemove = (0, _react.useCallback)(function (id) { dispatch(_Canvas.default.removeShape(id)); }, []); // DID MOUNT (0, _react.useEffect)(function () { console.info('SKETCH', 'mounting'); dispatch(_Canvas.default.initShapes(props.shapes)); s.canvas = new _Canvas2.default('canvas', { opacity: tools.opacity, onShapeRemove: handleShapeRemove, setDrawing: function setDrawing(isDrawing) { return dispatch(_Canvas.default.setDrawing(isDrawing)); } }); s.canvas.setStoreShapes(shapes); addListeners(); // register all listeners // when unmounting return function () { console.info('SKETCH', 'unmounting'); s.canvas.deinitialize(); removeListeners(); // clear all listeners }; }, []); // fetch shapes (0, _react.useEffect)(function () { s.canvas.setStoreShapes(shapes); s.canvas.redraw(); }, [shapes]); // resize (0, _react.useEffect)(function () { s.canvas.resize(props.size); }, [props.size.width, props.size.height]); // update opacity (0, _react.useEffect)(function () { s.canvas.setOpacity(tools.opacity); }, [tools.opacity]); // on selected tool change (0, _react.useEffect)(function () { if (tools.selected) { s.canvas.disableSelection(); // add mouse events (and remove prev) s.canvas.removeMouseListeners(); s.canvas.addMouseListeners(mousedown, mousemove); } else { s.canvas.enableSelection(); s.canvas.removeMouseListeners(); } }, [tools.selected]); var addListeners = function addListeners() { console.info('registering listeners'); // Tools dispatches // I prefer to use a custom dispatcher to trigger events which seems more like // native events than redux actions. I don't like to manage every syncronization // with useEffect or componentDidMount because we always have to compare prev props // with new props. _EventDispatcher.default.register('save', save); _EventDispatcher.default.register('shapeRemoved', handleShapeRemoval); _EventDispatcher.default.register('shapeSelected', handleShapeSelection); _EventDispatcher.default.register('redraw', function () { s.canvas.redraw.bind(s.canvas); }); // obeserve canvas selection. s.canvas.addSelectionListeners(handleSelectionCreation, handleSelectionUpdate, handleSelectionClear); // shape modification s.canvas.addShapeUpdateListener(handleShapeEdit); }; var removeListeners = function removeListeners() { _EventDispatcher.default.unregister('shapeRemoved', handleShapeRemoval); _EventDispatcher.default.unregister('shapeSelected', handleShapeSelection); _EventDispatcher.default.unregister('redraw', s.canvas.redraw); s.canvas.removeSelectionListeners(); s.canvas.removeShapeUpdateListener(); }; var mousedown = function mousedown(e) { if (s.canvas.getActiveSelection() && !s.canvas.drawing || !tools.selected) { return false; } dispatch(_Canvas.default.setDrawing(true)); s.canvas.drawShape(tools.selected, 'mousedown', e, handleDrawEnd); }; var mousemove = function mousemove(e) { if (s.canvas.getActiveSelection() && !s.canvas.isDrawing || !tools.selected) { return false; } s.canvas.drawShape(tools.selected, 'mousemove', e, handleDrawEnd); }; var handleDrawEnd = function handleDrawEnd(shape) { dispatch(_Canvas.default.addShape({ id: shape.id, name: shape.name, type: shape.type, mode: shape.mode, threshold: shape.threshold, data: s.canvas.fabric2redux(shape) })); // notify the object list about selection _EventDispatcher.default.emit('shapeSelected', [shape.id], 'canvas'); }; return /*#__PURE__*/_react.default.createElement("div", { className: _SketchModule.default.canvasWrapper }, /*#__PURE__*/_react.default.createElement(_semanticUiReact.Image, { style: { position: 'absolute', width: '1080px', height: '607px' }, src: "".concat(props.photo) }), /*#__PURE__*/_react.default.createElement("canvas", { id: "canvas", className: _SketchModule.default.canvas })); }; Sketch.propTypes = { width: _propTypes.default.number, height: _propTypes.default.number, size: _propTypes.default.shape({ width: _propTypes.default.number, height: _propTypes.default.number }), photo: _propTypes.default.string, shapes: _propTypes.default.string, save_callback: _propTypes.default.func }; var _default = (0, _reactSizeme.withSize)({ monitorHeight: true })(Sketch); exports.default = _default;