@pie-lib/plot 2.7.3 → 2.8.0-beta.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 +19 -8
- package/NEXT.CHANGELOG.json +1 -0
- package/lib/grid-draggable.js +52 -16
- package/lib/grid-draggable.js.map +1 -1
- package/lib/label.js +17 -5
- package/lib/label.js.map +1 -1
- package/lib/root.js +76 -31
- package/lib/root.js.map +1 -1
- package/lib/trig.js +1 -1
- package/lib/trig.js.map +1 -1
- package/lib/utils.js +24 -2
- package/lib/utils.js.map +1 -1
- package/package.json +7 -4
- package/src/__tests__/__snapshots__/grid-draggable.test.jsx.snap +185 -0
- package/src/__tests__/__snapshots__/root.test.jsx.snap +18 -0
- package/src/__tests__/draggable.test.jsx +23 -0
- package/src/__tests__/grid-draggable.test.jsx +326 -0
- package/src/__tests__/root.test.jsx +118 -0
- package/src/__tests__/trig.test.js +174 -0
- package/src/__tests__/utils.test.js +233 -0
- package/src/grid-draggable.jsx +52 -8
- package/src/label.jsx +14 -3
- package/src/root.jsx +82 -35
- package/src/trig.js +1 -1
- package/src/utils.js +14 -0
package/src/root.jsx
CHANGED
|
@@ -8,8 +8,16 @@ import { color, Readable } from '@pie-lib/render-ui';
|
|
|
8
8
|
import EditableHtml from '@pie-lib/editable-html';
|
|
9
9
|
import cn from 'classnames';
|
|
10
10
|
import Label from './label';
|
|
11
|
+
import { extractTextFromHTML, isEmptyObject, isEmptyString } from './utils';
|
|
11
12
|
|
|
12
13
|
export class Root extends React.Component {
|
|
14
|
+
constructor(props) {
|
|
15
|
+
super(props);
|
|
16
|
+
this.state = {
|
|
17
|
+
titleHeight: 0,
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
|
|
13
21
|
static propTypes = {
|
|
14
22
|
title: PropTypes.string,
|
|
15
23
|
children: ChildrenType,
|
|
@@ -29,6 +37,8 @@ export class Root extends React.Component {
|
|
|
29
37
|
rootRef: PropTypes.func,
|
|
30
38
|
onChangeLabels: PropTypes.func,
|
|
31
39
|
titlePlaceholder: PropTypes.string,
|
|
40
|
+
mathMlOptions: PropTypes.object,
|
|
41
|
+
labelsCharactersLimit: PropTypes.number,
|
|
32
42
|
};
|
|
33
43
|
|
|
34
44
|
mouseMove = (g) => {
|
|
@@ -54,6 +64,7 @@ export class Root extends React.Component {
|
|
|
54
64
|
componentDidMount() {
|
|
55
65
|
const g = select(this.g);
|
|
56
66
|
g.on('mousemove', this.mouseMove.bind(this, g));
|
|
67
|
+
this.measureTitleHeight();
|
|
57
68
|
}
|
|
58
69
|
|
|
59
70
|
componentWillUnmount() {
|
|
@@ -61,9 +72,19 @@ export class Root extends React.Component {
|
|
|
61
72
|
g.on('mousemove', null);
|
|
62
73
|
}
|
|
63
74
|
|
|
75
|
+
componentDidUpdate(prevProps) {
|
|
76
|
+
if (prevProps.title !== this.props.title) {
|
|
77
|
+
this.measureTitleHeight();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
64
81
|
onChangeLabel = (newValue, side) => {
|
|
65
82
|
const { labels, onChangeLabels, isChart } = this.props;
|
|
66
83
|
|
|
84
|
+
if (!onChangeLabels) {
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
|
|
67
88
|
if (isChart) {
|
|
68
89
|
if (side === 'left') {
|
|
69
90
|
onChangeLabels('range', newValue);
|
|
@@ -80,6 +101,18 @@ export class Root extends React.Component {
|
|
|
80
101
|
});
|
|
81
102
|
};
|
|
82
103
|
|
|
104
|
+
measureTitleHeight = () => {
|
|
105
|
+
const titleElement = document.getElementById('editable-title');
|
|
106
|
+
if (titleElement) {
|
|
107
|
+
const titleHeight = titleElement.clientHeight;
|
|
108
|
+
this.setState({ titleHeight, prevTitle: this.props.title });
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
handleKeyDown = () => {
|
|
113
|
+
setTimeout(this.measureTitleHeight, 0);
|
|
114
|
+
};
|
|
115
|
+
|
|
83
116
|
render() {
|
|
84
117
|
const {
|
|
85
118
|
disabledTitle,
|
|
@@ -99,6 +132,7 @@ export class Root extends React.Component {
|
|
|
99
132
|
title,
|
|
100
133
|
rootRef,
|
|
101
134
|
mathMlOptions = {},
|
|
135
|
+
labelsCharactersLimit,
|
|
102
136
|
} = this.props;
|
|
103
137
|
const {
|
|
104
138
|
size: { width = 500, height = 500 },
|
|
@@ -107,14 +141,18 @@ export class Root extends React.Component {
|
|
|
107
141
|
} = graphProps;
|
|
108
142
|
|
|
109
143
|
const topPadding = 40;
|
|
110
|
-
const leftPadding =
|
|
111
|
-
const
|
|
144
|
+
const leftPadding = isEmptyString(extractTextFromHTML(labels?.left)) && isEmptyObject(labelsPlaceholders) ? 48 : 70;
|
|
145
|
+
const rightPadding =
|
|
146
|
+
isEmptyString(extractTextFromHTML(labels?.right)) && isEmptyObject(labelsPlaceholders) ? 48 : 70;
|
|
147
|
+
const finalWidth = width + leftPadding + rightPadding + (domain.padding || 0) * 2;
|
|
112
148
|
const finalHeight = height + topPadding * 2 + (range.padding || 0) * 2;
|
|
113
149
|
|
|
114
150
|
const activeTitlePlugins = [
|
|
115
151
|
'bold',
|
|
116
152
|
'italic',
|
|
117
153
|
'underline',
|
|
154
|
+
'superscript',
|
|
155
|
+
'subscript',
|
|
118
156
|
'strikethrough',
|
|
119
157
|
'math',
|
|
120
158
|
// 'languageCharacters'
|
|
@@ -124,11 +162,11 @@ export class Root extends React.Component {
|
|
|
124
162
|
const nbOfVerticalLines = parseInt(width / 100);
|
|
125
163
|
const nbOfHorizontalLines = parseInt(actualHeight / 100);
|
|
126
164
|
const sideGridlinesPadding = parseInt(actualHeight % 100);
|
|
127
|
-
|
|
165
|
+
const { titleHeight } = this.state;
|
|
128
166
|
return (
|
|
129
167
|
<div className={classes.root}>
|
|
130
168
|
{showPixelGuides && (
|
|
131
|
-
<div className={classes.topPixelGuides} style={{ marginLeft: isChart ?
|
|
169
|
+
<div className={classes.topPixelGuides} style={{ marginLeft: isChart ? 80 : showLabels ? 30 : 10 }}>
|
|
132
170
|
{[...Array(nbOfVerticalLines + 1).keys()].map((value) => (
|
|
133
171
|
<Readable false key={`top-guide-${value}`}>
|
|
134
172
|
<div className={classes.topPixelIndicator}>
|
|
@@ -142,34 +180,37 @@ export class Root extends React.Component {
|
|
|
142
180
|
{showTitle &&
|
|
143
181
|
(disabledTitle ? (
|
|
144
182
|
<div
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
}
|
|
149
|
-
}
|
|
183
|
+
id="editable-title"
|
|
184
|
+
style={{
|
|
185
|
+
...(isChart && { width: finalWidth }),
|
|
186
|
+
...(isEmptyString(extractTextFromHTML(title)) && { display: 'none' }),
|
|
187
|
+
}}
|
|
150
188
|
className={cn(isChart ? classes.chartTitle : classes.graphTitle, classes.disabledTitle)}
|
|
151
189
|
dangerouslySetInnerHTML={{ __html: title || '' }}
|
|
152
190
|
/>
|
|
153
191
|
) : (
|
|
154
|
-
<
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
192
|
+
<div id="editable-title">
|
|
193
|
+
<EditableHtml
|
|
194
|
+
style={
|
|
195
|
+
isChart && {
|
|
196
|
+
width: finalWidth,
|
|
197
|
+
}
|
|
158
198
|
}
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
199
|
+
className={cn(
|
|
200
|
+
{ [classes.rightMargin]: showPixelGuides },
|
|
201
|
+
isChart ? classes.chartTitle : classes.graphTitle,
|
|
202
|
+
)}
|
|
203
|
+
markup={title || ''}
|
|
204
|
+
onChange={onChangeTitle}
|
|
205
|
+
placeholder={
|
|
206
|
+
(defineChart && titlePlaceholder) || (!disabledTitle && 'Click here to add a title for this graph')
|
|
207
|
+
}
|
|
208
|
+
toolbarOpts={{ noPadding: true, noBorder: true }}
|
|
209
|
+
activePlugins={activeTitlePlugins}
|
|
210
|
+
disableScrollbar
|
|
211
|
+
onKeyDown={this.handleKeyDown}
|
|
212
|
+
/>
|
|
213
|
+
</div>
|
|
173
214
|
))}
|
|
174
215
|
{showLabels && !isChart && (
|
|
175
216
|
<Label
|
|
@@ -181,6 +222,7 @@ export class Root extends React.Component {
|
|
|
181
222
|
graphWidth={finalWidth}
|
|
182
223
|
onChange={(value) => this.onChangeLabel(value, 'top')}
|
|
183
224
|
mathMlOptions={mathMlOptions}
|
|
225
|
+
charactersLimit={labelsCharactersLimit}
|
|
184
226
|
/>
|
|
185
227
|
)}
|
|
186
228
|
<div className={classes.wrapper}>
|
|
@@ -196,6 +238,7 @@ export class Root extends React.Component {
|
|
|
196
238
|
isDefineChartLeftLabel={isChart && defineChart}
|
|
197
239
|
onChange={(value) => this.onChangeLabel(value, 'left')}
|
|
198
240
|
mathMlOptions={mathMlOptions}
|
|
241
|
+
charactersLimit={labelsCharactersLimit}
|
|
199
242
|
/>
|
|
200
243
|
)}
|
|
201
244
|
<svg width={finalWidth} height={finalHeight} className={defineChart ? classes.defineChart : classes.chart}>
|
|
@@ -207,7 +250,7 @@ export class Root extends React.Component {
|
|
|
207
250
|
}
|
|
208
251
|
}}
|
|
209
252
|
className={classes.graphBox}
|
|
210
|
-
transform={`translate(${leftPadding}, ${topPadding})`}
|
|
253
|
+
transform={`translate(${leftPadding + (domain.padding || 0)}, ${topPadding + (range.padding || 0)})`}
|
|
211
254
|
>
|
|
212
255
|
{children}
|
|
213
256
|
</g>
|
|
@@ -222,6 +265,7 @@ export class Root extends React.Component {
|
|
|
222
265
|
graphWidth={finalWidth}
|
|
223
266
|
onChange={(value) => this.onChangeLabel(value, 'right')}
|
|
224
267
|
mathMlOptions={mathMlOptions}
|
|
268
|
+
charactersLimit={labelsCharactersLimit}
|
|
225
269
|
/>
|
|
226
270
|
)}
|
|
227
271
|
{showPixelGuides && (
|
|
@@ -229,7 +273,7 @@ export class Root extends React.Component {
|
|
|
229
273
|
className={classes.sidePixelGuides}
|
|
230
274
|
style={{
|
|
231
275
|
paddingTop: sideGridlinesPadding,
|
|
232
|
-
marginTop:
|
|
276
|
+
marginTop: 31,
|
|
233
277
|
}}
|
|
234
278
|
>
|
|
235
279
|
{[...Array(nbOfHorizontalLines + 1).keys()].reverse().map((value) => (
|
|
@@ -248,10 +292,12 @@ export class Root extends React.Component {
|
|
|
248
292
|
placeholder={labelsPlaceholders?.bottom}
|
|
249
293
|
graphHeight={finalHeight}
|
|
250
294
|
graphWidth={finalWidth}
|
|
295
|
+
titleHeight={titleHeight}
|
|
251
296
|
isChartBottomLabel={isChart && !defineChart}
|
|
252
297
|
isDefineChartBottomLabel={isChart && defineChart}
|
|
253
298
|
onChange={(value) => this.onChangeLabel(value, 'bottom')}
|
|
254
299
|
mathMlOptions={mathMlOptions}
|
|
300
|
+
charactersLimit={labelsCharactersLimit}
|
|
255
301
|
/>
|
|
256
302
|
)}
|
|
257
303
|
</div>
|
|
@@ -259,11 +305,12 @@ export class Root extends React.Component {
|
|
|
259
305
|
}
|
|
260
306
|
}
|
|
261
307
|
|
|
308
|
+
// use default color theme style to avoid color contrast issues
|
|
262
309
|
const styles = (theme) => ({
|
|
263
310
|
root: {
|
|
264
311
|
border: `solid 1px ${color.primaryLight()}`,
|
|
265
|
-
color: color.
|
|
266
|
-
backgroundColor:
|
|
312
|
+
color: color.defaults.TEXT,
|
|
313
|
+
backgroundColor: theme.palette.common.white,
|
|
267
314
|
touchAction: 'none',
|
|
268
315
|
position: 'relative',
|
|
269
316
|
},
|
|
@@ -284,13 +331,13 @@ const styles = (theme) => ({
|
|
|
284
331
|
userSelect: 'none',
|
|
285
332
|
},
|
|
286
333
|
graphTitle: {
|
|
287
|
-
color: color.
|
|
334
|
+
color: color.defaults.TEXT,
|
|
288
335
|
fontSize: theme.typography.fontSize + 2,
|
|
289
336
|
padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit / 2}px 0`,
|
|
290
337
|
textAlign: 'center',
|
|
291
338
|
},
|
|
292
339
|
chartTitle: {
|
|
293
|
-
color: color.
|
|
340
|
+
color: color.defaults.TEXT,
|
|
294
341
|
fontSize: theme.typography.fontSize + 4,
|
|
295
342
|
padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit / 2}px 0`,
|
|
296
343
|
textAlign: 'center',
|
|
@@ -306,7 +353,7 @@ const styles = (theme) => ({
|
|
|
306
353
|
paddingTop: '6px',
|
|
307
354
|
},
|
|
308
355
|
topPixelIndicator: {
|
|
309
|
-
color: color.
|
|
356
|
+
color: color.defaults.PRIMARY_LIGHT,
|
|
310
357
|
display: 'flex',
|
|
311
358
|
flexDirection: 'column',
|
|
312
359
|
alignItems: 'center',
|
|
@@ -321,7 +368,7 @@ const styles = (theme) => ({
|
|
|
321
368
|
marginRight: '6px',
|
|
322
369
|
},
|
|
323
370
|
sidePixelIndicator: {
|
|
324
|
-
color: color.
|
|
371
|
+
color: color.defaults.PRIMARY_LIGHT,
|
|
325
372
|
textAlign: 'right',
|
|
326
373
|
height: '20px',
|
|
327
374
|
pointerEvents: 'none',
|
package/src/trig.js
CHANGED
package/src/utils.js
CHANGED
|
@@ -154,3 +154,17 @@ export const amountToIncreaseWidth = (longestWord) => {
|
|
|
154
154
|
|
|
155
155
|
return longestWord * 20;
|
|
156
156
|
};
|
|
157
|
+
|
|
158
|
+
export const extractTextFromHTML = (htmlString) => {
|
|
159
|
+
const parser = new DOMParser();
|
|
160
|
+
const doc = parser?.parseFromString(htmlString, 'text/html');
|
|
161
|
+
return doc?.body?.textContent || '';
|
|
162
|
+
};
|
|
163
|
+
|
|
164
|
+
export const isEmptyObject = (obj) => {
|
|
165
|
+
return obj && Object.keys(obj).length === 0 && obj.constructor === Object;
|
|
166
|
+
};
|
|
167
|
+
|
|
168
|
+
export const isEmptyString = (str) => {
|
|
169
|
+
return typeof str === 'string' && str.trim() === '';
|
|
170
|
+
};
|