svg / d3.js coins arrondis sur un coin d'un rectangle

Je sais que svg a une fonction intégrée pour faire des coins arrondis, mais je dois faire des coins arrondis sur seulement 2 des quatre coins.

Je sais que je peux dessiner plusieurs rectangles les uns sur les autres pour imiter cela, mais cela semble un peu ringard. Toute façon de le faire en utilisant l'écrêtage ou tout d3.méthode js?

Maintenant j'ai un graphique à barres horizontales qui a rectangles comme:

    rects.enter().append("rect")
        .attr("x",function(d,i) { return x(0); })
        .attr("width",function(d) { return x(d.value) - x(0); })
        .attr("height",y.rangeBand())
        .attr("y",function(d) { return y(d.name); })

J'essaie de produire des coins arrondis sur le côté droit du rect, mais je ne sais pas comment le faire.

25
demandé sur paxRoman 2012-08-24 23:44:32

5 réponses

En développant la réponse de @ robert-longson, vous pouvez utiliser les commandes D'arc elliptique de SVG pour créer les coins, en conjonction avec les commandes lineto pour les bords droits. Ceux-ci sont utilisés avec éléments de chemin. Voici une implémentation possible:

// Returns path data for a rectangle with rounded right corners.
// The top-left corner is ⟨x,y⟩.
function rightRoundedRect(x, y, width, height, radius) {
  return "M" + x + "," + y
       + "h" + (width - radius)
       + "a" + radius + "," + radius + " 0 0 1 " + radius + "," + radius
       + "v" + (height - 2 * radius)
       + "a" + radius + "," + radius + " 0 0 1 " + -radius + "," + radius
       + "h" + (radius - width)
       + "z";
}

Vous pouvez alors appeler cette fonction pour calculer l'attribut "d". Par exemple:

rects.enter().append("path")
    .attr("d", function(d) {
      return rightRoundedRect(x(0), y(d.name), x(d.value) - x(0), y.rangeBand(), 10);
    });

Exemple en direct:

Facultatif: Si vous aimez, vous pouvez refactoriser le rightRoundedRect à configurable, plutôt que de prendre beaucoup d'arguments. Cette approche serait similaire aux générateurs de forme intégrés de D3 . Par exemple, vous pouvez utiliser un générateur rect comme ceci:

rects.enter().append("path")
    .attr("d", rightRoundedRect()
      .x(x(0))
      .y(function(d) { return y(d.name); })
      .width(function(d) { return x(d.value) - x(0); })
      .height(y.rangeBand())
      .radius(10));

Pour plus de détails sur cette approche, consultez le tutoriel Fonction configurable.

57
répondu mbostock 2014-02-17 23:30:49

Juste pour développer les réponses données, Voici une fonction plus complète pour retourner le chemin pour votre rect.

x: x-coordinate
y: y-coordinate
w: width
h: height
r: corner radius
tl: top_left rounded?
tr: top_right rounded?
bl: bottom_left rounded?
br: bottom_right rounded?

function rounded_rect(x, y, w, h, r, tl, tr, bl, br) {
    var retval;
    retval  = "M" + (x + r) + "," + y;
    retval += "h" + (w - 2*r);
    if (tr) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + r; }
    else { retval += "h" + r; retval += "v" + r; }
    retval += "v" + (h - 2*r);
    if (br) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + r; }
    else { retval += "v" + r; retval += "h" + -r; }
    retval += "h" + (2*r - w);
    if (bl) { retval += "a" + r + "," + r + " 0 0 1 " + -r + "," + -r; }
    else { retval += "h" + -r; retval += "v" + -r; }
    retval += "v" + (2*r - h);
    if (tl) { retval += "a" + r + "," + r + " 0 0 1 " + r + "," + -r; }
    else { retval += "v" + -r; retval += "h" + r; }
    retval += "z";
    return retval;
}
29
répondu stackmate 2012-11-22 03:50:44

Au cas où d'autres finiraient par vouloir arrondir tous les coins d'un élément rect, vous pouvez ajouter un attribut rx à l'élément rect (comme le mentionne @mbostock dans son violon ci-dessus):

var rectangle = group.append("rect")
    .attr("width", 60)
    .attr("height", 75)
    .attr("rx", 4)
    .style("fill", function(d) { return "#e6653e"; })
    .style("stroke", function(d) { return d3.rgb("#e6653e").darker(); })
6
répondu duhaime 2017-01-23 12:53:22

Vous pouvez utiliser un chemin qui trace un rectangle avec deux coins arrondis.

3
répondu Robert Longson 2012-08-24 22:58:36

Toute personne qui cherche une version Eslinted de stackmate-s Réponse:

function roundedRect(x, y, w, h, r, tl, tr, bl, br) {
  let retval;
  retval = `M${x + r},${y}`;
  retval += `h${w - (2 * r)}`;
  if (tr) {
    retval += `a${r},${r} 0 0 1 ${r},${r}`;
  } else {
    retval += `h${r}`; retval += `v${r}`;
  }
  retval += `v${h - (2 * r)}`;
  if (br) {
    retval += `a${r},${r} 0 0 1 ${-r},${r}`;
  } else {
    retval += `v${r}`; retval += `h${-r}`;
  }
  retval += `h${(2 * r) - w}`;
  if (bl) {
    retval += `a${r},${r} 0 0 1 ${-r},${-r}`;
  } else {
    retval += `h${-r}`; retval += `v${-r}`;
  }
  retval += `v${((2 * r) - h)}`;
  if (tl) {
    retval += `a${r},${r} 0 0 1 ${r},${-r}`;
  } else {
    retval += `v${-r}`; retval += `h${r}`;
  }
  retval += 'z';
  return retval;
}
2
répondu Barna Burom 2017-02-24 14:38:50