@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
package/src/hotspot/image.jsx
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import { Image } from 'react-konva';
|
|
3
|
+
import { Group, Image, Text, Tag, Label } from 'react-konva';
|
|
4
4
|
|
|
5
5
|
class ImageComponent extends React.Component {
|
|
6
6
|
constructor(props) {
|
|
7
7
|
super(props);
|
|
8
8
|
this.state = {
|
|
9
|
-
image: null
|
|
9
|
+
image: null,
|
|
10
|
+
showTooltip: false,
|
|
10
11
|
};
|
|
11
12
|
}
|
|
12
13
|
|
|
@@ -34,22 +35,33 @@ class ImageComponent extends React.Component {
|
|
|
34
35
|
|
|
35
36
|
handleLoad = () => {
|
|
36
37
|
this.setState({
|
|
37
|
-
image: this.image
|
|
38
|
+
image: this.image,
|
|
38
39
|
});
|
|
39
40
|
};
|
|
40
41
|
|
|
41
42
|
render() {
|
|
42
|
-
const { x, y } = this.props;
|
|
43
|
-
const { image } = this.state;
|
|
43
|
+
const { x, y, tooltip } = this.props;
|
|
44
|
+
const { image, showTooltip } = this.state;
|
|
44
45
|
|
|
45
46
|
return (
|
|
46
|
-
<
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
47
|
+
<Group>
|
|
48
|
+
<Image
|
|
49
|
+
width={20}
|
|
50
|
+
height={20}
|
|
51
|
+
x={x}
|
|
52
|
+
y={y}
|
|
53
|
+
image={image}
|
|
54
|
+
onMouseEnter={() => this.setState({ showTooltip: true })}
|
|
55
|
+
onMouseLeave={() => this.setState({ showTooltip: false })}
|
|
56
|
+
/>
|
|
57
|
+
|
|
58
|
+
{showTooltip && tooltip && (
|
|
59
|
+
<Label x={x - 30} y={y + 25}>
|
|
60
|
+
<Tag fill="white" cornerRadius={5} opacity={0.9} />
|
|
61
|
+
<Text text={tooltip} padding={5} />
|
|
62
|
+
</Label>
|
|
63
|
+
)}
|
|
64
|
+
</Group>
|
|
53
65
|
);
|
|
54
66
|
}
|
|
55
67
|
}
|
|
@@ -57,7 +69,8 @@ class ImageComponent extends React.Component {
|
|
|
57
69
|
ImageComponent.propTypes = {
|
|
58
70
|
src: PropTypes.string.isRequired,
|
|
59
71
|
x: PropTypes.number.isRequired,
|
|
60
|
-
y: PropTypes.number.isRequired
|
|
72
|
+
y: PropTypes.number.isRequired,
|
|
73
|
+
tooltip: PropTypes.string,
|
|
61
74
|
};
|
|
62
75
|
|
|
63
76
|
export default ImageComponent;
|
package/src/hotspot/index.jsx
CHANGED
|
@@ -1,18 +1,54 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import Typography from '@material-ui/core/Typography';
|
|
4
|
-
import
|
|
5
|
-
import
|
|
4
|
+
import CorrectAnswerToggle from '@pie-lib/correct-answer-toggle';
|
|
5
|
+
import { Collapsible, hasText, PreviewPrompt } from '@pie-lib/render-ui';
|
|
6
6
|
import { withStyles } from '@material-ui/core/styles';
|
|
7
7
|
|
|
8
|
+
import Container from './container';
|
|
9
|
+
|
|
8
10
|
class HotspotComponent extends React.Component {
|
|
9
11
|
constructor(props) {
|
|
10
12
|
super(props);
|
|
11
13
|
this.state = {
|
|
12
|
-
showCorrect: false
|
|
14
|
+
showCorrect: false,
|
|
15
|
+
observer: null,
|
|
16
|
+
scale: 1,
|
|
13
17
|
};
|
|
14
18
|
}
|
|
15
19
|
|
|
20
|
+
componentDidMount() {
|
|
21
|
+
this.observer = new MutationObserver((mutations) => {
|
|
22
|
+
mutations.forEach(() => {
|
|
23
|
+
const target = document.getElementById('question-container')?.style?.cssText;
|
|
24
|
+
const zoom = target?.substring(target.indexOf('--pie-zoom') + 11, target.lastIndexOf('%'));
|
|
25
|
+
|
|
26
|
+
const zoomParsed = zoom?.replace(/\s/g, '');
|
|
27
|
+
if (zoomParsed) {
|
|
28
|
+
const newScale = parseFloat(zoomParsed) / 100;
|
|
29
|
+
if (newScale !== this.state.scale) {
|
|
30
|
+
this.setState({
|
|
31
|
+
scale: parseFloat(zoomParsed) / 100,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
} else if (!zoomParsed && this.state.scale !== 1) {
|
|
35
|
+
this.setState({
|
|
36
|
+
scale: 1,
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const target = document.getElementById('question-container');
|
|
43
|
+
if (target) {
|
|
44
|
+
this.observer.observe(target, { attributes: true, attributeFilter: ['style'] });
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
componentWillUnmount() {
|
|
49
|
+
this.observer?.disconnect();
|
|
50
|
+
}
|
|
51
|
+
|
|
16
52
|
onToggle = () => {
|
|
17
53
|
const { showCorrect } = this.state;
|
|
18
54
|
this.setState({ showCorrect: !showCorrect });
|
|
@@ -33,29 +69,37 @@ class HotspotComponent extends React.Component {
|
|
|
33
69
|
dimensions,
|
|
34
70
|
rationale,
|
|
35
71
|
teacherInstructions,
|
|
36
|
-
strokeWidth
|
|
72
|
+
strokeWidth,
|
|
73
|
+
responseCorrect,
|
|
37
74
|
},
|
|
38
75
|
onSelectChoice,
|
|
39
|
-
classes
|
|
76
|
+
classes,
|
|
40
77
|
} = this.props;
|
|
41
|
-
|
|
78
|
+
const { showCorrect } = this.state;
|
|
42
79
|
const isEvaluateMode = mode === 'evaluate';
|
|
80
|
+
const showCorrectAnswerToggle = isEvaluateMode && !responseCorrect;
|
|
43
81
|
|
|
44
82
|
return (
|
|
45
83
|
<div>
|
|
46
|
-
{
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
84
|
+
{showCorrectAnswerToggle && (
|
|
85
|
+
<CorrectAnswerToggle
|
|
86
|
+
show={showCorrectAnswerToggle}
|
|
87
|
+
toggled={showCorrect}
|
|
88
|
+
onToggle={this.onToggle.bind(this)}
|
|
89
|
+
/>
|
|
90
|
+
)}
|
|
91
|
+
{showCorrectAnswerToggle && <br />}
|
|
92
|
+
{teacherInstructions && hasText(teacherInstructions) && (
|
|
93
|
+
<Collapsible
|
|
94
|
+
labels={{ hidden: 'Show Teacher Instructions', visible: 'Hide Teacher Instructions' }}
|
|
95
|
+
className={classes.collapsible}
|
|
96
|
+
>
|
|
97
|
+
<PreviewPrompt className="prompt" prompt={teacherInstructions} />
|
|
98
|
+
</Collapsible>
|
|
99
|
+
)}
|
|
56
100
|
|
|
57
101
|
<Typography className={classes.prompt}>
|
|
58
|
-
<
|
|
102
|
+
<PreviewPrompt className="prompt" prompt={prompt} />
|
|
59
103
|
</Typography>
|
|
60
104
|
|
|
61
105
|
{imageUrl ? (
|
|
@@ -71,20 +115,16 @@ class HotspotComponent extends React.Component {
|
|
|
71
115
|
shapes={shapes}
|
|
72
116
|
disabled={disabled}
|
|
73
117
|
strokeWidth={strokeWidth}
|
|
118
|
+
scale={this.state.scale}
|
|
119
|
+
showCorrect={showCorrect}
|
|
74
120
|
/>
|
|
75
121
|
) : null}
|
|
76
122
|
|
|
77
|
-
{
|
|
78
|
-
|
|
79
|
-
<
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
>
|
|
83
|
-
<div dangerouslySetInnerHTML={{ __html: rationale }} />
|
|
84
|
-
</Collapsible>
|
|
85
|
-
)
|
|
86
|
-
}
|
|
87
|
-
|
|
123
|
+
{rationale && hasText(rationale) && (
|
|
124
|
+
<Collapsible labels={{ hidden: 'Show Rationale', visible: 'Hide Rationale' }} className={classes.collapsible}>
|
|
125
|
+
<PreviewPrompt className="prompt" prompt={rationale} />
|
|
126
|
+
</Collapsible>
|
|
127
|
+
)}
|
|
88
128
|
</div>
|
|
89
129
|
);
|
|
90
130
|
}
|
|
@@ -94,21 +134,21 @@ HotspotComponent.propTypes = {
|
|
|
94
134
|
classes: PropTypes.object,
|
|
95
135
|
model: PropTypes.object.isRequired,
|
|
96
136
|
onSelectChoice: PropTypes.func.isRequired,
|
|
97
|
-
session: PropTypes.object.isRequired
|
|
137
|
+
session: PropTypes.object.isRequired,
|
|
98
138
|
};
|
|
99
139
|
|
|
100
140
|
HotspotComponent.defaultProps = {
|
|
101
|
-
classes: {}
|
|
141
|
+
classes: {},
|
|
102
142
|
};
|
|
103
143
|
|
|
104
|
-
const styles = theme => ({
|
|
144
|
+
const styles = (theme) => ({
|
|
105
145
|
collapsible: {
|
|
106
146
|
paddingTop: theme.spacing.unit * 2,
|
|
107
147
|
paddingBottom: theme.spacing.unit * 2,
|
|
108
148
|
},
|
|
109
149
|
prompt: {
|
|
110
|
-
fontSize: 'inherit'
|
|
111
|
-
}
|
|
150
|
+
fontSize: 'inherit',
|
|
151
|
+
},
|
|
112
152
|
});
|
|
113
153
|
|
|
114
154
|
export default withStyles(styles)(HotspotComponent);
|
package/src/hotspot/polygon.jsx
CHANGED
|
@@ -14,10 +14,10 @@ class PolygonComponent extends React.Component {
|
|
|
14
14
|
getPolygonCenter = (points) => {
|
|
15
15
|
const x = points.map(({ x }) => x);
|
|
16
16
|
const y = points.map(({ y }) => y);
|
|
17
|
-
const minX = Math.min.apply
|
|
18
|
-
const maxX = Math.max.apply
|
|
19
|
-
const minY = Math.min.apply
|
|
20
|
-
const maxY = Math.max.apply
|
|
17
|
+
const minX = Math.min.apply(null, x);
|
|
18
|
+
const maxX = Math.max.apply(null, x);
|
|
19
|
+
const minY = Math.min.apply(null, y);
|
|
20
|
+
const maxY = Math.max.apply(null, y);
|
|
21
21
|
return [(minX + maxX) / 2, (minY + maxY) / 2];
|
|
22
22
|
};
|
|
23
23
|
|
|
@@ -51,20 +51,11 @@ class PolygonComponent extends React.Component {
|
|
|
51
51
|
document.body.style.cursor = 'default';
|
|
52
52
|
};
|
|
53
53
|
|
|
54
|
-
getEvaluateOutlineColor = (isCorrect, outlineColor) =>
|
|
54
|
+
getEvaluateOutlineColor = (isCorrect, markAsCorrect, outlineColor) =>
|
|
55
|
+
markAsCorrect ? 'green' : isCorrect ? outlineColor : 'red';
|
|
55
56
|
|
|
56
|
-
getOutlineWidth = (selected, strokeWidth) =>
|
|
57
|
-
|
|
58
|
-
getEvaluateText = (isCorrect, selected) => {
|
|
59
|
-
if (selected && isCorrect) {
|
|
60
|
-
return 'Correctly\nselected';
|
|
61
|
-
} else if (selected && !isCorrect) {
|
|
62
|
-
return 'Incorrectly\nselected';
|
|
63
|
-
} else if (!selected && isCorrect) {
|
|
64
|
-
return 'Correctly\nunselected';
|
|
65
|
-
}
|
|
66
|
-
return 'Incorrectly\nunselected';
|
|
67
|
-
};
|
|
57
|
+
getOutlineWidth = (showCorrectEnabled, selected, markAsCorrect, strokeWidth) =>
|
|
58
|
+
markAsCorrect || (!markAsCorrect && !showCorrectEnabled && selected) ? strokeWidth : 0;
|
|
68
59
|
|
|
69
60
|
render() {
|
|
70
61
|
const {
|
|
@@ -75,37 +66,57 @@ class PolygonComponent extends React.Component {
|
|
|
75
66
|
outlineColor,
|
|
76
67
|
selected,
|
|
77
68
|
points,
|
|
78
|
-
|
|
69
|
+
evaluateText,
|
|
70
|
+
strokeWidth,
|
|
71
|
+
scale,
|
|
72
|
+
markAsCorrect,
|
|
73
|
+
showCorrectEnabled,
|
|
79
74
|
} = this.props;
|
|
80
75
|
|
|
81
76
|
const outlineColorParsed = isEvaluateMode
|
|
82
|
-
? this.getEvaluateOutlineColor(isCorrect, outlineColor)
|
|
77
|
+
? this.getEvaluateOutlineColor(isCorrect, markAsCorrect, outlineColor)
|
|
83
78
|
: outlineColor;
|
|
84
|
-
const outlineWidth = this.getOutlineWidth(selected, strokeWidth);
|
|
79
|
+
const outlineWidth = this.getOutlineWidth(showCorrectEnabled, selected, markAsCorrect, strokeWidth);
|
|
85
80
|
|
|
86
81
|
const pointsParsed = this.parsePointsForKonva(points);
|
|
87
82
|
const center = this.getPolygonCenter(points);
|
|
88
83
|
const iconX = center[0];
|
|
89
84
|
const iconY = center[1];
|
|
90
85
|
|
|
91
|
-
//
|
|
92
|
-
// Correctly
|
|
93
|
-
//
|
|
94
|
-
// Incorrectly
|
|
86
|
+
// "Show Correct Answer" Enabled:
|
|
87
|
+
// - Correctly Selected: white checkmark in green circle
|
|
88
|
+
// - Correctly Not Selected: none
|
|
89
|
+
// - Incorrectly Selected: none
|
|
90
|
+
// - Incorrectly Not Selected: white checkmark in green circle
|
|
91
|
+
// "Show Correct Answer" Disabled:
|
|
92
|
+
// - Correctly Selected:
|
|
93
|
+
// - white checkmark in green circle
|
|
94
|
+
// - heavy outline, as on “Gather”
|
|
95
|
+
// - Correctly Not Selected: none
|
|
96
|
+
// - Incorrectly Selected:
|
|
97
|
+
// - white "X" in red circle
|
|
98
|
+
// - heavy outline around the selection should appear in red
|
|
99
|
+
// - Incorrectly Not Selected: white "X" in red circle
|
|
95
100
|
let iconSrc;
|
|
96
101
|
|
|
97
|
-
if (
|
|
98
|
-
if (isCorrect) {
|
|
102
|
+
if (showCorrectEnabled) {
|
|
103
|
+
if ((selected && isCorrect) || (!selected && !isCorrect)) {
|
|
99
104
|
iconSrc = faCorrect;
|
|
100
|
-
}
|
|
105
|
+
}
|
|
106
|
+
} else {
|
|
107
|
+
if (selected) {
|
|
108
|
+
if (isCorrect) {
|
|
109
|
+
iconSrc = faCorrect;
|
|
110
|
+
} else {
|
|
111
|
+
iconSrc = faWrong;
|
|
112
|
+
}
|
|
113
|
+
} else if (!isCorrect) {
|
|
101
114
|
iconSrc = faWrong;
|
|
102
115
|
}
|
|
103
|
-
} else if (!isCorrect) {
|
|
104
|
-
iconSrc = faWrong;
|
|
105
116
|
}
|
|
106
117
|
|
|
107
118
|
return (
|
|
108
|
-
<Group>
|
|
119
|
+
<Group scaleX={scale} scaleY={scale}>
|
|
109
120
|
<Line
|
|
110
121
|
points={pointsParsed}
|
|
111
122
|
closed={true}
|
|
@@ -119,13 +130,7 @@ class PolygonComponent extends React.Component {
|
|
|
119
130
|
onMouseLeave={this.handleMouseLeave}
|
|
120
131
|
onMouseEnter={this.handleMouseEnter}
|
|
121
132
|
/>
|
|
122
|
-
{
|
|
123
|
-
<Image
|
|
124
|
-
src={iconSrc}
|
|
125
|
-
x={iconX}
|
|
126
|
-
y={iconY}
|
|
127
|
-
/>
|
|
128
|
-
): null}
|
|
133
|
+
{isEvaluateMode && iconSrc ? <Image src={iconSrc} x={iconX} y={iconY} tooltip={evaluateText} /> : null}
|
|
129
134
|
</Group>
|
|
130
135
|
);
|
|
131
136
|
}
|
|
@@ -135,7 +140,7 @@ const styles = () => ({
|
|
|
135
140
|
base: {
|
|
136
141
|
cursor: 'pointer',
|
|
137
142
|
opacity: 0.5,
|
|
138
|
-
position: 'relative'
|
|
143
|
+
position: 'relative',
|
|
139
144
|
},
|
|
140
145
|
});
|
|
141
146
|
|
|
@@ -150,11 +155,17 @@ PolygonComponent.propTypes = {
|
|
|
150
155
|
outlineColor: PropTypes.string.isRequired,
|
|
151
156
|
points: PropTypes.array.isRequired,
|
|
152
157
|
selected: PropTypes.bool.isRequired,
|
|
153
|
-
|
|
158
|
+
evaluateText: PropTypes.string,
|
|
159
|
+
strokeWidth: PropTypes.number,
|
|
160
|
+
scale: PropTypes.number,
|
|
161
|
+
markAsCorrect: PropTypes.bool.isRequired,
|
|
162
|
+
showCorrectEnabled: PropTypes.bool.isRequired,
|
|
154
163
|
};
|
|
155
164
|
|
|
156
165
|
PolygonComponent.defaultProps = {
|
|
157
|
-
|
|
166
|
+
evaluateText: null,
|
|
167
|
+
strokeWidth: 5,
|
|
168
|
+
scale: 1,
|
|
158
169
|
};
|
|
159
170
|
|
|
160
171
|
export default withStyles(styles)(PolygonComponent);
|
|
@@ -32,20 +32,11 @@ class RectComponent extends React.Component {
|
|
|
32
32
|
document.body.style.cursor = 'default';
|
|
33
33
|
};
|
|
34
34
|
|
|
35
|
-
getEvaluateOutlineColor = (isCorrect, outlineColor) =>
|
|
35
|
+
getEvaluateOutlineColor = (isCorrect, markAsCorrect, outlineColor) =>
|
|
36
|
+
markAsCorrect ? 'green' : isCorrect ? outlineColor : 'red';
|
|
36
37
|
|
|
37
|
-
getOutlineWidth = (selected, strokeWidth) =>
|
|
38
|
-
|
|
39
|
-
getEvaluateText = (isCorrect, selected) => {
|
|
40
|
-
if (selected && isCorrect) {
|
|
41
|
-
return 'Correctly\nselected';
|
|
42
|
-
} else if (selected && !isCorrect) {
|
|
43
|
-
return 'Incorrectly\nselected';
|
|
44
|
-
} else if (!selected && isCorrect) {
|
|
45
|
-
return 'Correctly\nunselected';
|
|
46
|
-
}
|
|
47
|
-
return 'Incorrectly\nunselected';
|
|
48
|
-
};
|
|
38
|
+
getOutlineWidth = (showCorrectEnabled, selected, markAsCorrect, strokeWidth) =>
|
|
39
|
+
markAsCorrect || (!markAsCorrect && !showCorrectEnabled && selected) ? strokeWidth : 0;
|
|
49
40
|
|
|
50
41
|
render() {
|
|
51
42
|
const {
|
|
@@ -59,36 +50,56 @@ class RectComponent extends React.Component {
|
|
|
59
50
|
width,
|
|
60
51
|
x,
|
|
61
52
|
y,
|
|
62
|
-
|
|
53
|
+
evaluateText,
|
|
54
|
+
strokeWidth,
|
|
55
|
+
scale,
|
|
56
|
+
markAsCorrect,
|
|
57
|
+
showCorrectEnabled,
|
|
63
58
|
} = this.props;
|
|
64
59
|
|
|
65
60
|
const outlineColorParsed = isEvaluateMode
|
|
66
|
-
? this.getEvaluateOutlineColor(isCorrect, outlineColor)
|
|
61
|
+
? this.getEvaluateOutlineColor(isCorrect, markAsCorrect, outlineColor)
|
|
67
62
|
: outlineColor;
|
|
68
63
|
|
|
69
|
-
const outlineWidth = this.getOutlineWidth(selected, strokeWidth);
|
|
70
|
-
|
|
71
|
-
const iconX =
|
|
72
|
-
const iconY =
|
|
73
|
-
|
|
74
|
-
//
|
|
75
|
-
// Correctly
|
|
76
|
-
//
|
|
77
|
-
// Incorrectly
|
|
64
|
+
const outlineWidth = this.getOutlineWidth(showCorrectEnabled, selected, markAsCorrect, strokeWidth);
|
|
65
|
+
|
|
66
|
+
const iconX = x + width / 2 - 10;
|
|
67
|
+
const iconY = y + height / 2 - 10;
|
|
68
|
+
|
|
69
|
+
// "Show Correct Answer" Enabled:
|
|
70
|
+
// - Correctly Selected: white checkmark in green circle
|
|
71
|
+
// - Correctly Not Selected: none
|
|
72
|
+
// - Incorrectly Selected: none
|
|
73
|
+
// - Incorrectly Not Selected: white checkmark in green circle
|
|
74
|
+
// "Show Correct Answer" Disabled:
|
|
75
|
+
// - Correctly Selected:
|
|
76
|
+
// - white checkmark in green circle
|
|
77
|
+
// - heavy outline, as on “Gather”
|
|
78
|
+
// - Correctly Not Selected: none
|
|
79
|
+
// - Incorrectly Selected:
|
|
80
|
+
// - white "X" in red circle
|
|
81
|
+
// - heavy outline around the selection should appear in red
|
|
82
|
+
// - Incorrectly Not Selected: white "X" in red circle
|
|
78
83
|
let iconSrc;
|
|
79
84
|
|
|
80
|
-
if (
|
|
81
|
-
if (isCorrect) {
|
|
85
|
+
if (showCorrectEnabled) {
|
|
86
|
+
if ((selected && isCorrect) || (!selected && !isCorrect)) {
|
|
82
87
|
iconSrc = faCorrect;
|
|
83
|
-
}
|
|
88
|
+
}
|
|
89
|
+
} else {
|
|
90
|
+
if (selected) {
|
|
91
|
+
if (isCorrect) {
|
|
92
|
+
iconSrc = faCorrect;
|
|
93
|
+
} else {
|
|
94
|
+
iconSrc = faWrong;
|
|
95
|
+
}
|
|
96
|
+
} else if (!isCorrect) {
|
|
84
97
|
iconSrc = faWrong;
|
|
85
98
|
}
|
|
86
|
-
} else if (!isCorrect) {
|
|
87
|
-
iconSrc = faWrong;
|
|
88
99
|
}
|
|
89
100
|
|
|
90
101
|
return (
|
|
91
|
-
<Group>
|
|
102
|
+
<Group scaleX={scale} scaleY={scale}>
|
|
92
103
|
<Rect
|
|
93
104
|
classes={classes.base}
|
|
94
105
|
width={width}
|
|
@@ -104,13 +115,7 @@ class RectComponent extends React.Component {
|
|
|
104
115
|
x={x}
|
|
105
116
|
y={y}
|
|
106
117
|
/>
|
|
107
|
-
{
|
|
108
|
-
<Image
|
|
109
|
-
src={iconSrc}
|
|
110
|
-
x={iconX}
|
|
111
|
-
y={iconY}
|
|
112
|
-
/>
|
|
113
|
-
): null}
|
|
118
|
+
{isEvaluateMode && iconSrc ? <Image src={iconSrc} x={iconX} y={iconY} tooltip={evaluateText} /> : null}
|
|
114
119
|
</Group>
|
|
115
120
|
);
|
|
116
121
|
}
|
|
@@ -120,7 +125,7 @@ const styles = () => ({
|
|
|
120
125
|
base: {
|
|
121
126
|
cursor: 'pointer',
|
|
122
127
|
opacity: 0.5,
|
|
123
|
-
position: 'relative'
|
|
128
|
+
position: 'relative',
|
|
124
129
|
},
|
|
125
130
|
});
|
|
126
131
|
|
|
@@ -138,12 +143,18 @@ RectComponent.propTypes = {
|
|
|
138
143
|
width: PropTypes.number.isRequired,
|
|
139
144
|
x: PropTypes.number.isRequired,
|
|
140
145
|
y: PropTypes.number.isRequired,
|
|
141
|
-
|
|
146
|
+
evaluateText: PropTypes.string,
|
|
147
|
+
strokeWidth: PropTypes.number,
|
|
148
|
+
scale: PropTypes.number,
|
|
149
|
+
markAsCorrect: PropTypes.bool.isRequired,
|
|
150
|
+
showCorrectEnabled: PropTypes.bool.isRequired,
|
|
142
151
|
};
|
|
143
152
|
|
|
144
153
|
RectComponent.defaultProps = {
|
|
145
154
|
isCorrect: false,
|
|
146
|
-
|
|
155
|
+
evaluateText: null,
|
|
156
|
+
strokeWidth: 5,
|
|
157
|
+
scale: 1,
|
|
147
158
|
};
|
|
148
159
|
|
|
149
160
|
export default withStyles(styles)(RectComponent);
|
package/src/index.js
CHANGED
|
@@ -1,10 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import ReactDOM from 'react-dom';
|
|
3
3
|
import { renderMath } from '@pie-lib/math-rendering';
|
|
4
|
-
import {
|
|
5
|
-
SessionChangedEvent,
|
|
6
|
-
ModelSetEvent
|
|
7
|
-
} from '@pie-framework/pie-player-events';
|
|
4
|
+
import { SessionChangedEvent, ModelSetEvent } from '@pie-framework/pie-player-events';
|
|
8
5
|
|
|
9
6
|
import HotspotComponent from './hotspot';
|
|
10
7
|
import { updateSessionValue } from './session-updater';
|
|
@@ -13,13 +10,7 @@ export default class Hotspot extends HTMLElement {
|
|
|
13
10
|
set model(m) {
|
|
14
11
|
this._model = m;
|
|
15
12
|
|
|
16
|
-
this.dispatchEvent(
|
|
17
|
-
new ModelSetEvent(
|
|
18
|
-
this.tagName.toLowerCase(),
|
|
19
|
-
this.isComplete(),
|
|
20
|
-
!!this._model
|
|
21
|
-
)
|
|
22
|
-
);
|
|
13
|
+
this.dispatchEvent(new ModelSetEvent(this.tagName.toLowerCase(), this.isComplete(), !!this._model));
|
|
23
14
|
this._render();
|
|
24
15
|
}
|
|
25
16
|
|
|
@@ -28,9 +19,7 @@ export default class Hotspot extends HTMLElement {
|
|
|
28
19
|
return false;
|
|
29
20
|
}
|
|
30
21
|
|
|
31
|
-
return (
|
|
32
|
-
Array.isArray(this._session.answers) && this._session.answers.length > 0
|
|
33
|
-
);
|
|
22
|
+
return Array.isArray(this._session.answers) && this._session.answers.length > 0;
|
|
34
23
|
}
|
|
35
24
|
|
|
36
25
|
set session(s) {
|
|
@@ -42,12 +31,14 @@ export default class Hotspot extends HTMLElement {
|
|
|
42
31
|
this._render();
|
|
43
32
|
}
|
|
44
33
|
|
|
34
|
+
get session() {
|
|
35
|
+
return this._session;
|
|
36
|
+
}
|
|
37
|
+
|
|
45
38
|
onSelectChoice(data) {
|
|
46
39
|
updateSessionValue(this._session, this._model, data);
|
|
47
40
|
|
|
48
|
-
this.dispatchEvent(
|
|
49
|
-
new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete())
|
|
50
|
-
);
|
|
41
|
+
this.dispatchEvent(new SessionChangedEvent(this.tagName.toLowerCase(), this.isComplete()));
|
|
51
42
|
|
|
52
43
|
this._render();
|
|
53
44
|
}
|
|
@@ -61,8 +52,9 @@ export default class Hotspot extends HTMLElement {
|
|
|
61
52
|
const el = React.createElement(HotspotComponent, {
|
|
62
53
|
model: this._model,
|
|
63
54
|
session: this._session,
|
|
64
|
-
onSelectChoice: this.onSelectChoice.bind(this)
|
|
55
|
+
onSelectChoice: this.onSelectChoice.bind(this),
|
|
65
56
|
});
|
|
57
|
+
|
|
66
58
|
ReactDOM.render(el, this, () => {
|
|
67
59
|
renderMath(this);
|
|
68
60
|
});
|
package/src/session-updater.js
CHANGED
|
@@ -4,7 +4,7 @@ export function updateSessionValue(session, model, data) {
|
|
|
4
4
|
session.answers = session.answers || [];
|
|
5
5
|
|
|
6
6
|
if (!selected) {
|
|
7
|
-
session.answers = session.answers.filter(answer => answer.id !== id);
|
|
7
|
+
session.answers = session.answers.filter((answer) => answer.id !== id);
|
|
8
8
|
} else {
|
|
9
9
|
const item = { id };
|
|
10
10
|
if (multipleCorrect) {
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
-
|
|
3
|
-
exports[`Image snapshots image renders 1`] = `
|
|
4
|
-
<Image
|
|
5
|
-
height={20}
|
|
6
|
-
image={null}
|
|
7
|
-
width={20}
|
|
8
|
-
x={5}
|
|
9
|
-
y={5}
|
|
10
|
-
/>
|
|
11
|
-
`;
|
|
12
|
-
|
|
13
|
-
exports[`Image snapshots x y position renders 1`] = `
|
|
14
|
-
<Image
|
|
15
|
-
height={20}
|
|
16
|
-
image={null}
|
|
17
|
-
width={20}
|
|
18
|
-
x={10}
|
|
19
|
-
y={10}
|
|
20
|
-
/>
|
|
21
|
-
`;
|