@pie-element/hotspot 4.7.18-next.85 → 4.8.1-beta.587
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/CHANGELOG.md +485 -0
- package/configure/CHANGELOG.md +425 -0
- package/configure/lib/button.js.map +1 -1
- package/configure/lib/defaults.js +24 -2
- package/configure/lib/defaults.js.map +1 -1
- package/configure/lib/hotspot-container.js +44 -23
- package/configure/lib/hotspot-container.js.map +1 -1
- package/configure/lib/hotspot-drawable.js +11 -5
- package/configure/lib/hotspot-drawable.js.map +1 -1
- package/configure/lib/hotspot-palette.js +1 -1
- package/configure/lib/hotspot-palette.js.map +1 -1
- package/configure/lib/hotspot-polygon.js +1 -1
- package/configure/lib/hotspot-polygon.js.map +1 -1
- package/configure/lib/hotspot-rectangle.js +1 -1
- package/configure/lib/hotspot-rectangle.js.map +1 -1
- package/configure/lib/index.js +17 -3
- package/configure/lib/index.js.map +1 -1
- package/configure/lib/root.js +133 -27
- package/configure/lib/root.js.map +1 -1
- package/configure/lib/upload-control.js.map +1 -1
- package/configure/lib/utils.js +18 -4
- package/configure/lib/utils.js.map +1 -1
- package/configure/package.json +4 -4
- package/configure/src/__tests__/__snapshots__/hotspot-container.test.js.snap +2 -1
- package/configure/src/__tests__/__snapshots__/root.test.js.snap +56 -4
- package/configure/src/__tests__/hotspot-container.test.js +98 -71
- package/configure/src/__tests__/hotspot-drawable.test.js +48 -49
- package/configure/src/__tests__/index.test.js +28 -51
- package/configure/src/__tests__/root.test.js +162 -82
- package/configure/src/__tests__/utils.test.js +112 -98
- package/configure/src/button.jsx +4 -4
- package/configure/src/defaults.js +36 -18
- package/configure/src/hotspot-container.jsx +107 -97
- package/configure/src/hotspot-drawable.jsx +59 -53
- package/configure/src/hotspot-palette.jsx +12 -25
- package/configure/src/hotspot-polygon.jsx +20 -22
- package/configure/src/hotspot-rectangle.jsx +5 -15
- package/configure/src/index.js +32 -18
- package/configure/src/root.jsx +120 -51
- package/configure/src/upload-control.jsx +9 -20
- package/configure/src/utils.js +51 -22
- package/controller/CHANGELOG.md +72 -0
- package/controller/lib/defaults.js +2 -2
- package/controller/lib/defaults.js.map +1 -1
- package/controller/lib/index.js +57 -9
- package/controller/lib/index.js.map +1 -1
- package/controller/lib/utils.js.map +1 -1
- package/controller/package.json +2 -2
- package/controller/src/__tests__/index.test.js +99 -55
- package/controller/src/defaults.js +5 -9
- package/controller/src/index.js +58 -34
- package/controller/src/utils.js +9 -6
- package/docs/config-schema.json +217 -0
- package/docs/config-schema.json.md +169 -0
- package/docs/demo/config.js +2 -2
- package/docs/demo/generate.js +54 -35
- package/docs/demo/session.js +2 -2
- package/docs/pie-schema.json +59 -0
- package/docs/pie-schema.json.md +47 -0
- package/lib/hotspot/container.js +44 -7
- package/lib/hotspot/container.js.map +1 -1
- package/lib/hotspot/icons.js.map +1 -1
- package/lib/hotspot/image.js +35 -8
- package/lib/hotspot/image.js.map +1 -1
- package/lib/hotspot/index.js +72 -18
- package/lib/hotspot/index.js.map +1 -1
- package/lib/hotspot/polygon.js +51 -32
- package/lib/hotspot/polygon.js.map +1 -1
- package/lib/hotspot/rectangle.js +51 -32
- package/lib/hotspot/rectangle.js.map +1 -1
- package/lib/index.js +4 -1
- package/lib/index.js.map +1 -1
- package/lib/session-updater.js.map +1 -1
- package/package.json +7 -4
- package/src/__tests__/__snapshots__/{container-test.jsx.snap → container.test.jsx.snap} +8 -0
- package/src/__tests__/__snapshots__/image.test.jsx.snap +43 -0
- package/src/__tests__/__snapshots__/{polygon-test.jsx.snap → polygon.test.jsx.snap} +11 -0
- package/src/__tests__/__snapshots__/{rectangle-test.jsx.snap → rectangle.test.jsx.snap} +11 -0
- package/src/__tests__/container.test.jsx +214 -0
- package/src/__tests__/{image-test.jsx → image.test.jsx} +10 -2
- package/src/__tests__/polygon.test.jsx +235 -0
- package/src/__tests__/rectangle.test.jsx +237 -0
- package/src/__tests__/{session-updater-test.jsx → session-updater.test.jsx} +22 -31
- package/src/hotspot/container.jsx +60 -23
- package/src/hotspot/icons.js +4 -2
- package/src/hotspot/image.jsx +26 -13
- package/src/hotspot/index.jsx +73 -33
- package/src/hotspot/polygon.jsx +51 -40
- package/src/hotspot/rectangle.jsx +51 -40
- package/src/index.js +10 -18
- package/src/session-updater.js +1 -1
- package/src/__tests__/__snapshots__/image-test.jsx.snap +0 -21
- package/src/__tests__/container-test.jsx +0 -143
- package/src/__tests__/polygon-test.jsx +0 -76
- package/src/__tests__/rectangle-test.jsx +0 -77
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React, { Component } from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import classNames from 'classnames';
|
|
3
4
|
import { withStyles } from '@material-ui/core/styles/index';
|
|
4
5
|
import Help from '@material-ui/icons/Help';
|
|
5
6
|
|
|
@@ -10,6 +11,7 @@ import { getAllShapes, groupShapes } from './utils';
|
|
|
10
11
|
|
|
11
12
|
const isImage = (file) => {
|
|
12
13
|
const imageType = /image.*/;
|
|
14
|
+
|
|
13
15
|
return file.type.match(imageType);
|
|
14
16
|
};
|
|
15
17
|
|
|
@@ -19,7 +21,7 @@ export class Container extends Component {
|
|
|
19
21
|
return {
|
|
20
22
|
...prevState,
|
|
21
23
|
shapes: getAllShapes(nextProps.shapes),
|
|
22
|
-
}
|
|
24
|
+
};
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
constructor(props) {
|
|
@@ -28,16 +30,18 @@ export class Container extends Component {
|
|
|
28
30
|
this.state = {
|
|
29
31
|
dragEnabled: true,
|
|
30
32
|
// always transform shapes map into shapes array at this level
|
|
31
|
-
shapes: getAllShapes(props.shapes)
|
|
32
|
-
}
|
|
33
|
+
shapes: getAllShapes(props.shapes),
|
|
34
|
+
};
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
handleFileRead = (file) => {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
+
if (file instanceof Blob) {
|
|
39
|
+
const { onImageUpload } = this.props;
|
|
40
|
+
const reader = new FileReader();
|
|
38
41
|
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
reader.onloadend = () => onImageUpload(reader.result);
|
|
43
|
+
reader.readAsDataURL(file);
|
|
44
|
+
}
|
|
41
45
|
};
|
|
42
46
|
|
|
43
47
|
handleUploadImage = (e) => {
|
|
@@ -47,8 +51,17 @@ export class Container extends Component {
|
|
|
47
51
|
};
|
|
48
52
|
|
|
49
53
|
enableDropzone = () => this.setState({ dropzoneActive: true });
|
|
54
|
+
|
|
50
55
|
disableDropzone = () => this.setState({ dropzoneActive: false });
|
|
51
56
|
|
|
57
|
+
handleOnPaste = (e) => {
|
|
58
|
+
const { files } = e.clipboardData;
|
|
59
|
+
|
|
60
|
+
if (files && isImage(files[0])) {
|
|
61
|
+
this.handleFileRead(files[0]);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
|
|
52
65
|
handleOnDrop = (e) => {
|
|
53
66
|
e.preventDefault();
|
|
54
67
|
|
|
@@ -63,6 +76,7 @@ export class Container extends Component {
|
|
|
63
76
|
} else if (isImage(files[0])) {
|
|
64
77
|
this.handleFileRead(files[0]);
|
|
65
78
|
}
|
|
79
|
+
|
|
66
80
|
this.disableDropzone();
|
|
67
81
|
};
|
|
68
82
|
|
|
@@ -82,13 +96,13 @@ export class Container extends Component {
|
|
|
82
96
|
this.disableDropzone();
|
|
83
97
|
};
|
|
84
98
|
|
|
85
|
-
onUpdateShapes = newShapes => {
|
|
99
|
+
onUpdateShapes = (newShapes) => {
|
|
86
100
|
const { onUpdateShapes } = this.props;
|
|
87
101
|
|
|
88
102
|
this.setState(
|
|
89
103
|
{ shapes: newShapes },
|
|
90
104
|
// always transform shapes array back into shapes map when saving changes
|
|
91
|
-
() => onUpdateShapes(groupShapes(newShapes))
|
|
105
|
+
() => onUpdateShapes(groupShapes(newShapes)),
|
|
92
106
|
);
|
|
93
107
|
};
|
|
94
108
|
|
|
@@ -97,7 +111,7 @@ export class Container extends Component {
|
|
|
97
111
|
|
|
98
112
|
if (shapes && shapes.length) {
|
|
99
113
|
// sort by index value
|
|
100
|
-
let newShapes = shapes.sort((a, b) =>
|
|
114
|
+
let newShapes = shapes.sort((a, b) => parseInt(a.index) - parseInt(b.index));
|
|
101
115
|
|
|
102
116
|
newShapes = newShapes ? newShapes.slice(0, newShapes.length - 1) : [];
|
|
103
117
|
|
|
@@ -108,7 +122,9 @@ export class Container extends Component {
|
|
|
108
122
|
handleClearAll = () => this.onUpdateShapes([]);
|
|
109
123
|
|
|
110
124
|
handleEnableDrag = () => this.setState({ dragEnabled: true });
|
|
125
|
+
|
|
111
126
|
handleDisableDrag = () => this.setState({ dragEnabled: false });
|
|
127
|
+
|
|
112
128
|
handleInputClick = () => this.input.click();
|
|
113
129
|
|
|
114
130
|
toggleTooltip = () => this.setState({ showTooltip: !this.state.showTooltip });
|
|
@@ -117,30 +133,34 @@ export class Container extends Component {
|
|
|
117
133
|
const {
|
|
118
134
|
classes,
|
|
119
135
|
dimensions,
|
|
136
|
+
hasErrors,
|
|
120
137
|
hotspotColor,
|
|
121
138
|
imageUrl,
|
|
122
139
|
multipleCorrect,
|
|
123
140
|
onUpdateImageDimension,
|
|
124
141
|
outlineColor,
|
|
125
142
|
strokeWidth,
|
|
126
|
-
preserveAspectRatioEnabled
|
|
143
|
+
preserveAspectRatioEnabled,
|
|
127
144
|
} = this.props;
|
|
128
|
-
const {
|
|
129
|
-
dropzoneActive,
|
|
130
|
-
dragEnabled,
|
|
131
|
-
showTooltip
|
|
132
|
-
} = this.state;
|
|
145
|
+
const { dropzoneActive, dragEnabled, showTooltip } = this.state;
|
|
133
146
|
const { shapes } = this.state;
|
|
134
147
|
|
|
135
148
|
return (
|
|
136
149
|
<div className={classes.base}>
|
|
137
|
-
<div
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
150
|
+
<div
|
|
151
|
+
className={classNames(classes.box, {
|
|
152
|
+
[classes.boxError]: hasErrors && !dropzoneActive,
|
|
153
|
+
[classes.boxActive]: dropzoneActive,
|
|
154
|
+
})}
|
|
155
|
+
{...(dragEnabled
|
|
156
|
+
? {
|
|
157
|
+
onDragExit: this.handleOnDragExit,
|
|
158
|
+
onDragLeave: this.handleOnDragExit,
|
|
159
|
+
onDragOver: this.handleOnDragOver,
|
|
160
|
+
onDrop: this.handleOnDrop,
|
|
161
|
+
onPaste: this.handleOnPaste,
|
|
162
|
+
}
|
|
163
|
+
: {})}
|
|
144
164
|
>
|
|
145
165
|
<div className={classes.toolbar}>
|
|
146
166
|
{imageUrl && (
|
|
@@ -155,54 +175,46 @@ export class Container extends Component {
|
|
|
155
175
|
}}
|
|
156
176
|
/>
|
|
157
177
|
)}
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
label="Undo"
|
|
162
|
-
/>
|
|
163
|
-
<Button
|
|
164
|
-
disabled={!(shapes && shapes.length)}
|
|
165
|
-
onClick={this.handleClearAll}
|
|
166
|
-
label="Clear all"
|
|
167
|
-
/>
|
|
178
|
+
|
|
179
|
+
<Button disabled={!(shapes && shapes.length)} onClick={this.handleUndo} label="Undo" />
|
|
180
|
+
<Button disabled={!(shapes && shapes.length)} onClick={this.handleClearAll} label="Clear all" />
|
|
168
181
|
</div>
|
|
169
182
|
|
|
170
183
|
<div
|
|
171
|
-
ref={ref => {
|
|
184
|
+
ref={(ref) => {
|
|
172
185
|
this.imageSection = ref;
|
|
173
186
|
}}
|
|
174
|
-
className={classes.drawableHeight}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
187
|
+
className={classes.drawableHeight}
|
|
188
|
+
>
|
|
189
|
+
{imageUrl ? (
|
|
190
|
+
<Drawable
|
|
191
|
+
dimensions={dimensions}
|
|
192
|
+
disableDrag={this.handleDisableDrag}
|
|
193
|
+
enableDrag={this.handleEnableDrag}
|
|
194
|
+
imageUrl={imageUrl}
|
|
195
|
+
hotspotColor={hotspotColor}
|
|
196
|
+
multipleCorrect={multipleCorrect}
|
|
197
|
+
onUpdateImageDimension={onUpdateImageDimension}
|
|
198
|
+
onUpdateShapes={this.onUpdateShapes}
|
|
199
|
+
outlineColor={outlineColor}
|
|
200
|
+
shapes={shapes}
|
|
201
|
+
strokeWidth={strokeWidth}
|
|
202
|
+
preserveAspectRatioEnabled={preserveAspectRatioEnabled}
|
|
203
|
+
/>
|
|
204
|
+
) : (
|
|
205
|
+
<div className={classNames(classes.drawableHeight, classes.centered)}>
|
|
206
|
+
<label>Drag and drop or upload image from computer</label>
|
|
207
|
+
<br />
|
|
208
|
+
<UploadControl
|
|
209
|
+
label="Upload Image"
|
|
210
|
+
onInputClick={this.handleInputClick}
|
|
211
|
+
onUploadImage={this.handleUploadImage}
|
|
212
|
+
setRef={(ref) => {
|
|
213
|
+
this.input = ref;
|
|
214
|
+
}}
|
|
190
215
|
/>
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
<div className={`${classes.drawableHeight} ${classes.centered}`}>
|
|
194
|
-
<label>Drag and drop or upload image from computer</label>
|
|
195
|
-
<br/>
|
|
196
|
-
<UploadControl
|
|
197
|
-
label="Upload Image"
|
|
198
|
-
onInputClick={this.handleInputClick}
|
|
199
|
-
onUploadImage={this.handleUploadImage}
|
|
200
|
-
setRef={(ref) => {
|
|
201
|
-
this.input = ref;
|
|
202
|
-
}}
|
|
203
|
-
/>
|
|
204
|
-
</div>
|
|
205
|
-
)}
|
|
216
|
+
</div>
|
|
217
|
+
)}
|
|
206
218
|
</div>
|
|
207
219
|
|
|
208
220
|
{imageUrl && (
|
|
@@ -210,60 +222,58 @@ export class Container extends Component {
|
|
|
210
222
|
{showTooltip && (
|
|
211
223
|
<div className={classes.tooltipContent}>
|
|
212
224
|
<label>
|
|
213
|
-
Click and drag to create a hotspot. Click the hotspot to mark correct. Click
|
|
214
|
-
again to unmark.
|
|
225
|
+
Click and drag to create a hotspot. Click the hotspot to mark correct. Click again to unmark.
|
|
215
226
|
</label>
|
|
216
|
-
<div className={classes.tooltipArrow}/>
|
|
227
|
+
<div className={classes.tooltipArrow} />
|
|
217
228
|
</div>
|
|
218
229
|
)}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
onMouseOut={this.toggleTooltip}
|
|
222
|
-
onMouseOver={this.toggleTooltip}
|
|
223
|
-
/>
|
|
230
|
+
|
|
231
|
+
<Help className={classes.icon} onMouseOut={this.toggleTooltip} onMouseOver={this.toggleTooltip} />
|
|
224
232
|
</div>
|
|
225
233
|
)}
|
|
226
234
|
</div>
|
|
227
235
|
</div>
|
|
228
|
-
|
|
229
236
|
);
|
|
230
237
|
}
|
|
231
238
|
}
|
|
232
239
|
|
|
233
|
-
const styles = theme => ({
|
|
240
|
+
const styles = (theme) => ({
|
|
234
241
|
base: {
|
|
235
|
-
marginTop: theme.spacing.unit * 2
|
|
242
|
+
marginTop: theme.spacing.unit * 2,
|
|
236
243
|
},
|
|
237
244
|
box: {
|
|
238
245
|
border: '1px solid #E0E1E6',
|
|
239
|
-
borderRadius: '5px'
|
|
246
|
+
borderRadius: '5px',
|
|
240
247
|
},
|
|
241
248
|
boxActive: {
|
|
242
|
-
border: '1px solid #0032C2'
|
|
249
|
+
border: '1px solid #0032C2',
|
|
250
|
+
},
|
|
251
|
+
boxError: {
|
|
252
|
+
border: '1px solid red',
|
|
243
253
|
},
|
|
244
254
|
centered: {
|
|
245
255
|
alignItems: 'center',
|
|
246
256
|
display: 'flex',
|
|
247
257
|
flexDirection: 'column',
|
|
248
|
-
justifyContent: 'center'
|
|
258
|
+
justifyContent: 'center',
|
|
249
259
|
},
|
|
250
260
|
drawableHeight: {
|
|
251
261
|
minHeight: 350,
|
|
252
|
-
paddingBottom:
|
|
253
|
-
paddingRight:
|
|
262
|
+
paddingBottom: theme.spacing.unit * 5,
|
|
263
|
+
paddingRight: theme.spacing.unit * 5,
|
|
254
264
|
},
|
|
255
265
|
icon: {
|
|
256
266
|
'&:hover': {
|
|
257
267
|
color: '#333131',
|
|
258
|
-
cursor: 'help'
|
|
268
|
+
cursor: 'help',
|
|
259
269
|
},
|
|
260
|
-
color: '#C1C1C1'
|
|
270
|
+
color: '#C1C1C1',
|
|
261
271
|
},
|
|
262
272
|
replaceButton: {
|
|
263
273
|
marginLeft: 0,
|
|
264
274
|
},
|
|
265
275
|
replaceSection: {
|
|
266
|
-
marginRight: 'auto'
|
|
276
|
+
marginRight: 'auto',
|
|
267
277
|
},
|
|
268
278
|
toolbar: {
|
|
269
279
|
backgroundColor: '#ECEDF1',
|
|
@@ -272,25 +282,25 @@ const styles = theme => ({
|
|
|
272
282
|
borderTopRightRadius: '5px',
|
|
273
283
|
display: 'flex',
|
|
274
284
|
justifyContent: 'flex-end',
|
|
275
|
-
padding:
|
|
285
|
+
padding: theme.spacing.unit,
|
|
276
286
|
},
|
|
277
287
|
tooltip: {
|
|
278
288
|
position: 'relative',
|
|
279
289
|
textAlign: 'right',
|
|
280
|
-
padding:
|
|
290
|
+
padding: theme.spacing.unit,
|
|
281
291
|
},
|
|
282
292
|
tooltipContent: {
|
|
283
293
|
background: '#333131',
|
|
284
294
|
borderRadius: '4px',
|
|
285
295
|
color: '#FFFFFF',
|
|
286
|
-
fontSize:
|
|
296
|
+
fontSize: theme.typography.fontSize,
|
|
287
297
|
lineHeight: '18px',
|
|
288
|
-
marginTop: '-
|
|
289
|
-
padding:
|
|
298
|
+
marginTop: '-60px',
|
|
299
|
+
padding: theme.spacing.unit,
|
|
290
300
|
position: 'absolute',
|
|
291
301
|
right: '5px',
|
|
292
302
|
textAlign: 'left',
|
|
293
|
-
width: '300px'
|
|
303
|
+
width: '300px',
|
|
294
304
|
},
|
|
295
305
|
tooltipArrow: {
|
|
296
306
|
width: 0,
|
|
@@ -299,10 +309,10 @@ const styles = theme => ({
|
|
|
299
309
|
borderRight: '10px solid transparent',
|
|
300
310
|
borderTop: '10px solid #333131',
|
|
301
311
|
marginBottom: -10,
|
|
302
|
-
marginTop: '
|
|
312
|
+
marginTop: '4px',
|
|
303
313
|
position: 'absolute',
|
|
304
|
-
right: '5px'
|
|
305
|
-
}
|
|
314
|
+
right: '5px',
|
|
315
|
+
},
|
|
306
316
|
});
|
|
307
317
|
|
|
308
318
|
Container.propTypes = {
|
|
@@ -317,14 +327,14 @@ Container.propTypes = {
|
|
|
317
327
|
outlineColor: PropTypes.string.isRequired,
|
|
318
328
|
shapes: PropTypes.shape({
|
|
319
329
|
rectangles: PropTypes.array,
|
|
320
|
-
polygons: PropTypes.array
|
|
330
|
+
polygons: PropTypes.array,
|
|
321
331
|
}).isRequired,
|
|
322
332
|
strokeWidth: PropTypes.number,
|
|
323
|
-
preserveAspectRatioEnabled: PropTypes.bool
|
|
333
|
+
preserveAspectRatioEnabled: PropTypes.bool,
|
|
324
334
|
};
|
|
335
|
+
|
|
325
336
|
Container.defaultProps = {
|
|
326
|
-
strokeWidth: 5
|
|
337
|
+
strokeWidth: 5,
|
|
327
338
|
};
|
|
328
339
|
|
|
329
|
-
|
|
330
340
|
export default withStyles(styles)(Container);
|
|
@@ -9,6 +9,8 @@ import Rectangle from './hotspot-rectangle';
|
|
|
9
9
|
import Polygon from './hotspot-polygon';
|
|
10
10
|
import { updateImageDimensions, getUpdatedShapes } from './utils';
|
|
11
11
|
|
|
12
|
+
const IMAGE_MAX_WIDTH = 800;
|
|
13
|
+
|
|
12
14
|
export class Drawable extends React.Component {
|
|
13
15
|
static getDerivedStateFromProps(nextProps, prevState) {
|
|
14
16
|
let dimensions = nextProps.dimensions;
|
|
@@ -20,7 +22,7 @@ export class Drawable extends React.Component {
|
|
|
20
22
|
return {
|
|
21
23
|
...prevState,
|
|
22
24
|
dimensions: dimensions,
|
|
23
|
-
}
|
|
25
|
+
};
|
|
24
26
|
}
|
|
25
27
|
|
|
26
28
|
constructor(props) {
|
|
@@ -34,7 +36,7 @@ export class Drawable extends React.Component {
|
|
|
34
36
|
height: 0,
|
|
35
37
|
width: 0,
|
|
36
38
|
},
|
|
37
|
-
}
|
|
39
|
+
};
|
|
38
40
|
}
|
|
39
41
|
|
|
40
42
|
/// start of handling HotSpots section
|
|
@@ -43,7 +45,7 @@ export class Drawable extends React.Component {
|
|
|
43
45
|
const { onUpdateShapes, shapes } = this.props;
|
|
44
46
|
// Add a new rectangle at the mouse position with 0 width and height
|
|
45
47
|
const newShapes = shapes.slice();
|
|
46
|
-
const value = max(newShapes.map(c => parseInt(c.id)).filter(id => !isNaN(id))) || 0;
|
|
48
|
+
const value = max(newShapes.map((c) => parseInt(c.id)).filter((id) => !isNaN(id))) || 0;
|
|
47
49
|
|
|
48
50
|
newShapes.push({
|
|
49
51
|
id: `${value + 1}`,
|
|
@@ -52,7 +54,7 @@ export class Drawable extends React.Component {
|
|
|
52
54
|
x: e.evt.layerX,
|
|
53
55
|
y: e.evt.layerY,
|
|
54
56
|
group: 'rectangles',
|
|
55
|
-
index: shapes.length
|
|
57
|
+
index: shapes.length,
|
|
56
58
|
});
|
|
57
59
|
|
|
58
60
|
this.setState({ isDrawing: true, isDrawingShapeId: `${value + 1}` });
|
|
@@ -84,7 +86,7 @@ export class Drawable extends React.Component {
|
|
|
84
86
|
const mouseX = e.evt.layerX;
|
|
85
87
|
const mouseY = e.evt.layerY;
|
|
86
88
|
|
|
87
|
-
const currShapeIndex = shapes.findIndex(shape => shape.id === isDrawingShapeId);
|
|
89
|
+
const currShapeIndex = shapes.findIndex((shape) => shape.id === isDrawingShapeId);
|
|
88
90
|
const currShape = shapes[currShapeIndex];
|
|
89
91
|
|
|
90
92
|
if (currShape) {
|
|
@@ -98,7 +100,7 @@ export class Drawable extends React.Component {
|
|
|
98
100
|
height: newHeight,
|
|
99
101
|
width: newWidth,
|
|
100
102
|
x: currShape.x,
|
|
101
|
-
y: currShape.y
|
|
103
|
+
y: currShape.y,
|
|
102
104
|
};
|
|
103
105
|
|
|
104
106
|
// On mouse move don't trigger any event. Put the shapes on this state instead.
|
|
@@ -109,12 +111,12 @@ export class Drawable extends React.Component {
|
|
|
109
111
|
|
|
110
112
|
handleOnDragEnd = (id, updatedProps) => {
|
|
111
113
|
const { shapes, onUpdateShapes } = this.props;
|
|
112
|
-
const newShapes = shapes.map(shape => {
|
|
114
|
+
const newShapes = shapes.map((shape) => {
|
|
113
115
|
if (shape.id === id) {
|
|
114
116
|
return {
|
|
115
117
|
...shape,
|
|
116
|
-
...updatedProps
|
|
117
|
-
}
|
|
118
|
+
...updatedProps,
|
|
119
|
+
};
|
|
118
120
|
}
|
|
119
121
|
return shape;
|
|
120
122
|
});
|
|
@@ -129,17 +131,17 @@ export class Drawable extends React.Component {
|
|
|
129
131
|
let newShapes = [];
|
|
130
132
|
|
|
131
133
|
if (multipleCorrect) {
|
|
132
|
-
newShapes = shapes.map(shape => {
|
|
134
|
+
newShapes = shapes.map((shape) => {
|
|
133
135
|
if (shape.id === id) {
|
|
134
136
|
shape.correct = !shape.correct;
|
|
135
137
|
}
|
|
136
138
|
return shape;
|
|
137
|
-
})
|
|
139
|
+
});
|
|
138
140
|
} else {
|
|
139
|
-
newShapes = shapes.map(shape => {
|
|
141
|
+
newShapes = shapes.map((shape) => {
|
|
140
142
|
shape.correct = shape.id === id;
|
|
141
143
|
return shape;
|
|
142
|
-
})
|
|
144
|
+
});
|
|
143
145
|
}
|
|
144
146
|
|
|
145
147
|
onUpdateShapes(cloneDeep(newShapes));
|
|
@@ -153,15 +155,20 @@ export class Drawable extends React.Component {
|
|
|
153
155
|
const elementStyle = getComputedStyle(target);
|
|
154
156
|
const newHeight = parseFloat(elementStyle.height);
|
|
155
157
|
const newWidth = parseFloat(elementStyle.width);
|
|
158
|
+
const aspectWidth = newWidth / IMAGE_MAX_WIDTH;
|
|
156
159
|
|
|
157
|
-
const dimensions =
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
160
|
+
const dimensions =
|
|
161
|
+
newWidth > IMAGE_MAX_WIDTH
|
|
162
|
+
? {
|
|
163
|
+
height: newHeight / aspectWidth,
|
|
164
|
+
width: IMAGE_MAX_WIDTH,
|
|
165
|
+
}
|
|
166
|
+
: {
|
|
167
|
+
height: newHeight,
|
|
168
|
+
width: newWidth,
|
|
169
|
+
};
|
|
161
170
|
|
|
162
|
-
this.setState(
|
|
163
|
-
{ dimensions },
|
|
164
|
-
() => onUpdateImageDimension(dimensions));
|
|
171
|
+
this.setState({ dimensions }, () => onUpdateImageDimension(dimensions));
|
|
165
172
|
|
|
166
173
|
resizeHandle.addEventListener('mousedown', this.initialiseResize, false);
|
|
167
174
|
};
|
|
@@ -176,47 +183,43 @@ export class Drawable extends React.Component {
|
|
|
176
183
|
let drawable = true;
|
|
177
184
|
|
|
178
185
|
// Do not allow resizing over the hotspots
|
|
179
|
-
shapes &&
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
+
shapes &&
|
|
187
|
+
shapes.forEach((shape) => {
|
|
188
|
+
const right = shape.x + shape.width + 5;
|
|
189
|
+
const bottom = shape.y + shape.height + 5;
|
|
190
|
+
if (x <= right || y <= bottom) {
|
|
191
|
+
drawable = false;
|
|
192
|
+
}
|
|
193
|
+
});
|
|
186
194
|
return drawable;
|
|
187
195
|
}
|
|
188
196
|
|
|
189
197
|
startResizing = (e) => {
|
|
190
198
|
const bounds = e.target.getBoundingClientRect();
|
|
191
199
|
const box = this.image;
|
|
192
|
-
const {
|
|
193
|
-
disableDrag,
|
|
194
|
-
preserveAspectRatioEnabled,
|
|
195
|
-
dimensions,
|
|
196
|
-
shapes
|
|
197
|
-
} = this.props;
|
|
200
|
+
const { disableDrag, preserveAspectRatioEnabled, dimensions, shapes } = this.props;
|
|
198
201
|
|
|
199
202
|
// todo previously we had state.dimensions, is it needed?
|
|
200
203
|
const { width, height } = updateImageDimensions(
|
|
201
204
|
dimensions,
|
|
202
205
|
{
|
|
203
206
|
width: e.clientX - bounds.left,
|
|
204
|
-
height: e.clientY - bounds.top
|
|
207
|
+
height: e.clientY - bounds.top,
|
|
205
208
|
},
|
|
206
|
-
preserveAspectRatioEnabled
|
|
209
|
+
preserveAspectRatioEnabled,
|
|
207
210
|
);
|
|
208
211
|
|
|
209
212
|
const resizeValid = this.checkIfResizeValid(width, height);
|
|
210
213
|
const hasMinimumWidth = width > 150 && height > 150;
|
|
211
214
|
|
|
212
|
-
if (resizeValid && hasMinimumWidth) {
|
|
215
|
+
if (resizeValid && hasMinimumWidth && box) {
|
|
213
216
|
box.style.width = `${width}px`;
|
|
214
217
|
box.style.height = `${height}px`;
|
|
215
218
|
|
|
216
219
|
this.setState({
|
|
217
220
|
resizing: true,
|
|
218
221
|
dimensions: { height: height, width: width },
|
|
219
|
-
stateShapes: getUpdatedShapes(dimensions, { width, height }, shapes)
|
|
222
|
+
stateShapes: getUpdatedShapes(dimensions, { width, height }, shapes),
|
|
220
223
|
});
|
|
221
224
|
}
|
|
222
225
|
|
|
@@ -250,12 +253,12 @@ export class Drawable extends React.Component {
|
|
|
250
253
|
hotspotColor,
|
|
251
254
|
outlineColor,
|
|
252
255
|
shapes,
|
|
253
|
-
strokeWidth
|
|
256
|
+
strokeWidth,
|
|
254
257
|
} = this.props;
|
|
255
258
|
const {
|
|
256
259
|
stateShapes,
|
|
257
260
|
isDrawing,
|
|
258
|
-
dimensions: { height: heightFromState, width: widthFromState }
|
|
261
|
+
dimensions: { height: heightFromState, width: widthFromState },
|
|
259
262
|
} = this.state;
|
|
260
263
|
const shapesToUse = stateShapes || shapes;
|
|
261
264
|
|
|
@@ -266,15 +269,18 @@ export class Drawable extends React.Component {
|
|
|
266
269
|
<img
|
|
267
270
|
className={classes.image}
|
|
268
271
|
onLoad={this.handleOnImageLoad}
|
|
269
|
-
ref={ref => {
|
|
272
|
+
ref={(ref) => {
|
|
270
273
|
this.image = ref;
|
|
271
274
|
}}
|
|
272
275
|
src={imageUrl}
|
|
273
|
-
{...height && width ? { style: { height, width } } : {}}
|
|
276
|
+
{...(height && width ? { style: { height, width } } : {})}
|
|
277
|
+
/>
|
|
278
|
+
<div
|
|
279
|
+
ref={(ref) => {
|
|
280
|
+
this.resize = ref;
|
|
281
|
+
}}
|
|
282
|
+
className={classes.resize}
|
|
274
283
|
/>
|
|
275
|
-
<div ref={ref => {
|
|
276
|
-
this.resize = ref;
|
|
277
|
-
}} className={classes.resize}/>
|
|
278
284
|
</div>
|
|
279
285
|
)}
|
|
280
286
|
|
|
@@ -282,9 +288,9 @@ export class Drawable extends React.Component {
|
|
|
282
288
|
className={classes.stage}
|
|
283
289
|
height={heightFromState || height}
|
|
284
290
|
width={widthFromState || width}
|
|
285
|
-
onMouseDown={this.handleOnMouseDown
|
|
286
|
-
onMouseUp={this.handleOnMouseUp
|
|
287
|
-
onMouseMove={this.handleMouseMove
|
|
291
|
+
onMouseDown={this.handleOnMouseDown}
|
|
292
|
+
onMouseUp={this.handleOnMouseUp}
|
|
293
|
+
onMouseMove={this.handleMouseMove}
|
|
288
294
|
>
|
|
289
295
|
<Layer>
|
|
290
296
|
{shapesToUse.map((shape, index) => {
|
|
@@ -318,7 +324,7 @@ export class Drawable extends React.Component {
|
|
|
318
324
|
|
|
319
325
|
const styles = () => ({
|
|
320
326
|
base: {
|
|
321
|
-
position: 'relative'
|
|
327
|
+
position: 'relative',
|
|
322
328
|
},
|
|
323
329
|
image: {
|
|
324
330
|
alignItems: 'center',
|
|
@@ -327,7 +333,7 @@ const styles = () => ({
|
|
|
327
333
|
},
|
|
328
334
|
imageContainer: {
|
|
329
335
|
position: 'relative',
|
|
330
|
-
width: 'fit-content'
|
|
336
|
+
width: 'fit-content',
|
|
331
337
|
},
|
|
332
338
|
resize: {
|
|
333
339
|
borderBottom: '1px solid #727272',
|
|
@@ -337,13 +343,13 @@ const styles = () => ({
|
|
|
337
343
|
height: '10px',
|
|
338
344
|
position: 'absolute',
|
|
339
345
|
right: '-10px',
|
|
340
|
-
width: '10px'
|
|
346
|
+
width: '10px',
|
|
341
347
|
},
|
|
342
348
|
stage: {
|
|
343
349
|
left: 0,
|
|
344
350
|
top: 0,
|
|
345
|
-
position: 'absolute'
|
|
346
|
-
}
|
|
351
|
+
position: 'absolute',
|
|
352
|
+
},
|
|
347
353
|
});
|
|
348
354
|
|
|
349
355
|
Drawable.propTypes = {
|
|
@@ -359,7 +365,7 @@ Drawable.propTypes = {
|
|
|
359
365
|
outlineColor: PropTypes.string.isRequired,
|
|
360
366
|
shapes: PropTypes.array.isRequired,
|
|
361
367
|
strokeWidth: PropTypes.number,
|
|
362
|
-
preserveAspectRatioEnabled: PropTypes.bool
|
|
368
|
+
preserveAspectRatioEnabled: PropTypes.bool,
|
|
363
369
|
};
|
|
364
370
|
|
|
365
371
|
export default withStyles(styles)(Drawable);
|