2

Using svg.js, I have drawn a (game) board, which is essentially a group of hexagon shaped paths. After all hexes are added, I would like to rotate the whole group by -60 degrees, and then read out a minimal, rectangular box that encompasses the resulting (visual) shape.

Appearance of the board and the box (hand-drawn in red) I want:

enter image description here

But I can't figure out how to get the red box; all I ever get seem to be boxes around the blue shape (which is of course the bbox of the whole group, itself rotated):

enter image description here

Some hints I found were to use an outer group (containing in turn the group that collects the fields); rotate the inner group, and get bbox() from the outer group; unfortunately, this changed nothing. Alternatively, some sources on the web suggested to use rbox() instead, but that again changed nothing, and isn't even in the documentation of svg.js 3.0.

For completeness the code that does the related things, even though this matter seems to be a more general issue. I realize I could circumvent the problem by avoiding the rotation in the first place, but I'd like to find a solution that allows to adress a series of similar cases without manual tweaking.

 draw_board() {
        let grp = this.canvas.group();
        for (let field of this.fields) {
            field.hex_display = grp.use(hexsym).size(this.w*this.hex_scale,this.h*this.hex_scale)
                .center(field.cx,field.cy)
                .addClass("hex_field")
                .addClass(this.color);

        }
        let count = this.field.length;
        let clipper = this.canvas.clip().path()
              .M(...this.center(0,0))
              .L(...this.center(0,count-1))
              .L(...this.center(count-1,count-1))
              .L(...this.center(count-1,0))
              .Z();
        grp.clipWith(clipper);
        grp.rotate(-60);
        let bb = grp.bbox();
        this.canvas.viewbox(bb.x,bb.y,bb.w,bb.h)
    }

Any pointers how to approach this?

DavidP
  • 105
  • 3
  • 12

2 Answers2

1

Here's an example to expand on @RobertLongson comment. Red is getBoundingClientRect, green is getBBox. I'm not sure if the either will do the trick for you though. Using getBoundingClientRect would require figuring in the position of the svg in relation to the document--which is why it's offset.

var rotate = 0;

function doRotation() {
  rotate += 10;
  if (rotate === 360) {
    rotate = 0;
  }
  var pathElement = document.querySelector('#path_1');
  pathElement.setAttribute('transform', 'rotate(' + rotate + ' 40 40 )');
  var groupElement = document.querySelector('#group_1');
  var rectBBox = document.querySelector('#rect_1');
  var rectBoundingClientRect = document.querySelector('#rect_2');

  var bboxGroup = groupElement.getBBox();
  rectBBox.setAttribute('x', bboxGroup.x);
  rectBBox.setAttribute('y', bboxGroup.y);
  rectBBox.setAttribute('width', bboxGroup.width);
  rectBBox.setAttribute('height', bboxGroup.height);

  var boundingClientRectGroup = groupElement.getBoundingClientRect();
  rectBoundingClientRect.setAttribute('x', boundingClientRectGroup.x);
  rectBoundingClientRect.setAttribute('y', boundingClientRectGroup.y);
  rectBoundingClientRect.setAttribute('width', boundingClientRectGroup.width);
  rectBoundingClientRect.setAttribute('height', boundingClientRectGroup.height);
}
setInterval(doRotation, 100);
svg {
  overflow: visible
}
<svg height="100px" viewBox="0 0 100 100">
  <g  id="group_1">
  <path id="path_1" d="M35,25 L60,25 L50,50 L25,50 Z"></path>
  </g>
  <rect vector-effect="non-scaling-stroke" id="rect_1" stroke="#00ff00" stroke-width="1" fill="none"> </rect> 
  <rect  vector-effect="non-scaling-stroke" id="rect_2" stroke="#ff0000" stroke-width="1" fill="none"></rect> 
</svg>
Ted
  • 14,757
  • 2
  • 41
  • 58
0

Use rbox. It's as simple as grp.rbox(this.canvas)

Rbox is basically a wrapper around getBoundingClientRect. However, if you pass in an element, the box is transformed into the coordinate system of that element. In your case you need the coordinates in the canvas coord system.

If you call rbox without a parameter, it will give you a box in screen coordinates with added scroll (unlike getBoundingClientRect)

Here is the link to the docs: https://svgjs.dev/docs/3.0/manipulating/#rbox

wout
  • 2,477
  • 2
  • 21
  • 32
Fuzzyma
  • 7,619
  • 6
  • 28
  • 60