2 votes

Bounding box / bbox pour un groupe après rotation dans svg.js

En utilisant svg.js, j'ai dessiné un plateau (de jeu), qui est essentiellement un groupe de chemins en forme d'hexagone. Une fois tous les hexagones ajoutés, je voudrais faire pivoter l'ensemble du groupe de -60 degrés, puis lire une boîte rectangulaire minimale qui englobe la forme (visuelle) résultante.

Apparence de la planche et de la boîte (dessinée à la main en rouge) que je souhaite :

enter image description here

Mais je n'arrive pas à trouver comment obtenir la boîte rouge ; tout ce que j'obtiens semble être des boîtes autour de la forme bleue (qui est bien sûr la bbox de tout le groupe, elle-même tournée) :

enter image description here

Les conseils que j'ai trouvés étaient d'utiliser un groupe extérieur (contenant à son tour le groupe qui collecte les champs) ; de faire tourner le groupe intérieur, et d'obtenir bbox() du groupe extérieur ; malheureusement, cela n'a rien changé. Alternativement, certaines sources sur le web suggéraient d'utiliser rbox() à la place, mais là encore, cela ne changeait rien, et ce n'est même pas dans la documentation de svg.js 3.0.

Pour être complet, le code qui fait les choses connexes, même si cette question semble être un problème plus général. Je me rends compte que je pourrais contourner le problème en évitant la rotation en premier lieu, mais j'aimerais trouver une solution qui permette de traiter une série de cas similaires sans modification manuelle.

 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)
    }

Avez-vous des conseils sur la manière d'aborder cette question ?

1voto

Ted Points 564

Voici un exemple pour développer le commentaire de @RobertLongson. Rouge est getBoundingClientRect le vert est getBBox . Je ne sais pas si l'un ou l'autre fera l'affaire pour vous. Utilisation de getBoundingClientRect nécessiterait de prendre en compte la position du svg par rapport au document - c'est pourquoi il est décalé.

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>

0voto

Fuzzyma Points 2870

Utilisez rbox. C'est aussi simple que grp.rbox(this.canvas)

Rbox est essentiellement une enveloppe autour de getBoundingClientRect. Cependant, si vous passez dans un élément, la boîte est transformée dans le système de coordonnées de cet élément. Dans votre cas, vous avez besoin des coordonnées dans le système de coordonnées du canevas.

Si vous appelez rbox sans paramètre, il vous donnera une boîte en coordonnées d'écran avec un scroll ajouté (contrairement à getBoundingClientRect).

Voici le lien vers les documents : https://svgjs.dev/docs/3.0/manipulating/#rbox

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X