import * as React from 'react' import { useThree, ThreeEvent } from '@react-three/fiber' import { CanvasTexture } from 'three' import { useGizmoContext } from './GizmoHelper' type AxisProps = { color: string rotation: [number, number, number] scale?: [number, number, number] } type AxisHeadProps = JSX.IntrinsicElements['sprite'] & { arcStyle: string label?: string labelColor: string axisHeadScale?: number disabled?: boolean font: string onClick?: (e: ThreeEvent) => null } type GizmoViewportProps = JSX.IntrinsicElements['group'] & { axisColors?: [string, string, string] axisScale?: [number, number, number] labels?: [string, string, string] axisHeadScale?: number labelColor?: string hideNegativeAxes?: boolean hideAxisHeads?: boolean disabled?: boolean font?: string onClick?: (e: ThreeEvent) => null } function Axis({ scale = [0.8, 0.05, 0.05], color, rotation }: AxisProps) { return ( ) } function AxisHead({ onClick, font, disabled, arcStyle, label, labelColor, axisHeadScale = 1, ...props }: AxisHeadProps) { const gl = useThree((state) => state.gl) const texture = React.useMemo(() => { const canvas = document.createElement('canvas') canvas.width = 64 canvas.height = 64 const context = canvas.getContext('2d')! context.beginPath() context.arc(32, 32, 16, 0, 2 * Math.PI) context.closePath() context.fillStyle = arcStyle context.fill() if (label) { context.font = font context.textAlign = 'center' context.fillStyle = labelColor context.fillText(label, 32, 41) } return new CanvasTexture(canvas) }, [arcStyle, label, labelColor, font]) const [active, setActive] = React.useState(false) const scale = (label ? 1 : 0.75) * (active ? 1.2 : 1) * axisHeadScale const handlePointerOver = (e: ThreeEvent) => { e.stopPropagation() setActive(true) } const handlePointerOut = (e: ThreeEvent) => { e.stopPropagation() setActive(false) } return ( ) } export const GizmoViewport = ({ hideNegativeAxes, hideAxisHeads, disabled, font = '18px Inter var, Arial, sans-serif', axisColors = ['#ff2060', '#20df80', '#2080ff'], axisHeadScale = 1, axisScale, labels = ['X', 'Y', 'Z'], labelColor = '#000', onClick, ...props }: GizmoViewportProps) => { const [colorX, colorY, colorZ] = axisColors const { tweenCamera } = useGizmoContext() const axisHeadProps = { font, disabled, labelColor, onClick, axisHeadScale, onPointerDown: !disabled ? (e: ThreeEvent) => { tweenCamera(e.object.position) e.stopPropagation() } : undefined, } return ( {!hideAxisHeads && ( <> {!hideNegativeAxes && ( <> )} )} ) }