@pie-lib/tools 2.0.2-next.1 → 2.0.3-next.0
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/dist/_virtual/_rolldown/runtime.js +11 -0
- package/dist/anchor-utils.d.ts +60 -0
- package/dist/anchor-utils.js +87 -0
- package/dist/anchor.d.ts +13 -0
- package/dist/anchor.js +17 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +5 -0
- package/dist/node_modules/.bun/assert@1.5.1/node_modules/assert/assert.js +174 -0
- package/dist/node_modules/.bun/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/actualApply.js +13 -0
- package/dist/node_modules/.bun/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/functionApply.js +8 -0
- package/dist/node_modules/.bun/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/functionCall.js +8 -0
- package/dist/node_modules/.bun/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/index.js +16 -0
- package/dist/node_modules/.bun/call-bind-apply-helpers@1.0.2/node_modules/call-bind-apply-helpers/reflectApply.js +8 -0
- package/dist/node_modules/.bun/call-bound@1.0.4/node_modules/call-bound/index.js +14 -0
- package/dist/node_modules/.bun/degrees-radians@1.0.3/node_modules/degrees-radians/index.js +12 -0
- package/dist/node_modules/.bun/dunder-proto@1.0.1/node_modules/dunder-proto/get.js +19 -0
- package/dist/node_modules/.bun/es-define-property@1.0.1/node_modules/es-define-property/index.js +14 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/eval.js +8 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/index.js +8 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/range.js +8 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/ref.js +8 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/syntax.js +8 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/type.js +8 -0
- package/dist/node_modules/.bun/es-errors@1.3.0/node_modules/es-errors/uri.js +8 -0
- package/dist/node_modules/.bun/es-object-atoms@1.1.2/node_modules/es-object-atoms/index.js +8 -0
- package/dist/node_modules/.bun/function-bind@1.1.2/node_modules/function-bind/implementation.js +34 -0
- package/dist/node_modules/.bun/function-bind@1.1.2/node_modules/function-bind/index.js +10 -0
- package/dist/node_modules/.bun/get-intrinsic@1.3.0/node_modules/get-intrinsic/index.js +283 -0
- package/dist/node_modules/.bun/get-proto@1.0.1/node_modules/get-proto/Object.getPrototypeOf.js +9 -0
- package/dist/node_modules/.bun/get-proto@1.0.1/node_modules/get-proto/Reflect.getPrototypeOf.js +8 -0
- package/dist/node_modules/.bun/get-proto@1.0.1/node_modules/get-proto/index.js +19 -0
- package/dist/node_modules/.bun/gopd@1.2.0/node_modules/gopd/gOPD.js +8 -0
- package/dist/node_modules/.bun/gopd@1.2.0/node_modules/gopd/index.js +15 -0
- package/dist/node_modules/.bun/has-symbols@1.1.0/node_modules/has-symbols/index.js +12 -0
- package/dist/node_modules/.bun/has-symbols@1.1.0/node_modules/has-symbols/shams.js +23 -0
- package/dist/node_modules/.bun/hasown@2.0.4/node_modules/hasown/index.js +10 -0
- package/dist/node_modules/.bun/inherits@2.0.3/node_modules/inherits/inherits_browser.js +19 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/abs.js +8 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/floor.js +8 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/isNaN.js +10 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/max.js +8 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/min.js +8 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/pow.js +8 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/round.js +8 -0
- package/dist/node_modules/.bun/math-intrinsics@1.1.0/node_modules/math-intrinsics/sign.js +12 -0
- package/dist/node_modules/.bun/object-keys@1.1.1/node_modules/object-keys/implementation.js +77 -0
- package/dist/node_modules/.bun/object-keys@1.1.1/node_modules/object-keys/index.js +20 -0
- package/dist/node_modules/.bun/object-keys@1.1.1/node_modules/object-keys/isArguments.js +12 -0
- package/dist/node_modules/.bun/object.assign@4.1.7/node_modules/object.assign/implementation.js +29 -0
- package/dist/node_modules/.bun/object.assign@4.1.7/node_modules/object.assign/polyfill.js +27 -0
- package/dist/node_modules/.bun/radians-degrees@1.0.0/node_modules/radians-degrees/index.js +11 -0
- package/dist/node_modules/.bun/react-portal@4.3.0_6dbf9a050bc9aadb/node_modules/react-portal/es/LegacyPortal.js +77 -0
- package/dist/node_modules/.bun/react-portal@4.3.0_6dbf9a050bc9aadb/node_modules/react-portal/es/Portal.js +55 -0
- package/dist/node_modules/.bun/react-portal@4.3.0_6dbf9a050bc9aadb/node_modules/react-portal/es/PortalCompat.js +9 -0
- package/dist/node_modules/.bun/react-portal@4.3.0_6dbf9a050bc9aadb/node_modules/react-portal/es/utils.js +4 -0
- package/dist/node_modules/.bun/trigonometry-calculator@2.0.0/node_modules/trigonometry-calculator/lib/index.js +53 -0
- package/dist/node_modules/.bun/trigonometry-equations@2.0.1/node_modules/trigonometry-equations/lib/index.js +129 -0
- package/dist/node_modules/.bun/util@0.10.4/node_modules/util/support/isBufferBrowser.js +10 -0
- package/dist/node_modules/.bun/util@0.10.4/node_modules/util/util.js +262 -0
- package/dist/protractor/graphic.d.ts +13 -0
- package/dist/protractor/graphic.js +85 -0
- package/dist/protractor/index.d.ts +29 -0
- package/dist/protractor/index.js +56 -0
- package/dist/rotatable.d.ts +56 -0
- package/dist/rotatable.js +210 -0
- package/dist/ruler/graphic.d.ts +20 -0
- package/dist/ruler/graphic.js +53 -0
- package/dist/ruler/index.d.ts +32 -0
- package/dist/ruler/index.js +77 -0
- package/dist/ruler/unit-type.d.ts +30 -0
- package/dist/ruler/unit-type.js +38 -0
- package/dist/ruler/unit.d.ts +21 -0
- package/dist/ruler/unit.js +69 -0
- package/dist/style-utils.d.ts +12 -0
- package/dist/style-utils.js +5 -0
- package/dist/transform-origin.d.ts +18 -0
- package/dist/transform-origin.js +21 -0
- package/package.json +31 -25
- package/CHANGELOG.json +0 -1
- package/CHANGELOG.md +0 -622
- package/LICENSE.md +0 -5
- package/lib/anchor-utils.js +0 -193
- package/lib/anchor-utils.js.map +0 -1
- package/lib/anchor.js +0 -33
- package/lib/anchor.js.map +0 -1
- package/lib/index.js +0 -33
- package/lib/index.js.map +0 -1
- package/lib/protractor/graphic.js +0 -147
- package/lib/protractor/graphic.js.map +0 -1
- package/lib/protractor/index.js +0 -90
- package/lib/protractor/index.js.map +0 -1
- package/lib/rotatable.js +0 -335
- package/lib/rotatable.js.map +0 -1
- package/lib/ruler/graphic.js +0 -89
- package/lib/ruler/graphic.js.map +0 -1
- package/lib/ruler/index.js +0 -114
- package/lib/ruler/index.js.map +0 -1
- package/lib/ruler/unit-type.js +0 -55
- package/lib/ruler/unit-type.js.map +0 -1
- package/lib/ruler/unit.js +0 -124
- package/lib/ruler/unit.js.map +0 -1
- package/lib/style-utils.js +0 -21
- package/lib/style-utils.js.map +0 -1
- package/lib/transform-origin.js +0 -71
- package/lib/transform-origin.js.map +0 -1
- package/src/__tests__/anchor-utils.test.js +0 -131
- package/src/__tests__/rotatable.test.jsx +0 -263
- package/src/__tests__/transform-origin.test.jsx +0 -24
- package/src/anchor-utils.js +0 -153
- package/src/anchor.jsx +0 -20
- package/src/index.js +0 -6
- package/src/protractor/__tests__/graphic.test.jsx +0 -64
- package/src/protractor/__tests__/index.test.jsx +0 -65
- package/src/protractor/graphic.jsx +0 -82
- package/src/protractor/index.jsx +0 -67
- package/src/rotatable.jsx +0 -290
- package/src/ruler/__tests__/graphic.test.jsx +0 -64
- package/src/ruler/__tests__/index.test.jsx +0 -85
- package/src/ruler/__tests__/unit-type.test.jsx +0 -66
- package/src/ruler/__tests__/unit.test.jsx +0 -68
- package/src/ruler/graphic.jsx +0 -48
- package/src/ruler/index.jsx +0 -78
- package/src/ruler/unit-type.jsx +0 -39
- package/src/ruler/unit.jsx +0 -83
- package/src/style-utils.js +0 -7
- package/src/transform-origin.jsx +0 -60
|
@@ -1,263 +0,0 @@
|
|
|
1
|
-
import { render } from '@testing-library/react';
|
|
2
|
-
import { Rotatable } from '../rotatable';
|
|
3
|
-
import React from 'react';
|
|
4
|
-
import { distanceBetween } from '../anchor-utils';
|
|
5
|
-
|
|
6
|
-
import Point from '@mapbox/point-geometry';
|
|
7
|
-
|
|
8
|
-
jest.mock('../anchor-utils', () => ({
|
|
9
|
-
distanceBetween: jest.fn(() => ({ x: 2, y: 2 })),
|
|
10
|
-
toPoint: jest.fn(() => ({ x: 0, y: 0 })),
|
|
11
|
-
getAnchor: jest.fn(() => ({ left: 0, top: 0 })),
|
|
12
|
-
toDegrees: jest.fn(() => 90),
|
|
13
|
-
arctangent: jest.fn(() => 90),
|
|
14
|
-
}));
|
|
15
|
-
|
|
16
|
-
const event = (x = 0, y = 0) => ({
|
|
17
|
-
pageX: x,
|
|
18
|
-
pageY: y,
|
|
19
|
-
clientX: x,
|
|
20
|
-
clientY: y,
|
|
21
|
-
preventDefault: jest.fn(),
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
describe('rotatable', () => {
|
|
25
|
-
describe('rendering', () => {
|
|
26
|
-
// Note: The Rotatable component has a bug where this.handles is undefined
|
|
27
|
-
// when no handle prop is provided, causing componentWillUnmount to crash.
|
|
28
|
-
// We patch the prototype to fix this for testing.
|
|
29
|
-
beforeAll(() => {
|
|
30
|
-
const originalInit = Rotatable.prototype.initHandles;
|
|
31
|
-
Rotatable.prototype.initHandles = function () {
|
|
32
|
-
this.handles = this.handles || [];
|
|
33
|
-
return originalInit.call(this);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
const originalUnmount = Rotatable.prototype.componentWillUnmount;
|
|
37
|
-
Rotatable.prototype.componentWillUnmount = function () {
|
|
38
|
-
this.handles = this.handles || [];
|
|
39
|
-
return originalUnmount.call(this);
|
|
40
|
-
};
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('renders children', () => {
|
|
44
|
-
const { container } = render(<Rotatable classes={{}}>foo</Rotatable>);
|
|
45
|
-
expect(container).toHaveTextContent('foo');
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('renders with handle prop', () => {
|
|
49
|
-
const { container } = render(
|
|
50
|
-
<Rotatable handle={[{ class: 'handle', origin: 'bottom left' }]} classes={{}}>
|
|
51
|
-
<div className="handle">foo</div>
|
|
52
|
-
</Rotatable>,
|
|
53
|
-
);
|
|
54
|
-
expect(container).toHaveTextContent('foo');
|
|
55
|
-
expect(container.querySelector('.handle')).toBeInTheDocument();
|
|
56
|
-
});
|
|
57
|
-
|
|
58
|
-
it('renders with startPosition prop', () => {
|
|
59
|
-
const { container } = render(
|
|
60
|
-
<Rotatable classes={{}} startPosition={{ left: 50, top: 100 }}>
|
|
61
|
-
foo
|
|
62
|
-
</Rotatable>,
|
|
63
|
-
);
|
|
64
|
-
expect(container).toHaveTextContent('foo');
|
|
65
|
-
});
|
|
66
|
-
});
|
|
67
|
-
|
|
68
|
-
describe('logic', () => {
|
|
69
|
-
let el, instance, mockRef;
|
|
70
|
-
|
|
71
|
-
beforeEach(() => {
|
|
72
|
-
// Mock DOM elements
|
|
73
|
-
el = {
|
|
74
|
-
addEventListener: jest.fn(),
|
|
75
|
-
removeEventListener: jest.fn(),
|
|
76
|
-
};
|
|
77
|
-
|
|
78
|
-
mockRef = {
|
|
79
|
-
querySelector: jest.fn(() => el),
|
|
80
|
-
getBoundingClientRect: jest.fn(() => ({
|
|
81
|
-
left: 0,
|
|
82
|
-
top: 0,
|
|
83
|
-
width: 100,
|
|
84
|
-
height: 100,
|
|
85
|
-
})),
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
// Mock document methods
|
|
89
|
-
document.addEventListener = jest.fn();
|
|
90
|
-
document.removeEventListener = jest.fn();
|
|
91
|
-
|
|
92
|
-
// Create component instance directly
|
|
93
|
-
const props = {
|
|
94
|
-
handle: [{ class: 'foo', origin: 'bottom left' }],
|
|
95
|
-
classes: { rotatable: 'rotatable' },
|
|
96
|
-
children: <div className={'foo'}>foo</div>,
|
|
97
|
-
startPosition: { left: 0, top: 0 },
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
instance = new Rotatable(props);
|
|
101
|
-
instance.rotatable = mockRef;
|
|
102
|
-
|
|
103
|
-
// Mock clientWidth and clientHeight for originToXY
|
|
104
|
-
Object.defineProperty(instance.rotatable, 'clientWidth', { value: 100, writable: true });
|
|
105
|
-
Object.defineProperty(instance.rotatable, 'clientHeight', { value: 100, writable: true });
|
|
106
|
-
|
|
107
|
-
// Mock setState to be synchronous for testing
|
|
108
|
-
instance.setState = jest.fn((updater, callback) => {
|
|
109
|
-
if (typeof updater === 'function') {
|
|
110
|
-
instance.state = { ...instance.state, ...updater(instance.state) };
|
|
111
|
-
} else {
|
|
112
|
-
instance.state = { ...instance.state, ...updater };
|
|
113
|
-
}
|
|
114
|
-
if (callback) callback();
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// Initialize the component
|
|
118
|
-
instance.componentDidMount();
|
|
119
|
-
|
|
120
|
-
// Manually set up handles array if it's still undefined after mount
|
|
121
|
-
if (!instance.handles) {
|
|
122
|
-
instance.handles = [{ el, mousedownHandler: jest.fn() }];
|
|
123
|
-
}
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
describe('rotate', () => {
|
|
127
|
-
describe('init', () => {
|
|
128
|
-
it('call el.addEventListener(mousedown)', () => {
|
|
129
|
-
expect(el.addEventListener).toBeCalledWith('mousedown', expect.anything());
|
|
130
|
-
});
|
|
131
|
-
it('call el.addEventListener(mouseup)', () => {
|
|
132
|
-
expect(el.addEventListener).toBeCalledWith('mouseup', instance.rotateStop);
|
|
133
|
-
});
|
|
134
|
-
});
|
|
135
|
-
|
|
136
|
-
describe('rotateStart', () => {
|
|
137
|
-
let e;
|
|
138
|
-
beforeEach(() => {
|
|
139
|
-
e = event();
|
|
140
|
-
|
|
141
|
-
distanceBetween.mockReturnValue({
|
|
142
|
-
x: 22,
|
|
143
|
-
y: 4,
|
|
144
|
-
});
|
|
145
|
-
instance.state.origin = 'bottom right';
|
|
146
|
-
|
|
147
|
-
instance.state.position = {
|
|
148
|
-
left: 0,
|
|
149
|
-
top: 0,
|
|
150
|
-
};
|
|
151
|
-
|
|
152
|
-
instance.rotateStart('bottom left')(e);
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
it('calls event.preventDefault()', () => {
|
|
156
|
-
instance.rotateStart('bottom left')(e);
|
|
157
|
-
expect(e.preventDefault).toBeCalled();
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
it('updates the position if origin has change', () => {
|
|
161
|
-
expect(instance.state.position).toMatchObject({
|
|
162
|
-
left: 22,
|
|
163
|
-
top: 4,
|
|
164
|
-
});
|
|
165
|
-
});
|
|
166
|
-
|
|
167
|
-
it('updates the startAngle', () => {
|
|
168
|
-
expect(instance.state.startAngle).toEqual(90);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
it('updates the anchor', () => {
|
|
172
|
-
expect(instance.state.anchor).toMatchObject({
|
|
173
|
-
left: 0,
|
|
174
|
-
top: 0,
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
describe('rotate', () => {
|
|
180
|
-
let e;
|
|
181
|
-
beforeEach(() => {
|
|
182
|
-
e = event();
|
|
183
|
-
|
|
184
|
-
instance.state.anchor = {
|
|
185
|
-
left: 0,
|
|
186
|
-
top: 0,
|
|
187
|
-
};
|
|
188
|
-
|
|
189
|
-
instance.state.isRotating = true;
|
|
190
|
-
instance.rotate(e);
|
|
191
|
-
});
|
|
192
|
-
it('calls event.preventDefault()', () => {
|
|
193
|
-
expect(e.preventDefault).toBeCalled();
|
|
194
|
-
});
|
|
195
|
-
});
|
|
196
|
-
|
|
197
|
-
describe('rotateStop', () => {
|
|
198
|
-
let e;
|
|
199
|
-
|
|
200
|
-
beforeEach(() => {
|
|
201
|
-
e = event();
|
|
202
|
-
instance.state.isRotating = true;
|
|
203
|
-
instance.rotateStop(e);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
it('unsets the anchor', () => {
|
|
207
|
-
expect(instance.state.anchor).toEqual(null);
|
|
208
|
-
});
|
|
209
|
-
it('unsets the anchor', () => {
|
|
210
|
-
expect(instance.state.anchor).toEqual(null);
|
|
211
|
-
});
|
|
212
|
-
it('sets the isRotating to false', () => {
|
|
213
|
-
expect(instance.state.isRotating).toEqual(false);
|
|
214
|
-
});
|
|
215
|
-
|
|
216
|
-
it('calls document.removeEventListener(mousemove, rotate)', () => {
|
|
217
|
-
expect(document.removeEventListener).toBeCalledWith('mousemove', instance.rotate);
|
|
218
|
-
});
|
|
219
|
-
it('calls document.removeEventListener(mousemove), drag', () => {
|
|
220
|
-
expect(document.removeEventListener).toBeCalledWith('mousemove', instance.drag);
|
|
221
|
-
});
|
|
222
|
-
});
|
|
223
|
-
});
|
|
224
|
-
|
|
225
|
-
describe('drag', () => {
|
|
226
|
-
describe('mouseDown', () => {
|
|
227
|
-
it('calls document.addEventListener(mousemove)', () => {
|
|
228
|
-
instance.mouseDown(event());
|
|
229
|
-
|
|
230
|
-
expect(document.addEventListener).toBeCalledWith('mousemove', instance.drag);
|
|
231
|
-
});
|
|
232
|
-
});
|
|
233
|
-
|
|
234
|
-
describe('mouseup', () => {
|
|
235
|
-
it('calls document.removeEventListener(mousemove)', () => {
|
|
236
|
-
instance.state.translate = { x: 10, y: 10 };
|
|
237
|
-
instance.mouseUp({});
|
|
238
|
-
|
|
239
|
-
expect(document.removeEventListener).toBeCalledWith('mousemove', instance.drag);
|
|
240
|
-
});
|
|
241
|
-
|
|
242
|
-
it('updates the state', () => {
|
|
243
|
-
instance.state.translate = { x: 10, y: 10 };
|
|
244
|
-
instance.state.position = { left: 0, top: 0 };
|
|
245
|
-
instance.mouseUp({});
|
|
246
|
-
|
|
247
|
-
expect(instance.state.position).toEqual({
|
|
248
|
-
left: 10,
|
|
249
|
-
top: 10,
|
|
250
|
-
});
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
describe('drag', () => {
|
|
255
|
-
it('updates translate', () => {
|
|
256
|
-
instance.state.dragPoint = new Point(100, 100);
|
|
257
|
-
instance.drag(event(101, 101));
|
|
258
|
-
expect(instance.state.translate).toEqual({ x: 1, y: 1 });
|
|
259
|
-
});
|
|
260
|
-
});
|
|
261
|
-
});
|
|
262
|
-
});
|
|
263
|
-
});
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { parse } from '../transform-origin';
|
|
2
|
-
|
|
3
|
-
describe('transform-origin', () => {
|
|
4
|
-
describe('parse', () => {
|
|
5
|
-
const assert = (origin, expected) => {
|
|
6
|
-
it(`${origin} => ${JSON.stringify(expected)}`, () => {
|
|
7
|
-
const out = parse({ width: 100, height: 100 }, origin);
|
|
8
|
-
expect(out).toEqual(expected);
|
|
9
|
-
});
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
assert(undefined, { x: 50, y: 50 });
|
|
13
|
-
assert('right', { x: 100, y: 50 });
|
|
14
|
-
assert('20%', { x: 20, y: 50 });
|
|
15
|
-
assert('left', { x: 0, y: 50 });
|
|
16
|
-
assert('top right', { x: 100, y: 0 });
|
|
17
|
-
assert('right top', { x: 100, y: 0 });
|
|
18
|
-
assert('bottom left', { x: 0, y: 100 });
|
|
19
|
-
assert('left bottom', { x: 0, y: 100 });
|
|
20
|
-
assert('0% 100%', { x: 0, y: 100 });
|
|
21
|
-
assert('100% 0%', { x: 100, y: 0 });
|
|
22
|
-
assert('10px 43px', { x: 10, y: 43 });
|
|
23
|
-
});
|
|
24
|
-
});
|
package/src/anchor-utils.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { trigCalculator } from 'trigonometry-calculator';
|
|
2
|
-
import Point from '@mapbox/point-geometry';
|
|
3
|
-
import debug from 'debug';
|
|
4
|
-
import { parse as parseOrigin } from './transform-origin';
|
|
5
|
-
|
|
6
|
-
const log = debug('@pie-lib:tools:anchor-utils');
|
|
7
|
-
|
|
8
|
-
export const toDegrees = (radians) => radians * (180 / Math.PI);
|
|
9
|
-
export const toRadians = (degrees) => degrees * (Math.PI / 180);
|
|
10
|
-
|
|
11
|
-
export const normalizeAngle = (a) => {
|
|
12
|
-
if (a > 360) {
|
|
13
|
-
return a % 360;
|
|
14
|
-
} else if (a < 0) {
|
|
15
|
-
return 360 + (a % 360);
|
|
16
|
-
}
|
|
17
|
-
return a;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
export const toPoint = (rect, edge) => {
|
|
21
|
-
const out = parseOrigin(rect, edge);
|
|
22
|
-
return new Point(out.x, out.y);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Get the distance between to anchor points in a rect.
|
|
27
|
-
* @param {{width: number, height: number}} rect - the rect
|
|
28
|
-
* @param {number} degrees - the degrees
|
|
29
|
-
* @param {string} from - from anchor
|
|
30
|
-
* @param {string} to - to anchor
|
|
31
|
-
* @returns {Point} point - the distance as a Point
|
|
32
|
-
*/
|
|
33
|
-
export const distanceBetween = (rect, degrees, from, to) => {
|
|
34
|
-
const center = new Point(rect.width / 2, rect.height / 2);
|
|
35
|
-
const radians = toRadians(degrees);
|
|
36
|
-
const fromCenter = center.rotateAround(radians, toPoint(rect, from));
|
|
37
|
-
const toCenter = center.rotateAround(radians, toPoint(rect, to));
|
|
38
|
-
const diff = fromCenter.sub(toCenter);
|
|
39
|
-
return diff;
|
|
40
|
-
};
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* For a corner string, a point and a rect, return a relative x,y from that point to a corner.
|
|
44
|
-
* Note that the y value descends as it goes down (unlike for a screen's y value), so this is only really useful for math functions.
|
|
45
|
-
* @example
|
|
46
|
-
* ```
|
|
47
|
-
* getXAndY('top-left', {width: 100, height: 100}, 10, 10) //=> {x:10, y: -90}
|
|
48
|
-
* ```
|
|
49
|
-
* @param {*} corner
|
|
50
|
-
* @param {*} rect
|
|
51
|
-
* @param {*} point
|
|
52
|
-
*/
|
|
53
|
-
export const getXAndY = (corner, rect, point) => {
|
|
54
|
-
if (corner === 'top-left') {
|
|
55
|
-
const x = point.x * -1;
|
|
56
|
-
const y = point.y;
|
|
57
|
-
return { x, y };
|
|
58
|
-
} else if (corner === 'bottom-left') {
|
|
59
|
-
const x = point.x * -1;
|
|
60
|
-
const y = point.y - rect.height;
|
|
61
|
-
return { x, y };
|
|
62
|
-
} else if (corner === 'top-right') {
|
|
63
|
-
const x = rect.width - point.x;
|
|
64
|
-
const y = point.y;
|
|
65
|
-
return { x, y };
|
|
66
|
-
} else if (corner === 'bottom-right') {
|
|
67
|
-
const x = rect.width - point.x;
|
|
68
|
-
const y = point.y - rect.height;
|
|
69
|
-
return { x, y };
|
|
70
|
-
}
|
|
71
|
-
};
|
|
72
|
-
|
|
73
|
-
export const arctangent = (x, y) => toDegrees(Math.atan2(x, y));
|
|
74
|
-
|
|
75
|
-
export const getAngleAndHypotenuse = (corner, rect, point) => {
|
|
76
|
-
const { x, y } = getXAndY(corner, rect, point);
|
|
77
|
-
const degrees = arctangent(x, y);
|
|
78
|
-
const hypotenuse = Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2));
|
|
79
|
-
return { x, y, degrees, hypotenuse };
|
|
80
|
-
};
|
|
81
|
-
|
|
82
|
-
const getPosition = (side, rect, point, angle, calcAngle) => {
|
|
83
|
-
if (angle === 0) {
|
|
84
|
-
return side === 'left' ? point.x : point.y;
|
|
85
|
-
}
|
|
86
|
-
const points = anglePoints(angle);
|
|
87
|
-
const key = points[side];
|
|
88
|
-
|
|
89
|
-
const { degrees, hypotenuse } = getAngleAndHypotenuse(key, rect, point);
|
|
90
|
-
|
|
91
|
-
const ra = calcAngle(degrees);
|
|
92
|
-
|
|
93
|
-
if (ra === 0) {
|
|
94
|
-
return hypotenuse;
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
const t = {
|
|
98
|
-
angles: { 0: ra, 1: 90 },
|
|
99
|
-
sides: { 1: hypotenuse },
|
|
100
|
-
};
|
|
101
|
-
const out = trigCalculator(t);
|
|
102
|
-
return out.sides[2];
|
|
103
|
-
};
|
|
104
|
-
|
|
105
|
-
export const getTop = (rect, point, angle) => {
|
|
106
|
-
return getPosition('top', rect, point, angle, (degrees) => {
|
|
107
|
-
return Math.abs(angle + degrees);
|
|
108
|
-
});
|
|
109
|
-
};
|
|
110
|
-
|
|
111
|
-
export const getLeft = (rect, point, angle) => {
|
|
112
|
-
return getPosition('left', rect, point, angle, (degrees) => {
|
|
113
|
-
return Math.abs(angle + degrees + 90);
|
|
114
|
-
});
|
|
115
|
-
};
|
|
116
|
-
|
|
117
|
-
/**
|
|
118
|
-
* Calculate the position of an anchor within a bounding rect, if the source rect has been rotated by an angle.
|
|
119
|
-
* It does this by finding the appropriate corner of the src rect, that touches the bounding rect, calculates
|
|
120
|
-
* the hypotenuse (h) of that anchor to that point. Then using that plus the rotation it calculates
|
|
121
|
-
* the sides of the triangle and returns the length of the side that touches the bounding rect.
|
|
122
|
-
* @param {{width: number, height: number}} rect - the rect which contains the point
|
|
123
|
-
* @param {{x:number, y: number}} point - the point within the rect
|
|
124
|
-
* @param {number} angle - the angle in degrees that the rect has rotated.
|
|
125
|
-
* @returns {{left: number, top: number}} position
|
|
126
|
-
*/
|
|
127
|
-
export const getAnchor = (rect, point, angle) => {
|
|
128
|
-
log('[getAnchor] rect: ', rect, 'point:', point, 'angle: ', angle);
|
|
129
|
-
if (point.x > rect.width) {
|
|
130
|
-
throw new Error(`x: ${point.x} cannot be greater than width: ${rect.width}`);
|
|
131
|
-
}
|
|
132
|
-
if (point.y > rect.height) {
|
|
133
|
-
throw new Error(`y: ${point.y} cannot be greater than height: ${rect.height}`);
|
|
134
|
-
}
|
|
135
|
-
const a = normalizeAngle(angle);
|
|
136
|
-
const top = getTop(rect, point, a);
|
|
137
|
-
const left = getLeft(rect, point, a);
|
|
138
|
-
|
|
139
|
-
log('[getAnchor] top: ', top, 'left: ', left);
|
|
140
|
-
return { top, left };
|
|
141
|
-
};
|
|
142
|
-
|
|
143
|
-
const anglePoints = (angle) => {
|
|
144
|
-
if (angle <= 90) {
|
|
145
|
-
return { top: 'top-left', left: 'bottom-left' };
|
|
146
|
-
} else if (angle > 90 && angle <= 180) {
|
|
147
|
-
return { top: 'bottom-left', left: 'bottom-right' };
|
|
148
|
-
} else if (angle > 180 && angle <= 270) {
|
|
149
|
-
return { top: 'bottom-right', left: 'top-right' };
|
|
150
|
-
} else if (angle > 270 && angle < 360) {
|
|
151
|
-
return { top: 'top-right', left: 'top-left' };
|
|
152
|
-
}
|
|
153
|
-
};
|
package/src/anchor.jsx
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { styled } from '@mui/material/styles';
|
|
3
|
-
|
|
4
|
-
const StyledAnchor = styled('div')(({ theme }) => ({
|
|
5
|
-
cursor: 'pointer',
|
|
6
|
-
width: '20px',
|
|
7
|
-
height: '20px',
|
|
8
|
-
position: 'absolute',
|
|
9
|
-
borderRadius: '10px',
|
|
10
|
-
backgroundColor: `var(--ruler-bg, ${theme.palette.primary.contrastText})`,
|
|
11
|
-
transition: 'background-color 200ms ease-in',
|
|
12
|
-
border: `solid 1px var(--ruler-stroke, ${theme.palette.primary.dark})`,
|
|
13
|
-
'&:hover': {
|
|
14
|
-
backgroundColor: `var(--ruler-bg-hover, ${theme.palette.primary.light})`,
|
|
15
|
-
},
|
|
16
|
-
}));
|
|
17
|
-
|
|
18
|
-
const Anchor = ({ ...props }) => <StyledAnchor {...props} />;
|
|
19
|
-
|
|
20
|
-
export default Anchor;
|
package/src/index.js
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import { render } from '@testing-library/react';
|
|
2
|
-
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
|
3
|
-
import { Graphic } from '../graphic';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
|
|
6
|
-
describe('graphic', () => {
|
|
7
|
-
const theme = createTheme();
|
|
8
|
-
|
|
9
|
-
const renderComponent = (props = {}) => {
|
|
10
|
-
return render(
|
|
11
|
-
<ThemeProvider theme={theme}>
|
|
12
|
-
<Graphic {...props} />
|
|
13
|
-
</ThemeProvider>,
|
|
14
|
-
);
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
describe('rendering', () => {
|
|
18
|
-
it('renders svg with correct viewBox', () => {
|
|
19
|
-
const { container } = renderComponent();
|
|
20
|
-
const svg = container.querySelector('svg');
|
|
21
|
-
expect(svg).toBeInTheDocument();
|
|
22
|
-
expect(svg).toHaveAttribute('viewBox', '0 0 102 61');
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
it('renders path element', () => {
|
|
26
|
-
const { container } = renderComponent();
|
|
27
|
-
const path = container.querySelector('path');
|
|
28
|
-
expect(path).toBeInTheDocument();
|
|
29
|
-
expect(path).toHaveAttribute('d', 'M 1,50 A 1,1 0 0 1 100,50 L 100,60 L 1,60 Z');
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
it('renders circle element', () => {
|
|
33
|
-
const { container } = renderComponent();
|
|
34
|
-
const circle = container.querySelector('circle');
|
|
35
|
-
expect(circle).toBeInTheDocument();
|
|
36
|
-
expect(circle).toHaveAttribute('r', '4');
|
|
37
|
-
expect(circle).toHaveAttribute('cx', '50.5');
|
|
38
|
-
expect(circle).toHaveAttribute('cy', '50');
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
it('renders multiple line elements', () => {
|
|
42
|
-
const { container } = renderComponent();
|
|
43
|
-
const lines = container.querySelectorAll('line');
|
|
44
|
-
// Should render 181 angle lines + 2 crosshair lines = 183+ lines
|
|
45
|
-
expect(lines.length).toBeGreaterThan(180);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
it('renders text elements for angles', () => {
|
|
49
|
-
const { container } = renderComponent();
|
|
50
|
-
const texts = container.querySelectorAll('text');
|
|
51
|
-
// Should render text for angles 0, 10, 20, ..., 180 (19 texts)
|
|
52
|
-
expect(texts.length).toBeGreaterThan(15);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('renders correct angle labels', () => {
|
|
56
|
-
const { container } = renderComponent();
|
|
57
|
-
const texts = container.querySelectorAll('text');
|
|
58
|
-
const textContents = Array.from(texts).map((t) => t.textContent);
|
|
59
|
-
expect(textContents).toContain('0');
|
|
60
|
-
expect(textContents).toContain('90');
|
|
61
|
-
expect(textContents).toContain('180');
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
});
|
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import { render, screen } from '@testing-library/react';
|
|
2
|
-
import { createTheme, ThemeProvider } from '@mui/material/styles';
|
|
3
|
-
import { Protractor } from '../index';
|
|
4
|
-
import React from 'react';
|
|
5
|
-
|
|
6
|
-
// Mock the Rotatable component to avoid complex DOM interactions
|
|
7
|
-
jest.mock('../../rotatable', () => {
|
|
8
|
-
return function MockRotatable({ children }) {
|
|
9
|
-
return <div data-testid="rotatable">{children}</div>;
|
|
10
|
-
};
|
|
11
|
-
});
|
|
12
|
-
|
|
13
|
-
// Mock the Graphic component
|
|
14
|
-
jest.mock('../graphic', () => {
|
|
15
|
-
return function MockGraphic() {
|
|
16
|
-
return <div data-testid="protractor-graphic" />;
|
|
17
|
-
};
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
describe('protractor', () => {
|
|
21
|
-
const theme = createTheme();
|
|
22
|
-
|
|
23
|
-
const renderComponent = (props = {}) => {
|
|
24
|
-
const defaultProps = {
|
|
25
|
-
width: 450,
|
|
26
|
-
...props,
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
return render(
|
|
30
|
-
<ThemeProvider theme={theme}>
|
|
31
|
-
<Protractor {...defaultProps} />
|
|
32
|
-
</ThemeProvider>,
|
|
33
|
-
);
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
describe('rendering', () => {
|
|
37
|
-
it('renders protractor component', () => {
|
|
38
|
-
renderComponent();
|
|
39
|
-
expect(screen.getByTestId('rotatable')).toBeInTheDocument();
|
|
40
|
-
expect(screen.getByTestId('protractor-graphic')).toBeInTheDocument();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
it('renders with default width', () => {
|
|
44
|
-
const { container } = renderComponent();
|
|
45
|
-
const protractorDiv = container.querySelector('div[style*="width"]');
|
|
46
|
-
expect(protractorDiv).toHaveStyle({ width: '450px' });
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
it('renders with custom width', () => {
|
|
50
|
-
const { container } = renderComponent({ width: 600 });
|
|
51
|
-
const protractorDiv = container.querySelector('div[style*="width"]');
|
|
52
|
-
expect(protractorDiv).toHaveStyle({ width: '600px' });
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
it('renders with custom startPosition', () => {
|
|
56
|
-
renderComponent({ startPosition: { left: 100, top: 200 } });
|
|
57
|
-
expect(screen.getByTestId('protractor-graphic')).toBeInTheDocument();
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
it('renders with className', () => {
|
|
61
|
-
const { container } = renderComponent({ className: 'custom-class' });
|
|
62
|
-
expect(screen.getByTestId('rotatable')).toBeInTheDocument();
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
});
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import { styled } from '@mui/material/styles';
|
|
3
|
-
import { range } from 'lodash-es';
|
|
4
|
-
import { noSelect, strokeColor } from '../style-utils';
|
|
5
|
-
|
|
6
|
-
const StyledLine = styled('line')(({ theme }) => ({
|
|
7
|
-
strokeWidth: '0.2',
|
|
8
|
-
stroke: strokeColor(theme),
|
|
9
|
-
}));
|
|
10
|
-
|
|
11
|
-
const Line = ({ angle, major, minor }) => (
|
|
12
|
-
<StyledLine
|
|
13
|
-
transform={`rotate(${angle}, 50.5,50)`}
|
|
14
|
-
style={{}}
|
|
15
|
-
x1="1"
|
|
16
|
-
x2={major ? 10 : minor ? 6 : 3}
|
|
17
|
-
y1="50"
|
|
18
|
-
y2="50"
|
|
19
|
-
/>
|
|
20
|
-
);
|
|
21
|
-
|
|
22
|
-
const StyledSpikeLine = styled('line')(({ theme }) => ({
|
|
23
|
-
strokeWidth: '0.2',
|
|
24
|
-
stroke: strokeColor(theme),
|
|
25
|
-
}));
|
|
26
|
-
|
|
27
|
-
const Spike = ({ angle }) => (
|
|
28
|
-
<StyledSpikeLine transform={`rotate(${angle}, 50.5,50)`} style={{}} x1="15" x2={'46'} y1="50" y2="50" />
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const StyledText = styled('text')(({ theme }) => ({
|
|
32
|
-
fontSize: '2.5px',
|
|
33
|
-
textAnchor: 'middle',
|
|
34
|
-
fill: strokeColor(theme),
|
|
35
|
-
...noSelect(),
|
|
36
|
-
}));
|
|
37
|
-
|
|
38
|
-
const Text = ({ angle }) => (
|
|
39
|
-
<StyledText transform={`rotate(${angle - 90}, 50.5, 50)`} x="50" y="12.5">
|
|
40
|
-
{angle}
|
|
41
|
-
</StyledText>
|
|
42
|
-
);
|
|
43
|
-
|
|
44
|
-
const StyledPath = styled('path')(({ theme }) => ({
|
|
45
|
-
strokeWidth: '0.2',
|
|
46
|
-
stroke: strokeColor(theme),
|
|
47
|
-
}));
|
|
48
|
-
|
|
49
|
-
const StyledGraphicLine = styled('line')(({ theme }) => ({
|
|
50
|
-
strokeWidth: '0.2',
|
|
51
|
-
stroke: strokeColor(theme),
|
|
52
|
-
}));
|
|
53
|
-
|
|
54
|
-
const StyledCircle = styled('circle')(({ theme }) => ({
|
|
55
|
-
strokeWidth: '0.2',
|
|
56
|
-
stroke: strokeColor(theme),
|
|
57
|
-
fill: 'none',
|
|
58
|
-
}));
|
|
59
|
-
|
|
60
|
-
export class Graphic extends React.PureComponent {
|
|
61
|
-
render() {
|
|
62
|
-
return (
|
|
63
|
-
<svg viewBox="0 0 102 61">
|
|
64
|
-
<StyledPath d="M 1,50 A 1,1 0 0 1 100,50 L 100,60 L 1,60 Z" fill="none" />
|
|
65
|
-
{range(0, 181).map((r) => (
|
|
66
|
-
<Line minor={r % 5 === 0} major={r % 10 === 0} angle={r} key={r} />
|
|
67
|
-
))}
|
|
68
|
-
{range(0, 181, 10).map((r) => (
|
|
69
|
-
<React.Fragment key={r}>
|
|
70
|
-
<Spike angle={r} />
|
|
71
|
-
<Text angle={r} />
|
|
72
|
-
</React.Fragment>
|
|
73
|
-
))}
|
|
74
|
-
<StyledCircle r="4" cx="50.5" cy="50" />
|
|
75
|
-
<StyledGraphicLine x1="48.5" x2="52.5" y1="50" y2="50" />
|
|
76
|
-
<StyledGraphicLine transform={'rotate(90 50.5 50)'} x1="48.5" x2="52.5" y1="50" y2="50" />
|
|
77
|
-
</svg>
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
export default Graphic;
|