@pie-lib/plot 2.7.4-next.0 → 2.8.0-beta.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.
- package/CHANGELOG.md +34 -7
- package/NEXT.CHANGELOG.json +1 -0
- 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/lib/draggable.js +0 -65
- package/lib/draggable.js.map +0 -1
- package/lib/graph-props.js +0 -53
- package/lib/graph-props.js.map +0 -1
- package/lib/grid-draggable.js +0 -345
- package/lib/grid-draggable.js.map +0 -1
- package/lib/index.js +0 -59
- package/lib/index.js.map +0 -1
- package/lib/label.js +0 -164
- package/lib/label.js.map +0 -1
- package/lib/root.js +0 -379
- package/lib/root.js.map +0 -1
- package/lib/trig.js +0 -196
- package/lib/trig.js.map +0 -1
- package/lib/types.js +0 -68
- package/lib/types.js.map +0 -1
- package/lib/utils.js +0 -210
- package/lib/utils.js.map +0 -1
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { shallow } from 'enzyme';
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import { Root } from '../root';
|
|
4
|
+
import { select, mouse } from 'd3-selection';
|
|
5
|
+
|
|
6
|
+
const scaleMock = () => {
|
|
7
|
+
const fn = jest.fn((n) => n);
|
|
8
|
+
fn.invert = jest.fn((n) => n);
|
|
9
|
+
return fn;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const graphProps = () => ({
|
|
13
|
+
scale: {
|
|
14
|
+
x: scaleMock(),
|
|
15
|
+
y: scaleMock(),
|
|
16
|
+
},
|
|
17
|
+
snap: {
|
|
18
|
+
x: jest.fn((n) => n),
|
|
19
|
+
y: jest.fn((n) => n),
|
|
20
|
+
},
|
|
21
|
+
domain: {
|
|
22
|
+
min: 0,
|
|
23
|
+
max: 1,
|
|
24
|
+
step: 1,
|
|
25
|
+
},
|
|
26
|
+
range: {
|
|
27
|
+
min: 0,
|
|
28
|
+
max: 1,
|
|
29
|
+
step: 1,
|
|
30
|
+
},
|
|
31
|
+
size: {
|
|
32
|
+
width: 400,
|
|
33
|
+
height: 400,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
const wrapper = (props) => {
|
|
38
|
+
props = {
|
|
39
|
+
classes: {},
|
|
40
|
+
graphProps: graphProps(),
|
|
41
|
+
...props,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return shallow(<Root {...props}>hi</Root>, { disableLifecycleMethods: true });
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
jest.mock('d3-selection', () => ({
|
|
48
|
+
select: jest.fn(),
|
|
49
|
+
mouse: jest.fn(),
|
|
50
|
+
}));
|
|
51
|
+
|
|
52
|
+
describe('root', () => {
|
|
53
|
+
describe('snapshot', () => {
|
|
54
|
+
it('matches', () => {
|
|
55
|
+
const w = wrapper();
|
|
56
|
+
expect(w).toMatchSnapshot();
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
describe('logic', () => {
|
|
61
|
+
describe('mousemove', () => {
|
|
62
|
+
describe('mount/unmount', () => {
|
|
63
|
+
it('adds mousemove listener on compenentDidMount', () => {
|
|
64
|
+
const w = wrapper();
|
|
65
|
+
const g = {
|
|
66
|
+
on: jest.fn(),
|
|
67
|
+
};
|
|
68
|
+
select.mockReturnValue(g);
|
|
69
|
+
w.instance().componentDidMount();
|
|
70
|
+
expect(g.on).toHaveBeenCalledWith('mousemove', expect.any(Function));
|
|
71
|
+
});
|
|
72
|
+
it('unsets mousemove listener on componentWillUnmount', () => {
|
|
73
|
+
const w = wrapper();
|
|
74
|
+
const g = {
|
|
75
|
+
on: jest.fn(),
|
|
76
|
+
};
|
|
77
|
+
select.mockReturnValue(g);
|
|
78
|
+
w.instance().componentWillUnmount();
|
|
79
|
+
expect(g.on).toHaveBeenCalledWith('mousemove', null);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('mouseMove function', () => {
|
|
84
|
+
let onMouseMove, w, gp;
|
|
85
|
+
beforeEach(() => {
|
|
86
|
+
onMouseMove = jest.fn();
|
|
87
|
+
gp = graphProps();
|
|
88
|
+
w = wrapper({
|
|
89
|
+
onMouseMove,
|
|
90
|
+
graphProps: gp,
|
|
91
|
+
});
|
|
92
|
+
mouse.mockReturnValue([0, 0]);
|
|
93
|
+
const g = { _groups: [[[0, 0]]] };
|
|
94
|
+
w.instance().mouseMove(g);
|
|
95
|
+
});
|
|
96
|
+
it('calls mouse', () => {
|
|
97
|
+
expect(mouse).toHaveBeenCalledWith([0, 0]);
|
|
98
|
+
});
|
|
99
|
+
it('calls, scale.x.invert', () => {
|
|
100
|
+
expect(gp.scale.x.invert).toHaveBeenCalledWith(0);
|
|
101
|
+
});
|
|
102
|
+
it('calls, scale.y.invert', () => {
|
|
103
|
+
expect(gp.scale.y.invert).toHaveBeenCalledWith(0);
|
|
104
|
+
});
|
|
105
|
+
it('calls, snap.x', () => {
|
|
106
|
+
expect(gp.snap.x).toHaveBeenCalledWith(0);
|
|
107
|
+
});
|
|
108
|
+
it('calls, snap.y', () => {
|
|
109
|
+
expect(gp.snap.y).toHaveBeenCalledWith(0);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
it('calls handler', () => {
|
|
113
|
+
expect(onMouseMove).toHaveBeenCalledWith({ x: 0, y: 0 });
|
|
114
|
+
});
|
|
115
|
+
});
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
});
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
import {
|
|
2
|
+
angle,
|
|
3
|
+
edge,
|
|
4
|
+
edges,
|
|
5
|
+
maxEdge,
|
|
6
|
+
minEdge,
|
|
7
|
+
toRadians,
|
|
8
|
+
toDegrees,
|
|
9
|
+
acuteXAngle,
|
|
10
|
+
acuteYAngle,
|
|
11
|
+
diffEdge,
|
|
12
|
+
} from '../trig';
|
|
13
|
+
import { xy } from '../utils';
|
|
14
|
+
import debug from 'debug';
|
|
15
|
+
import { getOpposingSide } from '../trig';
|
|
16
|
+
const log = debug('pie-lib:plot:trig:test');
|
|
17
|
+
|
|
18
|
+
const vs = (v) => {
|
|
19
|
+
if (!v) {
|
|
20
|
+
return '';
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if (Number.isFinite(v.x) && Number.isFinite(v.y)) {
|
|
24
|
+
return `[${v.x},${v.y}]`;
|
|
25
|
+
}
|
|
26
|
+
return JSON.stringify(v);
|
|
27
|
+
};
|
|
28
|
+
const p = (strings, ...values) => {
|
|
29
|
+
return strings.reduce((acc, s, index) => {
|
|
30
|
+
return `${acc}${s}${vs(values[index])}`;
|
|
31
|
+
}, '');
|
|
32
|
+
};
|
|
33
|
+
describe('trig', () => {
|
|
34
|
+
describe('angle', () => {
|
|
35
|
+
const assertAngle = (a, b, expected) => {
|
|
36
|
+
it(p`${a}, ${b} => ${toDegrees(expected)}`, () => {
|
|
37
|
+
const result = angle(a, b);
|
|
38
|
+
expect(result).toBeCloseTo(expected);
|
|
39
|
+
});
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
assertAngle(xy(0, 0), xy(1, 1), toRadians(45));
|
|
43
|
+
assertAngle(xy(0, 0), xy(0, 1), toRadians(90));
|
|
44
|
+
assertAngle(xy(0, 0), xy(-1, 1), toRadians(135));
|
|
45
|
+
assertAngle(xy(0, 0), xy(-1, 0), toRadians(180));
|
|
46
|
+
assertAngle(xy(0, 0), xy(-1, -1), toRadians(225));
|
|
47
|
+
assertAngle(xy(0, 0), xy(0, -1), toRadians(270));
|
|
48
|
+
assertAngle(xy(0, 0), xy(1, -1), toRadians(315));
|
|
49
|
+
assertAngle(xy(1, 1), xy(0, 0), toRadians(225));
|
|
50
|
+
assertAngle(xy(0, 0), xy(1, 1), toRadians(45));
|
|
51
|
+
assertAngle(xy(0, 0), xy(2, 1), toRadians(26.565));
|
|
52
|
+
assertAngle(xy(0, 0), xy(3, 1), toRadians(18.434));
|
|
53
|
+
assertAngle(xy(0, 0), xy(4, 1), toRadians(14.036));
|
|
54
|
+
assertAngle(xy(0, 0), xy(5, 1), toRadians(11.309));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
describe('acuteXAngle', () => {
|
|
58
|
+
const assertAcute = (input, expected) => {
|
|
59
|
+
it(`${toDegrees(input)} => ${toDegrees(expected)}`, () => {
|
|
60
|
+
const result = acuteXAngle(input);
|
|
61
|
+
log(`result: ${toDegrees(result)}`);
|
|
62
|
+
expect(result).toBeCloseTo(expected);
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
assertAcute(toRadians(45), toRadians(45));
|
|
67
|
+
assertAcute(toRadians(100), toRadians(80));
|
|
68
|
+
assertAcute(toRadians(190), toRadians(10));
|
|
69
|
+
assertAcute(toRadians(350), toRadians(10));
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
describe('acuteYAngle', () => {
|
|
73
|
+
const assertAcute = (input, expected) => {
|
|
74
|
+
it(`${toDegrees(input)} => ${toDegrees(expected)}`, () => {
|
|
75
|
+
const result = acuteYAngle(input);
|
|
76
|
+
log(`result: ${toDegrees(result)}`);
|
|
77
|
+
expect(result).toBeCloseTo(expected);
|
|
78
|
+
});
|
|
79
|
+
};
|
|
80
|
+
|
|
81
|
+
assertAcute(toRadians(45), toRadians(45));
|
|
82
|
+
assertAcute(toRadians(100), toRadians(10));
|
|
83
|
+
assertAcute(toRadians(190), toRadians(80));
|
|
84
|
+
assertAcute(toRadians(350), toRadians(80));
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
describe('edges', () => {
|
|
88
|
+
const assertEdges = (domain, range) => (from, to, expected) => {
|
|
89
|
+
it(p`${domain}, ${range} + ${from} -> ${to} => ${expected[0]}${expected[1]}`, () => {
|
|
90
|
+
const result = edges(domain, range)(from, to);
|
|
91
|
+
expect(result[0].x).toBeCloseTo(expected[0].x);
|
|
92
|
+
expect(result[0].y).toBeCloseTo(expected[0].y);
|
|
93
|
+
expect(result[1].x).toBeCloseTo(expected[1].x);
|
|
94
|
+
expect(result[1].y).toBeCloseTo(expected[1].y);
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
const one = assertEdges({ min: -4, max: 4 }, { min: -4, max: 4 });
|
|
99
|
+
one(xy(0, 0), xy(1, 1), [xy(4, 4), xy(-4, -4)]);
|
|
100
|
+
one(xy(0, 0), xy(2, 1), [xy(4, 2), xy(-4, -2)]);
|
|
101
|
+
one(xy(1, 1), xy(2, 2), [xy(4, 4), xy(-4, -4)]);
|
|
102
|
+
one(xy(1, 0), xy(2, 0), [xy(4, 0), xy(-4, 0)]);
|
|
103
|
+
one(xy(1, 0), xy(-2, 0), [xy(-4, 0), xy(4, 0)]);
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* domain {min: -5, max: 5, padding: 0, step: 1, labelStep: 1}labelStep: 1max: 5min: -5padding: 0step: 1__proto__: Object range: {min: -5, max: 5, padding: 0, step: 1, labelStep: 1} a: {x: -5, y: 0} b: {x: -5, y: 2} edges: Point {x: -5, y: 5} Point {x: -5, y: 2}
|
|
107
|
+
*/
|
|
108
|
+
const lineIssue = assertEdges({ min: -5, max: 5 }, { min: -5, max: 5 });
|
|
109
|
+
lineIssue(xy(-5, -0), xy(-5, 2), [xy(-5, 5), xy(-5, -5)]);
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
describe('diffEdge', () => {
|
|
113
|
+
const assertDiffEdge = (bounds, from, to, expected) => {
|
|
114
|
+
it(p`<${bounds}> ${from} -> ${to} => ${expected}`, () => {
|
|
115
|
+
const result = diffEdge(bounds, from, to);
|
|
116
|
+
expect(result.x).toBeCloseTo(expected.x);
|
|
117
|
+
expect(result.y).toBeCloseTo(expected.y);
|
|
118
|
+
});
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
const twoTwo = assertDiffEdge.bind(null, xy(2, 2));
|
|
122
|
+
twoTwo(xy(0, 0), xy(1, 1), xy(2, 2));
|
|
123
|
+
twoTwo(xy(0, 0), xy(1, 2), xy(1, 2));
|
|
124
|
+
twoTwo(xy(0, 0), xy(2, 2), xy(2, 2));
|
|
125
|
+
twoTwo(xy(0, 0), xy(2, 2), xy(2, 2));
|
|
126
|
+
twoTwo(xy(0, 0), xy(-1, 1), xy(-2, 2));
|
|
127
|
+
twoTwo(xy(0, 0), xy(-1, -1), xy(-2, -2));
|
|
128
|
+
const fourFour = assertDiffEdge.bind(null, xy(4, 4));
|
|
129
|
+
|
|
130
|
+
fourFour(xy(0, 0), xy(1, 1), xy(4, 4));
|
|
131
|
+
fourFour(xy(0, 0), xy(1, 2), xy(2, 4));
|
|
132
|
+
fourFour(xy(0, 0), xy(2, 1), xy(4, 2));
|
|
133
|
+
fourFour(xy(0, 0), xy(-1, 1), xy(-4, 4));
|
|
134
|
+
fourFour(xy(0, 0), xy(-1, 1), xy(-4, 4));
|
|
135
|
+
|
|
136
|
+
assertDiffEdge(xy(-4, -4), xy(0, 0), xy(-1, -1), xy(-4, -4));
|
|
137
|
+
assertDiffEdge(xy(4, 4), xy(1, 1), xy(2, 2), xy(4, 4));
|
|
138
|
+
assertDiffEdge(xy(4, 4), xy(2, 2), xy(3, 3), xy(4, 4));
|
|
139
|
+
assertDiffEdge(xy(-4, -4), xy(-1, -1), xy(-2, -2), xy(-4, -4));
|
|
140
|
+
assertDiffEdge(xy(-4, 4), xy(-1, -1), xy(-2, 0), xy(-4, 2));
|
|
141
|
+
|
|
142
|
+
const lineIssue = assertDiffEdge.bind(null, xy(-5, -5));
|
|
143
|
+
|
|
144
|
+
lineIssue(xy(-5, 2), xy(-5, 0), xy(-5, -5));
|
|
145
|
+
//Top Right
|
|
146
|
+
assertDiffEdge(xy(5, 5), xy(0, 5), xy(2, 5), xy(5, 5));
|
|
147
|
+
assertDiffEdge(xy(5, 5), xy(5, 0), xy(5, 1), xy(5, 5));
|
|
148
|
+
|
|
149
|
+
// //Bottom Right
|
|
150
|
+
assertDiffEdge(xy(5, -5), xy(5, 0), xy(5, -0.1), xy(5, -5));
|
|
151
|
+
assertDiffEdge(xy(5, -5), xy(0, -5), xy(1, -5), xy(5, -5));
|
|
152
|
+
|
|
153
|
+
//Top Left
|
|
154
|
+
assertDiffEdge(xy(-5, 5), xy(-5, 0), xy(-5, 0.1), xy(-5, 5));
|
|
155
|
+
assertDiffEdge(xy(-5, 5), xy(0, 5), xy(-1, 5), xy(-5, 5));
|
|
156
|
+
|
|
157
|
+
//Bottom Left
|
|
158
|
+
assertDiffEdge(xy(-5, -5), xy(-5, 0), xy(-5, -0.1), xy(-5, -5));
|
|
159
|
+
assertDiffEdge(xy(-5, -5), xy(0, -5), xy(-1, -5), xy(-5, -5));
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
describe('getOpposingSide', () => {
|
|
163
|
+
const assertOpposingSide = (hyp, angle, expected) => {
|
|
164
|
+
it(`${hyp}, ${angle} = ${expected}`, () => {
|
|
165
|
+
const radians = toRadians(angle);
|
|
166
|
+
const result = getOpposingSide(hyp, radians);
|
|
167
|
+
expect(result).toBeCloseTo(expected);
|
|
168
|
+
});
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
assertOpposingSide(1, 45, 0.707);
|
|
172
|
+
assertOpposingSide(1.25, 45, 0.88);
|
|
173
|
+
});
|
|
174
|
+
});
|
|
@@ -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
|
+
});
|
package/src/grid-draggable.jsx
CHANGED
|
@@ -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
|
-
//
|
|
141
|
+
// Ignore drag movement outside of the domain and range.
|
|
101
142
|
const rootNode = graphProps.getRootNode();
|
|
102
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
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 -
|
|
44
|
-
(side === 'bottom' && `${graphHeight -
|
|
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);
|