English 中文(简体)
沿vg条道路改变一个要素,同时将其置于中心观点
原标题:Move an element along the svg path while placing it in center viewport

我正试图制造一种滚动im,因为那一人创造了一条快车道,并增加了一条在用户滚动时沿着这条道路前进的因素。

是否有办法使该要素在电离层中心垂直地停留,同时在电离线上移动?

我尝试了以下的法典,但随着我最初的缩编,这个要素即使沿着这条道路走下去,从中途走过来,而且我可以看到,这个要素正在沿着这条道路前进。

const pathLength = Path_440.getTotalLength();

function clamp(min, val, max) {
  return Math.min(Math.max(min, val), max);
}

function updatePath() {
  const docElt = document.documentElement;
  const pathBox = theFill.getBoundingClientRect();
  const scrollProgress = clamp(
    0, -pathBox.y / (pathBox.height - docElt.clientHeight),
    1
  );

  pathIcon.style.offsetDistance = `${scrollProgress * 100}%`;

  // These lines fill in the dashes as you scroll down.
  const drawLength = pathLength * scrollProgress;
  const rest = pathLength - drawLength;
  theFill.style.strokeDasharray = `${drawLength}px ${rest}px`;
}

updatePath();
window.addEventListener("scroll", () => updatePath());
#pathIcon2 {
  position: absolute;
  inset: 0;
  width: 10px;
  height: 10px;
  background-size: 25px;
}

body {
  display: grid;
  align-items: center;
  align-content: center;
  justify-content: center;
  justify-items: center;
}

#pathIcon {
  position: absolute;
  inset: 0;
  width: 10px;
  height: 10px;
  background-size: 25px;
  offset-rotate: 0rad;
}

#Path_440 {
  stroke-width: 2;
  stroke: #001d36
}

#Path_444 {
  stroke-width: 4;
  stroke: #001d36
}

#theFill {
  stroke-width: 4;
  stroke: #55b0ff
}
<div style="height: 175px"></div>
<div style="position: relative">
  <svg width="543" height="7907" viewBox="0 0 543 7907" fill="none">
        <defs>
          <path
            id="Path_440"
            d="M125.5 1V1C125.5 79.173 188.872 142.545 267.045 142.545H393.878C419.836 142.545 445.339 149.367 467.83 162.327V162.327C513.721 188.769 542 237.703 542 290.666V313.599L539.827 333.733C534.083 386.937 499.558 432.677 449.965 452.783L424.708 463.022C419.644 465.075 415.15 468.319 411.607 472.48V472.48C406.374 478.625 403.5 486.433 403.5 494.505V504.159V504.159C403.5 517.05 393.05 527.5 380.159 527.5H11.5C5.70101 527.5 1 532.201 1 538V538V943.5V943.5C1 949.299 5.701 954 11.5 954H389.5V954C397.232 954 403.5 960.268 403.5 968V1352.34V2115.19C403.5 2149.43 375.742 2177.19 341.5 2177.19V2177.19C307.258 2177.19 279.5 2204.95 279.5 2239.19V2420C279.5 2427.18 273.68 2433 266.5 2433V2433H17C10.3726 2433 5 2438.37 5 2445V2445V2845V2845C5 2853.84 12.1634 2861 21 2861H266.5V2861C273.68 2861 279.5 2866.82 279.5 2874V4003.55C279.5 4057.53 235.736 4101.3 181.75 4101.3V4101.3C127.764 4101.3 84 4145.06 84 4199.05V4332.5V4332.5C84 4335.81 86.6863 4338.5 90 4338.5H182.5V4338.5C185.814 4338.5 188.5 4341.19 188.5 4344.5V4762C188.5 4764.76 186.261 4767 183.5 4767V4767H91C87.134 4767 84 4770.13 84 4774V4774V5105.66C84 5183.53 147.128 5246.66 225 5246.66H261.159C319.061 5246.66 366 5293.6 366 5351.5V5351.5V5456V5456C366 5463.46 359.956 5469.5 352.5 5469.5H112.5C103.94 5469.5 97 5476.44 97 5485V5485V5861.5V5861.5C97 5871.44 105.059 5879.5 115 5879.5H348V5879.5C357.941 5879.5 366 5887.56 366 5897.5V6447C366 6456.94 357.941 6465 348 6465V6465H111C104.096 6465 98.5 6470.6 98.5 6477.5V6477.5V6858.5V6858.5C98.5 6867.61 105.887 6875 115 6875H348V6875C357.941 6875 366 6883.06 366 6893V7574.93C366 7627.95 323.019 7670.93 270 7670.93V7670.93C216.981 7670.93 174 7713.91 174 7766.93V7906.5"
/></path>
        </defs>
        <use href="#Path_440" stroke-width="10" stroke-dasharray="20 10"></use>
        <use
          id="theFill"
          href="#Path_440"
          style="stroke-dasharray: 1991.82px, 9259.88px"
          stroke-width="10"
          stroke="#4cacff"
        ></use>
      </svg>
  <div id="pathIcon" stroke="#4cacff" style="
          offset-path: path(
             M 125.5 1 V 1 C 125.5 79.173 188.872 142.545 267.045 142.545 H 393.878 C 419.836 142.545 445.339 149.367 467.83 162.327 V 162.327 C 513.721 188.769 542 237.703 542 290.666 V 313.599 L 539.827 333.733 C 534.083 386.937 499.558 432.677 449.965 452.783 L 424.708 463.022 C 419.644 465.075 415.15 468.319 411.607 472.48 V 472.48 C 406.374 478.625 403.5 486.433 403.5 494.505 V 504.159 V 504.159 C 403.5 517.05 393.05 527.5 380.159 527.5 H 11.5 C 5.70101 527.5 1 532.201 1 538 V 538 V 943.5 V 943.5 C 1 949.299 5.701 954 11.5 954 H 389.5 V 954 C 397.232 954 403.5 960.268 403.5 968 V 1352.34 V 2115.19 C 403.5 2149.43 375.742 2177.19 341.5 2177.19 V 2177.19 C 307.258 2177.19 279.5 2204.95 279.5 2239.19 V 2420 C 279.5 2427.18 273.68 2433 266.5 2433 V 2433 H 17 C 10.3726 2433 5 2438.37 5 2445 V 2445 V 2845 V 2845 C 5 2853.84 12.1634 2861 21 2861 H 266.5 V 2861 C 273.68 2861 279.5 2866.82 279.5 2874 V 4003.55 C 279.5 4057.53 235.736 4101.3 181.75 4101.3 V 4101.3 C 127.764 4101.3 84 4145.06 84 4199.05 V 4332.5 V 4332.5 C 84 4335.81 86.6863 4338.5 90 4338.5 H 182.5 V 4338.5 C 185.814 4338.5 188.5 4341.19 188.5 4344.5 V 4762 C 188.5 4764.76 186.261 4767 183.5 4767 V 4767 H 91 C 87.134 4767 84 4770.13 84 4774 V 4774 V 5105.66 C 84 5183.53 147.128 5246.66 225 5246.66 H 261.159 C 319.061 5246.66 366 5293.6 366 5351.5 V 5351.5 V 5456 V 5456 C 366 5463.46 359.956 5469.5 352.5 5469.5 H 112.5 C 103.94 5469.5 97 5476.44 97 5485 V 5485 V 5861.5 V 5861.5 C 97 5871.44 105.059 5879.5 115 5879.5 H 348 V 5879.5 C 357.941 5879.5 366 5887.56 366 5897.5 V 6447 C 366 6456.94 357.941 6465 348 6465 V 6465 H 111 C 104.096 6465 98.5 6470.6 98.5 6477.5 V 6477.5 V 6858.5 V 6858.5 C 98.5 6867.61 105.887 6875 115 6875 H 348 V 6875 C 357.941 6875 366 6883.06 366 6893 V 7574.93 C 366 7627.95 323.019 7670.93 270 7670.93 V 7670.93 C 216.981 7670.93 174 7713.91 174 7766.93 V 7906.5 
          );
          offset-distance: 17.7024%;
          background-image: url( https://via.placeholder.com/25x25/FF0000?text=red );
        "></div>
</div>
问题回答

Length at point?

In your case you need to find a path length value to calculate a offset-distance value according to the current scroll y positions.
Unfortunately we can t accurately calculate path length values according to x/y values since there are probably multiple results e.g. if you path is self intersecting or has flat segments (running horizontally or vertically at certain segments).

然而,我们可以通过getPointAtLength(>>>。

另一个问题......getPointAtLength(>,当被称作数百或数千倍以上时,费用非常昂贵,因此,我们不得不在一次滚动活动中叫它(这也不利于大规模有辱人格的业绩)。

let svg = document.querySelector("svg");
let mPath = document.getElementById( Path_440 )
let strokePath = document.getElementById( theFill )

// add offset path based on svg
pathIcon.style.offsetPath = `path( ${mPath.getAttribute( d )} )`

// steps for pathlength lookup
let precision = 1000;

// get transform matrix to translate svg units to screen coordinates
let matrix = svg.getScreenCTM()

function getLengthLookup(path, precision = 100) {
  //create pathlength lookup
  let pathLength = path.getTotalLength();
  let lengthLookup = {
    yArr: [],
    lengthArr: [],
    pathLength: pathLength
  };

  // sample point to calculate Y at pathLengths
  let step = Math.floor(pathLength / precision);

  for (let l = 0; l < pathLength; l += step) {
    let pt = SVGToScreen(matrix, path.getPointAtLength(l));
    let y = pt.y;
    lengthLookup.yArr.push(y);
    lengthLookup.lengthArr.push(l);
  }
  return lengthLookup;
}

const lengthLookup = getLengthLookup(mPath, precision);
const {
  lengthArr,
  yArr,
  pathLength
} = lengthLookup;
const maxHeight = document.documentElement.scrollHeight - window.innerHeight;


window.addEventListener("scroll", (e) => {
  let scrollPosMid = getViewportMiddleY();
  midline.style.top = scrollPosMid + "px";

  // get y pos length
  let found = false;

  for (let i = 0; i < yArr.length && !found; i++) {
    // find next largest y in lookup
    let y = yArr[i];
    if (y >= scrollPosMid) {
      let length = lengthArr[i]

      // adjust length via interpolated approximation 
      let yPrev = yArr[i - 1] ? yArr[i - 1] : yArr[i];
      let lengthPrev = lengthArr[i - 1] ? lengthArr[i - 1] : length;
      let ratioL = 1 / lengthArr[i] * lengthPrev;
      let ratioY = 1 / y * scrollPosMid;
      let ratio = Math.max(ratioL, ratioY)

      let dashLength = lengthArr[i] * ratio;

      // calculate offsetDistance
      let offsetDist = 100 / pathLength * dashLength
      pathIcon.style.offsetDistance = offsetDist +  % ;

      // change dasharray
      strokePath.setAttribute("stroke-dasharray", `${dashLength} ${pathLength}`);

      // stop loop
      found = true;
    }
  }
});


/**
* Get the absolute center/middle y-coordinate 
* of the current scroll viewport
*/
function getViewportMiddleY() {
  const viewportHeight = window.innerHeight;
  const scrollY = window.scrollY || window.pageYOffset;
  const element = document.documentElement;
  const elementOffsetTop = element.offsetTop;
  const middleY = scrollY + viewportHeight / 2 + elementOffsetTop;
  return middleY;
}

/** Based on @Paul LeBeau s answer
 * https://stackoverflow.com/questions/48343436/how-to-convert-svg-element-coordinates-to-screen-coordinates#48354404
 */
function SVGToScreen(matrix, pt) {
  let p = new DOMPoint(pt.x, pt.y);
  p = p.matrixTransform(matrix);
  return p
}
svg {
  overflow: visible;
}

body {
  display: grid;
  align-items: center;
  align-content: center;
  justify-content: center;
  justify-items: center;
}

#pathIcon {
  position: absolute;
  inset: 0;
  width: 10px;
  height: 10px;
  background-size: 25px;
  offset-rotate: 0rad;
  transition: 0.2s;
}

#Path_440 {
  stroke-width: 2;
  stroke: #001d36
}

#midline {
  display: block;
  position: absolute;
  width: 100%;
  height: 1px;
  border-top: 1px solid orange
}
<div style="height: 175px"></div>
<div id="scrollDiv" style="position: relative">
  <svg width="543" height="7907" viewBox="0 0 543 7907" fill="none">
    <defs>
      <path id="Path_440" d="M125.5 1v0c0 78.2 63.4 141.5 141.5 141.5h126.9c25.9 0 51.4 6.9 73.9 19.8v0c45.9 26.5 74.2 75.4 74.2 128.4v22.9l-2.2 20.1c-5.7 53.2-40.2 99-89.8 119.1l-25.3 10.2c-5.1 2.1-9.6 5.3-13.1 9.5v0c-5.2 6.1-8.1 13.9-8.1 22v9.7v0c0 12.8-10.4 23.3-23.3 23.3h-368.7c-5.8 0-10.5 4.7-10.5 10.5v0v405.5v0c0 5.8 4.7 10.5 10.5 10.5h378v0c7.7 0 14 6.3 14 14v384.3v762.9c0 34.2-27.8 62-62 62v0c-34.2 0-62 27.7-62 62v180.8c0 7.2-5.8 13-13 13v0h-249.5c-6.6 0-12 5.4-12 12v0v400v0c0 8.8 7.2 16 16 16h245.5v0c7.2 0 13 5.8 13 13v1129.6c0 53.9-43.8 97.7-97.7 97.7v0c-54 0-97.8 43.8-97.8 97.8v133.4v0c0 3.3 2.7 6 6 6h92.5v0c3.3 0 6 2.7 6 6v417.5c0 2.8-2.2 5-5 5v0h-92.5c-3.9 0-7 3.1-7 7v0v331.7c0 77.8 63.1 141 141 141h36.2c57.9 0 104.8 46.9 104.8 104.8v0v104.5v0c0 7.5-6 13.5-13.5 13.5h-240c-8.6 0-15.5 6.9-15.5 15.5v0v376.5v0c0 9.9 8.1 18 18 18h233v0c9.9 0 18 8.1 18 18v549.5c0 9.9-8.1 18-18 18v0h-237c-6.9 0-12.5 5.6-12.5 12.5v0v381v0c0 9.1 7.4 16.5 16.5 16.5h233v0c9.9 0 18 8.1 18 18v681.9c0 53-43 96-96 96v0c-53 0-96 43-96 96v139.6" />
      </path>
    </defs>
    <use href="#Path_440" stroke-width="10" stroke-dasharray="20 10"></use>
    <use id="theFill" href="#Path_440" stroke-dasharray="1991.82, 9259.88" stroke-width="10" stroke="#4cacff"></use>
  </svg>
  <div id="pathIcon" stroke="#4cacff" style="
          offset-distance: 0%;
          background-image: url( https://via.placeholder.com/25x25/FF0000?text=red );
        "></div>
</div>

<div id="midline"></div>

Translate svg to screen coordinates

If your svg dimensions equal the size it s placed in HTML (e.g. the viewBox values equal the element css width and height and there are not margins) you may skip this step.
Otherwise we need to translate values: See also Paul LeBeaus s answer here:
"How to convert svg element coordinates to screen coordinates?"

Create a length-at-Y lookup

Before running any scroll event related scripts we collect and save several length at y values in a lookup object.
We re saving Y values translated to screen/HTMLDom values. This way we can directly check the current mid-viewport coordinate Y values against the lookup values within the scroll event update calls.





相关问题
CSS working only in Firefox

I am trying to create a search text-field like on the Apple website. The HTML looks like this: <div class="frm-search"> <div> <input class="btn" type="image" src="http://www....

image changed but appears the same in browser

I m writing a php script to crop an image. The script overwrites the old image with the new one, but when I reload the page (which is supposed to pickup the new image) I still see the old one. ...

Firefox background image horizontal centering oddity

I am building some basic HTML code for a CMS. One of the page-related options in the CMS is "background image" and "stretch page width / height to background image width / height." so that with large ...

Separator line in ASP.NET

I d like to add a simple separator line in an aspx web form. Does anyone know how? It sounds easy enough, but still I can t manage to find how to do it.. 10x!

热门标签