@configuratorware/configurator-frontendgui 1.55.3 → 1.55.5
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.
- package/App/Modules/Designer/Components/ImageEditDialog/index.js +13 -3
- package/App/Modules/Designer/Utils/SvgFixers.js +59 -1
- package/App/Modules/Designer/Utils/Transformers.js +1 -1
- package/App/Reducers/DesignData/Modifiers.js +63 -1
- package/App/Services/ConfiguratorService.js +19 -1
- package/App/Services/DesignDataService.js +21 -6
- package/App/configuration.js +3 -1
- package/package.json +4 -4
- package/src/App/Modules/Designer/Components/ImageEditDialog/index.js +11 -2
- package/src/App/Modules/Designer/Utils/SvgFixers.js +66 -0
- package/src/App/Modules/Designer/Utils/Transformers.js +5 -1
- package/src/App/Reducers/DesignData/Modifiers.js +58 -0
- package/src/App/Services/ConfiguratorService.js +17 -0
- package/src/App/Services/DesignDataService.js +24 -9
- package/src/App/Services/__tests__/ConfiguratorService.test.js +5 -1
- package/src/App/configuration.js +1 -0
|
@@ -114,12 +114,17 @@ var styles = function styles(theme) {
|
|
|
114
114
|
margin: theme.smallScreen.padding
|
|
115
115
|
}),
|
|
116
116
|
imageTabOptions: {
|
|
117
|
+
backgroundColor: '#E8E8EA',
|
|
118
|
+
borderRadius: '5px',
|
|
117
119
|
'& button': {
|
|
118
|
-
minWidth: '33%',
|
|
120
|
+
minWidth: '33.33%',
|
|
119
121
|
minHeight: 64,
|
|
120
122
|
textTransform: 'none',
|
|
121
123
|
fontSize: 15,
|
|
122
|
-
color:
|
|
124
|
+
color: theme.palette.primary.darkText
|
|
125
|
+
},
|
|
126
|
+
'& .MuiTabs-indicator': {
|
|
127
|
+
display: 'none'
|
|
123
128
|
}
|
|
124
129
|
},
|
|
125
130
|
colorizeCaption: {
|
|
@@ -270,7 +275,12 @@ var styles = function styles(theme) {
|
|
|
270
275
|
display: 'flex',
|
|
271
276
|
justifyContent: 'space-between'
|
|
272
277
|
}),
|
|
273
|
-
imageTab: _defineProperty({
|
|
278
|
+
imageTab: _defineProperty({
|
|
279
|
+
'&.Mui-selected': {
|
|
280
|
+
backgroundColor: theme.palette.primary.main,
|
|
281
|
+
color: '#FFFFFF'
|
|
282
|
+
}
|
|
283
|
+
}, theme.breakpoints.down('xs'), {
|
|
274
284
|
fontWeight: 'bold',
|
|
275
285
|
fontSize: '13px !important'
|
|
276
286
|
}),
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.preparePrintDesignData = exports.prepareDesignDataSnapshots = exports.getMatchAt = exports.embeddedSvgImageToInlineSvgContent = exports.alterObjectValues = exports.alterArrayValues = void 0;
|
|
6
|
+
exports.preparePrintDesignData = exports.prepareDesignDataSnapshots = exports.getMissingViewBox = exports.getMatchAt = exports.embeddedSvgImageToInlineSvgContent = exports.alterObjectValues = exports.alterArrayValues = void 0;
|
|
7
7
|
var getMatchAt = exports.getMatchAt = function getMatchAt(str, regexp) {
|
|
8
8
|
var idx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1;
|
|
9
9
|
var defaultValue = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : '';
|
|
@@ -38,4 +38,62 @@ var prepareDesignDataSnapshots = exports.prepareDesignDataSnapshots = function p
|
|
|
38
38
|
};
|
|
39
39
|
var preparePrintDesignData = exports.preparePrintDesignData = function preparePrintDesignData(svgMap) {
|
|
40
40
|
return alterObjectValues(svgMap, embeddedSvgImageToInlineSvgContent);
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Calculates the bounding viewBox for an SVG string.
|
|
45
|
+
* @param {string} svgString - The raw SVG string from the API.
|
|
46
|
+
* @returns {string} The calculated viewBox (e.g., "0 0 100 100").
|
|
47
|
+
*/
|
|
48
|
+
var getMissingViewBox = exports.getMissingViewBox = function getMissingViewBox(svgString, fallbackSize) {
|
|
49
|
+
var padding = 2;
|
|
50
|
+
|
|
51
|
+
// 1. Parse the SVG string into a DOM element
|
|
52
|
+
var parser = new DOMParser();
|
|
53
|
+
var doc = parser.parseFromString(svgString, 'image/svg+xml');
|
|
54
|
+
var svgElement = doc.querySelector('svg');
|
|
55
|
+
if (!svgElement) {
|
|
56
|
+
throw new Error('Invalid SVG string provided.');
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// 2. Prepare the SVG to be rendered invisibly
|
|
60
|
+
if (svgElement.style) {
|
|
61
|
+
svgElement.style.position = 'absolute';
|
|
62
|
+
svgElement.style.visibility = 'hidden';
|
|
63
|
+
svgElement.style.width = 'auto';
|
|
64
|
+
svgElement.style.height = 'auto';
|
|
65
|
+
} else {
|
|
66
|
+
svgElement.setAttribute('style', 'position: absolute; visibility: hidden; width: auto; height: auto;');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// 3. Wrap all children in a <g> tag.
|
|
70
|
+
// Calling getBBox() directly on the <svg> root can be unreliable across
|
|
71
|
+
// different browsers. A wrapper group guarantees we measure the actual content.
|
|
72
|
+
var wrapperGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
73
|
+
while (svgElement.firstChild) {
|
|
74
|
+
wrapperGroup.appendChild(svgElement.firstChild);
|
|
75
|
+
}
|
|
76
|
+
svgElement.appendChild(wrapperGroup);
|
|
77
|
+
|
|
78
|
+
// 4. Attach to the DOM so the browser can calculate layout dimensions
|
|
79
|
+
document.body.appendChild(svgElement);
|
|
80
|
+
|
|
81
|
+
// 5. Calculate the bounding box
|
|
82
|
+
var viewBox = "0 0 ".concat(fallbackSize.width, " ").concat(fallbackSize.height);
|
|
83
|
+
if (!wrapperGroup.getBBox) {
|
|
84
|
+
return viewBox;
|
|
85
|
+
}
|
|
86
|
+
try {
|
|
87
|
+
var bbox = wrapperGroup.getBBox();
|
|
88
|
+
var x = bbox.x - padding;
|
|
89
|
+
var y = bbox.y - padding;
|
|
90
|
+
var width = bbox.width + padding * 2;
|
|
91
|
+
var height = bbox.height + padding * 2;
|
|
92
|
+
// Construct the viewBox string: min-x, min-y, width, height
|
|
93
|
+
viewBox = "".concat(x, " ").concat(y, " ").concat(width, " ").concat(height);
|
|
94
|
+
} finally {
|
|
95
|
+
// 6. Clean up by removing the hidden SVG from the DOM
|
|
96
|
+
document.body.removeChild(svgElement);
|
|
97
|
+
}
|
|
98
|
+
return viewBox;
|
|
41
99
|
};
|
|
@@ -83,7 +83,7 @@ var prepareImageObjectData = exports.prepareImageObjectData = function prepareIm
|
|
|
83
83
|
return (0, _DesignDataService.getSvgContent)(url, true);
|
|
84
84
|
case 3:
|
|
85
85
|
svgContent = _context.v;
|
|
86
|
-
return _context.a(2, (0, _DesignDataService.applySvgContentOperations)(image.original, image.preview, displayColorPreview || gallery ? operations ? operations : image.operations : null, svgContent));
|
|
86
|
+
return _context.a(2, (0, _DesignDataService.applySvgContentOperations)(image.original, image.preview, displayColorPreview || gallery || originalVector ? operations ? operations : image.operations : null, svgContent));
|
|
87
87
|
}
|
|
88
88
|
}, _callee);
|
|
89
89
|
}));
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.setColorOnOperations = exports.replaceColorOnOperations = exports.removeVectorizeFromOperations = exports.reduceNumberOfDistinctColorsBy = exports.isOneColorAboveThreshold = exports.getEditDataFromOperations = exports.createVectorizeColorsMap = exports.compareOperations = exports.applyProductionMethodChangeToCanvasObjects = void 0;
|
|
6
|
+
exports.setColorOnOperations = exports.replaceColorOnOperations = exports.removeVectorizeFromOperations = exports.reduceNumberOfDistinctColorsBy = exports.isOneColorAboveThreshold = exports.getEditDataFromOperations = exports.extendCanvasDataWithMetricContentSize = exports.createVectorizeColorsMap = exports.compareOperations = exports.applyProductionMethodChangeToCanvasObjects = void 0;
|
|
7
7
|
var _cloneDeep = _interopRequireDefault(require("lodash/cloneDeep"));
|
|
8
8
|
var _isEqual = _interopRequireDefault(require("lodash/isEqual"));
|
|
9
9
|
var _omit = _interopRequireDefault(require("lodash/omit"));
|
|
@@ -247,4 +247,66 @@ var updateLockState = function updateLockState(newProductionMethod, oldProductio
|
|
|
247
247
|
});
|
|
248
248
|
}
|
|
249
249
|
return objects;
|
|
250
|
+
};
|
|
251
|
+
var extendCanvasDataWithMetricContentSize = exports.extendCanvasDataWithMetricContentSize = function extendCanvasDataWithMetricContentSize(canvasData) {
|
|
252
|
+
var b = {
|
|
253
|
+
minX: Infinity,
|
|
254
|
+
maxX: -Infinity,
|
|
255
|
+
minY: Infinity,
|
|
256
|
+
maxY: -Infinity
|
|
257
|
+
};
|
|
258
|
+
var mergeRotated = function mergeRotated(cx, cy, hw, hh, deg) {
|
|
259
|
+
var rad = deg * Math.PI / 180;
|
|
260
|
+
var c = Math.cos(rad);
|
|
261
|
+
var s = Math.sin(rad);
|
|
262
|
+
for (var _i = 0, _arr = [[-hw, -hh], [hw, -hh], [hw, hh], [-hw, hh]]; _i < _arr.length; _i++) {
|
|
263
|
+
var _arr$_i = _slicedToArray(_arr[_i], 2),
|
|
264
|
+
dx = _arr$_i[0],
|
|
265
|
+
dy = _arr$_i[1];
|
|
266
|
+
var x = cx + dx * c - dy * s;
|
|
267
|
+
var y = cy + dx * s + dy * c;
|
|
268
|
+
b.minX = Math.min(b.minX, x);
|
|
269
|
+
b.maxX = Math.max(b.maxX, x);
|
|
270
|
+
b.minY = Math.min(b.minY, y);
|
|
271
|
+
b.maxY = Math.max(b.maxY, y);
|
|
272
|
+
}
|
|
273
|
+
};
|
|
274
|
+
var mergeAxisAligned = function mergeAxisAligned(cx, cy, hw, hh) {
|
|
275
|
+
b.minX = Math.min(b.minX, cx - hw);
|
|
276
|
+
b.maxX = Math.max(b.maxX, cx + hw);
|
|
277
|
+
b.minY = Math.min(b.minY, cy - hh);
|
|
278
|
+
b.maxY = Math.max(b.maxY, cy + hh);
|
|
279
|
+
};
|
|
280
|
+
var _iterator2 = _createForOfIteratorHelper(canvasData.objects),
|
|
281
|
+
_step2;
|
|
282
|
+
try {
|
|
283
|
+
for (_iterator2.s(); !(_step2 = _iterator2.n()).done;) {
|
|
284
|
+
var object = _step2.value;
|
|
285
|
+
if (!object.metric) continue;
|
|
286
|
+
var w = object.metric.width || 0;
|
|
287
|
+
var h = object.metric.height || 0;
|
|
288
|
+
var hw = w / 2;
|
|
289
|
+
var hh = h / 2;
|
|
290
|
+
var cx = object.metric.x || 0;
|
|
291
|
+
var cy = object.metric.y || 0;
|
|
292
|
+
if (typeof object.rotation === 'number' && object.rotation !== 0 && w && h) {
|
|
293
|
+
mergeRotated(cx, cy, hw, hh, object.rotation);
|
|
294
|
+
} else {
|
|
295
|
+
mergeAxisAligned(cx, cy, hw, hh);
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
} catch (err) {
|
|
299
|
+
_iterator2.e(err);
|
|
300
|
+
} finally {
|
|
301
|
+
_iterator2.f();
|
|
302
|
+
}
|
|
303
|
+
if (!Number.isFinite(b.minX)) {
|
|
304
|
+
return canvasData;
|
|
305
|
+
}
|
|
306
|
+
return _objectSpread(_objectSpread({}, canvasData), {}, {
|
|
307
|
+
metricContentSize: {
|
|
308
|
+
width: Math.abs(b.maxX - b.minX),
|
|
309
|
+
height: Math.abs(b.maxY - b.minY)
|
|
310
|
+
}
|
|
311
|
+
});
|
|
250
312
|
};
|
|
@@ -355,11 +355,29 @@ var ConfiguratorService = exports["default"] = /*#__PURE__*/function (_AbstractC
|
|
|
355
355
|
roughDesignData[designAreaIdentifier] = {
|
|
356
356
|
objectCount: (0, _get["default"])(canvasData, 'objects.length'),
|
|
357
357
|
designProductionMethodIdentifier: designProductionMethodIdentifier,
|
|
358
|
-
colorAmount: colorAmount
|
|
358
|
+
colorAmount: colorAmount,
|
|
359
|
+
objects: this.getRoughDesignDataObjectDetails(designAreaData)
|
|
359
360
|
};
|
|
360
361
|
}
|
|
361
362
|
return roughDesignData;
|
|
362
363
|
}
|
|
364
|
+
}, {
|
|
365
|
+
key: "getRoughDesignDataObjectDetails",
|
|
366
|
+
value: function getRoughDesignDataObjectDetails(designData) {
|
|
367
|
+
var includeMetricData = (0, _configuration2.getConf)('designer.includeMetricContentSize', false);
|
|
368
|
+
return (0, _get["default"])(designData, 'canvasData.objects', []).map(function (object) {
|
|
369
|
+
var _object$metric, _object$metric2, _object$metric3, _object$metric4;
|
|
370
|
+
return _objectSpread({
|
|
371
|
+
uuid: object.uuid
|
|
372
|
+
}, includeMetricData ? {
|
|
373
|
+
x: ((_object$metric = object.metric) === null || _object$metric === void 0 ? void 0 : _object$metric.x) || 0,
|
|
374
|
+
y: ((_object$metric2 = object.metric) === null || _object$metric2 === void 0 ? void 0 : _object$metric2.y) || 0,
|
|
375
|
+
width: ((_object$metric3 = object.metric) === null || _object$metric3 === void 0 ? void 0 : _object$metric3.width) || 0,
|
|
376
|
+
height: ((_object$metric4 = object.metric) === null || _object$metric4 === void 0 ? void 0 : _object$metric4.height) || 0,
|
|
377
|
+
rotation: object.rotation || 0
|
|
378
|
+
} : {});
|
|
379
|
+
});
|
|
380
|
+
}
|
|
363
381
|
|
|
364
382
|
//// <-- ACTIONS -->
|
|
365
383
|
}, {
|
|
@@ -36,6 +36,7 @@ var _FontFaceRepository = require("../Modules/Designer/Utils/FontFaceRepository"
|
|
|
36
36
|
var _Selectors5 = require("../Reducers/DesignData/Selectors");
|
|
37
37
|
var _ImageEditUtils = require("../Modules/Designer/Utils/ImageEditUtils");
|
|
38
38
|
var _DesignElementSelectors = require("../Reducers/DesignArea/DesignElementSelectors");
|
|
39
|
+
var _SvgFixers = require("../Modules/Designer/Utils/SvgFixers");
|
|
39
40
|
var _designer_placeholder_logo = _interopRequireDefault(require("../../Resources/Images/designer_placeholder_logo.svg"));
|
|
40
41
|
var _this = void 0;
|
|
41
42
|
function _interopRequireDefault(e) { return e && e.__esModule ? e : { "default": e }; }
|
|
@@ -344,11 +345,15 @@ var applySvgContentOperations = exports.applySvgContentOperations = function app
|
|
|
344
345
|
var pixelHeight = Math.round(preview.height * scaleFactor);
|
|
345
346
|
var isSvgUpload = _Selectors2.vectorFormats.indexOf(original.format.toLowerCase()) !== -1;
|
|
346
347
|
if (svgTag.indexOf('viewBox=') === -1) {
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
348
|
+
var fallbackSize = isSvgUpload ? {
|
|
349
|
+
width: pixelWidth,
|
|
350
|
+
height: pixelHeight
|
|
351
|
+
} : {
|
|
352
|
+
width: preview.width,
|
|
353
|
+
height: preview.height
|
|
354
|
+
};
|
|
355
|
+
var viewBox = (0, _SvgFixers.getMissingViewBox)(svgContent, fallbackSize);
|
|
356
|
+
svgContent = svgContent.replace('<svg', "<svg viewBox=\"".concat(viewBox, "\""));
|
|
352
357
|
}
|
|
353
358
|
if (svgTag.indexOf('height=') === -1) {
|
|
354
359
|
if (isSvgUpload) {
|
|
@@ -1727,7 +1732,17 @@ var DesignDataService = exports["default"] = /*#__PURE__*/function () {
|
|
|
1727
1732
|
}, {
|
|
1728
1733
|
key: "setCanvasData",
|
|
1729
1734
|
value: function setCanvasData(canvasData, targetDesignAreaIdentifier) {
|
|
1730
|
-
|
|
1735
|
+
var extendedCanvasData = this.getExtendedCanvasData(canvasData);
|
|
1736
|
+
_ServiceLocator.Services.store.dispatch((0, _Actions.setCanvasData)(extendedCanvasData, targetDesignAreaIdentifier));
|
|
1737
|
+
}
|
|
1738
|
+
}, {
|
|
1739
|
+
key: "getExtendedCanvasData",
|
|
1740
|
+
value: function getExtendedCanvasData(canvasData) {
|
|
1741
|
+
var _canvasData$objects;
|
|
1742
|
+
if (!(0, _configuration.getConf)('designer.includeMetricContentSize', false) || !(canvasData !== null && canvasData !== void 0 && (_canvasData$objects = canvasData.objects) !== null && _canvasData$objects !== void 0 && _canvasData$objects.length)) {
|
|
1743
|
+
return canvasData;
|
|
1744
|
+
}
|
|
1745
|
+
return (0, _Modifiers.extendCanvasDataWithMetricContentSize)(canvasData);
|
|
1731
1746
|
}
|
|
1732
1747
|
}, {
|
|
1733
1748
|
key: "setColorAmount",
|
package/App/configuration.js
CHANGED
|
@@ -203,7 +203,9 @@ var applicationConfiguration = {
|
|
|
203
203
|
// the default canvas dpi as project specific option
|
|
204
204
|
maxColorAmount: 10,
|
|
205
205
|
// the default max number of colors in the colorizing feature
|
|
206
|
-
allowedImageUploadFormats: 'jpg,jpeg,svg,png,pdf,bmp,tif,tiff,eps,ai,gif'
|
|
206
|
+
allowedImageUploadFormats: 'jpg,jpeg,svg,png,pdf,bmp,tif,tiff,eps,ai,gif',
|
|
207
|
+
// the image formats users can upload to designareas / designer items
|
|
208
|
+
includeMetricContentSize: false // set true to include the metric content size in the design data
|
|
207
209
|
},
|
|
208
210
|
vectorizeImageQuality: 45000,
|
|
209
211
|
renderPreviewImagesForCheckout: true,
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@configuratorware/configurator-frontendgui",
|
|
3
|
-
"version": "1.55.
|
|
3
|
+
"version": "1.55.5",
|
|
4
4
|
"license": "UNLICENSED",
|
|
5
5
|
"private": false,
|
|
6
6
|
"main": "./index.js",
|
|
7
7
|
"dependencies": {
|
|
8
8
|
"@babel/polyfill": "^7.12.1",
|
|
9
|
-
"@configuratorware/scripts": "1.55.
|
|
9
|
+
"@configuratorware/scripts": "1.55.5",
|
|
10
10
|
"@material-ui/core": "^4.12.4",
|
|
11
11
|
"@material-ui/icons": "^4.11.3",
|
|
12
12
|
"@material-ui/lab": "^4.0.0-alpha.61",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"react-router-dom": "^5.3.4",
|
|
37
37
|
"react-swipeable": "^5.5.1",
|
|
38
38
|
"react-zoom-pan-pinch": "^2.1.3",
|
|
39
|
-
"redhotmagma-graphics-editor": "1.55.
|
|
40
|
-
"redhotmagma-visualization": "1.55.
|
|
39
|
+
"redhotmagma-graphics-editor": "1.55.5",
|
|
40
|
+
"redhotmagma-visualization": "1.55.5",
|
|
41
41
|
"redux": "^4.1.0",
|
|
42
42
|
"redux-logger": "^3.0.6",
|
|
43
43
|
"redux-persist": "^5.10.0",
|
|
@@ -103,12 +103,17 @@ const styles = theme => ({
|
|
|
103
103
|
},
|
|
104
104
|
},
|
|
105
105
|
imageTabOptions: {
|
|
106
|
+
backgroundColor: '#E8E8EA',
|
|
107
|
+
borderRadius: '5px',
|
|
106
108
|
'& button': {
|
|
107
|
-
minWidth: '33%',
|
|
109
|
+
minWidth: '33.33%',
|
|
108
110
|
minHeight: 64,
|
|
109
111
|
textTransform: 'none',
|
|
110
112
|
fontSize: 15,
|
|
111
|
-
color:
|
|
113
|
+
color: theme.palette.primary.darkText,
|
|
114
|
+
},
|
|
115
|
+
'& .MuiTabs-indicator': {
|
|
116
|
+
display: 'none',
|
|
112
117
|
},
|
|
113
118
|
},
|
|
114
119
|
colorizeCaption: {
|
|
@@ -283,6 +288,10 @@ const styles = theme => ({
|
|
|
283
288
|
},
|
|
284
289
|
},
|
|
285
290
|
imageTab: {
|
|
291
|
+
'&.Mui-selected': {
|
|
292
|
+
backgroundColor: theme.palette.primary.main,
|
|
293
|
+
color: '#FFFFFF',
|
|
294
|
+
},
|
|
286
295
|
[theme.breakpoints.down('xs')]: {
|
|
287
296
|
fontWeight: 'bold',
|
|
288
297
|
fontSize: '13px !important',
|
|
@@ -34,3 +34,69 @@ export const prepareDesignDataSnapshots = svgArrMap =>
|
|
|
34
34
|
alterObjectValues(svgArrMap, arr => alterArrayValues(arr, embeddedSvgImageToInlineSvgContent));
|
|
35
35
|
|
|
36
36
|
export const preparePrintDesignData = svgMap => alterObjectValues(svgMap, embeddedSvgImageToInlineSvgContent);
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Calculates the bounding viewBox for an SVG string.
|
|
40
|
+
* @param {string} svgString - The raw SVG string from the API.
|
|
41
|
+
* @returns {string} The calculated viewBox (e.g., "0 0 100 100").
|
|
42
|
+
*/
|
|
43
|
+
export const getMissingViewBox = (svgString, fallbackSize) => {
|
|
44
|
+
const padding = 2;
|
|
45
|
+
|
|
46
|
+
// 1. Parse the SVG string into a DOM element
|
|
47
|
+
const parser = new DOMParser();
|
|
48
|
+
const doc = parser.parseFromString(svgString, 'image/svg+xml');
|
|
49
|
+
const svgElement = doc.querySelector('svg');
|
|
50
|
+
|
|
51
|
+
if (!svgElement) {
|
|
52
|
+
throw new Error('Invalid SVG string provided.');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// 2. Prepare the SVG to be rendered invisibly
|
|
56
|
+
if (svgElement.style) {
|
|
57
|
+
svgElement.style.position = 'absolute';
|
|
58
|
+
svgElement.style.visibility = 'hidden';
|
|
59
|
+
svgElement.style.width = 'auto';
|
|
60
|
+
svgElement.style.height = 'auto';
|
|
61
|
+
} else {
|
|
62
|
+
svgElement.setAttribute(
|
|
63
|
+
'style',
|
|
64
|
+
'position: absolute; visibility: hidden; width: auto; height: auto;'
|
|
65
|
+
);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// 3. Wrap all children in a <g> tag.
|
|
69
|
+
// Calling getBBox() directly on the <svg> root can be unreliable across
|
|
70
|
+
// different browsers. A wrapper group guarantees we measure the actual content.
|
|
71
|
+
const wrapperGroup = document.createElementNS('http://www.w3.org/2000/svg', 'g');
|
|
72
|
+
while (svgElement.firstChild) {
|
|
73
|
+
wrapperGroup.appendChild(svgElement.firstChild);
|
|
74
|
+
}
|
|
75
|
+
svgElement.appendChild(wrapperGroup);
|
|
76
|
+
|
|
77
|
+
// 4. Attach to the DOM so the browser can calculate layout dimensions
|
|
78
|
+
document.body.appendChild(svgElement);
|
|
79
|
+
|
|
80
|
+
// 5. Calculate the bounding box
|
|
81
|
+
let viewBox = `0 0 ${fallbackSize.width} ${fallbackSize.height}`;
|
|
82
|
+
|
|
83
|
+
if (!wrapperGroup.getBBox) {
|
|
84
|
+
return viewBox;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
try {
|
|
88
|
+
const bbox = wrapperGroup.getBBox();
|
|
89
|
+
|
|
90
|
+
const x = bbox.x - padding;
|
|
91
|
+
const y = bbox.y - padding;
|
|
92
|
+
const width = bbox.width + padding * 2;
|
|
93
|
+
const height = bbox.height + padding * 2;
|
|
94
|
+
// Construct the viewBox string: min-x, min-y, width, height
|
|
95
|
+
viewBox = `${x} ${y} ${width} ${height}`;
|
|
96
|
+
} finally {
|
|
97
|
+
// 6. Clean up by removing the hidden SVG from the DOM
|
|
98
|
+
document.body.removeChild(svgElement);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
return viewBox;
|
|
102
|
+
};
|
|
@@ -47,7 +47,11 @@ export const prepareImageObjectData = rawObject => {
|
|
|
47
47
|
return applySvgContentOperations(
|
|
48
48
|
image.original,
|
|
49
49
|
image.preview,
|
|
50
|
-
displayColorPreview || gallery
|
|
50
|
+
displayColorPreview || gallery || originalVector
|
|
51
|
+
? operations
|
|
52
|
+
? operations
|
|
53
|
+
: image.operations
|
|
54
|
+
: null,
|
|
51
55
|
svgContent
|
|
52
56
|
);
|
|
53
57
|
};
|
|
@@ -254,3 +254,61 @@ const updateLockState = (newProductionMethod, oldProductionMethod, objects) => {
|
|
|
254
254
|
}
|
|
255
255
|
return objects;
|
|
256
256
|
};
|
|
257
|
+
|
|
258
|
+
export const extendCanvasDataWithMetricContentSize = canvasData => {
|
|
259
|
+
const b = { minX: Infinity, maxX: -Infinity, minY: Infinity, maxY: -Infinity };
|
|
260
|
+
|
|
261
|
+
const mergeRotated = (cx, cy, hw, hh, deg) => {
|
|
262
|
+
const rad = (deg * Math.PI) / 180;
|
|
263
|
+
const c = Math.cos(rad);
|
|
264
|
+
const s = Math.sin(rad);
|
|
265
|
+
for (const [dx, dy] of [
|
|
266
|
+
[-hw, -hh],
|
|
267
|
+
[hw, -hh],
|
|
268
|
+
[hw, hh],
|
|
269
|
+
[-hw, hh],
|
|
270
|
+
]) {
|
|
271
|
+
const x = cx + dx * c - dy * s;
|
|
272
|
+
const y = cy + dx * s + dy * c;
|
|
273
|
+
b.minX = Math.min(b.minX, x);
|
|
274
|
+
b.maxX = Math.max(b.maxX, x);
|
|
275
|
+
b.minY = Math.min(b.minY, y);
|
|
276
|
+
b.maxY = Math.max(b.maxY, y);
|
|
277
|
+
}
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
const mergeAxisAligned = (cx, cy, hw, hh) => {
|
|
281
|
+
b.minX = Math.min(b.minX, cx - hw);
|
|
282
|
+
b.maxX = Math.max(b.maxX, cx + hw);
|
|
283
|
+
b.minY = Math.min(b.minY, cy - hh);
|
|
284
|
+
b.maxY = Math.max(b.maxY, cy + hh);
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
for (const object of canvasData.objects) {
|
|
288
|
+
if (!object.metric) continue;
|
|
289
|
+
const w = object.metric.width || 0;
|
|
290
|
+
const h = object.metric.height || 0;
|
|
291
|
+
const hw = w / 2;
|
|
292
|
+
const hh = h / 2;
|
|
293
|
+
const cx = object.metric.x || 0;
|
|
294
|
+
const cy = object.metric.y || 0;
|
|
295
|
+
|
|
296
|
+
if (typeof object.rotation === 'number' && object.rotation !== 0 && w && h) {
|
|
297
|
+
mergeRotated(cx, cy, hw, hh, object.rotation);
|
|
298
|
+
} else {
|
|
299
|
+
mergeAxisAligned(cx, cy, hw, hh);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
if (!Number.isFinite(b.minX)) {
|
|
304
|
+
return canvasData;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
...canvasData,
|
|
309
|
+
metricContentSize: {
|
|
310
|
+
width: Math.abs(b.maxX - b.minX),
|
|
311
|
+
height: Math.abs(b.maxY - b.minY),
|
|
312
|
+
},
|
|
313
|
+
};
|
|
314
|
+
};
|
|
@@ -254,11 +254,28 @@ export default class ConfiguratorService extends AbstractConfiguratorService {
|
|
|
254
254
|
objectCount: get(canvasData, 'objects.length'),
|
|
255
255
|
designProductionMethodIdentifier,
|
|
256
256
|
colorAmount,
|
|
257
|
+
objects: this.getRoughDesignDataObjectDetails(designAreaData),
|
|
257
258
|
};
|
|
258
259
|
}
|
|
259
260
|
return roughDesignData;
|
|
260
261
|
}
|
|
261
262
|
|
|
263
|
+
getRoughDesignDataObjectDetails(designData) {
|
|
264
|
+
const includeMetricData = getConf('designer.includeMetricContentSize', false);
|
|
265
|
+
return get(designData, 'canvasData.objects', []).map(object => ({
|
|
266
|
+
uuid: object.uuid,
|
|
267
|
+
...(includeMetricData
|
|
268
|
+
? {
|
|
269
|
+
x: object.metric?.x || 0,
|
|
270
|
+
y: object.metric?.y || 0,
|
|
271
|
+
width: object.metric?.width || 0,
|
|
272
|
+
height: object.metric?.height || 0,
|
|
273
|
+
rotation: object.rotation || 0,
|
|
274
|
+
}
|
|
275
|
+
: {}),
|
|
276
|
+
}));
|
|
277
|
+
}
|
|
278
|
+
|
|
262
279
|
//// <-- ACTIONS -->
|
|
263
280
|
|
|
264
281
|
async saveConfiguration(configuration, configurationtype) {
|
|
@@ -40,7 +40,9 @@ import {
|
|
|
40
40
|
removeVectorizeFromOperations,
|
|
41
41
|
reduceNumberOfDistinctColorsBy,
|
|
42
42
|
applyProductionMethodChangeToCanvasObjects,
|
|
43
|
+
extendCanvasDataWithMetricContentSize,
|
|
43
44
|
} from '../Reducers/DesignData/Modifiers';
|
|
45
|
+
|
|
44
46
|
import {
|
|
45
47
|
clearDesignAreaSelection,
|
|
46
48
|
selectDesignArea,
|
|
@@ -116,6 +118,7 @@ import { FontFaceRepository } from '../Modules/Designer/Utils/FontFaceRepository
|
|
|
116
118
|
import { getAggregatedColorCount, isPlaceholderObject } from '../Reducers/DesignData/Selectors';
|
|
117
119
|
import { expandVectorizeColorsMap } from '../Modules/Designer/Utils/ImageEditUtils';
|
|
118
120
|
import { checkDesignElementRestrictionsWithRemovalCount } from '../Reducers/DesignArea/DesignElementSelectors';
|
|
121
|
+
import { getMissingViewBox } from '../Modules/Designer/Utils/SvgFixers';
|
|
119
122
|
|
|
120
123
|
import placeholderLogo from '../../Resources/Images/designer_placeholder_logo.svg';
|
|
121
124
|
|
|
@@ -418,14 +421,17 @@ export const applySvgContentOperations = (original, preview, operations, svgCont
|
|
|
418
421
|
const pixelHeight = Math.round(preview.height * scaleFactor);
|
|
419
422
|
const isSvgUpload = vectorFormats.indexOf(original.format.toLowerCase()) !== -1;
|
|
420
423
|
if (svgTag.indexOf('viewBox=') === -1) {
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
424
|
+
const fallbackSize = isSvgUpload
|
|
425
|
+
? {
|
|
426
|
+
width: pixelWidth,
|
|
427
|
+
height: pixelHeight,
|
|
428
|
+
}
|
|
429
|
+
: {
|
|
430
|
+
width: preview.width,
|
|
431
|
+
height: preview.height,
|
|
432
|
+
};
|
|
433
|
+
const viewBox = getMissingViewBox(svgContent, fallbackSize);
|
|
434
|
+
svgContent = svgContent.replace('<svg', `<svg viewBox="${viewBox}"`);
|
|
429
435
|
}
|
|
430
436
|
|
|
431
437
|
if (svgTag.indexOf('height=') === -1) {
|
|
@@ -1494,7 +1500,16 @@ export default class DesignDataService {
|
|
|
1494
1500
|
}
|
|
1495
1501
|
|
|
1496
1502
|
setCanvasData(canvasData, targetDesignAreaIdentifier) {
|
|
1497
|
-
|
|
1503
|
+
const extendedCanvasData = this.getExtendedCanvasData(canvasData);
|
|
1504
|
+
Services.store.dispatch(setCanvasData(extendedCanvasData, targetDesignAreaIdentifier));
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
getExtendedCanvasData(canvasData) {
|
|
1508
|
+
if (!getConf('designer.includeMetricContentSize', false) || !canvasData?.objects?.length) {
|
|
1509
|
+
return canvasData;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
return extendCanvasDataWithMetricContentSize(canvasData);
|
|
1498
1513
|
}
|
|
1499
1514
|
|
|
1500
1515
|
async setColorAmount(maxColorCount) {
|
|
@@ -98,7 +98,10 @@ describe('Services/ConfiguratorService', () => {
|
|
|
98
98
|
designdata: {
|
|
99
99
|
test_canvas: {
|
|
100
100
|
canvasData: {
|
|
101
|
-
objects: [
|
|
101
|
+
objects: [
|
|
102
|
+
{ type: 'Image', uuid: 'image_1' },
|
|
103
|
+
{ type: 'Text', uuid: 'text_1' },
|
|
104
|
+
],
|
|
102
105
|
},
|
|
103
106
|
colorAmount: 1,
|
|
104
107
|
designProductionMethodIdentifier: 'print',
|
|
@@ -135,6 +138,7 @@ describe('Services/ConfiguratorService', () => {
|
|
|
135
138
|
objectCount: 2,
|
|
136
139
|
colorAmount: 1,
|
|
137
140
|
designProductionMethodIdentifier: 'print',
|
|
141
|
+
objects: [{ uuid: 'image_1' }, { uuid: 'text_1' }],
|
|
138
142
|
},
|
|
139
143
|
},
|
|
140
144
|
customdata: {
|
package/src/App/configuration.js
CHANGED
|
@@ -214,6 +214,7 @@ let applicationConfiguration = {
|
|
|
214
214
|
dpi: 300, // the default canvas dpi as project specific option
|
|
215
215
|
maxColorAmount: 10, // the default max number of colors in the colorizing feature
|
|
216
216
|
allowedImageUploadFormats: 'jpg,jpeg,svg,png,pdf,bmp,tif,tiff,eps,ai,gif', // the image formats users can upload to designareas / designer items
|
|
217
|
+
includeMetricContentSize: false, // set true to include the metric content size in the design data
|
|
217
218
|
},
|
|
218
219
|
|
|
219
220
|
vectorizeImageQuality: 45000,
|