@configuratorware/configurator-admingui 1.38.0 → 1.38.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13,6 +13,8 @@ var _propTypes = _interopRequireDefault(require("prop-types"));
13
13
 
14
14
  var _debounce = _interopRequireDefault(require("lodash/debounce"));
15
15
 
16
+ var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
17
+
16
18
  var _funDraw = require("../../../../../Utils/FunDraw/funDraw");
17
19
 
18
20
  var _movableObject = require("../../../../../Utils/FunDraw/movableObject");
@@ -75,6 +77,80 @@ var AreaEditor = /*#__PURE__*/function (_React$Component) {
75
77
 
76
78
  _defineProperty(_assertThisInitialized(_this), "backgroundImage", null);
77
79
 
80
+ _defineProperty(_assertThisInitialized(_this), "onChangeDebounced", (0, _debounce["default"])(function (prevArea) {
81
+ var _assertThisInitialize = _assertThisInitialized(_this),
82
+ area = _assertThisInitialize.area;
83
+
84
+ var onChange = _this.props.onChange;
85
+ onChange && !(0, _isEqual["default"])(area, prevArea) && onChange();
86
+ }, 1000));
87
+
88
+ _defineProperty(_assertThisInitialized(_this), "setupAreaEditor", /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
89
+ var canvas, _canvas$parentElement, width, backgroundImageElement, textureAspectRatio;
90
+
91
+ return regeneratorRuntime.wrap(function _callee$(_context) {
92
+ while (1) {
93
+ switch (_context.prev = _context.next) {
94
+ case 0:
95
+ canvas = _this.canvasRef.current;
96
+ _this.ctx = canvas.getContext('2d');
97
+ _canvas$parentElement = canvas.parentElement.getBoundingClientRect(), width = _canvas$parentElement.width;
98
+ backgroundImageElement = _this.props.backgroundImageElement; // resize the canvas to fit the texture aspect ratio
99
+
100
+ textureAspectRatio = backgroundImageElement.width / backgroundImageElement.height;
101
+ canvas.width = width;
102
+ canvas.height = width / textureAspectRatio;
103
+ _context.next = 9;
104
+ return _this.createScaledArea();
105
+
106
+ case 9:
107
+ _this.area = _context.sent;
108
+
109
+ if (backgroundImageElement) {
110
+ _this.backgroundImage = (0, _funDraw.fitSize)((0, _funDraw.createImageObject)(backgroundImageElement), canvas.width, canvas.height);
111
+ }
112
+
113
+ _this._movableArea = (0, _movableObject.createMovableObjectWithControls)(canvas, _this.area, {
114
+ drawFunction: function drawFunction(object, ctx) {
115
+ (0, _funDraw.draw)(object, ctx); // draw the background image behind the area
116
+
117
+ ctx.save();
118
+ ctx.globalCompositeOperation = 'destination-over';
119
+ _this.backgroundImage && (0, _funDraw.draw)(_this.backgroundImage, ctx);
120
+ ctx.restore();
121
+
122
+ _this.onRedraw();
123
+ },
124
+ controlFactory: function controlFactory(object) {
125
+ return (0, _funDraw.setDefaultControls)(object, 20, 0);
126
+ },
127
+ onUpdate: function onUpdate(_ref2) {
128
+ var getData = _ref2.getData;
129
+
130
+ var _getData = getData(),
131
+ object = _getData.object;
132
+
133
+ var _assertThisInitialize2 = _assertThisInitialized(_this),
134
+ area = _assertThisInitialize2.area;
135
+
136
+ _this.area = object;
137
+
138
+ _this.onChangeDebounced(area);
139
+ }
140
+ });
141
+
142
+ _this._movableArea.init();
143
+
144
+ _this.onUpdate();
145
+
146
+ case 14:
147
+ case "end":
148
+ return _context.stop();
149
+ }
150
+ }
151
+ }, _callee);
152
+ })));
153
+
78
154
  _defineProperty(_assertThisInitialized(_this), "onRedraw", (0, _debounce["default"])(function () {
79
155
  var onRedraw = _this.props.onRedraw;
80
156
 
@@ -98,73 +174,20 @@ var AreaEditor = /*#__PURE__*/function (_React$Component) {
98
174
 
99
175
  _createClass(AreaEditor, [{
100
176
  key: "componentDidMount",
101
- value: function () {
102
- var _componentDidMount = _asyncToGenerator( /*#__PURE__*/regeneratorRuntime.mark(function _callee() {
103
- var _this2 = this;
104
-
105
- var canvas, backgroundImageElement;
106
- return regeneratorRuntime.wrap(function _callee$(_context) {
107
- while (1) {
108
- switch (_context.prev = _context.next) {
109
- case 0:
110
- canvas = this.canvasRef.current;
111
- this.ctx = canvas.getContext('2d');
112
- _context.next = 4;
113
- return this.createScaledArea();
114
-
115
- case 4:
116
- this.area = _context.sent;
117
- backgroundImageElement = this.props.backgroundImageElement;
118
-
119
- if (backgroundImageElement) {
120
- this.backgroundImage = (0, _funDraw.fitSize)((0, _funDraw.createImageObject)(backgroundImageElement), canvas.width, canvas.height);
121
- }
122
-
123
- this._movableArea = (0, _movableObject.createMovableObjectWithControls)(canvas, this.area, {
124
- drawFunction: function drawFunction(object, ctx) {
125
- (0, _funDraw.draw)(object, ctx); // draw the background image behind the area
126
-
127
- ctx.save();
128
- ctx.globalCompositeOperation = 'destination-over';
129
- _this2.backgroundImage && (0, _funDraw.draw)(_this2.backgroundImage, ctx);
130
- ctx.restore();
131
-
132
- _this2.onRedraw();
133
- },
134
- controlFactory: function controlFactory(object) {
135
- return (0, _funDraw.setDefaultControls)(object);
136
- },
137
- onUpdate: function onUpdate(_ref) {
138
- var getData = _ref.getData;
139
-
140
- var _getData = getData(),
141
- object = _getData.object;
142
-
143
- _this2.area = object;
144
- }
145
- });
146
-
147
- this._movableArea.init();
148
-
149
- this.onUpdate();
150
-
151
- case 10:
152
- case "end":
153
- return _context.stop();
154
- }
155
- }
156
- }, _callee, this);
157
- }));
158
-
159
- function componentDidMount() {
160
- return _componentDidMount.apply(this, arguments);
161
- }
162
-
163
- return componentDidMount;
164
- }()
177
+ value: function componentDidMount() {
178
+ this.setupAreaEditor();
179
+ window.addEventListener('resize', this.setupAreaEditor);
180
+ }
181
+ }, {
182
+ key: "componentDidUpdate",
183
+ value: function componentDidUpdate(prevProps, prevState, snapshot) {
184
+ prevProps.areaData !== this.props.areaData && this.setupAreaEditor();
185
+ }
165
186
  }, {
166
187
  key: "componentWillUnmount",
167
188
  value: function componentWillUnmount() {
189
+ window.removeEventListener('resize', this.setupAreaEditor);
190
+
168
191
  this._movableArea.dispose();
169
192
  }
170
193
  }, {
@@ -277,10 +300,9 @@ var AreaEditor = /*#__PURE__*/function (_React$Component) {
277
300
  value: function render() {
278
301
  return /*#__PURE__*/_react["default"].createElement("canvas", {
279
302
  ref: this.canvasRef,
280
- width: 500,
281
- height: 500,
282
303
  style: {
283
- border: '1px solid #000'
304
+ border: '1px solid #000',
305
+ maxWidth: '100%'
284
306
  }
285
307
  });
286
308
  }
@@ -0,0 +1,203 @@
1
+ "use strict";
2
+
3
+ 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); }
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports["default"] = exports.AreaEditorForm = void 0;
9
+
10
+ var _react = _interopRequireWildcard(require("react"));
11
+
12
+ var _get = _interopRequireDefault(require("lodash/get"));
13
+
14
+ var _debounce = _interopRequireDefault(require("lodash/debounce"));
15
+
16
+ var _TextField = _interopRequireDefault(require("@material-ui/core/TextField"));
17
+
18
+ var _styles = require("@material-ui/core/styles");
19
+
20
+ var _i18n = require("../../../../../App/i18n");
21
+
22
+ var _excluded = ["classes", "onChange", "value"];
23
+
24
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
25
+
26
+ 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); }
27
+
28
+ 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; }
29
+
30
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
31
+
32
+ function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
33
+
34
+ function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
35
+
36
+ function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
37
+
38
+ function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
39
+
40
+ function _iterableToArrayLimit(arr, i) { var _i = arr == null ? null : typeof Symbol !== "undefined" && arr[Symbol.iterator] || arr["@@iterator"]; if (_i == null) return; var _arr = []; var _n = true; var _d = false; var _s, _e; try { for (_i = _i.call(arr); !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
41
+
42
+ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
43
+
44
+ function _objectWithoutProperties(source, excluded) { if (source == null) return {}; var target = _objectWithoutPropertiesLoose(source, excluded); var key, i; if (Object.getOwnPropertySymbols) { var sourceSymbolKeys = Object.getOwnPropertySymbols(source); for (i = 0; i < sourceSymbolKeys.length; i++) { key = sourceSymbolKeys[i]; if (excluded.indexOf(key) >= 0) continue; if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue; target[key] = source[key]; } } return target; }
45
+
46
+ function _objectWithoutPropertiesLoose(source, excluded) { if (source == null) return {}; var target = {}; var sourceKeys = Object.keys(source); var key, i; for (i = 0; i < sourceKeys.length; i++) { key = sourceKeys[i]; if (excluded.indexOf(key) >= 0) continue; target[key] = source[key]; } return target; }
47
+
48
+ var toNumber = function toNumber(value) {
49
+ return Number(value) || 0;
50
+ };
51
+
52
+ var toRad = function toRad(deg) {
53
+ return Math.PI * deg / 180;
54
+ };
55
+
56
+ var toDeg = function toDeg(rad) {
57
+ return (180 * rad / Math.PI).toFixed(2);
58
+ };
59
+
60
+ var formatters = {
61
+ angle: function angle(v) {
62
+ return toDeg(toNumber(v));
63
+ },
64
+ number: function number(v) {
65
+ return toNumber(v).toFixed(2);
66
+ },
67
+ "boolean": function boolean(v) {
68
+ return !!v;
69
+ }
70
+ };
71
+
72
+ function persistEvent(fn) {
73
+ return function (evt) {
74
+ evt.persist();
75
+ fn(evt);
76
+ };
77
+ }
78
+
79
+ var NumberInput = (0, _styles.withStyles)({
80
+ root: {
81
+ maxWidth: 100,
82
+ marginRight: 20
83
+ }
84
+ })(function (_ref) {
85
+ var classes = _ref.classes,
86
+ onChange = _ref.onChange,
87
+ value = _ref.value,
88
+ props = _objectWithoutProperties(_ref, _excluded);
89
+
90
+ var _useState = (0, _react.useState)(value),
91
+ _useState2 = _slicedToArray(_useState, 2),
92
+ _value = _useState2[0],
93
+ _setValue = _useState2[1];
94
+
95
+ var _useState3 = (0, _react.useState)(false),
96
+ _useState4 = _slicedToArray(_useState3, 2),
97
+ focused = _useState4[0],
98
+ setFocused = _useState4[1];
99
+
100
+ var onFocus = function onFocus() {
101
+ return setFocused(true);
102
+ };
103
+
104
+ var onBlur = (0, _react.useMemo)(function () {
105
+ return function () {
106
+ _setValue(value);
107
+
108
+ setFocused(false);
109
+ };
110
+ }, [value]);
111
+ (0, _react.useEffect)(function () {
112
+ !focused && _setValue(value);
113
+ }, [value, focused]);
114
+ var onChangeDebounced = (0, _react.useMemo)(function () {
115
+ return persistEvent((0, _debounce["default"])(onChange, 50));
116
+ }, [onChange]);
117
+ return /*#__PURE__*/_react["default"].createElement(_TextField["default"], _extends({
118
+ type: "number",
119
+ className: classes.root,
120
+ onChange: function onChange(evt) {
121
+ _setValue(evt.target.value);
122
+
123
+ onChangeDebounced(evt);
124
+ },
125
+ onFocus: onFocus,
126
+ onBlur: onBlur,
127
+ value: _value
128
+ }, props));
129
+ });
130
+ var AreaEditorForm = (0, _styles.withStyles)({
131
+ sectionTitle: {
132
+ fontSize: '1.2em',
133
+ marginTop: '1.2em',
134
+ marginBottom: '0.6em'
135
+ },
136
+ groupTitle: {
137
+ marginTop: '0.6em'
138
+ }
139
+ })(function (_ref2) {
140
+ var designAreaData = _ref2.designAreaData,
141
+ onChange = _ref2.onChange,
142
+ className = _ref2.className,
143
+ classes = _ref2.classes;
144
+
145
+ var numberChangeHandler = function numberChangeHandler(evt) {
146
+ if (evt.target.value) {
147
+ onChange(evt.target.name, toNumber(evt.target.value));
148
+ }
149
+ };
150
+
151
+ var angleChangeHandler = function angleChangeHandler(evt) {
152
+ if (evt.target.value) {
153
+ onChange(evt.target.name, toRad(toNumber(evt.target.value)));
154
+ }
155
+ };
156
+
157
+ var format = function format(path) {
158
+ var formatter = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : formatters.number;
159
+ return formatter(toNumber((0, _get["default"])(designAreaData, path)));
160
+ };
161
+
162
+ return /*#__PURE__*/_react["default"].createElement("div", {
163
+ className: className
164
+ }, /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement(NumberInput, {
165
+ name: 'position.angle',
166
+ label: (0, _i18n.t)('designer.advancedEditor.rotation'),
167
+ onChange: angleChangeHandler,
168
+ value: format('position.angle', formatters.angle)
169
+ })), /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement("div", {
170
+ className: classes.groupTitle
171
+ }, (0, _i18n.t)('designer.advancedEditor.scaling')), /*#__PURE__*/_react["default"].createElement(NumberInput, {
172
+ name: 'position.width',
173
+ label: (0, _i18n.t)('designer.advancedEditor.width'),
174
+ onChange: numberChangeHandler,
175
+ value: format('position.width'),
176
+ inputProps: {
177
+ min: 1
178
+ }
179
+ }), /*#__PURE__*/_react["default"].createElement(NumberInput, {
180
+ name: 'position.height',
181
+ label: (0, _i18n.t)('designer.advancedEditor.height'),
182
+ onChange: numberChangeHandler,
183
+ value: format('position.height'),
184
+ inputProps: {
185
+ min: 1
186
+ }
187
+ })), /*#__PURE__*/_react["default"].createElement("div", null, /*#__PURE__*/_react["default"].createElement("div", {
188
+ className: classes.groupTitle
189
+ }, (0, _i18n.t)('designer.advancedEditor.positioning')), /*#__PURE__*/_react["default"].createElement(NumberInput, {
190
+ name: 'position.x',
191
+ label: 'x',
192
+ onChange: numberChangeHandler,
193
+ value: format('position.x')
194
+ }), /*#__PURE__*/_react["default"].createElement(NumberInput, {
195
+ name: 'position.y',
196
+ label: 'y',
197
+ onChange: numberChangeHandler,
198
+ value: format('position.y')
199
+ })));
200
+ });
201
+ exports.AreaEditorForm = AreaEditorForm;
202
+ var _default = AreaEditorForm;
203
+ exports["default"] = _default;
@@ -89,7 +89,9 @@ var applyLinks = function applyLinks(prevData, nextData) {
89
89
  var options = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
90
90
  var positionRatio = options.positionRatio,
91
91
  _options$baseShapePad = options.baseShapePadding,
92
- baseShapePadding = _options$baseShapePad === void 0 ? _Constants.DEFAULT_BASE_SHAPE_PADDING : _options$baseShapePad; // set min value for area size
92
+ baseShapePadding = _options$baseShapePad === void 0 ? _Constants.DEFAULT_BASE_SHAPE_PADDING : _options$baseShapePad,
93
+ _options$recalculateP = options.recalculatePosition,
94
+ recalculatePosition = _options$recalculateP === void 0 ? true : _options$recalculateP; // set min value for area size
93
95
 
94
96
  if ((0, _get["default"])(nextData, 'position.width') <= sizeMin) {
95
97
  (0, _set["default"])(nextData, 'position.width', sizeMin);
@@ -142,19 +144,21 @@ var applyLinks = function applyLinks(prevData, nextData) {
142
144
  if ((0, _get["default"])(nextData, 'baseShape.r', 0) < minRadius) {
143
145
  (0, _set["default"])(nextData, 'baseShape.r', minRadius);
144
146
  }
145
- } // recalculating the position with the baseShape size change ratio
146
-
147
+ }
147
148
 
148
- withRatio(prevData, nextData, 'baseShape.width', function (r) {
149
- isFinite(r) && calcPathValue(nextData, 'position.x', function (v) {
150
- return v * r;
149
+ if (recalculatePosition) {
150
+ // recalculating the position with the baseShape size change ratio
151
+ withRatio(prevData, nextData, 'baseShape.width', function (r) {
152
+ isFinite(r) && calcPathValue(nextData, 'position.x', function (v) {
153
+ return v * r;
154
+ });
151
155
  });
152
- });
153
- withRatio(prevData, nextData, 'baseShape.height', function (r) {
154
- isFinite(r) && calcPathValue(nextData, 'position.y', function (v) {
155
- return v * r;
156
+ withRatio(prevData, nextData, 'baseShape.height', function (r) {
157
+ isFinite(r) && calcPathValue(nextData, 'position.y', function (v) {
158
+ return v * r;
159
+ });
156
160
  });
157
- });
161
+ }
158
162
  };
159
163
 
160
164
  exports.applyLinks = applyLinks;
@@ -81,6 +81,8 @@ var _sendMessage = require("../../../../../../Utils/Function/sendMessage");
81
81
 
82
82
  var _CircularProgress = _interopRequireDefault(require("@material-ui/core/CircularProgress"));
83
83
 
84
+ var _AreaEditorForm = _interopRequireDefault(require("../../Components/AreaEditorForm"));
85
+
84
86
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
85
87
 
86
88
  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); }
@@ -125,26 +127,58 @@ var styles = function styles(theme) {
125
127
  editorRoot: _defineProperty({
126
128
  display: 'flex',
127
129
  flexDirection: 'row',
130
+ height: 'calc(100vh - 180px)',
128
131
  '& > $header': _defineProperty({
129
132
  display: 'none'
130
133
  }, breakPoint.max, {
131
134
  display: 'block'
135
+ }),
136
+ '& > $header3DContainer': _defineProperty({
137
+ display: 'none'
138
+ }, breakPoint.max, {
139
+ display: 'flex'
132
140
  })
133
141
  }, breakPoint.max, {
134
142
  flexDirection: 'column'
135
143
  }),
136
144
  leftSide: {
137
- marginRight: 2 * theme.spacing.unit
145
+ marginRight: 2 * theme.spacing.unit,
146
+ flex: 1
138
147
  },
139
148
  header: {
140
149
  flex: 1
141
150
  },
151
+ header3D: {
152
+ flex: 1
153
+ },
154
+ header3DContainer: {
155
+ display: 'flex',
156
+ flexDirection: 'row'
157
+ },
142
158
  rightSide: {
143
159
  flex: 1,
144
160
  '& > $header': _defineProperty({}, breakPoint.max, {
145
161
  display: 'none'
146
162
  })
147
163
  },
164
+ rightSide3D: _defineProperty({
165
+ flex: 1,
166
+ '& > $header3DContainer': _defineProperty({}, breakPoint.max, {
167
+ display: 'none'
168
+ }),
169
+ display: 'flex',
170
+ flexDirection: 'column',
171
+ maxWidth: '50%',
172
+ marginLeft: 'auto',
173
+ overflow: 'hidden'
174
+ }, breakPoint.max, {
175
+ maxWidth: '100%'
176
+ }),
177
+ areaEditorForm: {
178
+ marginLeft: 4 * theme.spacing.unit,
179
+ marginBottom: 2 * theme.spacing.unit,
180
+ flex: 1
181
+ },
148
182
  title: {
149
183
  fontSize: 20,
150
184
  marginBottom: theme.spacing.unit
@@ -183,6 +217,12 @@ var styles = function styles(theme) {
183
217
  width: '100%',
184
218
  height: '39vw'
185
219
  },
220
+ visualizationContainer3D: {
221
+ width: 'auto',
222
+ flex: 1,
223
+ maxHeight: '100%',
224
+ overflow: 'hidden'
225
+ },
186
226
  loaderContainer: {
187
227
  minHeight: 400,
188
228
  display: 'flex',
@@ -337,8 +377,9 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
337
377
  var _this$props$designAre = _this.props.designArea,
338
378
  width = _this$props$designAre.width,
339
379
  height = _this$props$designAre.height;
340
- _this.baseShapeEditor && (0, _DataLinks.applyLinks)(previousData, nextData, {
341
- positionRatio: (width || 1) / (height || 1)
380
+ (0, _DataLinks.applyLinks)(previousData, nextData, {
381
+ positionRatio: (width || 1) / (height || 1),
382
+ recalculatePosition: isKindOf2D(_this.props.mode)
342
383
  });
343
384
  data.updateValues(nextData);
344
385
 
@@ -754,7 +795,7 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
754
795
  return dpm.title;
755
796
  }).join(', ');
756
797
  return /*#__PURE__*/_react["default"].createElement("div", {
757
- className: classes.header
798
+ className: isKindOf3D(mode) ? classes.header3D : classes.header
758
799
  }, /*#__PURE__*/_react["default"].createElement(_Typography["default"], {
759
800
  variant: "h3",
760
801
  className: classes.title
@@ -790,6 +831,18 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
790
831
  label: (0, _i18n.t)('designer.designArea.isDefaultView')
791
832
  }));
792
833
  }
834
+ }, {
835
+ key: "renderHeader3D",
836
+ value: function renderHeader3D(designAreaData) {
837
+ var classes = this.props.classes;
838
+ return /*#__PURE__*/_react["default"].createElement("div", {
839
+ className: classes.header3DContainer
840
+ }, this.renderHeader(), /*#__PURE__*/_react["default"].createElement(_AreaEditorForm["default"], {
841
+ designAreaData: designAreaData,
842
+ onChange: this.onChangeData,
843
+ className: classes.areaEditorForm
844
+ }));
845
+ }
793
846
  }, {
794
847
  key: "renderVisualization",
795
848
  value: function renderVisualization(designAreaData) {
@@ -818,8 +871,9 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
818
871
  }
819
872
 
820
873
  if (isKindOf3D(mode)) {
821
- return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, this.renderHeader(), /*#__PURE__*/_react["default"].createElement(_VisualizationContainer["default"], {
822
- three: three
874
+ return /*#__PURE__*/_react["default"].createElement(_react["default"].Fragment, null, this.renderHeader3D(designAreaData), /*#__PURE__*/_react["default"].createElement(_VisualizationContainer["default"], {
875
+ three: three,
876
+ className: classes.visualizationContainer3D
823
877
  }));
824
878
  }
825
879
 
@@ -830,7 +884,8 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
830
884
  value: function render() {
831
885
  var _this$props6 = this.props,
832
886
  designArea = _this$props6.designArea,
833
- classes = _this$props6.classes;
887
+ classes = _this$props6.classes,
888
+ mode = _this$props6.mode;
834
889
  var three = this.three;
835
890
 
836
891
  if (!designArea) {
@@ -861,7 +916,7 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
861
916
  className: classes.editorRoot
862
917
  }, loading && /*#__PURE__*/_react["default"].createElement(LoadingComponent, {
863
918
  fullSize: true
864
- }), this.renderHeader(), imageElement && /*#__PURE__*/_react["default"].createElement("div", {
919
+ }), isKindOf3D(mode) ? this.renderHeader3D(data) : this.renderHeader(), imageElement && /*#__PURE__*/_react["default"].createElement("div", {
865
920
  className: classes.leftSide
866
921
  }, /*#__PURE__*/_react["default"].createElement(_AreaEditor.AreaEditor, {
867
922
  backgroundImageElement: imageElement,
@@ -869,9 +924,10 @@ var VisualizationSettingsEdit = /*#__PURE__*/function (_Component) {
869
924
  maskObject: this.getCurrentMaskObject(),
870
925
  areaData: data && data.position,
871
926
  areaRatio: areaRatio,
872
- ref: this.areaEditorRef
927
+ ref: this.areaEditorRef,
928
+ onChange: this.updateData
873
929
  })), /*#__PURE__*/_react["default"].createElement("div", {
874
- className: classes.rightSide
930
+ className: isKindOf3D(mode) ? classes.rightSide3D : classes.rightSide
875
931
  }, this.renderVisualization(data), errors && /*#__PURE__*/_react["default"].createElement("ul", {
876
932
  className: classes.errors
877
933
  }, errors.map(function (e) {
@@ -35,7 +35,7 @@ var styles = function styles() {
35
35
  return {
36
36
  paperRoot: {
37
37
  maxWidth: '90vw',
38
- maxHeight: '90vw',
38
+ maxHeight: '90vh',
39
39
  marginTop: '16px',
40
40
  marginBottom: '16px'
41
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@configuratorware/configurator-admingui",
3
- "version": "1.38.0",
3
+ "version": "1.38.1",
4
4
  "license": "UNLICENSED",
5
5
  "private": false,
6
6
  "dependencies": {
@@ -29,7 +29,7 @@
29
29
  "react-redux-i18n": "^1.9.3",
30
30
  "react-router": "^3.2.6",
31
31
  "react-sortable-hoc": "^1.11.0",
32
- "redhotmagma-visualization": "1.38.0",
32
+ "redhotmagma-visualization": "1.38.1",
33
33
  "redux": "^4.1.0",
34
34
  "redux-logger": "^3.0.6",
35
35
  "redux-persist": "^5.10.0",
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
2
  import PropTypes from 'prop-types';
3
3
  import debounce from 'lodash/debounce';
4
+ import isEqual from 'lodash/isEqual';
4
5
  import {
5
6
  createImageObject,
6
7
  draw,
@@ -32,13 +33,34 @@ export class AreaEditor extends React.Component {
32
33
  activeControl = null;
33
34
  backgroundImage = null;
34
35
 
35
- async componentDidMount() {
36
+ componentDidMount() {
37
+ this.setupAreaEditor();
38
+ window.addEventListener('resize', this.setupAreaEditor);
39
+ }
40
+
41
+ componentDidUpdate(prevProps, prevState, snapshot) {
42
+ prevProps.areaData !== this.props.areaData && this.setupAreaEditor();
43
+ }
44
+
45
+ onChangeDebounced = debounce(prevArea => {
46
+ const { area } = this;
47
+ const { onChange } = this.props;
48
+ onChange && !isEqual(area, prevArea) && onChange();
49
+ }, 1000);
50
+
51
+ setupAreaEditor = async () => {
36
52
  const canvas = this.canvasRef.current;
37
53
  this.ctx = canvas.getContext('2d');
54
+ const { width } = canvas.parentElement.getBoundingClientRect();
55
+ const { backgroundImageElement } = this.props;
56
+
57
+ // resize the canvas to fit the texture aspect ratio
58
+ const textureAspectRatio = backgroundImageElement.width / backgroundImageElement.height;
59
+ canvas.width = width;
60
+ canvas.height = width / textureAspectRatio;
38
61
 
39
62
  this.area = await this.createScaledArea();
40
63
 
41
- const { backgroundImageElement } = this.props;
42
64
  if (backgroundImageElement) {
43
65
  this.backgroundImage = fitSize(
44
66
  createImageObject(backgroundImageElement),
@@ -59,19 +81,22 @@ export class AreaEditor extends React.Component {
59
81
 
60
82
  this.onRedraw();
61
83
  },
62
- controlFactory: object => setDefaultControls(object),
84
+ controlFactory: object => setDefaultControls(object, 20, 0),
63
85
  onUpdate: ({ getData }) => {
64
86
  const { object } = getData();
87
+ const { area } = this;
65
88
  this.area = object;
89
+ this.onChangeDebounced(area);
66
90
  },
67
91
  });
68
92
 
69
93
  this._movableArea.init();
70
94
 
71
95
  this.onUpdate();
72
- }
96
+ };
73
97
 
74
98
  componentWillUnmount() {
99
+ window.removeEventListener('resize', this.setupAreaEditor);
75
100
  this._movableArea.dispose();
76
101
  }
77
102
 
@@ -144,6 +169,6 @@ export class AreaEditor extends React.Component {
144
169
  canvasRef = React.createRef();
145
170
 
146
171
  render() {
147
- return <canvas ref={this.canvasRef} width={500} height={500} style={{ border: '1px solid #000' }} />;
172
+ return <canvas ref={this.canvasRef} style={{ border: '1px solid #000', maxWidth: '100%' }} />;
148
173
  }
149
174
  }
@@ -0,0 +1,139 @@
1
+ import React, { useEffect, useMemo, useState } from 'react';
2
+ import get from 'lodash/get';
3
+ import debounce from 'lodash/debounce';
4
+ import TextField from '@material-ui/core/TextField';
5
+ import { withStyles } from '@material-ui/core/styles';
6
+ import { t } from '../../../../../App/i18n';
7
+
8
+ const toNumber = value => Number(value) || 0;
9
+
10
+ const toRad = deg => (Math.PI * deg) / 180;
11
+
12
+ const toDeg = rad => ((180 * rad) / Math.PI).toFixed(2);
13
+
14
+ const formatters = {
15
+ angle: v => toDeg(toNumber(v)),
16
+ number: v => toNumber(v).toFixed(2),
17
+ boolean: v => !!v,
18
+ };
19
+
20
+ function persistEvent(fn) {
21
+ return function(evt) {
22
+ evt.persist();
23
+ fn(evt);
24
+ };
25
+ }
26
+
27
+ const NumberInput = withStyles({
28
+ root: {
29
+ maxWidth: 100,
30
+ marginRight: 20,
31
+ },
32
+ })(({ classes, onChange, value, ...props }) => {
33
+ const [_value, _setValue] = useState(value);
34
+ const [focused, setFocused] = useState(false);
35
+ const onFocus = () => setFocused(true);
36
+ const onBlur = useMemo(
37
+ () => () => {
38
+ _setValue(value);
39
+ setFocused(false);
40
+ },
41
+ [value]
42
+ );
43
+ useEffect(() => {
44
+ !focused && _setValue(value);
45
+ }, [value, focused]);
46
+ const onChangeDebounced = useMemo(() => persistEvent(debounce(onChange, 50)), [onChange]);
47
+ return (
48
+ <TextField
49
+ type="number"
50
+ className={classes.root}
51
+ onChange={evt => {
52
+ _setValue(evt.target.value);
53
+ onChangeDebounced(evt);
54
+ }}
55
+ onFocus={onFocus}
56
+ onBlur={onBlur}
57
+ value={_value}
58
+ {...props}
59
+ />
60
+ );
61
+ });
62
+
63
+ export const AreaEditorForm = withStyles({
64
+ sectionTitle: {
65
+ fontSize: '1.2em',
66
+ marginTop: '1.2em',
67
+ marginBottom: '0.6em',
68
+ },
69
+ groupTitle: {
70
+ marginTop: '0.6em',
71
+ },
72
+ })(({ designAreaData, onChange, className, classes }) => {
73
+ const numberChangeHandler = evt => {
74
+ if (evt.target.value) {
75
+ onChange(evt.target.name, toNumber(evt.target.value));
76
+ }
77
+ };
78
+
79
+ const angleChangeHandler = evt => {
80
+ if (evt.target.value) {
81
+ onChange(evt.target.name, toRad(toNumber(evt.target.value)));
82
+ }
83
+ };
84
+
85
+ const format = (path, formatter = formatters.number) => formatter(toNumber(get(designAreaData, path)));
86
+
87
+ return (
88
+ <div className={className}>
89
+ <div>
90
+ <NumberInput
91
+ name={'position.angle'}
92
+ label={t('designer.advancedEditor.rotation')}
93
+ onChange={angleChangeHandler}
94
+ value={format('position.angle', formatters.angle)}
95
+ />
96
+ </div>
97
+
98
+ <div>
99
+ <div className={classes.groupTitle}>{t('designer.advancedEditor.scaling')}</div>
100
+ <NumberInput
101
+ name={'position.width'}
102
+ label={t('designer.advancedEditor.width')}
103
+ onChange={numberChangeHandler}
104
+ value={format('position.width')}
105
+ inputProps={{
106
+ min: 1,
107
+ }}
108
+ />
109
+ <NumberInput
110
+ name={'position.height'}
111
+ label={t('designer.advancedEditor.height')}
112
+ onChange={numberChangeHandler}
113
+ value={format('position.height')}
114
+ inputProps={{
115
+ min: 1,
116
+ }}
117
+ />
118
+ </div>
119
+
120
+ <div>
121
+ <div className={classes.groupTitle}>{t('designer.advancedEditor.positioning')}</div>
122
+ <NumberInput
123
+ name={'position.x'}
124
+ label={'x'}
125
+ onChange={numberChangeHandler}
126
+ value={format('position.x')}
127
+ />
128
+ <NumberInput
129
+ name={'position.y'}
130
+ label={'y'}
131
+ onChange={numberChangeHandler}
132
+ value={format('position.y')}
133
+ />
134
+ </div>
135
+ </div>
136
+ );
137
+ });
138
+
139
+ export default AreaEditorForm;
@@ -57,7 +57,11 @@ export const multiplyToPixel = m => v => Math.round(v * m);
57
57
  const sizeMin = 5;
58
58
 
59
59
  export const applyLinks = (prevData, nextData, options = {}) => {
60
- const { positionRatio, baseShapePadding = DEFAULT_BASE_SHAPE_PADDING } = options;
60
+ const {
61
+ positionRatio,
62
+ baseShapePadding = DEFAULT_BASE_SHAPE_PADDING,
63
+ recalculatePosition = true,
64
+ } = options;
61
65
 
62
66
  // set min value for area size
63
67
  if (get(nextData, 'position.width') <= sizeMin) {
@@ -105,11 +109,13 @@ export const applyLinks = (prevData, nextData, options = {}) => {
105
109
  set(nextData, 'baseShape.r', minRadius);
106
110
  }
107
111
  }
108
- // recalculating the position with the baseShape size change ratio
109
- withRatio(prevData, nextData, 'baseShape.width', r => {
110
- isFinite(r) && calcPathValue(nextData, 'position.x', v => v * r);
111
- });
112
- withRatio(prevData, nextData, 'baseShape.height', r => {
113
- isFinite(r) && calcPathValue(nextData, 'position.y', v => v * r);
114
- });
112
+ if (recalculatePosition) {
113
+ // recalculating the position with the baseShape size change ratio
114
+ withRatio(prevData, nextData, 'baseShape.width', r => {
115
+ isFinite(r) && calcPathValue(nextData, 'position.x', v => v * r);
116
+ });
117
+ withRatio(prevData, nextData, 'baseShape.height', r => {
118
+ isFinite(r) && calcPathValue(nextData, 'position.y', v => v * r);
119
+ });
120
+ }
115
121
  };
@@ -48,6 +48,7 @@ import Checkbox from '../../../../../../UIComponents/Checkbox';
48
48
  import FormControlLabel from '../../../../../../UIComponents/FormControlLabel';
49
49
  import { sendMessage } from '../../../../../../Utils/Function/sendMessage';
50
50
  import CircularProgress from '@material-ui/core/CircularProgress';
51
+ import AreaEditorForm from '../../Components/AreaEditorForm';
51
52
 
52
53
  const styles = theme => {
53
54
  const breakPoint = {
@@ -57,22 +58,37 @@ const styles = theme => {
57
58
  editorRoot: {
58
59
  display: 'flex',
59
60
  flexDirection: 'row',
61
+ height: 'calc(100vh - 180px)',
60
62
  '& > $header': {
61
63
  display: 'none',
62
64
  [breakPoint.max]: {
63
65
  display: 'block',
64
66
  },
65
67
  },
68
+ '& > $header3DContainer': {
69
+ display: 'none',
70
+ [breakPoint.max]: {
71
+ display: 'flex',
72
+ },
73
+ },
66
74
  [breakPoint.max]: {
67
75
  flexDirection: 'column',
68
76
  },
69
77
  },
70
78
  leftSide: {
71
79
  marginRight: 2 * theme.spacing.unit,
80
+ flex: 1,
72
81
  },
73
82
  header: {
74
83
  flex: 1,
75
84
  },
85
+ header3D: {
86
+ flex: 1,
87
+ },
88
+ header3DContainer: {
89
+ display: 'flex',
90
+ flexDirection: 'row',
91
+ },
76
92
  rightSide: {
77
93
  flex: 1,
78
94
  '& > $header': {
@@ -81,6 +97,27 @@ const styles = theme => {
81
97
  },
82
98
  },
83
99
  },
100
+ rightSide3D: {
101
+ flex: 1,
102
+ '& > $header3DContainer': {
103
+ [breakPoint.max]: {
104
+ display: 'none',
105
+ },
106
+ },
107
+ display: 'flex',
108
+ flexDirection: 'column',
109
+ maxWidth: '50%',
110
+ marginLeft: 'auto',
111
+ overflow: 'hidden',
112
+ [breakPoint.max]: {
113
+ maxWidth: '100%',
114
+ },
115
+ },
116
+ areaEditorForm: {
117
+ marginLeft: 4 * theme.spacing.unit,
118
+ marginBottom: 2 * theme.spacing.unit,
119
+ flex: 1,
120
+ },
84
121
  title: {
85
122
  fontSize: 20,
86
123
  marginBottom: theme.spacing.unit,
@@ -120,6 +157,12 @@ const styles = theme => {
120
157
  width: '100%',
121
158
  height: '39vw',
122
159
  },
160
+ visualizationContainer3D: {
161
+ width: 'auto',
162
+ flex: 1,
163
+ maxHeight: '100%',
164
+ overflow: 'hidden',
165
+ },
123
166
  loaderContainer: {
124
167
  minHeight: 400,
125
168
  display: 'flex',
@@ -475,10 +518,10 @@ export class VisualizationSettingsEdit extends Component {
475
518
  designArea: { width, height },
476
519
  } = this.props;
477
520
 
478
- this.baseShapeEditor &&
479
- applyLinks(previousData, nextData, {
480
- positionRatio: (width || 1) / (height || 1),
481
- });
521
+ applyLinks(previousData, nextData, {
522
+ positionRatio: (width || 1) / (height || 1),
523
+ recalculatePosition: isKindOf2D(this.props.mode),
524
+ });
482
525
 
483
526
  data.updateValues(nextData);
484
527
  if (data.validate()) {
@@ -520,7 +563,7 @@ export class VisualizationSettingsEdit extends Component {
520
563
  .map(dpm => dpm.title)
521
564
  .join(', ');
522
565
  return (
523
- <div className={classes.header}>
566
+ <div className={isKindOf3D(mode) ? classes.header3D : classes.header}>
524
567
  <Typography variant="h3" className={classes.title}>
525
568
  <TranslationFinder
526
569
  data={designArea.texts}
@@ -572,6 +615,20 @@ export class VisualizationSettingsEdit extends Component {
572
615
  );
573
616
  }
574
617
 
618
+ renderHeader3D(designAreaData) {
619
+ const { classes } = this.props;
620
+ return (
621
+ <div className={classes.header3DContainer}>
622
+ {this.renderHeader()}
623
+ <AreaEditorForm
624
+ designAreaData={designAreaData}
625
+ onChange={this.onChangeData}
626
+ className={classes.areaEditorForm}
627
+ />
628
+ </div>
629
+ );
630
+ }
631
+
575
632
  renderVisualization(designAreaData) {
576
633
  const { mode, classes } = this.props;
577
634
  const { three } = this;
@@ -598,8 +655,8 @@ export class VisualizationSettingsEdit extends Component {
598
655
  if (isKindOf3D(mode)) {
599
656
  return (
600
657
  <React.Fragment>
601
- {this.renderHeader()}
602
- <VisualizationContainer three={three} />
658
+ {this.renderHeader3D(designAreaData)}
659
+ <VisualizationContainer three={three} className={classes.visualizationContainer3D} />
603
660
  </React.Fragment>
604
661
  );
605
662
  }
@@ -607,7 +664,7 @@ export class VisualizationSettingsEdit extends Component {
607
664
  }
608
665
 
609
666
  render() {
610
- const { designArea, classes } = this.props;
667
+ const { designArea, classes, mode } = this.props;
611
668
  const { three } = this;
612
669
  if (!designArea) {
613
670
  return null;
@@ -634,7 +691,7 @@ export class VisualizationSettingsEdit extends Component {
634
691
  <div className={classes.editorRoot}>
635
692
  {loading && <LoadingComponent fullSize />}
636
693
 
637
- {this.renderHeader()}
694
+ {isKindOf3D(mode) ? this.renderHeader3D(data) : this.renderHeader()}
638
695
 
639
696
  {imageElement && (
640
697
  <div className={classes.leftSide}>
@@ -645,11 +702,12 @@ export class VisualizationSettingsEdit extends Component {
645
702
  areaData={data && data.position}
646
703
  areaRatio={areaRatio}
647
704
  ref={this.areaEditorRef}
705
+ onChange={this.updateData}
648
706
  />
649
707
  </div>
650
708
  )}
651
709
 
652
- <div className={classes.rightSide}>
710
+ <div className={isKindOf3D(mode) ? classes.rightSide3D : classes.rightSide}>
653
711
  {this.renderVisualization(data)}
654
712
 
655
713
  {errors && (
@@ -13,7 +13,7 @@ import { provideLocalState, withLocalState } from '../../../../Utils/HOCs/LocalS
13
13
  const styles = () => ({
14
14
  paperRoot: {
15
15
  maxWidth: '90vw',
16
- maxHeight: '90vw',
16
+ maxHeight: '90vh',
17
17
  marginTop: '16px',
18
18
  marginBottom: '16px',
19
19
  },