0

Is there a way to a way to use position: sticky inside SVG? Similar to how this example work.

To complicate the matter slightly, I am looking to use position: sticky inside an SVG element inside another div with overflow:auto. I have a created an example of what I am trying to achieve inside this codesandbox.

Edit 1: Not sure whether this makes a difference, but for context in my own application I am using react & react-redux to include/exclude shapes to form a graph. The requirement is to keep some elements at the top of the view port when scrolling the same way Excel would if you would to freeze a header/row.

Edit 2: Updated the sandbox to include the answer's code

Ebbs
  • 1,030
  • 3
  • 20
  • 38

1 Answers1

3

No. position is a property that only applies to HTML elements. It is not valid inside an SVG.

You would need to use Javascript. Add an onscroll event handler to watch the scroll and reposition the SVG element.

window.addEventListener("scroll", function(evt) {

  document.getElementById("sticky-rect").setAttribute("y", screenYtoSVGUnits(window.scrollY) + 10);

});


// Converts a screen Y position to SVG units which have a viewBox transform
function screenYtoSVGUnits(val) {
  const svg = document.getElementById("mysvg");
  let pt = svg.createSVGPoint();
  pt.x = 0;
  pt.y = val;
  pt = pt.matrixTransform(svg.getCTM().inverse());
  return pt.y;
}
<svg id="mysvg" viewBox="0 0 100 500">
  <line x1="0" y1="0" x2="100" y2="500" stroke="black" stroke-width="1"/>
  <rect id="sticky-rect" x="0" y="10" width="100" height="10" fill="red"/>
</svg>
Paul LeBeau
  • 97,474
  • 9
  • 154
  • 181
  • After posting the question I actually started work on exactly this kind of solution as an alternate solution. Thanks for your help. – Ebbs Oct 16 '19 at 13:49
  • This is great. Do you think there's a way to apply to a so when we scroll, we have multiple sticky rects? – SixtyEight Oct 31 '22 at 13:22
  • @SixtyEight Yes you could do that. Although the `` element doesn't have `x` and `y` attributes. SO you would need to use a `transform` attribute instead. For example `.setAttribute("transform", "translate(0," + screenYtoSVGUnits(window.scrollY) + ")"));` – Paul LeBeau Nov 01 '22 at 20:57
  • It worked thanks a lot! Unfortunately is not performant enough since on my case, I wanna build a Gantt chart with panning both X and Y with both sticky axis. I'm using this for that but it flickers a lot. Can't find any suitable examples anywhere unfortunately. And my yAxis is categorical, I think scaleBand doesn't zoom. – SixtyEight Nov 03 '22 at 10:23
  • @SixtyEight were you able to do anything – Harxish Feb 03 '23 at 09:56