Skip to content

Commit

Permalink
feat: dynamic SVG size (#2)
Browse files Browse the repository at this point in the history
  • Loading branch information
mattrothenberg committed Feb 9, 2022
1 parent e8a4e7b commit bc0b1ab
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 31 deletions.
21 changes: 14 additions & 7 deletions example/index.tsx
Expand Up @@ -23,7 +23,7 @@ const App = () => {
startAngle: { value: 150, min: 0, max: 360, step: 1 },
endAngle: { value: 390, min: 0, max: 720, step: 1 },
numTicks: { value: 11, min: 0, max: 30, step: 1 },
padding: { value: 24, min: 0, max: 100, step: 1 },
padding: { value: 0, min: 0, max: 100, step: 1 },
});

const {
Expand Down Expand Up @@ -109,27 +109,34 @@ const App = () => {

return (
<div className="h-screen flex items-center justify-center">
<svg ref={ref} className="max-w-full">
<svg
ref={ref}
className="overflow-visible max-w-full border-2 border-gray-700"
>
<path
{...getArcProps({ offset, startAngle, endAngle })}
{...getArcProps({
offset,
startAngle,
endAngle,
strokeWidth: arcStrokeWidth,
})}
fill="none"
className="stroke-gray-100"
// @ts-ignore
strokeLinecap={strokeLineCap}
strokeWidth={arcStrokeWidth}
// strokeLinecap={strokeLineCap}
/>
{value > minValue && (
<path
{...getArcProps({
offset,
startAngle,
endAngle: valueToAngle(value),
strokeWidth: arcStrokeWidth,
})}
fill="none"
stroke={progressColor}
// @ts-ignore
strokeLinecap={strokeLineCap}
strokeWidth={arcStrokeWidth}
// strokeLinecap={strokeLineCap}
/>
)}
<g id="ticks">
Expand Down
81 changes: 57 additions & 24 deletions src/index.tsx
Expand Up @@ -26,58 +26,73 @@ interface GetLabelPropsParams {
offset: number;
}

interface GetArcPropsParams {
interface GetArcPropsParams extends React.SVGProps<SVGPathElement> {
offset?: number;
startAngle: number;
endAngle: number;
}

interface RedrawSVGParams {
padding: number;
}

function redrawSvg(node: SVGSVGElement, params: RedrawSVGParams) {
const { padding } = params;
const bbox = node.getBBox({ stroke: true });
const width = bbox.width;
const height = bbox.height;

node.setAttribute('width', String(width));
node.setAttribute('height', String(height));
node.setAttribute(
'viewBox',
`${bbox.x - padding / 2} ${bbox.y - padding / 2} ${width + padding} ${
height + padding
}`
);
}

function useSVGRef(params: UseGaugeParams) {
const { padding, size, startAngle, endAngle, numTicks } = params;
const ref = useRef(null);
const ref = useRef<SVGSVGElement>(null!);

const setRef = useCallback(
(node: any) => {
if (ref.current) {
}

if (node) {
var bbox = node.getBBox();
if (!bbox) {
throw new Error('Could not get bounding box of SVG.');
}
const width = bbox.width;
const height = bbox.height;
node.setAttribute('width', width);
node.setAttribute('height', height);
node.setAttribute(
'viewBox',
`${bbox.x - padding / 2} ${bbox.y - padding / 2} ${width + padding} ${
height + padding
}`
);
redrawSvg(node, {
padding,
});
}

ref.current = node;
},
[padding, size, startAngle, endAngle, numTicks]
);

return setRef;
return {
setRef,
svg: ref,
};
}

export function useGauge(params: UseGaugeParams) {
const { startAngle, endAngle, numTicks, size, domain } = params;
const { startAngle, endAngle, numTicks, size, domain, padding } = params;
const radius = size;
const [minValue, maxValue] = domain;
const ref = useSVGRef(params);
const { setRef: ref, svg } = useSVGRef(params);

const ticks = useMemo(() => {
return makeTickMarks(startAngle, endAngle, numTicks).reverse();
}, [startAngle, endAngle, numTicks]);

const getLabelProps = useCallback(
(params: GetLabelPropsParams) => {
if (svg.current) {
redrawSvg(svg.current, { padding });
}
const { angle, offset } = params;
const p1 = polarToCartesian(size / 2, size / 2, radius - offset, angle);

Expand All @@ -93,6 +108,9 @@ export function useGauge(params: UseGaugeParams) {

const getTickProps = useCallback(
(params: GetTickPropsParams) => {
if (svg.current) {
redrawSvg(svg.current, { padding });
}
const { length, angle } = params;
const p1 = polarToCartesian(size / 2, size / 2, radius, angle);
const p2 = polarToCartesian(size / 2, size / 2, radius + length, angle);
Expand Down Expand Up @@ -124,42 +142,57 @@ export function useGauge(params: UseGaugeParams) {

const getArcProps = useCallback(
(params: GetArcPropsParams) => {
const { offset = 0, startAngle, endAngle } = params;
const { offset = 0, startAngle, endAngle, strokeWidth, ...rest } = params;

let stroke = parseInt(String(strokeWidth));

if (svg.current) {
redrawSvg(svg.current, { padding });
}

let start = polarToCartesian(
size / 2,
size / 2,
radius + offset,
radius + offset + stroke,
endAngle
);

let end = polarToCartesian(
size / 2,
size / 2,
radius + offset,
radius + offset + stroke,
startAngle
);

let largeArcFlag = endAngle - startAngle <= 180 ? '0' : '1';
let d = [
'M',
start.x,
start.y,
'A',
radius + offset,
radius + offset,
radius + offset + stroke,
radius + offset + stroke,
0,
largeArcFlag,
0,
end.x,
end.y,
].join(' ');

return {
d,
strokeWidth,
...rest,
};
},
[size, radius]
);

const getNeedleProps = useCallback(
(params: GetNeedleParams) => {
if (svg.current) {
redrawSvg(svg.current, { padding });
}
const { value, baseRadius, tipRadius } = params;
const angle = valueToAngle(value);

Expand Down

0 comments on commit bc0b1ab

Please sign in to comment.