JSFiddle - React, Tailwind, and code Playground
by jpeter06
HTML
<svg id="svg" viewBox="-10 -10 173 61">
<defs>
<path id = "arrowDef"
d = "M -2.0286728,-0.44913063 0.01728976,-2.4950973 2.0632567,-0.44913063 H 1.2448717 V 2.0060262 h -2.4551595 v -2.45515683 z"
stroke-width = "0px" />
</defs>
<path class="infinity path" d="M153,20.89c0-45.88-74.95,0-74.95,0S.5,66.76.5,20.89s77.54,0,77.54,0S153,66.76,153,20.89Z" fill="none" stroke-width="12px" stroke="#fa0" vector-effect="non-scaling-stroke" marker="url(#diamond)"/>
<g class="arrow" >
<use xlink:href = "#arrowDef" />
</g>
<text x="38" class="small">click anywhere to start/stop</text>
<marker id="diamond" markerWidth="12" markerHeight="12" refX="6" refY="6"
markerUnits="userSpaceOnUse" orient="auto-start-reverse">
<circle cx="6" cy="6" r="3"
fill="transparent" stroke="black" stroke-width="1"/>
<rect x="4" y="5" width="4" height="2" fill="green" stroke="context-stroke" stroke-width="2"/>
</marker>
</svg>
CSS
body {
height: 100vh;
overflow: hidden;
display: grid;
place-items: center;
margin: 0;
}
svg {
overflow: visible;
width: 100%;
height: 100vh;
}
rect {
transform-origin: center;
transform-box: fill-box;
}
.path{
marker: url(#diamond);
}
.arrow{
transform-origin: center;
transform-box: fill-box;
stroke-width:0px;
stroke:red;
fill:blue;
}
.small { font: italic 6px sans-serif; }
JavaScript
// Query DOM Elements
const svg = document.getElementById("svg");
const w = 10;
const h = 5;
const step = 80;
const path = document.querySelector('.infinity');
const arrow = document.querySelector('.arrow');
const arrowList = [];
const totalLength = path.getTotalLength();
for(let i=0; i*step < totalLength; i++){
let g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
let aux = document.createElementNS('http://www.w3.org/2000/svg', 'use');
aux.setAttributeNS('http://www.w3.org/1999/xlink', "xlink:href", "#arrowDef");
g.appendChild(aux);
arrowList.push(g);
svg.appendChild(g);
}
console.log(arrowList);
let pos = 0;
let anim = true;
//animate();
// Create an object that gsap can animate
function animateAll(){
if(anim){
pos++;
const length = pos%totalLength;
for(let i=0; i*step < totalLength; i++){
animateArrow(arrowList[i], pos + i*step);
}
}
requestAnimationFrame(animateAll);
}
function animateArrow(g,pos){
const length = pos%totalLength;
const point = path.getPointAtLength(length);
const p1 = path.getPointAtLength(length + 5);
const p2 = path.getPointAtLength(length - 5);
var deg = Math.atan2(p1.y - p2.y, p1.x - p2.x) * (180 / Math.PI) + 90;
g.setAttribute('transform', "translate(" + point.x + ',' + point.y +
') rotate(' + deg + ')');
}
requestAnimationFrame(animateAll);
document.body.addEventListener('click', ()=>{
anim = ! anim;
}, true);
//OLD 1 arrow
/*
function animate(){
if(anim){
pos++;
const length = pos%totalLength;
const point = path.getPointAtLength(length);
const p1 = path.getPointAtLength(length + 5);
const p2 = path.getPointAtLength(length - 5);
var deg = Math.atan2(p1.y - p2.y, p1.x - p2.x) * (180 / Math.PI) + 90;
arrow.setAttribute('transform', "translate(" + point.x + ',' + point.y +
') rotate(' + deg + ')');
}
requestAnimationFrame(animate);
}
*/