UNPKG

victory-canvas

Version:
82 lines (81 loc) 2.54 kB
import React from "react"; import { getBarPath, getBarWidth, getCornerRadius, getPolarBarPath, getStyle } from "victory-bar"; import { useCanvasContext } from "./hooks/use-canvas-context"; const evaluateProps = props => { /** * Potential evaluated props of following must be evaluated in this order: * 1) `style` * 2) `barWidth` * 3) `cornerRadius` */ const style = getStyle(props.style, props); const barWidth = getBarWidth(props.barWidth, Object.assign({}, props, { style })); const cornerRadius = getCornerRadius(props.cornerRadius, Object.assign({}, props, { style, barWidth })); const modifiedProps = Object.assign({}, props, { style, barWidth, cornerRadius }); return modifiedProps; }; const usePreviousValue = value => { const ref = React.useRef(); React.useEffect(() => { ref.current = value; }); return ref.current; }; export const CanvasBar = props => { const { canvasRef } = useCanvasContext(); const modifiedProps = evaluateProps(props); const { polar, style, barWidth, cornerRadius, origin } = modifiedProps; const path2d = React.useMemo(() => { const p = polar ? getPolarBarPath(modifiedProps, cornerRadius) : getBarPath(modifiedProps, barWidth, cornerRadius); return new Path2D(p); }, [polar, barWidth, cornerRadius, modifiedProps]); const previousPath = usePreviousValue(path2d); const draw = React.useCallback((ctx, path) => { ctx.fillStyle = style.fill; ctx.strokeStyle = style.stroke; ctx.globalAlpha = style.fillOpacity; ctx.lineWidth = style.strokeWidth; if (polar) { ctx.translate(origin?.x || 0, origin?.y || 0); } ctx.fill(path); ctx.setTransform(1, 0, 0, 1, 0, 0); }, [style, origin, polar]); // This will clear the previous bar without clearing the entire canvas const clearPreviousPath = React.useCallback(ctx => { if (previousPath) { ctx.save(); // This ensures that the entire shape is erased const strokeWidth = style.strokeWidth || 0; ctx.lineWidth = strokeWidth + 2; ctx.globalCompositeOperation = "destination-out"; draw(ctx, previousPath); ctx.stroke(previousPath); ctx.restore(); } }, [draw, previousPath, style]); React.useEffect(() => { const ctx = canvasRef.current?.getContext("2d"); if (!ctx) return; clearPreviousPath(ctx); draw(ctx, path2d); }, [canvasRef, draw, polar, barWidth, cornerRadius, modifiedProps, path2d, clearPreviousPath]); return null; };