Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ node_modules
/coverage
/lib/dist
.*
_*
/_*
9 changes: 9 additions & 0 deletions docusaurus/docs/1_base_components/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"label": "Base components",
"position": 1,
"collapsible": false,
"link": {
"type": "generated-index",
"description": "Provided components"
}
}
2 changes: 1 addition & 1 deletion docusaurus/docs/3_examples/2_custom.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ function Example(props) {
height={i === active ? tickHeight * 3 : tickHeight}
key={i}
transform={`
rotate(${angleOffset + stepSize * i} ${center} ${center})
rotate(${angleOffset + stepSize * i} ${center[0]} ${center[1]})
translate( ${translateX} ${translateY})
`}
/>
Expand Down
9 changes: 9 additions & 0 deletions docusaurus/docs/3_examples/_category_.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"label": "Examples",
"position": 3,
"collapsible": false,
"link": {
"type": "generated-index",
"description": "Few examples"
}
}
2 changes: 1 addition & 1 deletion docusaurus/src/components/DnlGradientKnob3/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ function customScaleTick({
className={className}
key={i}
transform={`
rotate(${angleOffset + stepSize * i} ${center} ${center})
rotate(${angleOffset + stepSize * i} ${center[0]} ${center[1]})
translate( ${translateX} ${translateY})
`}
/>
Expand Down
2 changes: 1 addition & 1 deletion docusaurus/src/components/GradientKnob3/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default function KnobExample(props: { size: number }) {
fill={color}
key={i}
transform={`
rotate(${angleOffset + stepSize * i} ${center} ${center})
rotate(${angleOffset + stepSize * i} ${center[0]} ${center[1]})
translate( ${translateX} ${translateY})
`}
/>
Expand Down
3 changes: 2 additions & 1 deletion lib/src/Arc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,15 @@ interface Props {

export function Arc(props: Props) {
const state = useKnobContext('Arc');
const { geometry } = state;
const { percentage } = state;
const {
className,
backgroundClassName,
arcWidth,
color,
background,
radius = state.radius,
radius = geometry.radius,
} = props;
return (
<g>
Expand Down
48 changes: 17 additions & 31 deletions lib/src/Knob.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React, { PropsWithChildren, useEffect, useState } from 'react';
import React, { PropsWithChildren, useMemo } from 'react';
import useUpdate from './useUpdate';
import type { InteractiveHook, KnobState } from 'types';
import type { InteractiveHook, KnobGeometry, KnobState } from 'types';
import { KnobContext } from './context';

interface Props {
Expand Down Expand Up @@ -79,41 +79,27 @@ export function Knob(props: PropsWithChildren<Props>) {
onStart,
onEnd,
});
const radius = size / 2;
const center = size / 2;

const [knobState, setKnobState] = useState<KnobState>({
value,
percentage,
size,
angleOffset,
angleRange,
radius,
center,
steps,
});

useEffect(() => {
setKnobState({
value,
percentage,
const geometry = useMemo<KnobGeometry>(() => {
const radius = size / 2;
const cx = size / 2;
return {
size,
angleOffset,
angleRange,
radius,
center,
center: [cx, cx],
};
}, [size, angleOffset, angleRange]);

const knobState = useMemo<KnobState>(() => {
return {
value,
percentage,
geometry,
steps,
});
}, [
value,
percentage,
size,
angleOffset,
angleRange,
radius,
center,
steps,
]);
};
}, [value, percentage, geometry, steps]);

return (
<div
Expand Down
17 changes: 11 additions & 6 deletions lib/src/Label.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,15 @@
import React, { useMemo } from 'react';
import { useKnobContext } from './context';

function pointOnCircle(center: number, radius: number, angle: number) {
function pointOnCircle(
center: [number, number],
radius: number,
angle: number,
) {
const rad = (angle * Math.PI) / 180;
return {
x: center + radius * Math.cos(rad),
y: center + radius * Math.sin(rad),
x: center[0] + radius * Math.cos(rad),
y: center[1] + radius * Math.sin(rad),
};
}

Expand All @@ -24,11 +28,12 @@ interface Props {

export function Label(props: Props) {
const state = useKnobContext('Label');
const { angleRange, angleOffset, center } = state;
const { geometry } = state;
const { angleRange, angleOffset, center } = geometry;
const {
label,
percentage,
radius = state.radius,
radius = geometry.radius,
className,
style = {},
userSelect = 'none',
Expand All @@ -46,7 +51,7 @@ export function Label(props: Props) {
return <></>;
}
return (
<g transform={`translate( ${center - p.x} ${center - p.y})`}>
<g transform={`translate( ${center[0] - p.x} ${center[1] - p.y})`}>
<text
// @ts-expect-error
style={{ userSelect, ...style }}
Expand Down
17 changes: 9 additions & 8 deletions lib/src/Pointer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,16 @@ interface Props {

export function Pointer(props: React.PropsWithChildren<Props>) {
const state = useKnobContext('Pointer');
const { angleRange, angleOffset, center } = state;
const { geometry } = state;
const { angleRange, angleOffset, center } = geometry;
const {
children,
width,
height = width,
useRotation = true,
type,
percentage = state.percentage,
radius = state.radius,
radius = geometry.radius,
color = 'black',
className,
} = props;
Expand All @@ -75,15 +76,15 @@ export function Pointer(props: React.PropsWithChildren<Props>) {
return null;
}
if (useRotation) {
return `rotate(${
angleOffset + angleRange * percentage
} ${center} ${center})
translate( ${center} ${center - radius - (height ?? 0)})`;
return `rotate(${angleOffset + angleRange * percentage} ${
center[0]
} ${center[1]})
translate( ${center[0]} ${center[1] - radius - (height ?? 0)})`;
} else {
const angle =
((angleOffset + angleRange * percentage - 90) * Math.PI) / 180;
const x = center + radius * Math.cos(angle);
const y = center + radius * Math.sin(angle);
const x = center[0] + radius * Math.cos(angle);
const y = center[1] + radius * Math.sin(angle);
return `translate(${x} ${y})`;
}
}, [percentage, angleOffset, angleRange, center, radius, height]);
Expand Down
29 changes: 12 additions & 17 deletions lib/src/Power.tsx
Original file line number Diff line number Diff line change
@@ -1,31 +1,30 @@
import { KnobGeometry } from 'types';
import { useKnobContext } from './context';
import React, { useMemo } from 'react';

function pointOnCircle(center: number, radius: number, angle: number) {
function pointOnCircle(
center: [number, number],
radius: number,
angle: number,
) {
return {
x: center + radius * Math.cos(angle),
y: center + radius * Math.sin(angle),
x: center[0] + radius * Math.cos(angle),
y: center[1] + radius * Math.sin(angle),
};
}

function degTorad(deg: number) {
return (Math.PI * deg) / 180;
}

interface Geometry {
angleOffset: number;
angleRange: number;
center: number;
}

interface Position {
percentage: number;
radius: number;
width: number;
}

function calcPath(
geometry: Geometry,
geometry: KnobGeometry,
positionFrom: Position,
positionTo: Position | null,
): string | null {
Expand Down Expand Up @@ -97,23 +96,19 @@ interface Props {

export function Power(props: Props) {
const state = useKnobContext('Power');
const { percentage, angleOffset, angleRange, center } = state;
const { percentage, geometry } = state;
const {
interpolateTo,
color,
percentageFrom,
radiusFrom = state.radius,
radiusFrom = geometry.radius,
percentageTo,
radiusTo = state.radius,
radiusTo = geometry.radius,
widthFrom,
widthTo,
className,
} = props;

const geometry: Geometry = useMemo(() => {
return { angleOffset, angleRange, center };
}, [angleOffset, angleRange, center]);

const positionFrom: Position = useMemo(
() => ({
percentage: percentageFrom,
Expand Down
59 changes: 29 additions & 30 deletions lib/src/Range.tsx
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
import React, { useMemo } from 'react';
import { useKnobContext } from './context';
import { KnobGeometry } from 'types';

function pointOnCircle(
center: [number, number],
radius: number,
angle: number,
) {
return {
x: center[0] + radius * Math.cos(angle),
y: center[1] + radius * Math.sin(angle),
};
}

const pointOnCircle = (center: number, radius: number, angle: number) => ({
x: center + radius * Math.cos(angle),
y: center + radius * Math.sin(angle),
});
const degTorad = (deg: number) => (Math.PI * deg) / 180;

const clampDeg = (deg: number) =>
deg >= 360 ? 359.999 : deg <= -360 ? -359.999 : deg;

const calcPath = ({
percentageFrom,
percentageTo,
angleOffset,
angleRange,
arcWidth,
radius: outerRadius,
center,
}: {
percentageFrom: number;
percentageTo: number;
angleOffset: number;
angleRange: number;
arcWidth: number;
radius: number;
center: number;
}) => {
function calcPath(
geometry: KnobGeometry,
arcWidth: number,
outerRadius: number,
percentageFrom: number,
percentageTo: number,
) {
const { angleRange, angleOffset, center } = geometry;
const angle = angleRange * (percentageTo - percentageFrom);
const clampedAngle = clampDeg(angle);
const angleFrom = angleOffset - 90 + angleRange * percentageFrom;
Expand All @@ -48,7 +47,7 @@ const calcPath = ({
}L${p3.x},${p3.y} A${innerRadius},${innerRadius} 0 ${largeArcFlag} ${
1 - direction
} ${p4.x},${p4.y} L${p1.x},${p1.y}`;
};
}

interface Props {
color?: string;
Expand All @@ -65,12 +64,12 @@ interface Props {

export function Range(props: Props) {
const state = useKnobContext('Range');
const { percentage } = state;
const { percentage, geometry } = state;
const {
color,
percentageFrom = null,
percentageTo = null,
radius = state.radius,
radius = geometry.radius,
outerRadius,
arcWidth,
className,
Expand All @@ -94,13 +93,13 @@ export function Range(props: Props) {
if (pFrom === null || pTo === null) {
return null;
}
return calcPath({
return calcPath(
geometry,
arcWidth,
...state,
radius: outerRadius ?? radius ?? state.radius,
percentageFrom: pFrom,
percentageTo: pTo,
});
outerRadius ?? radius ?? geometry.radius,
pFrom,
pTo,
);
}, [pFrom, pTo, outerRadius, radius, state]);

if (d === null) {
Expand Down
Loading