@khanacademy/perseus-editor 2.5.2 → 2.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +22 -0
- package/dist/es/index.js +51 -73
- package/dist/es/index.js.map +1 -1
- package/dist/index.js +46 -70
- package/dist/index.js.map +1 -1
- package/dist/widgets/plotter-editor.d.ts +47 -23
- package/dist/widgets/plotter-editor.js.flow +47 -25
- package/package.json +2 -2
- package/src/components/checkbox.tsx +1 -0
- package/src/components/dropdown-option.tsx +1 -0
- package/src/components/form-wrapped-text-field.tsx +1 -0
- package/src/components/widget-editor.tsx +1 -0
- package/src/diffs/structured-item-diff.tsx +1 -0
- package/src/editor.tsx +1 -0
- package/src/hint-editor.tsx +1 -0
- package/src/katex-mhchem/parser.js +24 -24
- package/src/widgets/__stories__/label-image-editor.stories.tsx +1 -0
- package/src/widgets/__stories__/radio-editor.stories.tsx +1 -0
- package/src/widgets/definition-editor.tsx +1 -0
- package/src/widgets/dropdown-editor.tsx +1 -0
- package/src/widgets/example-widget.tsx +1 -0
- package/src/widgets/explanation-editor.tsx +1 -0
- package/src/widgets/graded-group-editor.tsx +1 -0
- package/src/widgets/grapher-editor.tsx +1 -0
- package/src/widgets/group-editor.tsx +1 -0
- package/src/widgets/iframe-editor.tsx +1 -0
- package/src/widgets/image-editor.tsx +5 -1
- package/src/widgets/interaction-editor.tsx +1 -0
- package/src/widgets/label-image/marker.tsx +1 -0
- package/src/widgets/lights-puzzle-editor.tsx +1 -0
- package/src/widgets/measurer-editor.tsx +1 -0
- package/src/widgets/number-line-editor.tsx +1 -0
- package/src/widgets/orderer-editor.tsx +1 -0
- package/src/widgets/passage-ref-editor.tsx +1 -0
- package/src/widgets/plotter-editor.tsx +253 -243
- package/src/widgets/simple-markdown-tester-editor.tsx +1 -0
- package/src/widgets/sorter-editor.tsx +1 -0
- package/tsconfig-build.tsbuildinfo +1 -1
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
/* eslint-disable @
|
|
1
|
+
/* eslint-disable @khanacademy/ts-no-error-suppressions */
|
|
2
|
+
/* eslint-disable react/no-unsafe */
|
|
2
3
|
import {number as knumber} from "@khanacademy/kmath";
|
|
3
4
|
import {
|
|
4
5
|
components,
|
|
@@ -6,7 +7,6 @@ import {
|
|
|
6
7
|
PlotterWidget,
|
|
7
8
|
Util,
|
|
8
9
|
} from "@khanacademy/perseus";
|
|
9
|
-
import PropTypes from "prop-types";
|
|
10
10
|
import * as React from "react";
|
|
11
11
|
import ReactDOM from "react-dom";
|
|
12
12
|
import _ from "underscore";
|
|
@@ -16,11 +16,20 @@ import BlurInput from "../components/blur-input";
|
|
|
16
16
|
const {InfoTip, NumberInput, RangeInput, TextListEditor} = components;
|
|
17
17
|
const Plotter = PlotterWidget.widget;
|
|
18
18
|
|
|
19
|
-
const BAR = "bar"
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
const BAR = "bar";
|
|
20
|
+
const LINE = "line";
|
|
21
|
+
const PIC = "pic";
|
|
22
|
+
const HISTOGRAM = "histogram";
|
|
23
|
+
const DOTPLOT = "dotplot";
|
|
24
|
+
|
|
25
|
+
const plotTypes = [BAR, LINE, PIC, HISTOGRAM, DOTPLOT];
|
|
26
|
+
type PlotType = typeof plotTypes[number];
|
|
27
|
+
|
|
28
|
+
const STARTING = "starting";
|
|
29
|
+
const CORRECT = "correct";
|
|
30
|
+
|
|
31
|
+
const editingStates = [STARTING, CORRECT];
|
|
32
|
+
type EditingState = typeof editingStates[number];
|
|
24
33
|
|
|
25
34
|
// Return a copy of array with length n, padded with given value
|
|
26
35
|
function padArray(array: any, n, value: any) {
|
|
@@ -38,39 +47,55 @@ const editorDefaults = {
|
|
|
38
47
|
snapsPerLine: 2,
|
|
39
48
|
} as const;
|
|
40
49
|
|
|
41
|
-
|
|
42
|
-
type:
|
|
43
|
-
labels:
|
|
44
|
-
categories:
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
50
|
+
type Props = {
|
|
51
|
+
type: PlotType;
|
|
52
|
+
labels: Array<string>;
|
|
53
|
+
categories: ReadonlyArray<string | number>;
|
|
54
|
+
scaleY: number;
|
|
55
|
+
maxY: number;
|
|
56
|
+
snapsPerLine: number;
|
|
57
|
+
picSize: number;
|
|
58
|
+
picBoxHeight: number;
|
|
59
|
+
picUrl: string;
|
|
60
|
+
plotDimensions: ReadonlyArray<number>;
|
|
61
|
+
labelInterval: number;
|
|
62
|
+
starting: ReadonlyArray<number>;
|
|
63
|
+
correct: ReadonlyArray<number>;
|
|
64
|
+
static: boolean;
|
|
65
|
+
onChange: any;
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
type DefaultProps = {
|
|
69
|
+
scaleY: Props["scaleY"];
|
|
70
|
+
maxY: Props["maxY"];
|
|
71
|
+
snapsPerLine: Props["snapsPerLine"];
|
|
72
|
+
correct: Props["correct"];
|
|
73
|
+
starting: Props["starting"];
|
|
74
|
+
type: Props["type"];
|
|
75
|
+
labels: Props["labels"];
|
|
76
|
+
categories: Props["categories"];
|
|
77
|
+
picSize: Props["picSize"];
|
|
78
|
+
picBoxHeight: Props["picBoxHeight"];
|
|
79
|
+
plotDimensions: Props["plotDimensions"];
|
|
80
|
+
labelInterval: Props["labelInterval"];
|
|
81
|
+
picUrl: Props["picUrl"];
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
type State = {
|
|
85
|
+
editing: EditingState;
|
|
86
|
+
pic: any;
|
|
87
|
+
loadedUrl: string | null;
|
|
88
|
+
minX: number | null;
|
|
89
|
+
maxX: number | null;
|
|
90
|
+
tickStep: number | null;
|
|
91
|
+
};
|
|
63
92
|
|
|
64
93
|
const formatNumber = (num) => "$" + knumber.round(num, 2) + "$";
|
|
65
94
|
|
|
66
|
-
type Props = any;
|
|
67
|
-
type State = any;
|
|
68
|
-
|
|
69
95
|
class PlotterEditor extends React.Component<Props, State> {
|
|
70
|
-
static propTypes = widgetPropTypes;
|
|
71
96
|
static widgetName = "plotter" as const;
|
|
72
97
|
|
|
73
|
-
static defaultProps:
|
|
98
|
+
static defaultProps: DefaultProps = {
|
|
74
99
|
...editorDefaults,
|
|
75
100
|
correct: [1],
|
|
76
101
|
starting: [1],
|
|
@@ -84,6 +109,7 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
84
109
|
plotDimensions: [275, 200],
|
|
85
110
|
labelInterval: 1,
|
|
86
111
|
|
|
112
|
+
// @ts-expect-error - TS2322
|
|
87
113
|
get picUrl() {
|
|
88
114
|
const staticUrl = Dependencies.getDependencies().staticUrl;
|
|
89
115
|
if (staticUrl) {
|
|
@@ -95,7 +121,7 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
95
121
|
};
|
|
96
122
|
|
|
97
123
|
state: State = {
|
|
98
|
-
editing: this.props.static ?
|
|
124
|
+
editing: this.props.static ? STARTING : CORRECT,
|
|
99
125
|
pic: null,
|
|
100
126
|
loadedUrl: null,
|
|
101
127
|
minX: null,
|
|
@@ -131,6 +157,169 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
131
157
|
}
|
|
132
158
|
};
|
|
133
159
|
|
|
160
|
+
handleChangeTickStep: (arg1: number) => void = (value) => {
|
|
161
|
+
this.setState({
|
|
162
|
+
tickStep: value,
|
|
163
|
+
});
|
|
164
|
+
};
|
|
165
|
+
|
|
166
|
+
handleChangeRange: (arg1: [number, number]) => void = (newValue) => {
|
|
167
|
+
this.setState({
|
|
168
|
+
minX: newValue[0],
|
|
169
|
+
maxX: newValue[1],
|
|
170
|
+
});
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
changeLabelInterval: (arg1: number) => void = (value) => {
|
|
174
|
+
this.props.onChange({
|
|
175
|
+
labelInterval: value,
|
|
176
|
+
});
|
|
177
|
+
};
|
|
178
|
+
|
|
179
|
+
handlePlotterChange: (arg1: any) => void = (newProps) => {
|
|
180
|
+
const props: Record<string, any> = {};
|
|
181
|
+
props[this.state.editing] = newProps.values;
|
|
182
|
+
this.props.onChange(props);
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
changeType: (arg1: any) => void = (type) => {
|
|
186
|
+
let categories;
|
|
187
|
+
if (type === HISTOGRAM) {
|
|
188
|
+
// Switching to histogram, add a label (0) to the left
|
|
189
|
+
// @ts-expect-error - TS2769
|
|
190
|
+
categories = [formatNumber(0)].concat(this.props.categories);
|
|
191
|
+
this.props.onChange({type: type, categories: categories});
|
|
192
|
+
} else if (this.props.type === HISTOGRAM) {
|
|
193
|
+
// Switching from histogram, remove a label from the left
|
|
194
|
+
categories = this.props.categories.slice(1);
|
|
195
|
+
this.props.onChange({type: type, categories: categories});
|
|
196
|
+
} else {
|
|
197
|
+
this.props.onChange({type: type});
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
if (categories) {
|
|
201
|
+
// eslint-disable-next-line react/no-string-refs
|
|
202
|
+
const node = ReactDOM.findDOMNode(this.refs.categories);
|
|
203
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
204
|
+
node.value = categories.join(", ");
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
changeLabel: (arg1: number, arg2: any) => void = (i, e) => {
|
|
209
|
+
const labels = _.clone(this.props.labels);
|
|
210
|
+
labels[i] = e.target.value;
|
|
211
|
+
this.props.onChange({labels: labels});
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
changePicUrl: (arg1: string) => void = (value) => {
|
|
215
|
+
// We don't need the labels and other data in the plotter, so just
|
|
216
|
+
// extract the raw image and use that.
|
|
217
|
+
// TODO(emily): Maybe indicate that such a change has happened?
|
|
218
|
+
const url = Util.getRealImageUrl(value);
|
|
219
|
+
|
|
220
|
+
this.props.onChange({picUrl: url});
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
changeCategories: (arg1: any) => void = (categories) => {
|
|
224
|
+
let n = categories.length;
|
|
225
|
+
if (this.props.type === HISTOGRAM) {
|
|
226
|
+
// Histograms with n labels/categories have n - 1 buckets
|
|
227
|
+
n--;
|
|
228
|
+
}
|
|
229
|
+
const value = this.props.scaleY;
|
|
230
|
+
|
|
231
|
+
this.props.onChange({
|
|
232
|
+
categories: categories,
|
|
233
|
+
correct: padArray(this.props.correct, n, value),
|
|
234
|
+
starting: padArray(this.props.starting, n, value),
|
|
235
|
+
});
|
|
236
|
+
};
|
|
237
|
+
|
|
238
|
+
changeScale: (arg1: any) => void = (e) => {
|
|
239
|
+
const oldScale = this.props.scaleY;
|
|
240
|
+
const newScale = +e.target.value || editorDefaults.scaleY;
|
|
241
|
+
|
|
242
|
+
const scale = function (value: any) {
|
|
243
|
+
return (value * newScale) / oldScale;
|
|
244
|
+
};
|
|
245
|
+
|
|
246
|
+
const maxY = scale(this.props.maxY);
|
|
247
|
+
|
|
248
|
+
this.props.onChange({
|
|
249
|
+
scaleY: newScale,
|
|
250
|
+
maxY: maxY,
|
|
251
|
+
correct: _.map(this.props.correct, scale),
|
|
252
|
+
starting: _.map(this.props.starting, scale),
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
256
|
+
ReactDOM.findDOMNode(this.refs.maxY).value = maxY; // eslint-disable-line react/no-string-refs
|
|
257
|
+
};
|
|
258
|
+
|
|
259
|
+
changeMax: (arg1: any) => void = (e) => {
|
|
260
|
+
this.props.onChange({
|
|
261
|
+
maxY: +e.target.value || editorDefaults.maxY,
|
|
262
|
+
});
|
|
263
|
+
};
|
|
264
|
+
|
|
265
|
+
changeSnaps: (arg1: any) => void = (e) => {
|
|
266
|
+
this.props.onChange({
|
|
267
|
+
snapsPerLine: +e.target.value || editorDefaults.snapsPerLine,
|
|
268
|
+
});
|
|
269
|
+
};
|
|
270
|
+
|
|
271
|
+
changeEditing: (arg1: EditingState) => void = (editing) => {
|
|
272
|
+
this.setState({editing: editing});
|
|
273
|
+
};
|
|
274
|
+
|
|
275
|
+
setCategoriesFromScale: () => void = () => {
|
|
276
|
+
const scale = this.state.tickStep || 1;
|
|
277
|
+
const min = this.state.minX || 0;
|
|
278
|
+
const max = this.state.maxX || 0;
|
|
279
|
+
const length = Math.floor((max - min) / scale) * scale;
|
|
280
|
+
|
|
281
|
+
let categories;
|
|
282
|
+
if (this.props.type === HISTOGRAM || this.props.type === DOTPLOT) {
|
|
283
|
+
// Ranges for histogram and dotplot labels should start at zero
|
|
284
|
+
categories = _.range(0, length + scale, scale);
|
|
285
|
+
} else {
|
|
286
|
+
categories = _.range(scale, length + scale, scale);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
categories = _.map(categories, (num) => num + min);
|
|
290
|
+
categories = _.map(categories, formatNumber);
|
|
291
|
+
|
|
292
|
+
this.changeCategories(categories);
|
|
293
|
+
|
|
294
|
+
// eslint-disable-next-line react/no-string-refs
|
|
295
|
+
const node = ReactDOM.findDOMNode(this.refs.categories);
|
|
296
|
+
|
|
297
|
+
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
298
|
+
node.value = categories.join(", ");
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
serialize: () => any = () => {
|
|
302
|
+
const json = _.pick(
|
|
303
|
+
this.props,
|
|
304
|
+
"correct",
|
|
305
|
+
"starting",
|
|
306
|
+
"type",
|
|
307
|
+
"labels",
|
|
308
|
+
"categories",
|
|
309
|
+
"scaleY",
|
|
310
|
+
"maxY",
|
|
311
|
+
"snapsPerLine",
|
|
312
|
+
"labelInterval",
|
|
313
|
+
);
|
|
314
|
+
|
|
315
|
+
if (this.props.type === PIC) {
|
|
316
|
+
// @ts-expect-error [FEI-5003] - TS2339 - Property 'picUrl' does not exist on type 'Pick<Readonly<any> & Readonly<{ children?: ReactNode; }>, "type" | "correct" | "labels" | "categories" | "starting" | "scaleY" | "maxY" | "snapsPerLine" | "labelInterval">'.
|
|
317
|
+
json.picUrl = this.props.picUrl;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
return json;
|
|
321
|
+
};
|
|
322
|
+
|
|
134
323
|
render(): React.ReactNode {
|
|
135
324
|
const setFromScale = _.contains(
|
|
136
325
|
[LINE, HISTOGRAM, DOTPLOT],
|
|
@@ -146,52 +335,34 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
146
335
|
<div className="perseus-widget-plotter-editor">
|
|
147
336
|
<div>
|
|
148
337
|
Chart type:{" "}
|
|
149
|
-
{
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
type,
|
|
163
|
-
)}
|
|
164
|
-
/>
|
|
165
|
-
{type}
|
|
166
|
-
</label>
|
|
167
|
-
);
|
|
168
|
-
},
|
|
169
|
-
this,
|
|
170
|
-
)}
|
|
338
|
+
{plotTypes.map((type) => {
|
|
339
|
+
return (
|
|
340
|
+
<label key={type}>
|
|
341
|
+
<input
|
|
342
|
+
type="radio"
|
|
343
|
+
name="chart-type"
|
|
344
|
+
checked={this.props.type === type}
|
|
345
|
+
onChange={_.partial(this.changeType, type)}
|
|
346
|
+
/>
|
|
347
|
+
{type}
|
|
348
|
+
</label>
|
|
349
|
+
);
|
|
350
|
+
}, this)}
|
|
171
351
|
</div>
|
|
172
352
|
<div>
|
|
173
353
|
Labels:{" "}
|
|
174
|
-
{
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
<
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
)}
|
|
187
|
-
// @ts-expect-error [FEI-5003] - TS2683 - 'this' implicitly has type 'any' because it does not have a type annotation.
|
|
188
|
-
defaultValue={this.props.labels[i]}
|
|
189
|
-
/>
|
|
190
|
-
</label>
|
|
191
|
-
);
|
|
192
|
-
},
|
|
193
|
-
this,
|
|
194
|
-
)}
|
|
354
|
+
{["x", "y"].map((axis, i) => {
|
|
355
|
+
return (
|
|
356
|
+
<label key={axis}>
|
|
357
|
+
{axis + ":"}
|
|
358
|
+
<input
|
|
359
|
+
type="text"
|
|
360
|
+
onChange={_.partial(this.changeLabel, i)}
|
|
361
|
+
defaultValue={this.props.labels[i]}
|
|
362
|
+
/>
|
|
363
|
+
</label>
|
|
364
|
+
);
|
|
365
|
+
}, this)}
|
|
195
366
|
</div>
|
|
196
367
|
|
|
197
368
|
{setFromScale && (
|
|
@@ -332,16 +503,16 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
332
503
|
)}
|
|
333
504
|
<div>
|
|
334
505
|
Editing values:{" "}
|
|
335
|
-
{
|
|
506
|
+
{editingStates.map((editing) => (
|
|
336
507
|
<label key={editing}>
|
|
337
508
|
<input
|
|
338
509
|
type="radio"
|
|
339
510
|
disabled={
|
|
340
|
-
editing ===
|
|
511
|
+
editing === CORRECT && this.props.static
|
|
341
512
|
}
|
|
342
513
|
checked={
|
|
343
514
|
this.props.static
|
|
344
|
-
? editing ===
|
|
515
|
+
? editing === STARTING
|
|
345
516
|
: this.state.editing === editing
|
|
346
517
|
}
|
|
347
518
|
onChange={(e) => this.changeEditing(editing)}
|
|
@@ -363,6 +534,7 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
363
534
|
</p>
|
|
364
535
|
</InfoTip>
|
|
365
536
|
</div>
|
|
537
|
+
{/* @ts-expect-error - TS2769 */}
|
|
366
538
|
<Plotter
|
|
367
539
|
{...props}
|
|
368
540
|
starting={this.props[this.state.editing]}
|
|
@@ -371,168 +543,6 @@ class PlotterEditor extends React.Component<Props, State> {
|
|
|
371
543
|
</div>
|
|
372
544
|
);
|
|
373
545
|
}
|
|
374
|
-
|
|
375
|
-
handleChangeTickStep: (arg1: number) => void = (value) => {
|
|
376
|
-
this.setState({
|
|
377
|
-
tickStep: value,
|
|
378
|
-
});
|
|
379
|
-
};
|
|
380
|
-
|
|
381
|
-
handleChangeRange: (arg1: [number, number]) => void = (newValue) => {
|
|
382
|
-
this.setState({
|
|
383
|
-
minX: newValue[0],
|
|
384
|
-
maxX: newValue[1],
|
|
385
|
-
});
|
|
386
|
-
};
|
|
387
|
-
|
|
388
|
-
changeLabelInterval: (arg1: number) => void = (value) => {
|
|
389
|
-
this.props.onChange({
|
|
390
|
-
labelInterval: value,
|
|
391
|
-
});
|
|
392
|
-
};
|
|
393
|
-
|
|
394
|
-
handlePlotterChange: (arg1: any) => void = (newProps) => {
|
|
395
|
-
const props: Record<string, any> = {};
|
|
396
|
-
props[this.state.editing] = newProps.values;
|
|
397
|
-
this.props.onChange(props);
|
|
398
|
-
};
|
|
399
|
-
|
|
400
|
-
changeType: (arg1: any) => void = (type) => {
|
|
401
|
-
let categories;
|
|
402
|
-
if (type === HISTOGRAM) {
|
|
403
|
-
// Switching to histogram, add a label (0) to the left
|
|
404
|
-
categories = [formatNumber(0)].concat(this.props.categories);
|
|
405
|
-
this.props.onChange({type: type, categories: categories});
|
|
406
|
-
} else if (this.props.type === HISTOGRAM) {
|
|
407
|
-
// Switching from histogram, remove a label from the left
|
|
408
|
-
categories = this.props.categories.slice(1);
|
|
409
|
-
this.props.onChange({type: type, categories: categories});
|
|
410
|
-
} else {
|
|
411
|
-
this.props.onChange({type: type});
|
|
412
|
-
}
|
|
413
|
-
|
|
414
|
-
if (categories) {
|
|
415
|
-
// eslint-disable-next-line react/no-string-refs
|
|
416
|
-
const node = ReactDOM.findDOMNode(this.refs.categories);
|
|
417
|
-
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
418
|
-
node.value = categories.join(", ");
|
|
419
|
-
}
|
|
420
|
-
};
|
|
421
|
-
|
|
422
|
-
changeLabel: (arg1: number, arg2: any) => void = (i, e) => {
|
|
423
|
-
const labels = _.clone(this.props.labels);
|
|
424
|
-
labels[i] = e.target.value;
|
|
425
|
-
this.props.onChange({labels: labels});
|
|
426
|
-
};
|
|
427
|
-
|
|
428
|
-
changePicUrl: (arg1: string) => void = (value) => {
|
|
429
|
-
// We don't need the labels and other data in the plotter, so just
|
|
430
|
-
// extract the raw image and use that.
|
|
431
|
-
// TODO(emily): Maybe indicate that such a change has happened?
|
|
432
|
-
const url = Util.getRealImageUrl(value);
|
|
433
|
-
|
|
434
|
-
this.props.onChange({picUrl: url});
|
|
435
|
-
};
|
|
436
|
-
|
|
437
|
-
changeCategories: (arg1: any) => void = (categories) => {
|
|
438
|
-
let n = categories.length;
|
|
439
|
-
if (this.props.type === HISTOGRAM) {
|
|
440
|
-
// Histograms with n labels/categories have n - 1 buckets
|
|
441
|
-
n--;
|
|
442
|
-
}
|
|
443
|
-
const value = this.props.scaleY;
|
|
444
|
-
|
|
445
|
-
this.props.onChange({
|
|
446
|
-
categories: categories,
|
|
447
|
-
correct: padArray(this.props.correct, n, value),
|
|
448
|
-
starting: padArray(this.props.starting, n, value),
|
|
449
|
-
});
|
|
450
|
-
};
|
|
451
|
-
|
|
452
|
-
changeScale: (arg1: any) => void = (e) => {
|
|
453
|
-
const oldScale = this.props.scaleY;
|
|
454
|
-
const newScale = +e.target.value || editorDefaults.scaleY;
|
|
455
|
-
|
|
456
|
-
const scale = function (value: any) {
|
|
457
|
-
return (value * newScale) / oldScale;
|
|
458
|
-
};
|
|
459
|
-
|
|
460
|
-
const maxY = scale(this.props.maxY);
|
|
461
|
-
|
|
462
|
-
this.props.onChange({
|
|
463
|
-
scaleY: newScale,
|
|
464
|
-
maxY: maxY,
|
|
465
|
-
correct: _.map(this.props.correct, scale),
|
|
466
|
-
starting: _.map(this.props.starting, scale),
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
470
|
-
ReactDOM.findDOMNode(this.refs.maxY).value = maxY; // eslint-disable-line react/no-string-refs
|
|
471
|
-
};
|
|
472
|
-
|
|
473
|
-
changeMax: (arg1: any) => void = (e) => {
|
|
474
|
-
this.props.onChange({
|
|
475
|
-
maxY: +e.target.value || editorDefaults.maxY,
|
|
476
|
-
});
|
|
477
|
-
};
|
|
478
|
-
|
|
479
|
-
changeSnaps: (arg1: any) => void = (e) => {
|
|
480
|
-
this.props.onChange({
|
|
481
|
-
snapsPerLine: +e.target.value || editorDefaults.snapsPerLine,
|
|
482
|
-
});
|
|
483
|
-
};
|
|
484
|
-
|
|
485
|
-
changeEditing: (arg1: string) => void = (editing) => {
|
|
486
|
-
this.setState({editing: editing});
|
|
487
|
-
};
|
|
488
|
-
|
|
489
|
-
setCategoriesFromScale: () => void = () => {
|
|
490
|
-
const scale = this.state.tickStep || 1;
|
|
491
|
-
const min = this.state.minX || 0;
|
|
492
|
-
const max = this.state.maxX || 0;
|
|
493
|
-
const length = Math.floor((max - min) / scale) * scale;
|
|
494
|
-
|
|
495
|
-
let categories;
|
|
496
|
-
if (this.props.type === HISTOGRAM || this.props.type === DOTPLOT) {
|
|
497
|
-
// Ranges for histogram and dotplot labels should start at zero
|
|
498
|
-
categories = _.range(0, length + scale, scale);
|
|
499
|
-
} else {
|
|
500
|
-
categories = _.range(scale, length + scale, scale);
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
categories = _.map(categories, (num) => num + min);
|
|
504
|
-
categories = _.map(categories, formatNumber);
|
|
505
|
-
|
|
506
|
-
this.changeCategories(categories);
|
|
507
|
-
|
|
508
|
-
// eslint-disable-next-line react/no-string-refs
|
|
509
|
-
const node = ReactDOM.findDOMNode(this.refs.categories);
|
|
510
|
-
|
|
511
|
-
// @ts-expect-error [FEI-5003] - TS2531 - Object is possibly 'null'. | TS2339 - Property 'value' does not exist on type 'Element | Text'.
|
|
512
|
-
node.value = categories.join(", ");
|
|
513
|
-
};
|
|
514
|
-
|
|
515
|
-
serialize: () => any = () => {
|
|
516
|
-
const json = _.pick(
|
|
517
|
-
this.props,
|
|
518
|
-
"correct",
|
|
519
|
-
"starting",
|
|
520
|
-
"type",
|
|
521
|
-
"labels",
|
|
522
|
-
"categories",
|
|
523
|
-
"scaleY",
|
|
524
|
-
"maxY",
|
|
525
|
-
"snapsPerLine",
|
|
526
|
-
"labelInterval",
|
|
527
|
-
);
|
|
528
|
-
|
|
529
|
-
if (this.props.type === PIC) {
|
|
530
|
-
// @ts-expect-error [FEI-5003] - TS2339 - Property 'picUrl' does not exist on type 'Pick<Readonly<any> & Readonly<{ children?: ReactNode; }>, "type" | "correct" | "labels" | "categories" | "starting" | "scaleY" | "maxY" | "snapsPerLine" | "labelInterval">'.
|
|
531
|
-
json.picUrl = this.props.picUrl;
|
|
532
|
-
}
|
|
533
|
-
|
|
534
|
-
return json;
|
|
535
|
-
};
|
|
536
546
|
}
|
|
537
547
|
|
|
538
548
|
export default PlotterEditor;
|