Home > Blockchain >  offset-anchor places svg shape in a wrong position
offset-anchor places svg shape in a wrong position

Time:12-18

I am failing to understand how to change the value of offset-anchor match to my expectations.

Update. It doesn't seem like Google Chrome supports offset-anchor as of 17-12-2022. The ticket to support this property can be found here (it boils down to a relatively small update in .cpp file). The ticket tracking support of the entire spec can be found here.

I'm drawing an arrow and I'm trying to make the actual anchor (e.g. dot used for moving) to be at the arrow's head, and not the tail.

The example below highlights the default anchor used to move the arrow. If I change the value of offset-anchor to, say, offset-anchor: left of the arrow it jumps to a weird position. If I set it to offset-anchor: right, it disappears completely. Why?

How do I control the value offset-anchor in an expected way?

Not sure if I should, but I could probably look into whether offset-rotate is what I need. But I really want to understand first what's wrong with my attempts to control offset-anchor property.

P.S. My code is based on what I've observed at: https://developer.mozilla.org/en-US/docs/Web/CSS/offset-anchor. However, it seems like I am missing something crucial when modelling my animation after example at that page.

<style>
#placeholder {}

#arrow {
  offset-path: path("M275,50 h-200");
  animation: move 3s;
}
    
#offset-anchor-1 {
  offset-path: path("M275,50 h-200");
  animation: move 3s;
}
    
#rectangle {
  offset-path: path("m575,50 h-200");
  animation: move 3s;
}

#offset-anchor-2 {
  offset-path: path("m575,50 h-200");
  animation: move 3s;
}
    
@keyframes move {
  100% {
    offset-distance: 100%;
  }
}
</style>
<svg height=100 width=650 viewPort="0 0 100 650" style="border: 1px solid #999">
  <path id="arrow" d="M0,0 h50" stroke-width="2" stroke="black" marker-end="url(#arrow-head)"></path>    
  <path id="travel-path1" d="M275,50 h-200" stroke-width="1" stroke-dasharray="4" stroke="red"></path>
  <circle id="offset-anchor-1" cx="0" cy="0" r="4" fill="red"></circle>
    
  <rect id="rectangle" x="0" y="0" width="50" height="20" fill="yellow" stroke="navy" stroke-width="1"></rect>
  <path id="travel-path2" d="M575,50 h-200" stroke-width="1" stroke-dasharray="4" stroke="red"></path>
  <circle id="offset-anchor-2" cx="0" cy="0" r="4" fill="red"></circle>
  
  <defs>
    <marker id="arrow-head" markerWidth="5" markerHeight="5" refX="2.5" refY="2.5" viewBox="0 0 5 5" orient="auto">
      <polygon points="0,5 1.6666666666666667,2.5 0,0 5,2.5" fill="black"></polygon>
    </marker>
  </defs>
</svg>

CodePudding user response:

My way to go about these problems is to firmly stay in the SVG way of describing relations, with coordinate systems.

While traveling along the offset-path, the arrow and the rect are drawn in a coordinate system with its origin at the position of the dot. The x axis points in the direction of movement - the implicitely set offset-rotate: auto says so. Accordingly, the x axis points left and the y axis points up. Relative to the root coordinate system, it is rotated around by 180°.

If you want to have the arrow marker at the end of the path, and that at the position of the dot, the path needs to end at 0,0. The beginning should appear away from the direction of movement (to the right), so it needs to have a negative x value. Instead of d="M0,0 h50", write d="M-50,0 H0".

If you want to have the rectangle to the right and above the dot, define it to the left and below the origin of its coordinate system. Instead of x="0" y="0" width="50" height="20", write x="-50" y="0" width="50" height="20".

<style>
#placeholder {}

#arrow {
  offset-path: path("M275,50 h-200");
  animation: move 3s;
}
    
#offset-anchor-1 {
  offset-path: path("M275,50 h-200");
  animation: move 3s;
}
    
#rectangle {
  offset-path: path("m575,50 h-200");
  animation: move 3s;
}

#offset-anchor-2 {
  offset-path: path("m575,50 h-200");
  animation: move 3s;
}
    
@keyframes move {
  100% {
    offset-distance: 100%;
  }
}
</style>
<svg height=100 width=650 viewPort="0 0 100 650" style="border: 1px solid #999">
  <path id="arrow" d="M-50,0 H0" stroke-width="2" stroke="black" marker-end="url(#arrow-head)"></path>    
  <path id="travel-path1" d="M275,50 h-200" stroke-width="1" stroke-dasharray="4" stroke="red"></path>
  <circle id="offset-anchor-1" cx="0" cy="0" r="4" fill="red"></circle>
    
  <rect id="rectangle" x="-50" y="0" width="50" height="20" fill="yellow" stroke="navy" stroke-width="1"></rect>
  <path id="travel-path2" d="M575,50 h-200" stroke-width="1" stroke-dasharray="4" stroke="red"></path>
  <circle id="offset-anchor-2" cx="0" cy="0" r="4" fill="red"></circle>
  
  <defs>
    <marker id="arrow-head" markerWidth="5" markerHeight="5" refX="2.5" refY="2.5" viewBox="0 0 5 5" orient="auto">
      <polygon points="0,5 1.6666666666666667,2.5 0,0 5,2.5" fill="black"></polygon>
    </marker>
  </defs>
</svg>

CodePudding user response:

I managed to address the original issue by specifying the offset-anchor like this:

offset-anchor: top 0px left 50px

This works as expected in Chrome 108. However, as pointed out in an update to the text of original question, offset-anchor doesn't seem to be supported officially.

  • Related