import { useRef, useEffect, useState, useMemo, useId } from 'react'; import './CurvedLoop.css'; const CurvedLoop = ({ marqueeText = '1', speed = 2, className, curveAmount = 400, direction = 'left', interactive = true }) => { const text = useMemo(() => { const hasTrailing = /\s|\u00A0$/.test(marqueeText); return (hasTrailing ? marqueeText.replace(/\s+$/, '') : marqueeText) + '\u00A0'; }, [marqueeText]); const measureRef = useRef(null); const textPathRef = useRef(null); const pathRef = useRef(null); const [spacing, setSpacing] = useState(0); const [offset, setOffset] = useState(0); const uid = useId(); const pathId = `curve-${uid}`; const pathD = `M-100,40 Q500,${40 + curveAmount} 1540,40`; const dragRef = useRef(false); const lastXRef = useRef(0); const dirRef = useRef(direction); const velRef = useRef(0); const textLength = spacing; const totalText = textLength ? Array(Math.ceil(1800 / textLength) + 2) .fill(text) .join('') : text; const ready = spacing > 0; useEffect(() => { if (measureRef.current) setSpacing(measureRef.current.getComputedTextLength()); }, [text, className]); useEffect(() => { if (!spacing) return; if (textPathRef.current) { const initial = -spacing; textPathRef.current.setAttribute('startOffset', initial + 'px'); setOffset(initial); } }, [spacing]); useEffect(() => { if (!spacing || !ready) return; let frame = 0; const step = () => { if (!dragRef.current && textPathRef.current) { const delta = dirRef.current === 'right' ? speed : -speed; const currentOffset = parseFloat(textPathRef.current.getAttribute('startOffset') || '0'); let newOffset = currentOffset + delta; const wrapPoint = spacing; if (newOffset <= -wrapPoint) newOffset += wrapPoint; if (newOffset > 0) newOffset -= wrapPoint; textPathRef.current.setAttribute('startOffset', newOffset + 'px'); setOffset(newOffset); } frame = requestAnimationFrame(step); }; frame = requestAnimationFrame(step); return () => cancelAnimationFrame(frame); }, [spacing, speed, ready]); const onPointerDown = e => { if (!interactive) return; dragRef.current = true; lastXRef.current = e.clientX; velRef.current = 0; e.target.setPointerCapture(e.pointerId); }; const onPointerMove = e => { if (!interactive || !dragRef.current || !textPathRef.current) return; const dx = e.clientX - lastXRef.current; lastXRef.current = e.clientX; velRef.current = dx; const currentOffset = parseFloat(textPathRef.current.getAttribute('startOffset') || '0'); let newOffset = currentOffset + dx; const wrapPoint = spacing; if (newOffset <= -wrapPoint) newOffset += wrapPoint; if (newOffset > 0) newOffset -= wrapPoint; textPathRef.current.setAttribute('startOffset', newOffset + 'px'); setOffset(newOffset); }; const endDrag = () => { if (!interactive) return; dragRef.current = false; dirRef.current = velRef.current > 0 ? 'right' : 'left'; }; const cursorStyle = interactive ? (dragRef.current ? 'grabbing' : 'grab') : 'auto'; return (
{text} {ready && ( {totalText} )}
); }; export default CurvedLoop;
Åpningstider Fre 10.00 – 19.00 | Lør 10.00 – 19.00 | Søn 10.00 – 17.00

Makeløs custom fra John D’Agostino!

Packard Coupe fra 1958 ble bare produsert i 675 eksemplarer, og en av dem er garantert unik. Dette er “Rita”, John D’Agostinos makeløse custom som nå kommer til Oslo Motor Show.

Dette er et avansert prosjekt når det gjelder karosseri; blant annet er dørene forlenget med åtte tommer, og hengslene er flyttet til B-stolpen. Hele området rundt førerplassen er formet med et engelsk hjul, og lakken er blendende vakker. Se den selv på Oslo Motor Show!