@pie-element/drawing-response 12.1.2-next.1 → 12.1.2

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.
Files changed (172) hide show
  1. package/CHANGELOG.json +547 -0
  2. package/CHANGELOG.md +1966 -0
  3. package/LICENSE.md +5 -0
  4. package/README.md +1 -0
  5. package/configure/CHANGELOG.json +367 -0
  6. package/configure/CHANGELOG.md +1766 -0
  7. package/configure/lib/button.js +37 -0
  8. package/configure/lib/button.js.map +1 -0
  9. package/configure/lib/defaults.js +116 -0
  10. package/configure/lib/defaults.js.map +1 -0
  11. package/configure/lib/image-container.js +307 -0
  12. package/configure/lib/image-container.js.map +1 -0
  13. package/configure/lib/index.js +147 -0
  14. package/configure/lib/index.js.map +1 -0
  15. package/configure/lib/root.js +219 -0
  16. package/configure/lib/root.js.map +1 -0
  17. package/configure/package.json +24 -0
  18. package/configure/src/__tests__/image-container.test.jsx +231 -0
  19. package/configure/src/__tests__/index.test.js +72 -0
  20. package/configure/src/__tests__/root.test.jsx +110 -0
  21. package/configure/src/button.jsx +33 -0
  22. package/configure/src/defaults.js +80 -0
  23. package/configure/src/image-container.jsx +316 -0
  24. package/configure/src/index.js +167 -0
  25. package/configure/src/root.jsx +198 -0
  26. package/controller/CHANGELOG.json +52 -0
  27. package/controller/CHANGELOG.md +261 -0
  28. package/controller/lib/defaults.js +22 -0
  29. package/controller/lib/defaults.js.map +1 -0
  30. package/controller/lib/index.js +84 -0
  31. package/controller/lib/index.js.map +1 -0
  32. package/controller/package.json +16 -0
  33. package/controller/src/__tests__/index.test.js +172 -0
  34. package/controller/src/defaults.js +12 -0
  35. package/controller/src/index.js +71 -0
  36. package/docs/config-schema.json +1766 -0
  37. package/docs/config-schema.json.md +1313 -0
  38. package/docs/demo/config.js +8 -0
  39. package/docs/demo/generate.js +14 -0
  40. package/docs/demo/index.html +1 -0
  41. package/docs/demo/session.js +37 -0
  42. package/docs/pie-schema.json +823 -0
  43. package/docs/pie-schema.json.md +606 -0
  44. package/lib/drawing-response/button.js +49 -0
  45. package/lib/drawing-response/button.js.map +1 -0
  46. package/lib/drawing-response/constants.js +43 -0
  47. package/lib/drawing-response/constants.js.map +1 -0
  48. package/lib/drawing-response/container.js +327 -0
  49. package/lib/drawing-response/container.js.map +1 -0
  50. package/lib/drawing-response/drawable-circle.js +80 -0
  51. package/lib/drawing-response/drawable-circle.js.map +1 -0
  52. package/lib/drawing-response/drawable-eraser.js +64 -0
  53. package/lib/drawing-response/drawable-eraser.js.map +1 -0
  54. package/lib/drawing-response/drawable-free-path.js +71 -0
  55. package/lib/drawing-response/drawable-free-path.js.map +1 -0
  56. package/lib/drawing-response/drawable-helper.js +34 -0
  57. package/lib/drawing-response/drawable-helper.js.map +1 -0
  58. package/lib/drawing-response/drawable-image.js +41 -0
  59. package/lib/drawing-response/drawable-image.js.map +1 -0
  60. package/lib/drawing-response/drawable-line.js +75 -0
  61. package/lib/drawing-response/drawable-line.js.map +1 -0
  62. package/lib/drawing-response/drawable-main.js +345 -0
  63. package/lib/drawing-response/drawable-main.js.map +1 -0
  64. package/lib/drawing-response/drawable-palette.js +140 -0
  65. package/lib/drawing-response/drawable-palette.js.map +1 -0
  66. package/lib/drawing-response/drawable-rectangle.js +80 -0
  67. package/lib/drawing-response/drawable-rectangle.js.map +1 -0
  68. package/lib/drawing-response/drawable-text.js +295 -0
  69. package/lib/drawing-response/drawable-text.js.map +1 -0
  70. package/lib/drawing-response/drawable-transformer.js +52 -0
  71. package/lib/drawing-response/drawable-transformer.js.map +1 -0
  72. package/lib/drawing-response/factory.js +22 -0
  73. package/lib/drawing-response/factory.js.map +1 -0
  74. package/lib/drawing-response/icon.js +55 -0
  75. package/lib/drawing-response/icon.js.map +1 -0
  76. package/lib/drawing-response/index.js +91 -0
  77. package/lib/drawing-response/index.js.map +1 -0
  78. package/lib/index.js +68 -0
  79. package/lib/index.js.map +1 -0
  80. package/package.json +19 -83
  81. package/src/__tests__/drawing-index-test.jsx +103 -0
  82. package/src/drawing-response/__tests__/container.test.jsx +82 -0
  83. package/src/drawing-response/__tests__/drawable-helper.test.jsx +24 -0
  84. package/src/drawing-response/__tests__/drawing-main.test.jsx +855 -0
  85. package/src/drawing-response/__tests__/factory.test.js +13 -0
  86. package/src/drawing-response/button.jsx +45 -0
  87. package/src/drawing-response/constants.js +44 -0
  88. package/src/drawing-response/container.jsx +301 -0
  89. package/src/drawing-response/drawable-circle.jsx +74 -0
  90. package/src/drawing-response/drawable-eraser.jsx +53 -0
  91. package/src/drawing-response/drawable-free-path.jsx +59 -0
  92. package/src/drawing-response/drawable-helper.jsx +21 -0
  93. package/src/drawing-response/drawable-image.jsx +36 -0
  94. package/src/drawing-response/drawable-line.jsx +62 -0
  95. package/src/drawing-response/drawable-main.jsx +333 -0
  96. package/src/drawing-response/drawable-palette.jsx +99 -0
  97. package/src/drawing-response/drawable-rectangle.jsx +69 -0
  98. package/src/drawing-response/drawable-text.jsx +318 -0
  99. package/src/drawing-response/drawable-transformer.jsx +52 -0
  100. package/src/drawing-response/factory.js +17 -0
  101. package/src/drawing-response/icon.jsx +52 -0
  102. package/src/drawing-response/index.jsx +92 -0
  103. package/src/index.js +72 -0
  104. package/configure.js +0 -2
  105. package/controller.js +0 -1
  106. package/dist/author/button.d.ts +0 -29
  107. package/dist/author/button.js +0 -25
  108. package/dist/author/defaults.d.ts +0 -118
  109. package/dist/author/defaults.js +0 -86
  110. package/dist/author/image-container.d.ts +0 -42
  111. package/dist/author/image-container.js +0 -183
  112. package/dist/author/index.d.ts +0 -37
  113. package/dist/author/index.js +0 -79
  114. package/dist/author/root.d.ts +0 -17
  115. package/dist/author/root.js +0 -142
  116. package/dist/browser/MenuItem-DbAfJgc1.js +0 -10476
  117. package/dist/browser/MenuItem-DbAfJgc1.js.map +0 -1
  118. package/dist/browser/author/index.js +0 -37837
  119. package/dist/browser/author/index.js.map +0 -1
  120. package/dist/browser/browser-kkT1XVKw.js +0 -219
  121. package/dist/browser/browser-kkT1XVKw.js.map +0 -1
  122. package/dist/browser/controller/index.js +0 -61
  123. package/dist/browser/controller/index.js.map +0 -1
  124. package/dist/browser/delivery/index.js +0 -13560
  125. package/dist/browser/delivery/index.js.map +0 -1
  126. package/dist/browser/drawing-response.css +0 -2
  127. package/dist/controller/defaults.d.ts +0 -24
  128. package/dist/controller/defaults.js +0 -18
  129. package/dist/controller/index.d.ts +0 -13
  130. package/dist/controller/index.js +0 -46
  131. package/dist/delivery/drawing-response/button.d.ts +0 -31
  132. package/dist/delivery/drawing-response/button.js +0 -36
  133. package/dist/delivery/drawing-response/constants.d.ts +0 -16
  134. package/dist/delivery/drawing-response/constants.js +0 -40
  135. package/dist/delivery/drawing-response/container.d.ts +0 -32
  136. package/dist/delivery/drawing-response/container.js +0 -212
  137. package/dist/delivery/drawing-response/drawable-circle.d.ts +0 -18
  138. package/dist/delivery/drawing-response/drawable-circle.js +0 -51
  139. package/dist/delivery/drawing-response/drawable-eraser.d.ts +0 -17
  140. package/dist/delivery/drawing-response/drawable-eraser.js +0 -52
  141. package/dist/delivery/drawing-response/drawable-free-path.d.ts +0 -18
  142. package/dist/delivery/drawing-response/drawable-free-path.js +0 -52
  143. package/dist/delivery/drawing-response/drawable-helper.d.ts +0 -17
  144. package/dist/delivery/drawing-response/drawable-helper.js +0 -12
  145. package/dist/delivery/drawing-response/drawable-image.d.ts +0 -24
  146. package/dist/delivery/drawing-response/drawable-image.js +0 -28
  147. package/dist/delivery/drawing-response/drawable-line.d.ts +0 -18
  148. package/dist/delivery/drawing-response/drawable-line.js +0 -53
  149. package/dist/delivery/drawing-response/drawable-main.d.ts +0 -25
  150. package/dist/delivery/drawing-response/drawable-main.js +0 -210
  151. package/dist/delivery/drawing-response/drawable-palette.d.ts +0 -14
  152. package/dist/delivery/drawing-response/drawable-palette.js +0 -89
  153. package/dist/delivery/drawing-response/drawable-rectangle.d.ts +0 -18
  154. package/dist/delivery/drawing-response/drawable-rectangle.js +0 -49
  155. package/dist/delivery/drawing-response/drawable-text.d.ts +0 -30
  156. package/dist/delivery/drawing-response/drawable-text.js +0 -189
  157. package/dist/delivery/drawing-response/drawable-transformer.d.ts +0 -16
  158. package/dist/delivery/drawing-response/drawable-transformer.js +0 -35
  159. package/dist/delivery/drawing-response/factory.d.ts +0 -11
  160. package/dist/delivery/drawing-response/factory.js +0 -19
  161. package/dist/delivery/drawing-response/icon.d.ts +0 -19
  162. package/dist/delivery/drawing-response/icon.js +0 -52
  163. package/dist/delivery/drawing-response/index.d.ts +0 -18
  164. package/dist/delivery/drawing-response/index.js +0 -70
  165. package/dist/delivery/index.d.ts +0 -19
  166. package/dist/delivery/index.js +0 -47
  167. package/dist/index.d.ts +0 -1
  168. package/dist/index.iife.d.ts +0 -8
  169. package/dist/index.iife.js +0 -165
  170. package/dist/index.js +0 -2
  171. package/dist/runtime-support.d.ts +0 -12
  172. package/dist/runtime-support.js +0 -12
@@ -0,0 +1,13 @@
1
+ import factory from '../factory';
2
+
3
+ describe('factory', () => {
4
+ it('creates instance', () => {
5
+ const instance = factory('FreePathDrawable', {});
6
+ expect(instance).toBeDefined();
7
+ expect(instance.toJson().type).toEqual('FreePathDrawable');
8
+ });
9
+
10
+ it('throws error for unknown instance', () => {
11
+ expect(() => factory('?', {})).toThrow(/Can't find.*/);
12
+ });
13
+ });
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { styled } from '@mui/material/styles';
4
+ import Button from '@mui/material/Button';
5
+
6
+ const StyledButton = styled(Button)({
7
+ fontSize: '0.9em',
8
+ marginLeft: 8,
9
+ minWidth: 32,
10
+ height: 32,
11
+
12
+ '& span': {
13
+ '& svg': {
14
+ width: '1.3em !important',
15
+ height: '1.3em !important',
16
+ },
17
+ },
18
+ });
19
+
20
+ const CustomButton = ({ label, onClick, disabled, title }) => (
21
+ <StyledButton
22
+ title={title}
23
+ onClick={onClick}
24
+ disabled={disabled}
25
+ size="small"
26
+ variant="contained">
27
+ {label}
28
+ </StyledButton>
29
+ );
30
+
31
+ CustomButton.propTypes = {
32
+ disabled: PropTypes.bool,
33
+ label: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
34
+ onClick: PropTypes.func,
35
+ title: PropTypes.string,
36
+ };
37
+
38
+ CustomButton.defaultProps = {
39
+ disabled: false,
40
+ label: 'Add',
41
+ onClick: () => {},
42
+ title: '',
43
+ };
44
+
45
+ export default CustomButton;
@@ -0,0 +1,44 @@
1
+ export default {
2
+ tools: [
3
+ {
4
+ type: 'Select',
5
+ label: 'Select',
6
+ icon: 'mdiCursorDefault',
7
+ },
8
+ {
9
+ type: 'FreePathDrawable',
10
+ label: 'Free Draw',
11
+ icon: 'mdiPencil',
12
+ },
13
+ {
14
+ type: 'LineDrawable',
15
+ label: 'Line',
16
+ icon: 'mdiMinus',
17
+ },
18
+ {
19
+ type: 'RectangleDrawable',
20
+ label: 'Rectangle',
21
+ icon: 'mdiRectangle',
22
+ },
23
+ {
24
+ type: 'CircleDrawable',
25
+ label: 'Circle',
26
+ icon: 'mdiCircle',
27
+ },
28
+ {
29
+ type: 'Text',
30
+ label: 'Text Entry',
31
+ icon: 'mdiFormatColorText',
32
+ },
33
+ {
34
+ // ,{
35
+ // type: 'PaintBucket',
36
+ // label: 'Paint Bucket',
37
+ // icon: 'mdiFormatColorFill'
38
+ // },
39
+ type: 'EraserDrawable',
40
+ label: 'Eraser',
41
+ icon: 'mdiEraser',
42
+ },
43
+ ],
44
+ };
@@ -0,0 +1,301 @@
1
+ import React, { Component } from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { styled } from '@mui/material/styles';
4
+ import Translator from '@pie-lib/translator';
5
+
6
+ import constants from './constants';
7
+ import Button from './button';
8
+ import DrawablePalette from './drawable-palette';
9
+ import DrawableMain from './drawable-main';
10
+ import DrawableText from './drawable-text';
11
+ import Icon from './icon';
12
+
13
+ const { tools: TOOLS } = constants;
14
+ const { translator } = Translator;
15
+
16
+ const BaseContainer = styled('div')(({ theme }) => ({
17
+ marginTop: theme.spacing(2),
18
+ }));
19
+
20
+ const Box = styled('div')(({ theme }) => ({
21
+ border: '1px solid #E0E1E6',
22
+ borderRadius: '5px',
23
+ marginTop: theme.spacing(2),
24
+ backgroundColor: '#ECEDF1',
25
+ }));
26
+
27
+ const DrawableHeight = styled('div')({
28
+ minHeight: 350,
29
+ backgroundColor: '#fff',
30
+ });
31
+
32
+ const Toolbar = styled('div')(({ theme }) => ({
33
+ borderBottom: '1px solid #E0E1E6',
34
+ borderTopLeftRadius: '5px',
35
+ borderTopRightRadius: '5px',
36
+ padding: '12px 8px 4px',
37
+ boxSizing: 'border-box',
38
+ maxWidth: 'calc(100% - 163px)', // 163px is the width set on undoControls
39
+ '& button': {
40
+ marginBottom: theme.spacing(1),
41
+ },
42
+ }));
43
+
44
+ const ROGVAIV = ['red', 'orange', 'yellow', 'violet', 'blue', 'green', 'white', 'black'].map((c) => ({
45
+ value: c,
46
+ label: c,
47
+ }));
48
+
49
+ export class Container extends Component {
50
+ static propTypes = {
51
+ disabled: PropTypes.bool,
52
+ session: PropTypes.object.isRequired,
53
+ onSessionChange: PropTypes.func.isRequired,
54
+ imageDimensions: PropTypes.object.isRequired,
55
+ imageUrl: PropTypes.string.isRequired,
56
+ backgroundImageEnabled: PropTypes.bool.isRequired,
57
+ language: PropTypes.string,
58
+ };
59
+
60
+ constructor(props) {
61
+ super(props);
62
+ const TextEntry = new DrawableText();
63
+
64
+ this.state = {
65
+ scale: 1,
66
+ drawableDimensions: {
67
+ height: 0,
68
+ width: 0,
69
+ },
70
+ toolActive: TOOLS[0],
71
+ fillColor: 'white',
72
+ fillColorList: [
73
+ { value: 'transparent', label: 'no fill' },
74
+ { value: 'lightblue', label: 'light blue' },
75
+ { value: 'lightyellow', label: 'light yellow' },
76
+ ...ROGVAIV,
77
+ ],
78
+ outlineColor: 'black',
79
+ outlineColorList: ROGVAIV,
80
+ paintColor: 'red',
81
+ paintColorList: ROGVAIV,
82
+ TextEntry,
83
+ };
84
+ }
85
+
86
+ setTranslatedState(language) {
87
+ const translatedROGVAIV = ROGVAIV.map((c) => ({
88
+ value: c.value,
89
+ label: translator.t(`drawingResponse.${c.label}`, { lng: language }),
90
+ }));
91
+
92
+ this.setState({
93
+ fillColorList: [
94
+ { value: 'transparent', label: translator.t('drawingResponse.noFill', { lng: language }) },
95
+ { value: 'lightblue', label: translator.t('drawingResponse.lightblue', { lng: language }) },
96
+ { value: 'lightyellow', label: translator.t('drawingResponse.lightyellow', { lng: language }) },
97
+ ...translatedROGVAIV,
98
+ ],
99
+ paintColor: translator.t('drawingResponse.red', { lng: language }),
100
+ outlineColorList: translatedROGVAIV,
101
+ paintColorList: translatedROGVAIV,
102
+ });
103
+ }
104
+
105
+ UNSAFE_componentWillReceiveProps(props) {
106
+ const { language } = props;
107
+ this.setTranslatedState(language);
108
+ }
109
+
110
+ setDimensions() {
111
+ const checkExist = setInterval(() => {
112
+ try {
113
+ const { height, width } = this.drawable.getBoundingClientRect();
114
+ const effectiveWidth = this.props.session.width || width;
115
+
116
+ if (height !== 0 && width !== 0) {
117
+ this.setState({
118
+ drawableDimensions: {
119
+ height,
120
+ width: effectiveWidth,
121
+ },
122
+ });
123
+ }
124
+ } catch (e) {
125
+ // eslint-disable-next-line no-console
126
+ console.warn('setDimensions Error: ', e);
127
+ } finally {
128
+ clearInterval(checkExist);
129
+ }
130
+ }, 100);
131
+ }
132
+
133
+ componentDidMount() {
134
+ const { language } = this.props;
135
+ this.setTranslatedState(language);
136
+
137
+ this.setDimensions();
138
+
139
+ this.observer = new MutationObserver((mutations) => {
140
+ mutations.forEach(() => {
141
+ const target = document.getElementById('question-container')?.style?.cssText;
142
+ const zoom = target?.substring(target.indexOf('--pie-zoom') + 11, target.lastIndexOf('%'));
143
+ const zoomParsed = zoom?.replace(/\s/g, '');
144
+
145
+ if (zoomParsed) {
146
+ const newScale = parseFloat(zoomParsed) / 100;
147
+ if (newScale !== this.state.scale) {
148
+ this.setState({
149
+ scale: parseFloat(zoomParsed) / 100,
150
+ });
151
+ }
152
+ } else if (!zoomParsed && this.state.scale !== 1) {
153
+ this.setState({
154
+ scale: 1,
155
+ });
156
+ }
157
+ });
158
+ });
159
+
160
+ // Use ResizeObserver to detect when the drawable container becomes visible
161
+ // (e.g., after switching from build to item preview in New Item Bank) and trigger dimension calculation.
162
+ // This helps ensure the canvas is properly sized even when componentDidMount is not re-triggered.
163
+ this.resizeObserver = new ResizeObserver(() => {
164
+ this.setDimensions();
165
+ });
166
+
167
+ if (this.drawable) {
168
+ this.resizeObserver.observe(this.drawable);
169
+ }
170
+
171
+ const target = document.getElementById('question-container');
172
+ if (target) {
173
+ this.observer.observe(target, { attributes: true, attributeFilter: ['style'] });
174
+ }
175
+ }
176
+
177
+ componentWillUnmount() {
178
+ const { TextEntry } = this.state;
179
+
180
+ TextEntry.removeEventListeners();
181
+ this.observer?.disconnect();
182
+ this.resizeObserver?.disconnect();
183
+ }
184
+
185
+ handleMakeToolActive(tool) {
186
+ const { TextEntry } = this.state;
187
+ const { type } = tool;
188
+ const { language } = this.props;
189
+
190
+ if (type !== 'Text') {
191
+ this.setState({
192
+ toolActive: tool,
193
+ });
194
+ } else {
195
+ TextEntry.addNewTextEntry(language);
196
+ // Force update
197
+ this.setState({
198
+ updatedAt: new Date(),
199
+ });
200
+ }
201
+ }
202
+
203
+ checkIfToolIsDisabled = (type) => {
204
+ if (this.props.disabled) return true;
205
+
206
+ const { toolActive } = this.state;
207
+ // Text will never be disabled since on each "Text Entry" click a new text is added
208
+ if (type === 'Text') {
209
+ return false;
210
+ }
211
+ return type === toolActive.type;
212
+ };
213
+
214
+ handleColorChange(type, color) {
215
+ const cType = `${type}Color`;
216
+ this.setState({
217
+ [cType]: color,
218
+ });
219
+ }
220
+
221
+ render() {
222
+ const { disabled, imageUrl, imageDimensions, onSessionChange, session, backgroundImageEnabled, language } =
223
+ this.props;
224
+ const {
225
+ drawableDimensions,
226
+ toolActive,
227
+ fillColor,
228
+ fillColorList,
229
+ outlineColor,
230
+ outlineColorList,
231
+ paintColor,
232
+ paintColorList,
233
+ TextEntry,
234
+ } = this.state;
235
+
236
+ const heightToUse = drawableDimensions.height * this.state.scale;
237
+
238
+ return (
239
+ <BaseContainer>
240
+ {!disabled && (
241
+ <DrawablePalette
242
+ fillColor={fillColor}
243
+ fillList={fillColorList}
244
+ outlineColor={outlineColor}
245
+ outlineList={outlineColorList}
246
+ paintColor={paintColor}
247
+ paintList={paintColorList}
248
+ onFillColorChange={(color) => this.handleColorChange('fill', color)}
249
+ onOutlineColorChange={(color) => this.handleColorChange('outline', color)}
250
+ onPaintColorChange={(color) => this.handleColorChange('paint', color)}
251
+ language={language}
252
+ />
253
+ )}
254
+
255
+ <Box>
256
+ <Toolbar>
257
+ {TOOLS.map((tool) => {
258
+ const { type, label, icon } = tool;
259
+
260
+ return (
261
+ <Button
262
+ title={label}
263
+ key={type}
264
+ disabled={this.checkIfToolIsDisabled(type)}
265
+ onClick={() => this.handleMakeToolActive(tool)}
266
+ label={<Icon path={icon} />}
267
+ />
268
+ );
269
+ })}
270
+ </Toolbar>
271
+
272
+ <DrawableHeight
273
+ ref={(drawable) => {
274
+ this.drawable = drawable;
275
+ }}
276
+ style={{ height: heightToUse, maxHeight: heightToUse, overflow: 'scroll' }}
277
+ >
278
+ <DrawableMain
279
+ scale={this.state.scale}
280
+ session={session}
281
+ disabled={disabled}
282
+ onSessionChange={onSessionChange}
283
+ fillColor={fillColor}
284
+ outlineColor={outlineColor}
285
+ paintColor={paintColor}
286
+ imageUrl={imageUrl}
287
+ drawableDimensions={drawableDimensions}
288
+ imageDimensions={imageDimensions}
289
+ toolActive={toolActive}
290
+ TextEntry={TextEntry}
291
+ backgroundImageEnabled={backgroundImageEnabled}
292
+ language={language}
293
+ />
294
+ </DrawableHeight>
295
+ </Box>
296
+ </BaseContainer>
297
+ );
298
+ }
299
+ }
300
+
301
+ export default Container;
@@ -0,0 +1,74 @@
1
+ import React from 'react';
2
+ import { Circle } from 'react-konva';
3
+
4
+ import DrawableHelper from './drawable-helper';
5
+
6
+ export default class CircleDrawable extends DrawableHelper {
7
+ static TYPE = 'CircleDrawable';
8
+ constructor(props) {
9
+ super(props, CircleDrawable.TYPE);
10
+ const { startx, starty, x, y } = props;
11
+
12
+ this.startx = startx;
13
+ this.starty = starty;
14
+ this.x = x || startx;
15
+ this.y = y || starty;
16
+
17
+ const dx = this.startx - this.x;
18
+ const dy = this.starty - this.y;
19
+
20
+ this.radius = Math.sqrt(dx * dx + dy * dy);
21
+ }
22
+
23
+ registerMovement(x, y) {
24
+ this.x = x;
25
+ this.y = y;
26
+
27
+ const dx = this.startx - this.x;
28
+ const dy = this.starty - this.y;
29
+
30
+ this.radius = Math.sqrt(dx * dx + dy * dy);
31
+ }
32
+
33
+ handleOnClick(props) {
34
+ const { paint, paintColor, forceUpdate } = props;
35
+
36
+ if (paint) {
37
+ this.paintColor = paintColor;
38
+ forceUpdate();
39
+ }
40
+ }
41
+
42
+ handleDragEnd = (props, event) => {
43
+ const deltaX = this.startx - event.target.getX();
44
+ const deltaY = this.starty - event.target.getY();
45
+
46
+ this.startx = event.target.getX();
47
+ this.starty = event.target.getY();
48
+
49
+ this.x = this.x - deltaX;
50
+ this.y = this.y - deltaY;
51
+
52
+ props.handleSessionChange();
53
+ };
54
+
55
+ render(props) {
56
+ const { draggable, key, onMouseOverElement, onMouseOutElement } = props;
57
+
58
+ return (
59
+ <Circle
60
+ key={key}
61
+ draggable={draggable}
62
+ radius={this.radius}
63
+ x={this.startx}
64
+ y={this.starty}
65
+ fill={this.paintColor || this.fillColor}
66
+ onClick={() => this.handleOnClick(props)}
67
+ onDragEnd={this.handleDragEnd.bind(this, props)}
68
+ onMouseEnter={onMouseOverElement}
69
+ onMouseLeave={onMouseOutElement}
70
+ stroke={this.outlineColor}
71
+ />
72
+ );
73
+ }
74
+ }
@@ -0,0 +1,53 @@
1
+ import React from 'react';
2
+ import { Line } from 'react-konva';
3
+
4
+ import DrawableHelper from './drawable-helper';
5
+
6
+ export default class EraserDrawable extends DrawableHelper {
7
+ static TYPE = 'EraserDrawable';
8
+ constructor(props) {
9
+ super(props, EraserDrawable.TYPE);
10
+ const { startx, starty, points, posX, posY } = props;
11
+
12
+ this.points = points || [startx, starty];
13
+ this.posX = posX || 0;
14
+ this.posY = posY || 0;
15
+ }
16
+
17
+ registerMovement(x, y) {
18
+ this.points = [...this.points, x, y];
19
+ }
20
+
21
+ handleDragEnd = (props, event) => {
22
+ this.posX = event.target.getX();
23
+ this.posY = event.target.getY();
24
+
25
+ props.handleSessionChange();
26
+ };
27
+
28
+ render(props) {
29
+ const { draggable, key, onMouseOverElement, onMouseOutElement } = props;
30
+
31
+ return (
32
+ <Line
33
+ key={key}
34
+ draggable={draggable}
35
+ globalCompositeOperation="destination-out"
36
+ tension={0}
37
+ bezier={true}
38
+ points={this.points}
39
+ onDragEnd={this.handleDragEnd.bind(this, props)}
40
+ onMouseEnter={onMouseOverElement}
41
+ onMouseLeave={onMouseOutElement}
42
+ strokeStyle="#df4b26"
43
+ lineJoin="round"
44
+ lineWidth="5"
45
+ fill="white"
46
+ stroke="white"
47
+ strokeWidth={5}
48
+ x={this.posX}
49
+ y={this.posY}
50
+ />
51
+ );
52
+ }
53
+ }
@@ -0,0 +1,59 @@
1
+ import React from 'react';
2
+ import { Line } from 'react-konva';
3
+
4
+ import DrawableHelper from './drawable-helper';
5
+
6
+ export default class FreePathDrawable extends DrawableHelper {
7
+ static TYPE = 'FreePathDrawable';
8
+
9
+ constructor(props) {
10
+ super(props, FreePathDrawable.TYPE);
11
+ const { startx, starty, points, posX, posY } = props;
12
+
13
+ this.points = points || [startx, starty];
14
+ this.posX = posX || 0;
15
+ this.posY = posY || 0;
16
+ }
17
+
18
+ registerMovement(x, y) {
19
+ this.points = [...this.points, x, y];
20
+ }
21
+
22
+ handleOnClick(props) {
23
+ const { paint, paintColor, forceUpdate } = props;
24
+
25
+ if (paint) {
26
+ this.paintColor = paintColor;
27
+ forceUpdate();
28
+ }
29
+ }
30
+
31
+ handleDragEnd = (props, event) => {
32
+ this.posX = event.target.getX();
33
+ this.posY = event.target.getY();
34
+
35
+ props.handleSessionChange();
36
+ };
37
+
38
+ render(props) {
39
+ const { draggable, key, onMouseOverElement, onMouseOutElement } = props;
40
+
41
+ return (
42
+ <Line
43
+ key={key}
44
+ draggable={draggable}
45
+ tension={0}
46
+ bezier={true}
47
+ points={this.points}
48
+ fill={this.paintColor || this.fillColor}
49
+ onClick={() => this.handleOnClick(props)}
50
+ onDragEnd={this.handleDragEnd.bind(this, props)}
51
+ onMouseEnter={onMouseOverElement}
52
+ onMouseLeave={onMouseOutElement}
53
+ stroke={this.paintColor || this.outlineColor}
54
+ x={this.posX}
55
+ y={this.posY}
56
+ />
57
+ );
58
+ }
59
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Not using React in order to avoid performance issues.
3
+ * If you switch this class to a React one make sure that
4
+ * this interaction will not have performance leaks in pie-website nor in pits.
5
+ */
6
+ export default class DrawableHelper {
7
+ constructor(props, type) {
8
+ const { startx, starty, fillColor, outlineColor, createdAt } = props;
9
+ this.startx = startx;
10
+ this.starty = starty;
11
+ this.createdAt = createdAt;
12
+ this.fillColor = fillColor;
13
+ this.outlineColor = outlineColor;
14
+ this.type = type;
15
+ }
16
+
17
+ toJson() {
18
+ const base = JSON.parse(JSON.stringify(this));
19
+ return base;
20
+ }
21
+ }
@@ -0,0 +1,36 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import { styled } from '@mui/material/styles';
4
+
5
+ const ImageContainer = styled('div')({
6
+ position: 'relative',
7
+ width: 'fit-content',
8
+ });
9
+
10
+ const Image = styled('img')({
11
+ alignItems: 'center',
12
+ display: 'flex',
13
+ justifyContent: 'center',
14
+ });
15
+
16
+ const DrawableImage = ({ url, dimensions: { height, width } }) => (
17
+ <ImageContainer>
18
+ <Image
19
+ alt="drawing-response-image"
20
+ src={url}
21
+ style={{
22
+ height,
23
+ maxWidth: width,
24
+ maxHeight: 350,
25
+ width,
26
+ }}
27
+ />
28
+ </ImageContainer>
29
+ );
30
+
31
+ DrawableImage.propTypes = {
32
+ dimensions: PropTypes.object.isRequired,
33
+ url: PropTypes.string.isRequired,
34
+ };
35
+
36
+ export default DrawableImage;