zds-pickers 4.0.7 → 4.0.9
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/index.cjs.js +11 -11
- package/dist/index.cjs.js.map +1 -1
- package/dist/index.es.js +1194 -1818
- package/dist/index.es.js.map +1 -1
- package/dist/types/index.d.ts +2 -0
- package/dist/types/midi/export.d.ts +8 -9
- package/dist/types/other/OctavePlayer.d.ts +7 -1
- package/dist/types/other/SVGText.d.ts +11 -0
- package/dist/types/other/SoundFontProvider.d.ts +1 -0
- package/dist/types/pickers/ChannelMappingPicker.d.ts +2 -1
- package/dist/types/pickers/StatusPicker.d.ts +2 -2
- package/lib/hooks/useComponentSize.js +40 -0
- package/lib/hooks/useStateWithDynamicDefault.js +9 -0
- package/lib/index.js +21 -0
- package/lib/index.ts +2 -0
- package/lib/midi/ccValues.js +134 -0
- package/lib/midi/export.js +27 -0
- package/lib/midi/export.ts +2 -3
- package/lib/other/DefaultTooltip.js +3 -0
- package/lib/other/OctavePlayer.js +48 -0
- package/lib/other/OctavePlayer.tsx +1 -1
- package/lib/other/SVGText.js +109 -0
- package/lib/other/SVGText.tsx +2 -0
- package/lib/other/SoundFontProvider.js +87 -0
- package/lib/other/SoundFontProvider.tsx +2 -0
- package/lib/pickers/CCPicker.js +6 -0
- package/lib/pickers/ChannelMappingPicker.js +50 -0
- package/lib/pickers/ChannelMappingPicker.tsx +5 -1
- package/lib/pickers/ChannelPicker.js +21 -0
- package/lib/pickers/Knob.js +49 -0
- package/lib/pickers/KnobPicker.js +29 -0
- package/lib/pickers/LatchPicker.js +9 -0
- package/lib/pickers/MappingPicker.js +37 -0
- package/lib/pickers/NotePicker.js +45 -0
- package/lib/pickers/PianoPicker.js +27 -0
- package/lib/pickers/PolarityPicker.js +11 -0
- package/lib/pickers/ResponseCurve.js +154 -0
- package/lib/pickers/ResponseCurvePicker.js +19 -0
- package/lib/pickers/Select.js +79 -0
- package/lib/pickers/StatusPicker.js +5 -0
- package/lib/pickers/ValuePicker.js +23 -0
- package/lib/pickers/knobSkin10.js +93 -0
- package/lib/rotaryKnob/InternalInput.js +22 -0
- package/lib/rotaryKnob/Types.js +1 -0
- package/lib/rotaryKnob/helpers/DrawCircle.js +9 -0
- package/lib/rotaryKnob/helpers/DrawLine.js +9 -0
- package/lib/rotaryKnob/helpers/HelpersOverlay.js +26 -0
- package/lib/rotaryKnob/helpers/KnobVisualHelpers.js +52 -0
- package/lib/rotaryKnob/index.js +244 -0
- package/lib/rotaryKnob/knobdefaultskin.js +56 -0
- package/lib/rotaryKnob/utils.js +106 -0
- package/lib/utils.js +21 -0
- package/package.json +2 -3
- package/tsconfig.json +1 -1
- package/vite.config.ts +3 -19
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
const knobSkin10 = {
|
|
2
|
+
knobX: 71.44,
|
|
3
|
+
knobY: 71.44,
|
|
4
|
+
svg: `
|
|
5
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="207px" height="207px" viewBox="0 0 207 207" version="1.1">
|
|
6
|
+
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
|
|
7
|
+
<desc>Created with Sketch.</desc>
|
|
8
|
+
<defs>
|
|
9
|
+
<linearGradient x1="50%" y1="50%" x2="50%" y2="100%" id="27c61b0f-392f-962d-de12-cb9da898274b">
|
|
10
|
+
<stop stop-color="#444040" stop-opacity="0.51098279" offset="0%"/>
|
|
11
|
+
<stop stop-color="#131111" stop-opacity="0.893200861" offset="100%"/>
|
|
12
|
+
</linearGradient>
|
|
13
|
+
<circle id="e966567b-3869-4bcd-76b6-2cf084e45390" cx="100.497487" cy="100.497487" r="99.4974874"/>
|
|
14
|
+
<filter x="-3.3%" y="-3.3%" width="106.5%" height="106.5%" filterUnits="objectBoundingBox" id="e2e6829f-0086-96b2-e92a-6f3809b8ac61">
|
|
15
|
+
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"/>
|
|
16
|
+
<feOffset dx="0" dy="0" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>
|
|
17
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/>
|
|
18
|
+
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/>
|
|
19
|
+
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"/>
|
|
20
|
+
</filter>
|
|
21
|
+
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="0facd5c9-8e04-e83f-4842-8ba16f949942">
|
|
22
|
+
<stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"/>
|
|
23
|
+
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"/>
|
|
24
|
+
</linearGradient>
|
|
25
|
+
<circle id="c54189ed-7ea3-956c-f040-f0207548b268" cx="100.432161" cy="100.432161" r="86.4321608"/>
|
|
26
|
+
<filter x="-4.0%" y="-3.5%" width="108.1%" height="108.1%" filterUnits="objectBoundingBox" id="dedf2e7e-f008-c315-f682-e424d670f210">
|
|
27
|
+
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"/>
|
|
28
|
+
<feOffset dx="0" dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"/>
|
|
29
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/>
|
|
30
|
+
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"/>
|
|
31
|
+
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"/>
|
|
32
|
+
</filter>
|
|
33
|
+
|
|
34
|
+
<filter x="-5.3%" y="-11.3%" width="110.7%" height="122.6%" filterUnits="objectBoundingBox" id="12f618f7-e258-b597-3ed6-242484ddad8f">
|
|
35
|
+
<feOffset dx="0" dy="0" in="SourceAlpha" result="shadowOffsetOuter1"/>
|
|
36
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"/>
|
|
37
|
+
<feColorMatrix values="0 0 0 0 0.915577168 0 0 0 0 0.797591325 0 0 0 0 0.601479722 0 0 0 1 0" type="matrix" in="shadowBlurOuter1"/>
|
|
38
|
+
</filter>
|
|
39
|
+
<pattern id="3cc0e5b8-1f0a-886b-f635-8fcb19212870" width="8.04411765" height="8.04411765" x="21.9558824" y="21.9558824" patternUnits="userSpaceOnUse">
|
|
40
|
+
<use xlink:href="#2b8719c1-286b-ebf8-a488-ac66a6598fc5" transform="scale(0.167585784,0.167585784)"/>
|
|
41
|
+
</pattern>
|
|
42
|
+
<image id="2b8719c1-286b-ebf8-a488-ac66a6598fc5" width="48" height="48" xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAEGWlDQ1BrQ0dDb2xvclNwYWNlR2VuZXJpY1JHQgAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia219thzg25abkRE/BpDc3pqvphHvRFys2weqvp+krbWKIX7nhDbzLOItiM8358pTwdirqpPFnMF2xLc1WvLyOwTAibpbmvHHcvttU57y5+XqNZrLe3lE/Pq8eUj2fXKfOe3pfOjzhJYtB/yll5SDFcSDiH+hRkH25+L+sdxKEAMZahrlSX8ukqMOWy/jXW2m6M9LDBc31B9LFuv6gVKg/0Szi3KAr1kGq1GMjU/aLbnq6/lRxc4XfJ98hTargX++DbMJBSiYMIe9Ck1YAxFkKEAG3xbYaKmDDgYyFK0UGYpfoWYXG+fAPPI6tJnNwb7ClP7IyF+D+bjOtCpkhz6CFrIa/I6sFtNl8auFXGMTP34sNwI/JhkgEtmDz14ySfaRcTIBInmKPE32kxyyE2Tv+thKbEVePDfW/byMM1Kmm0XdObS7oGD/MypMXFPXrCwOtoYjyyn7BV29/MZfsVzpLDdRtuIZnbpXzvlf+ev8MvYr/Gqk4H/kV/G3csdazLuyTMPsbFhzd1UabQbjFvDRmcWJxR3zcfHkVw9GfpbJmeev9F08WW8uDkaslwX6avlWGU6NRKz0g/SHtCy9J30o/ca9zX3Kfc19zn3BXQKRO8ud477hLnAfc1/G9mrzGlrfexZ5GLdn6ZZrrEohI2wVHhZywjbhUWEy8icMCGNCUdiBlq3r+xafL549HQ5jH+an+1y+LlYBifuxAvRN/lVVVOlwlCkdVm9NOL5BE4wkQ2SMlDZU97hX86EilU/lUmkQUztTE6mx1EEPh7OmdqBtAvv8HdWpbrJS6tJj3n0CWdM6busNzRV3S9KTYhqvNiqWmuroiKgYhshMjmhTh9ptWhsF7970j/SbMrsPE1suR5z7DMC+P/Hs+y7ijrQAlhyAgccjbhjPygfeBTjzhNqy28EdkUh8C+DU9+z2v/oyeH791OncxHOs5y2AtTc7nb/f73TWPkD/qwBnjX8BoJ98VQNcC+8AAAFFSURBVGgF7djbDYMwDAXQBjEMYqyqY1WMxTppLiJIQIA8ariWkp8IPuweO60am67r7MstY8wwjuPH7dMz3uUua63p+/7r9rePIRW/9QmQzCV9ub0YgSIgzhxvQkjFb1EZBAdEKolkfJTqtnb7bv/zOJm58moRE0AzYgFoRawAGhE7gDZEEKAJcQjQgjgFaEBcAtgRUQBmRDSAFZEEYEQkA9gQWQAmRDaABVEEYEAUAx5H4EaGOyw+SMl66mbXzNOD4k6gCPNUY/CFwF1YOn5zRxJJRINqaUbUuZA/79sd3wm3xIdbdS60rXzo2XVCbO60/HxKJgFKKv4CkEziuyKBWAE0InYAbYggQBPiEKAFcQrQgLgEsCOiAMyIaAArIgnAiEgGsCGyAEyIbAALogjAgCgGPI7AX9w6F3JtqHMhnMWLFSrSD9jOnakVHpZYAAAAAElFTkSuQmCC"/>
|
|
43
|
+
</defs>
|
|
44
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
45
|
+
<g id="s10" transform="translate(3.000000, 3.000000)">
|
|
46
|
+
<g id="container">
|
|
47
|
+
<g id="Oval-2">
|
|
48
|
+
<use fill="black" fill-opacity="1" filter="url(#e2e6829f-0086-96b2-e92a-6f3809b8ac61)" xlink:href="#e966567b-3869-4bcd-76b6-2cf084e45390"/>
|
|
49
|
+
<use stroke="#979797" stroke-width="1" fill="url(#27c61b0f-392f-962d-de12-cb9da898274b)" fill-rule="evenodd" xlink:href="#e966567b-3869-4bcd-76b6-2cf084e45390"/>
|
|
50
|
+
</g>
|
|
51
|
+
<g id="Oval-2">
|
|
52
|
+
<use fill="black" fill-opacity="1" filter="url(#dedf2e7e-f008-c315-f682-e424d670f210)" xlink:href="#c54189ed-7ea3-956c-f040-f0207548b268"/>
|
|
53
|
+
<use fill="" fill-rule="evenodd" xlink:href="#c54189ed-7ea3-956c-f040-f0207548b268"/>
|
|
54
|
+
<use stroke="#4A4A4A" stroke-width="1" fill="url(#0facd5c9-8e04-e83f-4842-8ba16f949942)" fill-rule="evenodd" xlink:href="#c54189ed-7ea3-956c-f040-f0207548b268"/>
|
|
55
|
+
</g>
|
|
56
|
+
<g id="knob" transform="translate(28.574244, 28.574244)">
|
|
57
|
+
<circle id="Oval-5" fill="#322E2E" cx="71.4356094" cy="71.4356094" r="71.4356094"/>
|
|
58
|
+
<path d="M72.4209282,3.63066376 L88.6786876,16.869789 C81.585496,18.1548295 76.1662428,18.7973498 72.4209282,18.7973498 C68.6756135,18.7973498 63.2563604,18.1548295 56.1631688,16.869789 L72.4209282,3.63066376 Z" id="Rectangle" fill="#E6D7D7" transform="translate(72.420928, 11.214007) scale(1, -1) translate(-72.420928, -11.214007) "/>
|
|
59
|
+
</g>
|
|
60
|
+
<g id="label">
|
|
61
|
+
<g id="labeltext" fill-opacity="1" fill="#E6D7D7">
|
|
62
|
+
<text id="534f4e02-5541-3607-0966-af0b025d80e0" font-family="Helvetica" font-size="44" font-weight="normal" fill="#E6D7D7" class="text-7" filter="url(#12f618f7-e258-b597-3ed6-242484ddad8f)">
|
|
63
|
+
<tspan x="45.3246625" y="117.884225">10.10</tspan>
|
|
64
|
+
</text>
|
|
65
|
+
<text id="92ebe866-c281-70c7-7b0e-a373cee013a9" font-family="Helvetica" font-size="44" font-weight="normal" fill="#E6D7D7" class="text-7">
|
|
66
|
+
<tspan x="45.3246625" y="117.884225">10.10</tspan>
|
|
67
|
+
</text>
|
|
68
|
+
</g>
|
|
69
|
+
<circle id="Oval-6" stroke="#979797" fill-opacity="0.730000019" fill="url(#3cc0e5b8-1f0a-886b-f635-8fcb19212870)" transform="translate(100.351759, 100.351759) rotate(-45.000000) translate(-100.351759, -100.351759) " cx="100.351759" cy="100.351759" r="70.3517588"/>
|
|
70
|
+
</g>
|
|
71
|
+
</g>
|
|
72
|
+
</g>
|
|
73
|
+
</g>
|
|
74
|
+
</svg>
|
|
75
|
+
`,
|
|
76
|
+
updateAttributes: [
|
|
77
|
+
{
|
|
78
|
+
element: '#labeltext text tspan',
|
|
79
|
+
content: (_props, value) => value.toFixed(0),
|
|
80
|
+
attrs: [
|
|
81
|
+
{
|
|
82
|
+
name: 'text-anchor',
|
|
83
|
+
value: ( /* props, value */) => 'middle',
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
name: 'x',
|
|
87
|
+
value: ( /* props, value */) => '100',
|
|
88
|
+
},
|
|
89
|
+
],
|
|
90
|
+
},
|
|
91
|
+
],
|
|
92
|
+
};
|
|
93
|
+
export default knobSkin10;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
class InternalInput extends React.Component {
|
|
4
|
+
render() {
|
|
5
|
+
const props = this.props;
|
|
6
|
+
const hideStyle = {};
|
|
7
|
+
function onValChange(event) {
|
|
8
|
+
props.onChange(Number(event.target.value));
|
|
9
|
+
}
|
|
10
|
+
const { value, min, max, step, onChange, inputRef, ...rest } = props;
|
|
11
|
+
return (_jsx("input", { ref: inputRef, value: value, step: step, onChange: onValChange, style: hideStyle, type: "range", min: min, max: max, ...rest }));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(InternalInput, "defaultProps", {
|
|
15
|
+
enumerable: true,
|
|
16
|
+
configurable: true,
|
|
17
|
+
writable: true,
|
|
18
|
+
value: {
|
|
19
|
+
step: 1,
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
export default InternalInput;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
class DrawCircle extends React.Component {
|
|
4
|
+
render() {
|
|
5
|
+
const { r, borderColor = 'black', fillColor = 'transparent', borderWidth = 2, fillOpacity = 1, ...rest } = this.props;
|
|
6
|
+
return (_jsx("circle", { stroke: borderColor, fill: fillColor, fillOpacity: fillOpacity, r: r, ...rest }));
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export default DrawCircle;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
class DrawLine extends React.Component {
|
|
4
|
+
render() {
|
|
5
|
+
const { width = 2, color = 'black', p1, p2, ...rest } = this.props;
|
|
6
|
+
return (_jsx("line", { ...rest, stroke: color, strokeWidth: width, x1: p1.x, y1: p1.y, x2: p2.x, y2: p2.y }));
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
export default DrawLine;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import ReactDOM from 'react-dom';
|
|
4
|
+
/**
|
|
5
|
+
* Draws the overlay and the children
|
|
6
|
+
*/
|
|
7
|
+
class HelpersOverlay extends React.Component {
|
|
8
|
+
render() {
|
|
9
|
+
const { children, ...rest } = this.props;
|
|
10
|
+
const styles = {
|
|
11
|
+
overlay: Object.assign({
|
|
12
|
+
width: '100%',
|
|
13
|
+
height: '100vh',
|
|
14
|
+
top: 0,
|
|
15
|
+
left: 0,
|
|
16
|
+
zIndex: 2147483647,
|
|
17
|
+
margin: '0',
|
|
18
|
+
padding: '0',
|
|
19
|
+
boxSizing: 'border-box',
|
|
20
|
+
position: 'fixed',
|
|
21
|
+
}, this.props.overlayStyle),
|
|
22
|
+
};
|
|
23
|
+
return ReactDOM.createPortal(_jsx("div", { style: styles.overlay, ...rest, children: children }), document.body);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
export default HelpersOverlay;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import React from 'react';
|
|
3
|
+
import utils from '../utils';
|
|
4
|
+
import DrawCircle from './DrawCircle';
|
|
5
|
+
import DrawLine from './DrawLine';
|
|
6
|
+
import HelpersOverlay from './HelpersOverlay';
|
|
7
|
+
class KnobVisualHelpers extends React.Component {
|
|
8
|
+
constructor() {
|
|
9
|
+
super(...arguments);
|
|
10
|
+
Object.defineProperty(this, "state", {
|
|
11
|
+
enumerable: true,
|
|
12
|
+
configurable: true,
|
|
13
|
+
writable: true,
|
|
14
|
+
value: {
|
|
15
|
+
centerX: 0,
|
|
16
|
+
centerY: 0,
|
|
17
|
+
valueMarkerX: 0,
|
|
18
|
+
valueMarkerY: 0,
|
|
19
|
+
}
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
static getDerivedStateFromProps(props, state) {
|
|
23
|
+
//Calculate position
|
|
24
|
+
if (!props.svgRef)
|
|
25
|
+
return state;
|
|
26
|
+
const vbox = props.svgRef.getBoundingClientRect();
|
|
27
|
+
const halfWidth = vbox.width / 2;
|
|
28
|
+
//Calculate current angle segment end point
|
|
29
|
+
//Note: Not sure why we need to subtract 90 here
|
|
30
|
+
const valueMarkerX = props.radius * Math.cos(utils.toRadians(props.valueAngle - 90));
|
|
31
|
+
const valueMarkerY = props.radius * Math.sin(utils.toRadians(props.valueAngle - 90));
|
|
32
|
+
return {
|
|
33
|
+
...state,
|
|
34
|
+
centerX: vbox.left + halfWidth,
|
|
35
|
+
centerY: vbox.top + halfWidth,
|
|
36
|
+
valueMarkerX,
|
|
37
|
+
valueMarkerY,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
render() {
|
|
41
|
+
const markCircleColor = this.props.minimumDragDistance <= this.props.radius ? 'green' : 'grey';
|
|
42
|
+
const fillColor = this.props.minimumDragDistance <= this.props.radius
|
|
43
|
+
? '#88E22D'
|
|
44
|
+
: '#D8D8D8';
|
|
45
|
+
const minDistanceCueVisible = this.props.minimumDragDistance >= this.props.radius;
|
|
46
|
+
return (_jsx(HelpersOverlay, { children: _jsxs("svg", { style: { position: 'absolute', top: '0', left: '0' }, width: "100%", height: "100%", children: [_jsx("defs", { children: _jsx("marker", { id: "Triangle", viewBox: "0 0 10 10", refX: "1", refY: "5", markerWidth: "6", markerHeight: "6", orient: "auto", children: _jsx("path", { d: "M 0 0 L 10 5 L 0 10 z" }) }) }), _jsx(DrawCircle, { borderColor: markCircleColor, fillColor: fillColor, fillOpacity: 0.02, r: this.props.radius, cx: this.state.centerX, cy: this.state.centerY }), minDistanceCueVisible && (_jsx(DrawCircle, { borderColor: markCircleColor, fillColor: fillColor, fillOpacity: 0, r: this.props.minimumDragDistance, cx: this.state.centerX, cy: this.state.centerY })), _jsx(DrawLine, { p1: { x: this.state.centerX, y: this.state.centerY }, p2: {
|
|
47
|
+
x: this.state.valueMarkerX + this.state.centerX,
|
|
48
|
+
y: this.state.valueMarkerY + this.state.centerY,
|
|
49
|
+
}, markerEnd: "url(#Triangle)" })] }) }));
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export { KnobVisualHelpers };
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* Show the rotation circle and marker
|
|
4
|
+
* dispatches drag events
|
|
5
|
+
*/
|
|
6
|
+
import { drag } from 'd3-drag';
|
|
7
|
+
import { scaleLinear } from 'd3-scale';
|
|
8
|
+
import { select } from 'd3-selection';
|
|
9
|
+
import { useEffect, useRef, useState } from 'react';
|
|
10
|
+
import { SvgLoader, SvgProxy } from 'react-svgmt';
|
|
11
|
+
import InternalInput from './InternalInput';
|
|
12
|
+
import { KnobVisualHelpers } from './helpers/KnobVisualHelpers';
|
|
13
|
+
import defaultSkin from './knobdefaultskin';
|
|
14
|
+
import utils from './utils';
|
|
15
|
+
// function printDebugValues(obj) {
|
|
16
|
+
// console.log('------------')
|
|
17
|
+
// Object.keys(obj).forEach(key => {
|
|
18
|
+
// const value =
|
|
19
|
+
// typeof obj[key] === 'object' ? JSON.stringify(obj[key]) : obj[key]
|
|
20
|
+
// console.log(`${key}: ${value}`)
|
|
21
|
+
// })
|
|
22
|
+
// console.log('------------')
|
|
23
|
+
// }
|
|
24
|
+
/**
|
|
25
|
+
* Generic knob component
|
|
26
|
+
*/
|
|
27
|
+
const RotaryKnob = (props) => {
|
|
28
|
+
const { clampMax = 360, clampMin = 0, defaultValue = 0, disabled = false, format = (val) => val.toFixed(0), max = 100, min = 0, onChange = () => { }, onEnd = () => { }, onStart = () => { }, preciseMode = true, rotateDegrees = 0, skin = defaultSkin, step = 1, style, unlockDistance = 100, value, ...rest } = props;
|
|
29
|
+
const [isControlled, setIsControlled] = useState(value !== undefined);
|
|
30
|
+
const container = useRef(null);
|
|
31
|
+
const inputRef = useRef(null);
|
|
32
|
+
let scale;
|
|
33
|
+
let scaleProps;
|
|
34
|
+
const [state, setState] = useState({
|
|
35
|
+
svgRef: undefined,
|
|
36
|
+
dragging: false,
|
|
37
|
+
dragDistance: 0,
|
|
38
|
+
mousePos: { x: 0, y: 0 },
|
|
39
|
+
valueAngle: 0,
|
|
40
|
+
uncontrolledValue: 0,
|
|
41
|
+
});
|
|
42
|
+
// returns angles between 0 and 360 for values lower 0 or greater 360
|
|
43
|
+
const normalizeAngle = (angle) => {
|
|
44
|
+
if (angle < 0) {
|
|
45
|
+
//E.g -1 turns 359
|
|
46
|
+
return angle + 360;
|
|
47
|
+
}
|
|
48
|
+
if (angle > 360) {
|
|
49
|
+
return angle - 360;
|
|
50
|
+
}
|
|
51
|
+
return angle;
|
|
52
|
+
};
|
|
53
|
+
// converts a value to an angle for the knob respecting the additional rotateDegrees prop
|
|
54
|
+
const convertValueToAngle = (value) => {
|
|
55
|
+
const angle = (getScale()(value) + rotateDegrees) % 360;
|
|
56
|
+
return normalizeAngle(angle);
|
|
57
|
+
};
|
|
58
|
+
// converts an angle to a value for the knob respecting the additional rotateDegrees prop
|
|
59
|
+
const convertAngleToValue = (angle) => {
|
|
60
|
+
const angle2 = angle - rotateDegrees;
|
|
61
|
+
return getScale().invert(normalizeAngle(angle2));
|
|
62
|
+
};
|
|
63
|
+
const getScale = () => {
|
|
64
|
+
// Memoize scale so it's not recalculated every time
|
|
65
|
+
if (!scaleProps ||
|
|
66
|
+
scaleProps.min !== min ||
|
|
67
|
+
scaleProps.max !== max ||
|
|
68
|
+
scaleProps.clampMin !== clampMin ||
|
|
69
|
+
scaleProps.clampMax !== clampMax) {
|
|
70
|
+
if (rotateDegrees < 270 && rotateDegrees > 90) {
|
|
71
|
+
scale = scaleLinear().domain([min, max]).range([clampMin, clampMax]);
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
scale = scaleLinear().domain([max, min]).range([clampMax, clampMin]);
|
|
75
|
+
}
|
|
76
|
+
scale.clamp(true);
|
|
77
|
+
scaleProps = {
|
|
78
|
+
min: min,
|
|
79
|
+
max: max,
|
|
80
|
+
clampMin: clampMin,
|
|
81
|
+
clampMax: clampMax,
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
return scale;
|
|
85
|
+
};
|
|
86
|
+
useEffect(() => {
|
|
87
|
+
setIsControlled(value !== undefined);
|
|
88
|
+
setState(prevState => ({
|
|
89
|
+
...prevState,
|
|
90
|
+
uncontrolledValue: value ?? defaultValue ?? 0,
|
|
91
|
+
}));
|
|
92
|
+
if (container.current) {
|
|
93
|
+
// Remove existing drag behavior
|
|
94
|
+
select(container.current).on('.drag', null);
|
|
95
|
+
// Only setup new drag if not disabled
|
|
96
|
+
if (!disabled) {
|
|
97
|
+
setupDragging(select(container.current));
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}, [value, defaultValue, disabled]);
|
|
101
|
+
const saveRef = (elem) => {
|
|
102
|
+
if (!state.svgRef) {
|
|
103
|
+
setState({ ...state, svgRef: elem });
|
|
104
|
+
}
|
|
105
|
+
};
|
|
106
|
+
const onAngleChanged = (angle) => {
|
|
107
|
+
//Calculate domain value
|
|
108
|
+
const domainValue = convertAngleToValue(angle);
|
|
109
|
+
if (!isControlled) {
|
|
110
|
+
/**
|
|
111
|
+
* If the mode is 'uncontrolled' we need to update our local state
|
|
112
|
+
*/
|
|
113
|
+
setState(st => {
|
|
114
|
+
return { ...st, uncontrolledValue: domainValue };
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
if (!disabled)
|
|
118
|
+
onChange(domainValue);
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Returns the current value (depending on controlled/uncontrolled mode)
|
|
122
|
+
*/
|
|
123
|
+
const getValue = () => isControlled ? (value ?? 0) : (state.uncontrolledValue ?? 0);
|
|
124
|
+
const setupDragging = (elem) => {
|
|
125
|
+
if (!elem?.node())
|
|
126
|
+
return;
|
|
127
|
+
const node = elem.node();
|
|
128
|
+
if (!node)
|
|
129
|
+
return;
|
|
130
|
+
let vbox = node.getBoundingClientRect();
|
|
131
|
+
const cx = vbox.width / 2;
|
|
132
|
+
const cy = vbox.height / 2;
|
|
133
|
+
// Shared state via closure
|
|
134
|
+
let startPos;
|
|
135
|
+
let startAngle;
|
|
136
|
+
let initialAngle;
|
|
137
|
+
let monitoring = false;
|
|
138
|
+
function started(event) {
|
|
139
|
+
if (!event?.sourceEvent)
|
|
140
|
+
return;
|
|
141
|
+
if (!node)
|
|
142
|
+
return;
|
|
143
|
+
const currentValue = getValue();
|
|
144
|
+
vbox = node.getBoundingClientRect();
|
|
145
|
+
elem.classed('dragging', true);
|
|
146
|
+
onStart();
|
|
147
|
+
startPos = { x: event.x - cx, y: event.y - cy };
|
|
148
|
+
startAngle = utils.getAngleForPoint(startPos.x, startPos.y);
|
|
149
|
+
initialAngle = convertValueToAngle(currentValue);
|
|
150
|
+
monitoring = false;
|
|
151
|
+
// ...existing setState code...
|
|
152
|
+
}
|
|
153
|
+
function dragged(event) {
|
|
154
|
+
const currentPos = { x: event.x - cx, y: event.y - cy };
|
|
155
|
+
const distanceFromCenter = Math.sqrt(currentPos.x ** 2 + currentPos.y ** 2);
|
|
156
|
+
if (preciseMode) {
|
|
157
|
+
if (!monitoring && distanceFromCenter >= unlockDistance) {
|
|
158
|
+
startPos = currentPos;
|
|
159
|
+
startAngle = utils.getAngleForPoint(currentPos.x, currentPos.y);
|
|
160
|
+
monitoring = true;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
monitoring = true;
|
|
165
|
+
}
|
|
166
|
+
const currentAngle = utils.getAngleForPoint(currentPos.x, currentPos.y);
|
|
167
|
+
const deltaAngle = currentAngle - startAngle;
|
|
168
|
+
let finalAngle = initialAngle + deltaAngle;
|
|
169
|
+
finalAngle = normalizeAngle(finalAngle);
|
|
170
|
+
if (monitoring) {
|
|
171
|
+
onAngleChanged(finalAngle);
|
|
172
|
+
}
|
|
173
|
+
setState(prevState => ({
|
|
174
|
+
...prevState,
|
|
175
|
+
dragDistance: distanceFromCenter,
|
|
176
|
+
mousePos: {
|
|
177
|
+
x: event.sourceEvent.clientX,
|
|
178
|
+
y: event.sourceEvent.clientY,
|
|
179
|
+
},
|
|
180
|
+
valueAngle: monitoring ? finalAngle : initialAngle,
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
function ended() {
|
|
184
|
+
elem.classed('dragging', false);
|
|
185
|
+
setState(prevState => ({ ...prevState, dragging: false }));
|
|
186
|
+
onEnd();
|
|
187
|
+
inputRef.current?.focus();
|
|
188
|
+
}
|
|
189
|
+
const dragInstance = drag()
|
|
190
|
+
.container(() => node)
|
|
191
|
+
.on('start', started)
|
|
192
|
+
.on('drag', dragged)
|
|
193
|
+
.on('end', ended);
|
|
194
|
+
elem.call(dragInstance);
|
|
195
|
+
};
|
|
196
|
+
const onFormControlChange = (newVal) => {
|
|
197
|
+
if (!isControlled) {
|
|
198
|
+
/**
|
|
199
|
+
* If the mode is 'uncontrolled' we need to update our local state
|
|
200
|
+
*/
|
|
201
|
+
setState(prevState => ({ ...prevState, uncontrolledValue: newVal }));
|
|
202
|
+
}
|
|
203
|
+
if (!disabled)
|
|
204
|
+
onChange(newVal);
|
|
205
|
+
};
|
|
206
|
+
const currentValue = getValue();
|
|
207
|
+
const angle = convertValueToAngle(currentValue);
|
|
208
|
+
const styles = {
|
|
209
|
+
container: Object.assign({}, {
|
|
210
|
+
width: '50px',
|
|
211
|
+
height: '50px',
|
|
212
|
+
overflow: 'hidden',
|
|
213
|
+
position: 'relative',
|
|
214
|
+
userSelect: 'none',
|
|
215
|
+
cursor: 'crosshair',
|
|
216
|
+
}, style),
|
|
217
|
+
input: {
|
|
218
|
+
width: '50%',
|
|
219
|
+
position: 'absolute',
|
|
220
|
+
top: '0',
|
|
221
|
+
left: '-100%',
|
|
222
|
+
},
|
|
223
|
+
};
|
|
224
|
+
//Get custom updates defined by the skin
|
|
225
|
+
//Transform the updateAttributes array into a SvgProxy array
|
|
226
|
+
const updateAttrs = skin.updateAttributes;
|
|
227
|
+
const skinElemUpdates = updateAttrs
|
|
228
|
+
? updateAttrs.map((elemUpdate, ix) => {
|
|
229
|
+
let elemContent = null;
|
|
230
|
+
if (elemUpdate.content) {
|
|
231
|
+
elemContent = elemUpdate.content(props, currentValue);
|
|
232
|
+
}
|
|
233
|
+
const attributes = {};
|
|
234
|
+
//Call value function
|
|
235
|
+
//TODO: support string values
|
|
236
|
+
for (const attr of elemUpdate.attrs || []) {
|
|
237
|
+
attributes[attr.name] = attr.value(props, currentValue);
|
|
238
|
+
}
|
|
239
|
+
return (_jsx(SvgProxy, { selector: elemUpdate.element, ...attributes, children: elemContent }, ix));
|
|
240
|
+
})
|
|
241
|
+
: null;
|
|
242
|
+
return (_jsxs(_Fragment, { children: [_jsxs("div", { ref: container, style: styles.container, ...rest, children: [_jsx(InternalInput, { disabled: disabled, inputRef: inputRef, style: styles.input, value: currentValue, min: min, max: max, step: step, onChange: onFormControlChange }), _jsxs(SvgLoader, { height: "100%", svgXML: skin.svg, width: "100%", onSVGReady: saveRef, children: [_jsx(SvgProxy, { selector: "#knob", transform: `$ORIGINAL rotate(${angle}, ${skin.knobX}, ${skin.knobY})` }), skinElemUpdates] })] }), state.dragging && preciseMode && (_jsx(KnobVisualHelpers, { svgRef: state.svgRef, radius: state.dragDistance, mousePos: state.mousePos, minimumDragDistance: unlockDistance, valueAngle: state.valueAngle }))] }));
|
|
243
|
+
};
|
|
244
|
+
export default RotaryKnob;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export default {
|
|
2
|
+
knobX: 71,
|
|
3
|
+
knobY: 71,
|
|
4
|
+
svg: `
|
|
5
|
+
|
|
6
|
+
<svg width="204px" height="204px" viewBox="0 0 204 204" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
|
|
7
|
+
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
|
|
8
|
+
<desc>Created with Sketch.</desc>
|
|
9
|
+
<defs>
|
|
10
|
+
<linearGradient x1="50%" y1="50%" x2="50%" y2="100%" id="linearGradient-1">
|
|
11
|
+
<stop stop-color="#444040" stop-opacity="0.51098279" offset="0%"></stop>
|
|
12
|
+
<stop stop-color="#131111" stop-opacity="0.893200861" offset="100%"></stop>
|
|
13
|
+
</linearGradient>
|
|
14
|
+
<circle id="path-2" cx="98.0400009" cy="98.0400009" r="98.0400009"></circle>
|
|
15
|
+
<filter x="-3.3%" y="-3.3%" width="106.6%" height="106.6%" filterUnits="objectBoundingBox" id="filter-3">
|
|
16
|
+
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
|
|
17
|
+
<feOffset dx="0" dy="0" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
|
|
18
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
|
19
|
+
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"></feComposite>
|
|
20
|
+
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
|
21
|
+
</filter>
|
|
22
|
+
<linearGradient x1="50%" y1="0%" x2="50%" y2="100%" id="linearGradient-4">
|
|
23
|
+
<stop stop-color="#FFFFFF" stop-opacity="0.5" offset="0%"></stop>
|
|
24
|
+
<stop stop-color="#000000" stop-opacity="0.5" offset="100%"></stop>
|
|
25
|
+
</linearGradient>
|
|
26
|
+
<circle id="path-5" cx="98" cy="98" r="86"></circle>
|
|
27
|
+
<filter x="-4.1%" y="-3.5%" width="108.1%" height="108.1%" filterUnits="objectBoundingBox" id="filter-6">
|
|
28
|
+
<feMorphology radius="0.5" operator="dilate" in="SourceAlpha" result="shadowSpreadOuter1"></feMorphology>
|
|
29
|
+
<feOffset dx="0" dy="1" in="shadowSpreadOuter1" result="shadowOffsetOuter1"></feOffset>
|
|
30
|
+
<feGaussianBlur stdDeviation="2" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
|
|
31
|
+
<feComposite in="shadowBlurOuter1" in2="SourceAlpha" operator="out" result="shadowBlurOuter1"></feComposite>
|
|
32
|
+
<feColorMatrix values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.5 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
|
|
33
|
+
</filter>
|
|
34
|
+
</defs>
|
|
35
|
+
<g id="Page-1" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
|
|
36
|
+
<g id="s13" transform="translate(4.000000, 4.000000)">
|
|
37
|
+
<g id="container">
|
|
38
|
+
<g id="Oval-2">
|
|
39
|
+
<use fill="black" fill-opacity="1" filter="url(#filter-3)" xlink:href="#path-2"></use>
|
|
40
|
+
<use stroke="#979797" stroke-width="1" fill="url(#linearGradient-1)" fill-rule="evenodd" xlink:href="#path-2"></use>
|
|
41
|
+
</g>
|
|
42
|
+
<g id="Oval-2">
|
|
43
|
+
<use fill="black" fill-opacity="1" filter="url(#filter-6)" xlink:href="#path-5"></use>
|
|
44
|
+
<use fill="" fill-rule="evenodd" xlink:href="#path-5"></use>
|
|
45
|
+
<use stroke="#4A4A4A" stroke-width="1" fill="url(#linearGradient-4)" fill-rule="evenodd" xlink:href="#path-5"></use>
|
|
46
|
+
</g>
|
|
47
|
+
<g id="knob" transform="translate(27.431373, 27.431373)">
|
|
48
|
+
<circle id="Oval-5" fill="#322E2E" cx="71" cy="71" r="71"></circle>
|
|
49
|
+
<path d="M70.0686275,4.17063061 L86.5686275,65.2689929 C81.3642501,66.811221 75.8642501,67.5735686 70.0686275,67.5560356 C64.2730048,67.5385027 58.7730048,66.7761551 53.5686275,65.2689929 L70.0686275,4.17063061 Z" id="Rectangle-Copy" fill="#E6D7D7" transform="translate(70.068627, 35.863481) scale(1, -1) translate(-70.068627, -35.863481) "></path>
|
|
50
|
+
</g>
|
|
51
|
+
</g>
|
|
52
|
+
</g>
|
|
53
|
+
</g>
|
|
54
|
+
</svg>
|
|
55
|
+
`,
|
|
56
|
+
};
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
/** Note on viewbox/width
|
|
2
|
+
* This methods only work when the pixels match the svg units.
|
|
3
|
+
* when the viewbox is changed, or width is set they won't return
|
|
4
|
+
* the correct results
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Returns the global coordinates of a position given
|
|
8
|
+
* for a specific coordinate system
|
|
9
|
+
* @param {*} svgdoc
|
|
10
|
+
* @param {*} elem
|
|
11
|
+
* @param {*} x
|
|
12
|
+
* @param {*} y
|
|
13
|
+
*/
|
|
14
|
+
// function toGlobalCoordinates(svgdoc: any, elem: any, x: number, y: number) {
|
|
15
|
+
// var offset = svgdoc.getBoundingClientRect()
|
|
16
|
+
// var matrix = elem.getScreenCTM()
|
|
17
|
+
// return {
|
|
18
|
+
// x: matrix.a * x + matrix.c * y + matrix.e - offset.left,
|
|
19
|
+
// y: matrix.b * x + matrix.d * y + matrix.f - offset.top,
|
|
20
|
+
// }
|
|
21
|
+
// }
|
|
22
|
+
/**
|
|
23
|
+
* Converts a global position to a local one
|
|
24
|
+
* @param {*} svgdoc
|
|
25
|
+
* @param {*} elem
|
|
26
|
+
* @param {*} x
|
|
27
|
+
* @param {*} y
|
|
28
|
+
*/
|
|
29
|
+
// function toLocalCoordinates(svgdoc: any, elem: any, x: number, y: number) {
|
|
30
|
+
// const offset = svgdoc.getBoundingClientRect()
|
|
31
|
+
// const matrix = elem.getScreenCTM().inverse()
|
|
32
|
+
// return {
|
|
33
|
+
// x: matrix.a * x + matrix.c * y + matrix.e - offset.left,
|
|
34
|
+
// y: matrix.b * x + matrix.d * y + matrix.f - offset.top,
|
|
35
|
+
// }
|
|
36
|
+
// }
|
|
37
|
+
function toRadians(angle) {
|
|
38
|
+
return (angle * Math.PI) / 180;
|
|
39
|
+
}
|
|
40
|
+
function getQuadrant(x, y) {
|
|
41
|
+
if (x >= 0 && y >= 0)
|
|
42
|
+
return 1;
|
|
43
|
+
if (x <= 0 && y >= 0)
|
|
44
|
+
return 2;
|
|
45
|
+
if (x <= 0 && y <= 0)
|
|
46
|
+
return 3;
|
|
47
|
+
if (x >= 0 && y <= 0)
|
|
48
|
+
return 4;
|
|
49
|
+
return 1;
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Returns the angle (degrees) given a point.
|
|
53
|
+
* Assumes 0,0 as the center of the circle
|
|
54
|
+
* @param {number} x
|
|
55
|
+
* @param {number} y
|
|
56
|
+
*/
|
|
57
|
+
function getAngleForPoint(x, y) {
|
|
58
|
+
if (x === 0 && y === 0)
|
|
59
|
+
return 0;
|
|
60
|
+
const angle = Math.atan(x / y);
|
|
61
|
+
let angleDeg = (angle * 180) / Math.PI;
|
|
62
|
+
//The final value depends on the quadrant
|
|
63
|
+
const quadrant = getQuadrant(x, y);
|
|
64
|
+
if (quadrant === 1) {
|
|
65
|
+
angleDeg = 90 - angleDeg;
|
|
66
|
+
}
|
|
67
|
+
if (quadrant === 2) {
|
|
68
|
+
angleDeg = 90 - angleDeg;
|
|
69
|
+
}
|
|
70
|
+
if (quadrant === 3) {
|
|
71
|
+
angleDeg = 270 - angleDeg;
|
|
72
|
+
}
|
|
73
|
+
if (quadrant === 4) {
|
|
74
|
+
angleDeg = 270 - angleDeg;
|
|
75
|
+
}
|
|
76
|
+
return angleDeg;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Transforms the top/left variables of the rectangle
|
|
80
|
+
* returned by getBoundingClientRect to document based coordinates
|
|
81
|
+
* without the scroll.
|
|
82
|
+
* UPDATE
|
|
83
|
+
* @param {Rect} box
|
|
84
|
+
*/
|
|
85
|
+
function transformBoundingClientRectToDocument(box) {
|
|
86
|
+
let t;
|
|
87
|
+
t = document.documentElement || document.body.parentNode;
|
|
88
|
+
const scrollX = (typeof t.scrollLeft === 'number' ? t : document.body)
|
|
89
|
+
.scrollLeft;
|
|
90
|
+
t = document.documentElement || document.body.parentNode;
|
|
91
|
+
const scrollY = (typeof t.scrollTop === 'number' ? t : document.body)
|
|
92
|
+
.scrollTop;
|
|
93
|
+
//This assumes width == height
|
|
94
|
+
const ttop = box.top - scrollY;
|
|
95
|
+
const tleft = box.left - scrollX;
|
|
96
|
+
//info needed to draw line from center to mousepos
|
|
97
|
+
return { top: ttop, left: tleft, width: box.width, height: box.height };
|
|
98
|
+
}
|
|
99
|
+
export default {
|
|
100
|
+
// toGlobalCoordinates,
|
|
101
|
+
// toLocalCoordinates,
|
|
102
|
+
toRadians,
|
|
103
|
+
getQuadrant,
|
|
104
|
+
getAngleForPoint,
|
|
105
|
+
transformBoundingClientRectToDocument,
|
|
106
|
+
};
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// this just creates and fills a zero-indexed array array; 0, 1, 2, 3, etc
|
|
2
|
+
const arraySequence = (numberOfElements) => Array.from(new Array(numberOfElements).keys());
|
|
3
|
+
const assertRange = (value, max = 127, min = 0) => {
|
|
4
|
+
let result = typeof value === 'string' ? Number.parseInt(value, 10) : value;
|
|
5
|
+
if (Number.isNaN(result) || result === null) {
|
|
6
|
+
result = min;
|
|
7
|
+
}
|
|
8
|
+
return result >= min ? (result <= max ? result : max) : min;
|
|
9
|
+
};
|
|
10
|
+
const findObj = (key, value) => (arr) => arr?.find(item => item?.[key] === value);
|
|
11
|
+
const omit = (...keys) => (obj) => Object.entries(obj)
|
|
12
|
+
.filter(([key]) => !keys.flat().map(String).includes(key))
|
|
13
|
+
.reduce((_obj, [key, val]) => Object.assign(_obj, { [key]: val }), {});
|
|
14
|
+
const pick = (...keys) => (obj) => Object.entries(obj)
|
|
15
|
+
.filter(([key]) => keys.flat().map(String).includes(key))
|
|
16
|
+
.reduce((_obj, [key, val]) => Object.assign(_obj, { [key]: val }), {});
|
|
17
|
+
const set = (key, value) => (obj) => ({
|
|
18
|
+
...obj,
|
|
19
|
+
[key]: value,
|
|
20
|
+
});
|
|
21
|
+
export { arraySequence, assertRange, findObj, omit, pick, set };
|