@pie-lib/plot 2.7.3 → 2.7.4-next.1618

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.
@@ -0,0 +1,233 @@
1
+ import { AssertionError } from 'assert';
2
+ import * as utils from '../utils';
3
+
4
+ const xy = utils.xy;
5
+
6
+ const tick = (isMajor, v) => ({
7
+ major: isMajor,
8
+ value: v,
9
+ x: v,
10
+ });
11
+
12
+ const major = tick.bind(null, true);
13
+ const minor = tick.bind(null, false);
14
+
15
+ describe('utils', () => {
16
+ describe('getDelta', () => {
17
+ const assertDelta = (from, to, delta) => {
18
+ it(`returns a delta of: ${delta} for ${from} -> ${to}`, () => {
19
+ const d = utils.getDelta(from, to);
20
+ expect(d.x).toEqual(delta.x);
21
+ expect(d.y).toEqual(delta.y);
22
+ });
23
+ };
24
+ assertDelta(xy(0, 0), xy(0, 1), xy(0, 1));
25
+ assertDelta(xy(0, 1), xy(0, 0), xy(0, -1));
26
+ assertDelta(xy(1, 1), xy(3, 3), xy(2, 2));
27
+ assertDelta(xy(-1, -1), xy(3, 3), xy(4, 4));
28
+ assertDelta(xy(-1, -1), xy(-2, -5), xy(-1, -4));
29
+ });
30
+
31
+ describe('polygonToArea', () => {
32
+ const assertPolygon = (points, area) => {
33
+ it(`converts ${points} -> ${area}`, () => {
34
+ const result = utils.polygonToArea(points);
35
+ expect(result).toEqual(area);
36
+ });
37
+ };
38
+ assertPolygon([xy(0, 0), xy(1, 1), xy(1, -1)], {
39
+ left: 0,
40
+ top: 1,
41
+ bottom: -1,
42
+ right: 1,
43
+ });
44
+ assertPolygon([xy(0, 0), xy(3, 0), xy(2, -1), xy(4, -3), xy(1, -4), xy(2, -2)], {
45
+ left: 0,
46
+ top: 0,
47
+ bottom: -4,
48
+ right: 4,
49
+ });
50
+ });
51
+
52
+ describe('buildTickModel', () => {
53
+ let scaleFn;
54
+
55
+ beforeEach(() => {
56
+ scaleFn = jest.fn(function(v) {
57
+ return v;
58
+ });
59
+ });
60
+
61
+ it('builds major only ticks', () => {
62
+ let result = utils.buildTickModel({ min: 0, max: 2 }, { minor: 0 }, 1, scaleFn);
63
+ expect(result).toEqual([major(0), major(1), major(2)]);
64
+ });
65
+
66
+ it('builds minor + major ticks', () => {
67
+ let result = utils.buildTickModel({ min: 0, max: 2 }, { minor: 1 }, 0.5, scaleFn);
68
+ expect(result).toEqual([major(0), minor(0.5), major(1), minor(1.5), major(2)]);
69
+ });
70
+ });
71
+
72
+ describe('snapTo', () => {
73
+ let assertSnapTo = (min, max, interval, value, expected) => {
74
+ it(`snaps ${value} to ${expected} with domain ${min}<->${max} with interval: ${interval} `, () => {
75
+ let result = utils.snapTo(min, max, interval, value);
76
+ expect(result).toEqual(expected);
77
+ });
78
+ };
79
+
80
+ describe('with 0, 10, 0.25', () => {
81
+ let a = assertSnapTo.bind(null, 0, 10, 0.25);
82
+ a(1, 1);
83
+ a(1.2, 1.25);
84
+ a(0.2, 0.25);
85
+ a(5.2, 5.25);
86
+ a(5.125, 5.25);
87
+ a(5.124, 5);
88
+ });
89
+
90
+ describe('with 0, 10, 1', () => {
91
+ let a = assertSnapTo.bind(null, 0, 10, 1);
92
+ a(0, 0);
93
+ a(10, 10);
94
+ a(100, 10);
95
+ a(1, 1);
96
+ a(1.2, 1);
97
+ a(0.2, 0);
98
+ a(5.2, 5);
99
+ a(5.001, 5);
100
+ });
101
+ });
102
+
103
+ describe('getInterval', () => {
104
+ let assertGetInterval = (min, max, ticks, expected) => {
105
+ let paramsDescription = JSON.stringify(ticks);
106
+ it(`converts: ${paramsDescription} to ${JSON.stringify(expected)}`, () => {
107
+ let result = utils.getInterval({ min: min, max: max }, ticks);
108
+ expect(result).toEqual(expected);
109
+ });
110
+ };
111
+
112
+ describe('with bad params', () => {
113
+ it('throws an error if min > max', () => {
114
+ expect(() => {
115
+ let result = utils.convertFrequencyToInterval(
116
+ { min: 11, max: 10, tickFrequency: 1, betweenTickCount: 0 },
117
+ { interval: 10, major: 10 },
118
+ );
119
+ console.log('result: ', result);
120
+ }).toThrow(Error);
121
+ });
122
+
123
+ it('throws an error if min = max', () => {
124
+ expect(() => {
125
+ let result = utils.convertFrequencyToInterval(
126
+ { min: 10, max: 10, tickFrequency: 1, betweenTickCount: 0 },
127
+ { interval: 10, major: 10 },
128
+ );
129
+ console.log('result: ', result);
130
+ }).toThrow(Error);
131
+ });
132
+ });
133
+
134
+ describe('with domain 0 -> 1', () => {
135
+ let a = assertGetInterval.bind(null, 0, 1);
136
+ a({ major: 2, minor: 0 }, 1);
137
+ a({ major: 2, minor: 1 }, 0.5);
138
+ });
139
+
140
+ describe('with domain 0 -> 10', () => {
141
+ let a = assertGetInterval.bind(null, 0, 10);
142
+
143
+ it('throws an error if the tick frequency is less than 2', () => {
144
+ expect(() => {
145
+ let result = utils.convertFrequencyToInterval(
146
+ { min: 0, max: 10, tickFrequency: 1, betweenTickCount: 0 },
147
+ { interval: 10, major: 10 },
148
+ );
149
+ console.log('result: ', result);
150
+ }).toThrow(Error);
151
+ });
152
+
153
+ a({ major: 2, minor: 9 }, 1);
154
+ a({ major: 2, minor: 0 }, 10);
155
+ a({ major: 3, minor: 0 }, 5);
156
+ a({ major: 3, minor: 1 }, 2.5);
157
+ a({ major: 4, minor: 0 }, 3.3333);
158
+ a({ major: 5, minor: 0 }, 2.5);
159
+ a({ major: 6, minor: 0 }, 2);
160
+ a({ major: 7, minor: 0 }, 1.6667);
161
+ a({ major: 8, minor: 0 }, 1.4286);
162
+ a({ major: 9, minor: 0 }, 1.25);
163
+ a({ major: 10, minor: 0 }, 1.1111);
164
+ a({ major: 11, minor: 0 }, 1);
165
+ a({ major: 11, minor: 1 }, 0.5);
166
+ a({ major: 11, minor: 2 }, 0.3333);
167
+ });
168
+
169
+ describe('with domain 0 -> 100', () => {
170
+ let a = assertGetInterval.bind(null, 0, 100);
171
+ a({ major: 11, minor: 1 }, 5);
172
+ a({ major: 101, minor: 0 }, 1);
173
+ });
174
+
175
+ describe('with domain -5 - 5', () => {
176
+ let a = assertGetInterval.bind(null, -5, 5);
177
+ a({ major: 11, minor: 0 }, 1);
178
+ });
179
+
180
+ describe('with domain 0 - 5', () => {
181
+ let a = assertGetInterval.bind(null, 0, 5);
182
+ a({ major: 11, minor: 0 }, 0.5);
183
+ a({ major: 11, minor: 2 }, 0.1667);
184
+ a({ major: 11, minor: 1 }, 0.25);
185
+ });
186
+ });
187
+
188
+ describe('findLongestWord', () => {
189
+ it('should return 0 if label is undefined', () => {
190
+ const label = undefined;
191
+ const result = utils.findLongestWord(label);
192
+
193
+ expect(result).toEqual(0);
194
+ });
195
+
196
+ it('should return 0 if label is null', () => {
197
+ const label = null;
198
+ const result = utils.findLongestWord(label);
199
+
200
+ expect(result).toEqual(0);
201
+ });
202
+
203
+ it('should return 6 if the longest word from label has 6 letters', () => {
204
+ const label = 'Number of months';
205
+ const result = utils.findLongestWord(label);
206
+
207
+ expect(result).toEqual(6);
208
+ });
209
+ });
210
+
211
+ describe('amountToIncreaseWidth', () => {
212
+ it('should return 0 if longestWord is undefined', () => {
213
+ const longestWord = undefined;
214
+ const result = utils.amountToIncreaseWidth(longestWord);
215
+
216
+ expect(result).toEqual(0);
217
+ });
218
+
219
+ it('should return 0 if longestWord is null', () => {
220
+ const longestWord = null;
221
+ const result = utils.amountToIncreaseWidth(longestWord);
222
+
223
+ expect(result).toEqual(0);
224
+ });
225
+
226
+ it('should return 150 if longestWord is 10', () => {
227
+ const longestWord = 10;
228
+ const result = utils.amountToIncreaseWidth(longestWord);
229
+
230
+ expect(result).toEqual(200);
231
+ });
232
+ });
233
+ });
@@ -96,10 +96,57 @@ export const gridDraggable = (opts) => (Comp) => {
96
96
  return scaled;
97
97
  };
98
98
 
99
+ /**
100
+ * Retrieves the coordinates of a mouse or touch event relative to an SVG element.
101
+ * This method has been overwritten from the d3-selection library's clientPoint to handle touch events and improve clarity.
102
+ * @param {Element} node - The SVG element.
103
+ * @param {Event} event - The mouse or touch event.
104
+ * @returns {Array} - An array containing the coordinates [x, y] relative to the SVG element.
105
+ */
106
+ getClientPoint = (node, event) => {
107
+ if (!node || !event) {
108
+ return null;
109
+ }
110
+ const svg = node.ownerSVGElement || node;
111
+
112
+ if (svg && svg.createSVGPoint) {
113
+ let point = svg.createSVGPoint();
114
+ // Check if it's a touch event and use the first touch point
115
+ if (event.touches && event.touches.length > 0) {
116
+ const touch = event.touches[0];
117
+ point.x = touch.clientX;
118
+ point.y = touch.clientY;
119
+ } else {
120
+ // Fall back to mouse event properties
121
+ point.x = event.clientX;
122
+ point.y = event.clientY;
123
+ }
124
+ if (node.getScreenCTM) {
125
+ point = point.matrixTransform(node.getScreenCTM().inverse());
126
+ return [point.x, point.y];
127
+ } else {
128
+ return null;
129
+ }
130
+ }
131
+
132
+ const rect = node.getBoundingClientRect();
133
+ if (rect) {
134
+ return [event.clientX - rect.left - node.clientLeft, event.clientY - rect.top - node.clientTop];
135
+ } else {
136
+ return null;
137
+ }
138
+ };
139
+
99
140
  skipDragOutsideOfBounds = (dd, e, graphProps) => {
100
- // ignore drag movement outside of the domain and range.
141
+ // Ignore drag movement outside of the domain and range.
101
142
  const rootNode = graphProps.getRootNode();
102
- const [rawX, rawY] = clientPoint(rootNode, e);
143
+ const clientPoint = this.getClientPoint(rootNode, e);
144
+
145
+ if (clientPoint === null) {
146
+ return true; // Indicate that the drag is outside of bounds
147
+ }
148
+
149
+ const [rawX, rawY] = clientPoint;
103
150
  const { scale, domain, range } = graphProps;
104
151
  let x = scale.x.invert(rawX);
105
152
  let y = scale.y.invert(rawY);
@@ -195,13 +242,10 @@ export const gridDraggable = (opts) => (Comp) => {
195
242
  };
196
243
 
197
244
  render() {
198
- /* eslint-disable no-unused-vars */
199
- //Note: we pull onClick out so that it's not in ...rest.
200
- const { disabled, onClick, ...rest } = this.props;
201
- /* eslint-enable no-unused-vars */
202
-
245
+ const { disabled, ...rest } = this.props;
203
246
  const grid = this.grid();
204
- //prevent the text select icon from rendering.
247
+
248
+ // prevent the text select icon from rendering.
205
249
  const onMouseDown = (e) => e.nativeEvent.preventDefault();
206
250
 
207
251
  /**
package/src/label.jsx CHANGED
@@ -4,7 +4,7 @@ import cn from 'classnames';
4
4
  import EditableHtml from '@pie-lib/editable-html';
5
5
  import { withStyles } from '@material-ui/core/styles';
6
6
  import PropTypes from 'prop-types';
7
-
7
+ import { extractTextFromHTML, isEmptyString } from './utils';
8
8
  const LabelComponent = (props) => {
9
9
  const {
10
10
  classes,
@@ -20,6 +20,8 @@ const LabelComponent = (props) => {
20
20
  side,
21
21
  onChange,
22
22
  mathMlOptions = {},
23
+ charactersLimit,
24
+ titleHeight,
23
25
  } = props;
24
26
  const [rotatedToHorizontal, setRotatedToHorizontal] = useState(false);
25
27
  const activePlugins = [
@@ -40,8 +42,8 @@ const LabelComponent = (props) => {
40
42
  chartValue ||
41
43
  (isChartLeftLabel && `${graphHeight - 70}px`) ||
42
44
  (side === 'left' && `${graphHeight - 8}px`) ||
43
- (isChartBottomLabel && `${graphHeight - 30}px`) ||
44
- (side === 'bottom' && `${graphHeight - 90}px`) ||
45
+ (isChartBottomLabel && `${graphHeight - 60 + titleHeight}px`) ||
46
+ (side === 'bottom' && `${graphHeight - 120 + titleHeight}px`) ||
45
47
  0,
46
48
  left:
47
49
  (side === 'right' && `${graphWidth - 8}px`) ||
@@ -66,6 +68,7 @@ const LabelComponent = (props) => {
66
68
  [classes.rotateRightLabel]: side === 'right' && !rotatedToHorizontal,
67
69
  [classes.editLabel]: rotatedToHorizontal,
68
70
  [classes.customBottom]: isChartBottomLabel || isDefineChartBottomLabel,
71
+ [classes.displayNone]: disabledLabel && !isChart && isEmptyString(extractTextFromHTML(text)),
69
72
  })}
70
73
  style={rotatedToHorizontal ? rotatedStyle : defaultStyle}
71
74
  onClick={rotateLabel}
@@ -79,12 +82,14 @@ const LabelComponent = (props) => {
79
82
  placeholder={!disabledLabel && placeholder}
80
83
  toolbarOpts={{
81
84
  position: side === 'bottom' ? 'top' : 'bottom',
85
+ noPadding: true,
82
86
  noBorder: true,
83
87
  }}
84
88
  disableScrollbar
85
89
  activePlugins={activePlugins}
86
90
  onDone={() => setRotatedToHorizontal(false)}
87
91
  mathMlOptions={mathMlOptions}
92
+ charactersLimit={charactersLimit}
88
93
  />
89
94
  )}
90
95
  </div>
@@ -104,6 +109,9 @@ LabelComponent.propTypes = {
104
109
  text: PropTypes.string,
105
110
  side: PropTypes.string,
106
111
  onChange: PropTypes.func,
112
+ mathMlOptions: PropTypes.object,
113
+ charactersLimit: PropTypes.number,
114
+ titleHeight: PropTypes.number,
107
115
  };
108
116
 
109
117
  export default withStyles((theme) => ({
@@ -148,4 +156,7 @@ export default withStyles((theme) => ({
148
156
  customBottom: {
149
157
  position: 'absolute',
150
158
  },
159
+ displayNone: {
160
+ display: 'none',
161
+ },
151
162
  }))(LabelComponent);
package/src/root.jsx CHANGED
@@ -1,15 +1,24 @@
1
1
  import React from 'react';
2
- import { ChildrenType } from './types';
3
2
  import { withStyles } from '@material-ui/core/styles';
4
- import { select, mouse } from 'd3-selection';
5
3
  import PropTypes from 'prop-types';
6
- import { GraphPropsType } from './types';
4
+ import { select, mouse } from 'd3-selection';
5
+ import cn from 'classnames';
6
+
7
7
  import { color, Readable } from '@pie-lib/render-ui';
8
8
  import EditableHtml from '@pie-lib/editable-html';
9
- import cn from 'classnames';
9
+ import { ChildrenType } from './types';
10
+ import { GraphPropsType } from './types';
10
11
  import Label from './label';
12
+ import { extractTextFromHTML, isEmptyObject, isEmptyString } from './utils';
11
13
 
12
14
  export class Root extends React.Component {
15
+ constructor(props) {
16
+ super(props);
17
+ this.state = {
18
+ titleHeight: 0,
19
+ };
20
+ }
21
+
13
22
  static propTypes = {
14
23
  title: PropTypes.string,
15
24
  children: ChildrenType,
@@ -29,6 +38,8 @@ export class Root extends React.Component {
29
38
  rootRef: PropTypes.func,
30
39
  onChangeLabels: PropTypes.func,
31
40
  titlePlaceholder: PropTypes.string,
41
+ mathMlOptions: PropTypes.object,
42
+ labelsCharactersLimit: PropTypes.number,
32
43
  };
33
44
 
34
45
  mouseMove = (g) => {
@@ -54,6 +65,7 @@ export class Root extends React.Component {
54
65
  componentDidMount() {
55
66
  const g = select(this.g);
56
67
  g.on('mousemove', this.mouseMove.bind(this, g));
68
+ this.measureTitleHeight();
57
69
  }
58
70
 
59
71
  componentWillUnmount() {
@@ -61,9 +73,19 @@ export class Root extends React.Component {
61
73
  g.on('mousemove', null);
62
74
  }
63
75
 
76
+ componentDidUpdate(prevProps) {
77
+ if (prevProps.title !== this.props.title) {
78
+ this.measureTitleHeight();
79
+ }
80
+ }
81
+
64
82
  onChangeLabel = (newValue, side) => {
65
83
  const { labels, onChangeLabels, isChart } = this.props;
66
84
 
85
+ if (!onChangeLabels) {
86
+ return;
87
+ }
88
+
67
89
  if (isChart) {
68
90
  if (side === 'left') {
69
91
  onChangeLabels('range', newValue);
@@ -80,6 +102,18 @@ export class Root extends React.Component {
80
102
  });
81
103
  };
82
104
 
105
+ measureTitleHeight = () => {
106
+ const titleElement = this.titleRef;
107
+ if (titleElement) {
108
+ const titleHeight = titleElement.clientHeight;
109
+ this.setState({ titleHeight, prevTitle: this.props.title });
110
+ }
111
+ };
112
+
113
+ handleKeyDown = () => {
114
+ setTimeout(this.measureTitleHeight, 0);
115
+ };
116
+
83
117
  render() {
84
118
  const {
85
119
  disabledTitle,
@@ -99,6 +133,7 @@ export class Root extends React.Component {
99
133
  title,
100
134
  rootRef,
101
135
  mathMlOptions = {},
136
+ labelsCharactersLimit,
102
137
  } = this.props;
103
138
  const {
104
139
  size: { width = 500, height = 500 },
@@ -107,14 +142,18 @@ export class Root extends React.Component {
107
142
  } = graphProps;
108
143
 
109
144
  const topPadding = 40;
110
- const leftPadding = showLabels ? 80 : 60;
111
- const finalWidth = width + leftPadding * 2 + (domain.padding || 0) * 2;
145
+ const leftPadding = isEmptyString(extractTextFromHTML(labels?.left)) && isEmptyObject(labelsPlaceholders) ? 48 : 70;
146
+ const rightPadding =
147
+ isEmptyString(extractTextFromHTML(labels?.right)) && isEmptyObject(labelsPlaceholders) ? 48 : 70;
148
+ const finalWidth = width + leftPadding + rightPadding + (domain.padding || 0) * 2;
112
149
  const finalHeight = height + topPadding * 2 + (range.padding || 0) * 2;
113
150
 
114
151
  const activeTitlePlugins = [
115
152
  'bold',
116
153
  'italic',
117
154
  'underline',
155
+ 'superscript',
156
+ 'subscript',
118
157
  'strikethrough',
119
158
  'math',
120
159
  // 'languageCharacters'
@@ -124,11 +163,11 @@ export class Root extends React.Component {
124
163
  const nbOfVerticalLines = parseInt(width / 100);
125
164
  const nbOfHorizontalLines = parseInt(actualHeight / 100);
126
165
  const sideGridlinesPadding = parseInt(actualHeight % 100);
127
-
166
+ const { titleHeight } = this.state;
128
167
  return (
129
168
  <div className={classes.root}>
130
169
  {showPixelGuides && (
131
- <div className={classes.topPixelGuides} style={{ marginLeft: isChart ? 60 : showLabels ? 30 : 10 }}>
170
+ <div className={classes.topPixelGuides} style={{ marginLeft: isChart ? 80 : showLabels ? 30 : 10 }}>
132
171
  {[...Array(nbOfVerticalLines + 1).keys()].map((value) => (
133
172
  <Readable false key={`top-guide-${value}`}>
134
173
  <div className={classes.topPixelIndicator}>
@@ -142,34 +181,37 @@ export class Root extends React.Component {
142
181
  {showTitle &&
143
182
  (disabledTitle ? (
144
183
  <div
145
- style={
146
- isChart && {
147
- width: finalWidth,
148
- }
149
- }
184
+ ref={(r) => (this.titleRef = r)}
185
+ style={{
186
+ ...(isChart && { width: finalWidth }),
187
+ ...(isEmptyString(extractTextFromHTML(title)) && { display: 'none' }),
188
+ }}
150
189
  className={cn(isChart ? classes.chartTitle : classes.graphTitle, classes.disabledTitle)}
151
190
  dangerouslySetInnerHTML={{ __html: title || '' }}
152
191
  />
153
192
  ) : (
154
- <EditableHtml
155
- style={
156
- isChart && {
157
- width: finalWidth,
193
+ <div ref={(r) => (this.titleRef = r)}>
194
+ <EditableHtml
195
+ style={
196
+ isChart && {
197
+ width: finalWidth,
198
+ }
158
199
  }
159
- }
160
- className={cn(
161
- { [classes.rightMargin]: showPixelGuides },
162
- isChart ? classes.chartTitle : classes.graphTitle,
163
- )}
164
- markup={title || ''}
165
- onChange={onChangeTitle}
166
- placeholder={
167
- (defineChart && titlePlaceholder) || (!disabledTitle && 'Click here to add a title for this graph')
168
- }
169
- toolbarOpts={{ noBorder: true }}
170
- activePlugins={activeTitlePlugins}
171
- disableScrollbar
172
- />
200
+ className={cn(
201
+ { [classes.rightMargin]: showPixelGuides },
202
+ isChart ? classes.chartTitle : classes.graphTitle,
203
+ )}
204
+ markup={title || ''}
205
+ onChange={onChangeTitle}
206
+ placeholder={
207
+ (defineChart && titlePlaceholder) || (!disabledTitle && 'Click here to add a title for this graph')
208
+ }
209
+ toolbarOpts={{ noPadding: true, noBorder: true }}
210
+ activePlugins={activeTitlePlugins}
211
+ disableScrollbar
212
+ onKeyDown={this.handleKeyDown}
213
+ />
214
+ </div>
173
215
  ))}
174
216
  {showLabels && !isChart && (
175
217
  <Label
@@ -181,6 +223,7 @@ export class Root extends React.Component {
181
223
  graphWidth={finalWidth}
182
224
  onChange={(value) => this.onChangeLabel(value, 'top')}
183
225
  mathMlOptions={mathMlOptions}
226
+ charactersLimit={labelsCharactersLimit}
184
227
  />
185
228
  )}
186
229
  <div className={classes.wrapper}>
@@ -196,6 +239,7 @@ export class Root extends React.Component {
196
239
  isDefineChartLeftLabel={isChart && defineChart}
197
240
  onChange={(value) => this.onChangeLabel(value, 'left')}
198
241
  mathMlOptions={mathMlOptions}
242
+ charactersLimit={labelsCharactersLimit}
199
243
  />
200
244
  )}
201
245
  <svg width={finalWidth} height={finalHeight} className={defineChart ? classes.defineChart : classes.chart}>
@@ -207,7 +251,7 @@ export class Root extends React.Component {
207
251
  }
208
252
  }}
209
253
  className={classes.graphBox}
210
- transform={`translate(${leftPadding}, ${topPadding})`}
254
+ transform={`translate(${leftPadding + (domain.padding || 0)}, ${topPadding + (range.padding || 0)})`}
211
255
  >
212
256
  {children}
213
257
  </g>
@@ -222,6 +266,7 @@ export class Root extends React.Component {
222
266
  graphWidth={finalWidth}
223
267
  onChange={(value) => this.onChangeLabel(value, 'right')}
224
268
  mathMlOptions={mathMlOptions}
269
+ charactersLimit={labelsCharactersLimit}
225
270
  />
226
271
  )}
227
272
  {showPixelGuides && (
@@ -229,7 +274,7 @@ export class Root extends React.Component {
229
274
  className={classes.sidePixelGuides}
230
275
  style={{
231
276
  paddingTop: sideGridlinesPadding,
232
- marginTop: defineChart ? 25 : 31,
277
+ marginTop: 31,
233
278
  }}
234
279
  >
235
280
  {[...Array(nbOfHorizontalLines + 1).keys()].reverse().map((value) => (
@@ -248,10 +293,12 @@ export class Root extends React.Component {
248
293
  placeholder={labelsPlaceholders?.bottom}
249
294
  graphHeight={finalHeight}
250
295
  graphWidth={finalWidth}
296
+ titleHeight={titleHeight}
251
297
  isChartBottomLabel={isChart && !defineChart}
252
298
  isDefineChartBottomLabel={isChart && defineChart}
253
299
  onChange={(value) => this.onChangeLabel(value, 'bottom')}
254
300
  mathMlOptions={mathMlOptions}
301
+ charactersLimit={labelsCharactersLimit}
255
302
  />
256
303
  )}
257
304
  </div>
@@ -259,13 +306,15 @@ export class Root extends React.Component {
259
306
  }
260
307
  }
261
308
 
309
+ // use default color theme style to avoid color contrast issues
262
310
  const styles = (theme) => ({
263
311
  root: {
264
312
  border: `solid 1px ${color.primaryLight()}`,
265
- color: color.text(),
266
- backgroundColor: color.background(),
313
+ color: color.defaults.TEXT,
314
+ backgroundColor: theme.palette.common.white,
267
315
  touchAction: 'none',
268
316
  position: 'relative',
317
+ boxSizing: 'unset', // to override the default border-box in IBX that breaks the component width layout
269
318
  },
270
319
  wrapper: {
271
320
  display: 'flex',
@@ -284,13 +333,13 @@ const styles = (theme) => ({
284
333
  userSelect: 'none',
285
334
  },
286
335
  graphTitle: {
287
- color: color.text(),
336
+ color: color.defaults.TEXT,
288
337
  fontSize: theme.typography.fontSize + 2,
289
338
  padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit / 2}px 0`,
290
339
  textAlign: 'center',
291
340
  },
292
341
  chartTitle: {
293
- color: color.text(),
342
+ color: color.defaults.TEXT,
294
343
  fontSize: theme.typography.fontSize + 4,
295
344
  padding: `${theme.spacing.unit * 1.5}px ${theme.spacing.unit / 2}px 0`,
296
345
  textAlign: 'center',
@@ -306,7 +355,6 @@ const styles = (theme) => ({
306
355
  paddingTop: '6px',
307
356
  },
308
357
  topPixelIndicator: {
309
- color: color.primaryLight(),
310
358
  display: 'flex',
311
359
  flexDirection: 'column',
312
360
  alignItems: 'center',
@@ -321,7 +369,6 @@ const styles = (theme) => ({
321
369
  marginRight: '6px',
322
370
  },
323
371
  sidePixelIndicator: {
324
- color: color.primaryLight(),
325
372
  textAlign: 'right',
326
373
  height: '20px',
327
374
  pointerEvents: 'none',
package/src/trig.js CHANGED
@@ -1,4 +1,4 @@
1
- import { xy } from '../lib/utils';
1
+ import { xy } from './utils';
2
2
  import Point from '@mapbox/point-geometry';
3
3
  import debug from 'debug';
4
4
  const log = debug('pie-lib:plot:trig');
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
+ };