JSFiddle - React, Tailwind, and code Playground

by Ulrich Bangert

HTML

<script src="https://d3js.org/d3.v6.min.js"></script>
    <div id="pano-outer">
        <img id="pano-img"
            src="https://webentwicklung.ulrichbangert.de/images/2016-06-05_WolfenbĂĽttel_Bankplatz_Panorama_3708x640.jpg">
    </div>
    <svg width="300" height="300">
    </svg>

CSS

#pano-outer {
            width: 100%;
            overflow-x: auto;
        }

JavaScript

const svg = d3.select("svg")
            .append("g")
            .attr("transform", "translate(150,100)");
        // Create background arc
        const bgArc = d3.arc()
            .innerRadius(80)
            .outerRadius(85)
            .startAngle(0)
            .endAngle(Math.PI);

        svg.append("path")
            .attr("class", "bg-arc")
            .attr("d", bgArc)
            .attr("fill", "lightgrey");

        const panoOuter = document.querySelector('#pano-outer'),
            panoImg = document.querySelector('#pano-img');
        panoImg.addEventListener('load', event => {
            function update(start) {
                // Create sliding arc
                const arc = d3.arc()
                    .innerRadius(80)
                    .outerRadius(85)
                    .startAngle(start)
                    .endAngle(start + wArc);

                svg.append("path")
                    .attr("class", "arc")
                    .attr("d", arc)
                    .attr("fill", "green");

            }

            const wPanoImg = panoImg.naturalWidth,
                wArc = panoOuter.clientWidth / wPanoImg * Math.PI;
            update(0);
            panoOuter.addEventListener('scroll', event => {
                const scrollPos = panoOuter.scrollLeft,
                    arcPos = scrollPos / wPanoImg * Math.PI;
                svg.selectAll(".arc").remove();
                // svg.selectAll(".bg-arc").remove();
                update(arcPos);
            });
        });